Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH 3/3] i2400m-sdio: select IWMC3200TOP in Kconfig
From: Tomas Winkler @ 2009-09-23  5:36 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: davem, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
	inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <1253666644.2931.7.camel@localhost.localdomain>

On Wed, Sep 23, 2009 at 3:44 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Tomas,
>
>> i2400m-sdio requires iwmc3200top for its operation
>>
>> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
>> ---
>>  drivers/net/wimax/i2400m/Kconfig |    1 +
>>  1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
>> index d623b3d..7368ad5 100644
>> --- a/drivers/net/wimax/i2400m/Kconfig
>> +++ b/drivers/net/wimax/i2400m/Kconfig
>> @@ -25,6 +25,7 @@ config WIMAX_I2400M_SDIO
>>       tristate "Intel Wireless WiMAX Connection 2400 over SDIO"
>>       depends on WIMAX && MMC
>>       select WIMAX_I2400M
>> +     select IWMC3200TOP
>>       help
>>         Select if you have a device based on the Intel WiMAX
>>         Connection 2400 over SDIO.
>
> this is not true actually. Since the WiMAX hardware in my laptop doesn't
> require the top driver.
>
SDIO?

Thanks
Tomas

^ permalink raw reply

* Re: zd1211rw on ppc (iBook G4)
From: Hin-Tak Leung @ 2009-09-23  0:50 UTC (permalink / raw)
  To: Leonardo H. Souza Hamada; +Cc: linux-wireless
In-Reply-To: <4A9D7DC0.6050701@ufra.edu.br>

On Tue, Sep 1, 2009 at 9:02 PM, Leonardo H. Souza Hamada
<leonardo.hamada@ufra.edu.br> wrote:

> Hin-Tak Leung wrote:
>> I have a bunch of patches which bring the 2.22 vendor driver up to
>> 2.6.29 and 3.0 the vendor driver up to 2.6.30:
>> http://htl10.users.sourceforge.net/patchsets/
>> It doesn't fix the rw driver, but might be good enough for you?
>>
>
> I have downloaded the vendor driver and applied your patchset.
>
> Inserted the vendor  { USB_DEVICE(0x0411, 0x00DA) }, in
> ar2524drv/src/zdusb.c
>
> Recompiled as zd1211REV_B
>
> dmesg for vendor driver:
> udev: starting version 145
>
>  _____     ____    _    ____
> |__  /   _|  _ \  / \  / ___|
>  / / | | | | | |/ _ \ \___ \
>  / /| |_| | |_| / ___ \ ___) |
> /____\__, |____/_/   \_\____/
>     |___/
> zd1211 - version 3.0.0.56
> vendor_id = 0411
> product_id = 00da
> USB 2.0 Host
> Release Ver = 4810
> EEPORM Ver = 4330
> Finsih download Firmware. Ready to reboot
> Finsih download Firmware. Ready to reboot
> Finsih download Firmware. Ready to reboot
> ohci1394 0002:20:0e.0: enabling device (0000 -> 0002)
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> ohci1394: fw-host0: OHCI-1394 1.1 (PCI): IRQ=[40]
> MMIO=[f5000000-f50007ff]  Max Packet=[2048]  IR/IT contexts=[8/8]
> PA type: 2
> Airoha AL2230S_RF
> Overwrite CR157 = 0x0
> Overwrite CR47 = 0x10019
> zd1205_config: EEP(HWFeature)=0xF7D0
> AllowedChannel = 00013fff
> Region:0
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> usbcore: registered new interface driver zd1211
>
>
> I am able to do iwlist ath0 scanning, a list of acess point appears but
> sometimes this fails.
> iwlist ath0 scanning:
> ath0      Scan completed :
>          Cell 01 - Address: 00:21:91:0E:0B:F7
>                    ESSID:"adminWF10"
>                    Mode:Master
>                    Frequency=2.412 GHz (Channel 1)
>                    Quality=46/100  Signal level=-74 dBm  Noise
> level=-96 dBm
>                    Encryption key:off
>                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
>                              12 Mb/s; 24 Mb/s; 36 Mb/s; 9 Mb/s; 18 Mb/s
>                              48 Mb/s; 54 Mb/s
>                    Extra:bcn_int=100
>          Cell 02 - Address: 00:1D:0F:D1:4D:D2
>                    ESSID:"LGAA_P_CENTRAL_WF01"
>                    Mode:Master
>                    Frequency=2.437 GHz (Channel 6)
>                    Quality=43/100  Signal level=-76 dBm  Noise
> level=-96 dBm
>                    Encryption key:off
>                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
>                              12 Mb/s; 24 Mb/s; 36 Mb/s; 9 Mb/s; 18 Mb/s
>                              48 Mb/s; 54 Mb/s
>                    Extra:bcn_int=100
>          Cell 03 - Address: 00:1B:11:87:A7:0C
>                    ESSID:"ponto-acesso-mutsuo"
>                    Mode:Master
>                    Frequency=2.437 GHz (Channel 6)
>                    Quality=43/100  Signal level=-76 dBm  Noise
> level=-96 dBm
>                    Encryption key:off
>                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
>                              9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s; 36 Mb/s
>                              48 Mb/s; 54 Mb/s
>                    Extra:bcn_int=100
>
>
> Scan again, it fails and works seemingly in an unknown manner.
> iwlist ath0 scanning
> ath0      Failed to read scan data : Resource temporarily unavailable
>
>
> Some message in dmesg of relevance:
> ...
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> zd1211_USB_PACKAGE_READ_REGISTER: warning, restarting INT EP
> zd1211_readl retry OK
> ....(many times over)
>
> and
>
> 1211_readl failed for 5 attempts...Very Serious<3>1211_readl failed for
> 5 attempts...Very Serious<3>1211_readl failed for 5 attempts...Very
> Serious<3>1211_readl failed for 5 attempts...Very Serious<3>1211_readl
> failed for 5 attempts...Very Serious<3>1211_readl failed for 5
> attempts...Very Serious<3>1211_readl failed for 5 attempts...Very
> Serious<3>1211_readl failed for 5 attempts...Very Serious<3>1211_readl
> failed for 5 attempts...Very Serious<3>1211_readl failed for 5
> attempts...Very Serious<3>1211_readl failed for 5 attempts...Very
> Serious<3>1211_readl failed for 5 attempts...Very Serious<3>1211_readl
> failed for 5 attempts...Very Serious<3>1211_readl failed for 5
> attempts...Very Serious<3>1211_readl failed for 5 attempts...Very
> Serious<7>zd1205_notify_disjoin_event
>
> Giving up .... for now.

I found that one of the patches -
0004-forward-port-of-an-old-patch-from-the-internet.patch - is buggy,
and breaks USB 2.0 host... wanna undo that and have another go?
(that's also the one that adds the 'read failed after 5 attempts",
etc).

^ permalink raw reply

* Re: [PATCH 3/3] i2400m-sdio: select IWMC3200TOP in Kconfig
From: Marcel Holtmann @ 2009-09-23  0:44 UTC (permalink / raw)
  To: Tomas Winkler
  Cc: davem, linville, netdev, linux-wireless, linux-mmc, yi.zhu,
	inaky.perez-gonzalez, cindy.h.kao, guy.cohen, ron.rindjunsky
In-Reply-To: <1253662724-16497-4-git-send-email-tomas.winkler@intel.com>

Hi Tomas,

> i2400m-sdio requires iwmc3200top for its operation
> 
> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
> ---
>  drivers/net/wimax/i2400m/Kconfig |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
> index d623b3d..7368ad5 100644
> --- a/drivers/net/wimax/i2400m/Kconfig
> +++ b/drivers/net/wimax/i2400m/Kconfig
> @@ -25,6 +25,7 @@ config WIMAX_I2400M_SDIO
>  	tristate "Intel Wireless WiMAX Connection 2400 over SDIO"
>  	depends on WIMAX && MMC
>  	select WIMAX_I2400M
> +	select IWMC3200TOP
>  	help
>  	  Select if you have a device based on the Intel WiMAX
>  	  Connection 2400 over SDIO.

this is not true actually. Since the WiMAX hardware in my laptop doesn't
require the top driver.

Regards

Marcel



^ permalink raw reply

* [PATCH 3/3] i2400m-sdio: select IWMC3200TOP in Kconfig
From: Tomas Winkler @ 2009-09-22 23:38 UTC (permalink / raw)
  To: davem, linville, netdev, linux-wireless, linux-mmc
  Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
	ron.rindjunsky, Tomas Winkler
In-Reply-To: <1253662724-16497-3-git-send-email-tomas.winkler@intel.com>

i2400m-sdio requires iwmc3200top for its operation

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/net/wimax/i2400m/Kconfig |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
index d623b3d..7368ad5 100644
--- a/drivers/net/wimax/i2400m/Kconfig
+++ b/drivers/net/wimax/i2400m/Kconfig
@@ -25,6 +25,7 @@ config WIMAX_I2400M_SDIO
 	tristate "Intel Wireless WiMAX Connection 2400 over SDIO"
 	depends on WIMAX && MMC
 	select WIMAX_I2400M
+	select IWMC3200TOP
 	help
 	  Select if you have a device based on the Intel WiMAX
 	  Connection 2400 over SDIO.
-- 
1.6.0.6

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply related

* [PATCH 2/3] iwmc3200wifi: select IWMC3200TOP in Kconfig
From: Tomas Winkler @ 2009-09-22 23:38 UTC (permalink / raw)
  To: davem, linville, netdev, linux-wireless, linux-mmc
  Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
	ron.rindjunsky, Tomas Winkler
In-Reply-To: <1253662724-16497-2-git-send-email-tomas.winkler@intel.com>

iwmc3200wifi requires iwmc3200top  for its operation

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/net/wireless/iwmc3200wifi/Kconfig |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index c62da43..69faaf1 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -3,6 +3,7 @@ config IWM
 	depends on MMC && WLAN_80211 && EXPERIMENTAL
 	depends on CFG80211
 	select FW_LOADER
+	select IWMC3200TOP
 	help
 	  The Intel Wireless Multicomm 3200 hardware is a combo
 	  card with GPS, Bluetooth, WiMax and 802.11 radios. It
-- 
1.6.0.6

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply related

* [PATCH 1/3] iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
From: Tomas Winkler @ 2009-09-22 23:38 UTC (permalink / raw)
  To: davem, linville, netdev, linux-wireless, linux-mmc
  Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
	ron.rindjunsky, Tomas Winkler
In-Reply-To: <1253662724-16497-1-git-send-email-tomas.winkler@intel.com>

This patch adds Intel Wireless MultiCom 3200 top driver.
IWMC3200 is 4Wireless Com CHIP (GPS/BT/WiFi/WiMAX).
Top driver is responsible for device initialization and firmware download.
Firmware handled by top is responsible for top itself and
as well as bluetooth and GPS coms. (Wifi and WiMax provide their own
firmware)
In addition top driver is used to retrieve firmware logs
and supports other debugging features

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/Kconfig                   |    1 +
 drivers/misc/Makefile                  |    1 +
 drivers/misc/iwmc3200top/Kconfig       |   20 +
 drivers/misc/iwmc3200top/Makefile      |   29 ++
 drivers/misc/iwmc3200top/debugfs.c     |  145 +++++++
 drivers/misc/iwmc3200top/debugfs.h     |   61 +++
 drivers/misc/iwmc3200top/fw-download.c |  359 ++++++++++++++++
 drivers/misc/iwmc3200top/fw-msg.h      |  113 +++++
 drivers/misc/iwmc3200top/iwmc3200top.h |  202 +++++++++
 drivers/misc/iwmc3200top/log.c         |  339 +++++++++++++++
 drivers/misc/iwmc3200top/log.h         |  158 +++++++
 drivers/misc/iwmc3200top/main.c        |  702 ++++++++++++++++++++++++++++++++
 12 files changed, 2130 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/iwmc3200top/Kconfig
 create mode 100644 drivers/misc/iwmc3200top/Makefile
 create mode 100644 drivers/misc/iwmc3200top/debugfs.c
 create mode 100644 drivers/misc/iwmc3200top/debugfs.h
 create mode 100644 drivers/misc/iwmc3200top/fw-download.c
 create mode 100644 drivers/misc/iwmc3200top/fw-msg.h
 create mode 100644 drivers/misc/iwmc3200top/iwmc3200top.h
 create mode 100644 drivers/misc/iwmc3200top/log.c
 create mode 100644 drivers/misc/iwmc3200top/log.h
 create mode 100644 drivers/misc/iwmc3200top/main.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 68ab39d..6f85b43 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -236,5 +236,6 @@ config ISL29003
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
+source "drivers/misc/iwmc3200top/Kconfig"
 
 endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 36f733c..97f5303 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_SGI_GRU)		+= sgi-gru/
 obj-$(CONFIG_HP_ILO)		+= hpilo.o
 obj-$(CONFIG_ISL29003)		+= isl29003.o
 obj-$(CONFIG_C2PORT)		+= c2port/
+obj-$(CONFIG_IWMC3200TOP)      += iwmc3200top/
 obj-y				+= eeprom/
 obj-y				+= cb710/
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig
new file mode 100644
index 0000000..9e4b88f
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Kconfig
@@ -0,0 +1,20 @@
+config IWMC3200TOP
+        tristate "Intel Wireless MultiCom Top Driver"
+        depends on MMC && EXPERIMENTAL
+        select FW_LOADER
+	---help---
+	  Intel Wireless MultiCom 3200 Top driver is responsible for
+	  for firmware load and enabled coms enumeration
+
+config IWMC3200TOP_DEBUG
+	bool "Enable full debug output of iwmc3200top Driver"
+	depends on IWMC3200TOP
+	---help---
+	  Enable full debug output of iwmc3200top Driver
+
+config IWMC3200TOP_DEBUGFS
+	bool "Enable Debugfs debugging interface for iwmc3200top"
+	depends on IWMC3200TOP
+	---help---
+	  Enable creation of debugfs files for iwmc3200top
+
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile
new file mode 100644
index 0000000..fbf53fb
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Makefile
@@ -0,0 +1,29 @@
+# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+# drivers/misc/iwmc3200top/Makefile
+#
+# Copyright (C) 2009 Intel Corporation. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version
+# 2 as published by the Free Software Foundation.
+#
+# 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-1301, USA.
+#
+#
+# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+#  -
+#
+#
+
+obj-$(CONFIG_IWMC3200TOP)	+= iwmc3200top.o
+iwmc3200top-objs	:= main.o fw-download.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
+iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c
new file mode 100644
index 0000000..a531f6c
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.c
@@ -0,0 +1,145 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+#include "debugfs.h"
+
+/*      Constants definition        */
+#define HEXADECIMAL_RADIX	16
+
+/*      Functions definition        */
+
+
+/*      Debugfs macros       */
+#define DEBUGFS_ADD_DIR(name, parent) do {			\
+	dbgfs->dir_##name = debugfs_create_dir(#name, parent);	\
+	if (!(dbgfs->dir_##name))				\
+		goto err;					\
+} while (0)
+
+#define DEBUGFS_ADD_FILE(name, parent) do {				\
+	dbgfs->dbgfs_##parent##_files.file_##name =                     \
+	debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv,     \
+				&iwmct_dbgfs_##name##_ops);               \
+	if (!(dbgfs->dbgfs_##parent##_files.file_##name))		\
+		goto err;						\
+} while (0)
+
+#define DEBUGFS_REMOVE(name)  do {	\
+	debugfs_remove(name);		\
+	name = NULL;			\
+} while (0)
+
+#define DEBUGFS_READ_FUNC(name)						\
+ssize_t iwmct_dbgfs_##name##_read(struct file *file,			\
+				  char __user *user_buf,		\
+				  size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)					\
+ssize_t iwmct_dbgfs_##name##_write(struct file *file,			\
+				   const char __user *user_buf,		\
+				   size_t count, loff_t *ppos);
+
+#define DEBUGFS_READ_FILE_OPS(name)					\
+	DEBUGFS_READ_FUNC(name)						\
+	static const struct file_operations iwmct_dbgfs_##name##_ops = {  \
+		.read = iwmct_dbgfs_##name##_read,			\
+		.open = iwmct_dbgfs_open_file_generic,			\
+	};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)					\
+	DEBUGFS_WRITE_FUNC(name)					\
+	static const struct file_operations iwmct_dbgfs_##name##_ops = {  \
+		.write = iwmct_dbgfs_##name##_write,			\
+		.open = iwmct_dbgfs_open_file_generic,			\
+	};
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)				\
+	DEBUGFS_READ_FUNC(name)						\
+	DEBUGFS_WRITE_FUNC(name)					\
+	static const struct file_operations iwmct_dbgfs_##name##_ops = {\
+		.write = iwmct_dbgfs_##name##_write,			\
+		.read = iwmct_dbgfs_##name##_read,			\
+		.open = iwmct_dbgfs_open_file_generic,			\
+	};
+
+
+/*      Debugfs file ops definitions        */
+
+/*      Debugfs registration functions        */
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{
+	struct iwmct_debugfs *dbgfs;
+
+	dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
+	if (!dbgfs) {
+		LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
+					sizeof(struct iwmct_debugfs));
+		goto err;
+	}
+
+	priv->dbgfs = dbgfs;
+	dbgfs->name = name;
+	dbgfs->dir_drv = debugfs_create_dir(name, NULL);
+	if (!dbgfs->dir_drv) {
+		LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
+		goto err;
+	}
+
+
+err:
+	return;
+}
+
+/**
+ * Remove the debugfs files and directories
+ *
+ */
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{
+	if (!dbgfs)
+		return;
+
+
+	DEBUGFS_REMOVE(dbgfs->dir_drv);
+	kfree(dbgfs);
+
+	dbgfs = NULL;
+}
+
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h
new file mode 100644
index 0000000..24b1369
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.h
@@ -0,0 +1,61 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/debufs.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#ifndef __DEBUGFS_H__
+#define __DEBUGFS_H__
+
+
+#ifdef CONFIG_IWMC3200TOP_DEBUGFS
+
+#include <linux/debugfs.h>
+
+struct iwmct_debugfs {
+	const char *name;
+	struct dentry *dir_drv;
+	struct dir_drv_files {
+	} dbgfs_drv_files;
+};
+
+void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
+void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
+
+#else /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+/* struct iwmct_debugfs is empty if CONFIG_IWMC3200TOP_DEBUGFS is not defined */
+struct iwmct_debugfs {
+};
+
+static inline void
+iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
+{}
+
+static inline void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
+{}
+
+#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
+
+#endif /* __DEBUGFS_H__ */
+
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c
new file mode 100644
index 0000000..33cb693
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-download.c
@@ -0,0 +1,359 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-download.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#include <linux/firmware.h>
+#include <linux/mmc/sdio_func.h>
+#include <asm/unaligned.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+
+#define CHECKSUM_BYTES_NUM sizeof(u32)
+
+/**
+  init parser struct with file
+ */
+static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
+			      size_t file_size, size_t block_size)
+{
+	struct iwmct_parser *parser = &priv->parser;
+	struct iwmct_fw_hdr *fw_hdr = &parser->versions;
+
+	LOG_INFOEX(priv, INIT, "-->\n");
+
+	LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
+
+	parser->file = file;
+	parser->file_size = file_size;
+	parser->cur_pos = 0;
+	parser->buf = NULL;
+
+	parser->buf = kzalloc(block_size, GFP_KERNEL);
+	if (!parser->buf) {
+		LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
+		return -ENOMEM;
+	}
+	parser->buf_size = block_size;
+
+	/* extract fw versions */
+	memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr));
+	LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n"
+		"top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n",
+		fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision,
+		fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision,
+		fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision,
+		fw_hdr->tic_name);
+
+	parser->cur_pos += sizeof(struct iwmct_fw_hdr);
+
+	LOG_INFOEX(priv, INIT, "<--\n");
+	return 0;
+}
+
+static bool iwmct_checksum(struct iwmct_priv *priv)
+{
+	struct iwmct_parser *parser = &priv->parser;
+	__le32 *file = (__le32 *)parser->file;
+	int i, pad, steps;
+	u32 accum = 0;
+	u32 checksum;
+	u32 mask = 0xffffffff;
+
+	pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4;
+	steps =  (parser->file_size - CHECKSUM_BYTES_NUM) / 4;
+
+	LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps);
+
+	for (i = 0; i < steps; i++)
+		accum += le32_to_cpu(file[i]);
+
+	if (pad) {
+		mask <<= 8 * (4 - pad);
+		accum += le32_to_cpu(file[steps]) & mask;
+	}
+
+	checksum = get_unaligned_le32((__le32 *)(parser->file +
+			parser->file_size - CHECKSUM_BYTES_NUM));
+
+	LOG_INFO(priv, FW_DOWNLOAD,
+		"compare checksum accum=0x%x to checksum=0x%x\n",
+		accum, checksum);
+
+	return checksum == accum;
+}
+
+static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
+				  size_t *sec_size, __le32 *sec_addr)
+{
+	struct iwmct_parser *parser = &priv->parser;
+	struct iwmct_dbg *dbg = &priv->dbg;
+	struct iwmct_fw_sec_hdr *sec_hdr;
+
+	LOG_INFOEX(priv, INIT, "-->\n");
+
+	while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
+		<= parser->file_size) {
+
+		sec_hdr = (struct iwmct_fw_sec_hdr *)
+				(parser->file + parser->cur_pos);
+		parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr);
+
+		LOG_INFO(priv, FW_DOWNLOAD,
+			"sec hdr: type=%s addr=0x%x size=%d\n",
+			sec_hdr->type, sec_hdr->target_addr,
+			sec_hdr->data_size);
+
+		if (strcmp(sec_hdr->type, "ENT") == 0)
+			parser->entry_point = le32_to_cpu(sec_hdr->target_addr);
+		else if (strcmp(sec_hdr->type, "LBL") == 0)
+			strcpy(dbg->label_fw, parser->file + parser->cur_pos);
+		else if (((strcmp(sec_hdr->type, "TOP") == 0) &&
+			  (priv->barker & BARKER_DNLOAD_TOP_MSK)) ||
+			 ((strcmp(sec_hdr->type, "GPS") == 0) &&
+			  (priv->barker & BARKER_DNLOAD_GPS_MSK)) ||
+			 ((strcmp(sec_hdr->type, "BTH") == 0) &&
+			  (priv->barker & BARKER_DNLOAD_BT_MSK))) {
+			*sec_addr = sec_hdr->target_addr;
+			*sec_size = le32_to_cpu(sec_hdr->data_size);
+			*p_sec = parser->file + parser->cur_pos;
+			parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+			return 1;
+		} else if (strcmp(sec_hdr->type, "LOG") != 0)
+			LOG_WARNING(priv, FW_DOWNLOAD,
+				    "skipping section type %s\n",
+				    sec_hdr->type);
+
+		parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
+		LOG_INFO(priv, FW_DOWNLOAD,
+			"finished with section cur_pos=%zd\n", parser->cur_pos);
+	}
+
+	LOG_INFOEX(priv, INIT, "<--\n");
+	return 0;
+}
+
+static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
+				size_t sec_size, __le32 addr)
+{
+	struct iwmct_parser *parser = &priv->parser;
+	struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+	const u8 *cur_block = p_sec;
+	size_t sent = 0;
+	int cnt = 0;
+	int ret = 0;
+	u32 cmd = 0;
+
+	LOG_INFOEX(priv, INIT, "-->\n");
+	LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
+				addr, sec_size);
+
+	while (sent < sec_size) {
+		int i;
+		u32 chksm = 0;
+		u32 reset = atomic_read(&priv->reset);
+		/* actual FW data */
+		u32 data_size = min(parser->buf_size - sizeof(*hdr),
+				    sec_size - sent);
+		/* Pad to block size */
+		u32 trans_size = (data_size + sizeof(*hdr) +
+				  IWMC_SDIO_BLK_SIZE - 1) &
+				  ~(IWMC_SDIO_BLK_SIZE - 1);
+		++cnt;
+
+		/* in case of reset, interrupt FW DOWNLAOD */
+		if (reset) {
+			LOG_INFO(priv, FW_DOWNLOAD,
+				 "Reset detected. Abort FW download!!!");
+			ret = -ECANCELED;
+			goto exit;
+		}
+
+		memset(parser->buf, 0, parser->buf_size);
+		cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
+		cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+		cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
+		cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
+		hdr->data_size = cpu_to_le32(data_size);
+		hdr->target_addr = addr;
+
+		/* checksum is allowed for sizes divisible by 4 */
+		if (data_size & 0x3)
+			cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;
+
+		memcpy(hdr->data, cur_block, data_size);
+
+
+		if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {
+
+			chksm = data_size + le32_to_cpu(addr) + cmd;
+			for (i = 0; i < data_size >> 2; i++)
+				chksm += ((u32 *)cur_block)[i];
+
+			hdr->block_chksm = cpu_to_le32(chksm);
+			LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
+				 hdr->block_chksm);
+		}
+
+		LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
+				"sec_size=%zd, startAddress 0x%X\n",
+				cnt, trans_size, sent, sec_size, addr);
+
+		if (priv->dbg.dump)
+			LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);
+
+
+		hdr->cmd = cpu_to_le32(cmd);
+		/* send it down */
+		/* TODO: add more proper sending and error checking */
+		ret = iwmct_tx(priv, 0, parser->buf, trans_size);
+		if (ret != 0) {
+			LOG_INFO(priv, FW_DOWNLOAD,
+				"iwmct_tx returned %d\n", ret);
+			goto exit;
+		}
+
+		addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
+		sent += data_size;
+		cur_block = p_sec + sent;
+
+		if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
+			LOG_INFO(priv, FW_DOWNLOAD,
+				"Block number limit is reached [%d]\n",
+				priv->dbg.blocks);
+			break;
+		}
+	}
+
+	if (sent < sec_size)
+		ret = -EINVAL;
+exit:
+	LOG_INFOEX(priv, INIT, "<--\n");
+	return ret;
+}
+
+static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
+{
+	struct iwmct_parser *parser = &priv->parser;
+	struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
+	int ret;
+	u32 cmd;
+
+	LOG_INFOEX(priv, INIT, "-->\n");
+
+	memset(parser->buf, 0, parser->buf_size);
+	cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
+	if (jump) {
+		cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
+		hdr->target_addr = cpu_to_le32(parser->entry_point);
+		LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
+				parser->entry_point);
+	} else {
+		cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
+		LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
+	}
+
+	hdr->cmd = cpu_to_le32(cmd);
+
+	LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
+	/* send it down */
+	/* TODO: add more proper sending and error checking */
+	ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
+	if (ret)
+		LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
+
+	LOG_INFOEX(priv, INIT, "<--\n");
+	return 0;
+}
+
+int iwmct_fw_load(struct iwmct_priv *priv)
+{
+	const struct firmware *raw = NULL;
+	__le32 addr;
+	size_t len;
+	const u8 *pdata;
+	const u8 *name = "iwmc3200top.1.fw";
+	int ret = 0;
+
+	/* clear parser struct */
+	memset(&priv->parser, 0, sizeof(struct iwmct_parser));
+	if (!name) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	/* get the firmware */
+	ret = request_firmware(&raw, name, &priv->func->dev);
+	if (ret < 0) {
+		LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n",
+			  name, ret);
+		goto exit;
+	}
+
+	if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) {
+		LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n",
+			  name, sizeof(struct iwmct_fw_sec_hdr), raw->size);
+		goto exit;
+	}
+
+	LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", name);
+
+	ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
+	if (ret < 0) {
+		LOG_ERROR(priv, FW_DOWNLOAD,
+			  "iwmct_parser_init failed: Reason %d\n", ret);
+		goto exit;
+	}
+
+	/* checksum  */
+	if (!iwmct_checksum(priv)) {
+		LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	/* download firmware to device */
+	while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
+		if (iwmct_download_section(priv, pdata, len, addr)) {
+			LOG_ERROR(priv, FW_DOWNLOAD,
+				  "%s download section failed\n", name);
+			ret = -EIO;
+			goto exit;
+		}
+	}
+
+	iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
+
+exit:
+	kfree(priv->parser.buf);
+
+	if (raw)
+		release_firmware(raw);
+
+	raw = NULL;
+
+	return ret;
+}
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h
new file mode 100644
index 0000000..9e26b75
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-msg.h
@@ -0,0 +1,113 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/fw-msg.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#ifndef __FWMSG_H__
+#define __FWMSG_H__
+
+#define COMM_TYPE_D2H           	0xFF
+#define COMM_TYPE_H2D           	0xEE
+
+#define COMM_CATEGORY_OPERATIONAL      	0x00
+#define COMM_CATEGORY_DEBUG            	0x01
+#define COMM_CATEGORY_TESTABILITY      	0x02
+#define COMM_CATEGORY_DIAGNOSTICS      	0x03
+
+#define OP_DBG_ZSTR_MSG			cpu_to_le16(0x1A)
+
+#define FW_LOG_SRC_MAX			32
+#define FW_LOG_SRC_ALL			255
+
+#define FW_STRING_TABLE_ADDR		cpu_to_le32(0x0C000000)
+
+#define CMD_DBG_LOG_LEVEL		cpu_to_le16(0x0001)
+#define CMD_TST_DEV_RESET		cpu_to_le16(0x0060)
+#define CMD_TST_FUNC_RESET		cpu_to_le16(0x0062)
+#define CMD_TST_IFACE_RESET		cpu_to_le16(0x0064)
+#define CMD_TST_CPU_UTILIZATION		cpu_to_le16(0x0065)
+#define CMD_TST_TOP_DEEP_SLEEP		cpu_to_le16(0x0080)
+#define CMD_TST_WAKEUP			cpu_to_le16(0x0081)
+#define CMD_TST_FUNC_WAKEUP		cpu_to_le16(0x0082)
+#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST	cpu_to_le16(0x0083)
+#define CMD_TST_GET_MEM_DUMP		cpu_to_le16(0x0096)
+
+#define OP_OPR_ALIVE			cpu_to_le16(0x0010)
+#define OP_OPR_CMD_ACK			cpu_to_le16(0x001F)
+#define OP_OPR_CMD_NACK			cpu_to_le16(0x0020)
+#define OP_TST_MEM_DUMP			cpu_to_le16(0x0043)
+
+#define CMD_FLAG_PADDING_256		0x80
+
+#define FW_HCMD_BLOCK_SIZE      	256
+
+struct msg_hdr {
+	u8 type;
+	u8 category;
+	__le16 opcode;
+	u8 seqnum;
+	u8 flags;
+	__le16 length;
+} __attribute__((__packed__));
+
+struct log_hdr {
+	__le32 timestamp;
+	u8 severity;
+	u8 logsource;
+	__le16 reserved;
+} __attribute__((__packed__));
+
+struct mdump_hdr {
+	u8 dmpid;
+	u8 frag;
+	__le16 size;
+	__le32 addr;
+} __attribute__((__packed__));
+
+struct top_msg {
+	struct msg_hdr hdr;
+	union {
+		/* D2H messages */
+		struct {
+			struct log_hdr log_hdr;
+			u8 data[1];
+		} __attribute__((__packed__)) log;
+
+		struct {
+			struct log_hdr log_hdr;
+			struct mdump_hdr md_hdr;
+			u8 data[1];
+		} __attribute__((__packed__)) mdump;
+
+		/* H2D messages */
+		struct {
+			u8 logsource;
+			u8 sevmask;
+		} __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
+		struct mdump_hdr mdump_req;
+	} u;
+} __attribute__((__packed__));
+
+
+#endif /* __FWMSG_H__ */
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h
new file mode 100644
index 0000000..59e4b7a
--- /dev/null
+++ b/drivers/misc/iwmc3200top/iwmc3200top.h
@@ -0,0 +1,202 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/iwmc3200top.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#ifndef __IWMC3200TOP_H__
+#define __IWMC3200TOP_H__
+
+#define DRV_NAME "iwmc3200top"
+
+#define IWMC_SDIO_BLK_SIZE			256
+#define IWMC_DEFAULT_TR_BLK			64
+#define IWMC_SDIO_DATA_ADDR			0x0
+#define IWMC_SDIO_INTR_ENABLE_ADDR		0x14
+#define IWMC_SDIO_INTR_STATUS_ADDR		0x13
+#define IWMC_SDIO_INTR_CLEAR_ADDR		0x13
+#define IWMC_SDIO_INTR_GET_SIZE_ADDR		0x2C
+
+#define COMM_HUB_HEADER_LENGTH 16
+#define LOGGER_HEADER_LENGTH   10
+
+
+#define BARKER_DNLOAD_BT_POS		0
+#define BARKER_DNLOAD_BT_MSK		BIT(BARKER_DNLOAD_BT_POS)
+#define BARKER_DNLOAD_GPS_POS		1
+#define BARKER_DNLOAD_GPS_MSK		BIT(BARKER_DNLOAD_GPS_POS)
+#define BARKER_DNLOAD_TOP_POS		2
+#define BARKER_DNLOAD_TOP_MSK		BIT(BARKER_DNLOAD_TOP_POS)
+#define BARKER_DNLOAD_RESERVED1_POS	3
+#define BARKER_DNLOAD_RESERVED1_MSK	BIT(BARKER_DNLOAD_RESERVED1_POS)
+#define BARKER_DNLOAD_JUMP_POS		4
+#define BARKER_DNLOAD_JUMP_MSK		BIT(BARKER_DNLOAD_JUMP_POS)
+#define BARKER_DNLOAD_SYNC_POS		5
+#define BARKER_DNLOAD_SYNC_MSK		BIT(BARKER_DNLOAD_SYNC_POS)
+#define BARKER_DNLOAD_RESERVED2_POS	6
+#define BARKER_DNLOAD_RESERVED2_MSK	(0x3 << BARKER_DNLOAD_RESERVED2_POS)
+#define BARKER_DNLOAD_BARKER_POS	8
+#define BARKER_DNLOAD_BARKER_MSK	(0xffffff << BARKER_DNLOAD_BARKER_POS)
+
+#define IWMC_BARKER_REBOOT 	(0xdeadbe << BARKER_DNLOAD_BARKER_POS)
+/* whole field barker */
+#define IWMC_BARKER_ACK 	0xfeedbabe
+
+#define IWMC_CMD_SIGNATURE 	0xcbbc
+
+#define CMD_HDR_OPCODE_POS		0
+#define CMD_HDR_OPCODE_MSK_MSK		(0xf << CMD_HDR_OPCODE_MSK_POS)
+#define CMD_HDR_RESPONSE_CODE_POS	4
+#define CMD_HDR_RESPONSE_CODE_MSK	(0xf << CMD_HDR_RESPONSE_CODE_POS)
+#define CMD_HDR_USE_CHECKSUM_POS	8
+#define CMD_HDR_USE_CHECKSUM_MSK	BIT(CMD_HDR_USE_CHECKSUM_POS)
+#define CMD_HDR_RESPONSE_REQUIRED_POS	9
+#define CMD_HDR_RESPONSE_REQUIRED_MSK	BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
+#define CMD_HDR_DIRECT_ACCESS_POS	10
+#define CMD_HDR_DIRECT_ACCESS_MSK	BIT(CMD_HDR_DIRECT_ACCESS_POS)
+#define CMD_HDR_RESERVED_POS		11
+#define CMD_HDR_RESERVED_MSK		BIT(0x1f << CMD_HDR_RESERVED_POS)
+#define CMD_HDR_SIGNATURE_POS		16
+#define CMD_HDR_SIGNATURE_MSK		BIT(0xffff << CMD_HDR_SIGNATURE_POS)
+
+enum {
+	IWMC_OPCODE_PING = 0,
+	IWMC_OPCODE_READ = 1,
+	IWMC_OPCODE_WRITE = 2,
+	IWMC_OPCODE_JUMP = 3,
+	IWMC_OPCODE_REBOOT = 4,
+	IWMC_OPCODE_PERSISTENT_WRITE = 5,
+	IWMC_OPCODE_PERSISTENT_READ = 6,
+	IWMC_OPCODE_READ_MODIFY_WRITE = 7,
+	IWMC_OPCODE_LAST_COMMAND = 15
+};
+
+struct iwmct_fw_load_hdr {
+	__le32 cmd;
+	__le32 target_addr;
+	__le32 data_size;
+	__le32 block_chksm;
+	u8 data[0];
+};
+
+/**
+ * struct iwmct_fw_hdr
+ * holds all sw components versions
+ */
+struct iwmct_fw_hdr {
+	u8 top_major;
+	u8 top_minor;
+	u8 top_revision;
+	u8 gps_major;
+	u8 gps_minor;
+	u8 gps_revision;
+	u8 bt_major;
+	u8 bt_minor;
+	u8 bt_revision;
+	u8 tic_name[31];
+};
+
+/**
+ * struct iwmct_fw_sec_hdr
+ * @type: function type
+ * @data_size: section's data size
+ * @target_addr: download address
+ */
+struct iwmct_fw_sec_hdr {
+	u8 type[4];
+	__le32 data_size;
+	__le32 target_addr;
+};
+
+/**
+ * struct iwmct_parser
+ * @file: fw image
+ * @file_size: fw size
+ * @cur_pos: position in file
+ * @buf: temp buf for download
+ * @buf_size: size of buf
+ * @entry_point: address to jump in fw kick-off
+ */
+struct iwmct_parser {
+	const u8 *file;
+	size_t file_size;
+	size_t cur_pos;
+	u8 *buf;
+	size_t buf_size;
+	u32 entry_point;
+	struct iwmct_fw_hdr versions;
+};
+
+
+struct iwmct_work_struct {
+	struct list_head list;
+	ssize_t iosize;
+};
+
+struct iwmct_dbg {
+	int blocks;
+	bool dump;
+	bool jump;
+	bool direct;
+	bool checksum;
+	bool fw_download;
+	int block_size;
+	int download_trans_blks;
+
+	char label_fw[256];
+};
+
+struct iwmct_priv {
+	struct sdio_func *func;
+	struct iwmct_debugfs *dbgfs;
+	struct iwmct_parser parser;
+	atomic_t reset;
+	atomic_t dev_sync;
+	u32 trans_len;
+	u32 barker;
+	struct iwmct_dbg dbg;
+
+	/* drivers work queue */
+	struct workqueue_struct *wq;
+	struct workqueue_struct *bus_rescan_wq;
+	struct work_struct bus_rescan_worker;
+	struct work_struct isr_worker;
+
+	/* drivers wait queue */
+	wait_queue_head_t wait_q;
+
+	/* rx request list */
+	struct list_head read_req_list;
+};
+
+extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+		void *src, int count);
+
+extern int iwmct_fw_load(struct iwmct_priv *priv);
+
+extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
+extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
+extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
+extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
+
+#endif  /*  __IWMC3200TOP_H__  */
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c
new file mode 100644
index 0000000..96b5e4a
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.c
@@ -0,0 +1,339 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/ctype.h>
+#include "fw-msg.h"
+#include "iwmc3200top.h"
+#include "log.h"
+
+/* Maximal hexadecimal string size of the FW memdump message */
+#define LOG_MSG_SIZE_MAX		12400
+
+/* iwmct_logdefs is a global used by log macros */
+u8 iwmct_logdefs[LOG_SRC_MAX];
+static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
+
+
+static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
+{
+	int i;
+
+	if (src < size)
+		logdefs[src] = logmask;
+	else if (src == LOG_SRC_ALL)
+		for (i = 0; i < size; i++)
+			logdefs[i] = logmask;
+	else
+		return -1;
+
+	return 0;
+}
+
+
+int iwmct_log_set_filter(u8 src, u8 logmask)
+{
+	return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
+}
+
+
+int iwmct_log_set_fw_filter(u8 src, u8 logmask)
+{
+	return _log_set_log_filter(iwmct_fw_logdefs,
+				   FW_LOG_SRC_MAX, src, logmask);
+}
+
+
+static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
+			      int ilen, char *pref)
+{
+	int pos = 0;
+	int i;
+	int len;
+
+	for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
+		str[pos] = pref[i];
+
+	for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
+		len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
+
+	if (i < ilen)
+		return -1;
+
+	return 0;
+}
+
+/*	NOTE: This function is not thread safe.
+	Currently it's called only from sdio rx worker - no race there
+*/
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+	struct top_msg *msg;
+	static char logbuf[LOG_MSG_SIZE_MAX];
+
+	msg = (struct top_msg *)buf;
+
+	if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
+		LOG_ERROR(priv, FW_MSG, "Log message from TOP "
+			  "is too short %d (expected %zd)\n",
+			  len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
+		return;
+	}
+
+	if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
+		BIT(msg->u.log.log_hdr.severity)) ||
+	    !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
+		return;
+
+	switch (msg->hdr.category) {
+	case COMM_CATEGORY_TESTABILITY:
+		if (!(iwmct_logdefs[LOG_SRC_TST] &
+		      BIT(msg->u.log.log_hdr.severity)))
+			return;
+		if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+				       le16_to_cpu(msg->hdr.length) +
+				       sizeof(msg->hdr), "<TST>"))
+			LOG_WARNING(priv, TST,
+				  "TOP TST message is too long, truncating...");
+		LOG_WARNING(priv, TST, "%s\n", logbuf);
+		break;
+	case COMM_CATEGORY_DEBUG:
+		if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
+			LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
+				       ((u8 *)msg) + sizeof(msg->hdr)
+					+ sizeof(msg->u.log.log_hdr));
+		else {
+			if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
+					le16_to_cpu(msg->hdr.length)
+						+ sizeof(msg->hdr),
+					"<DBG>"))
+				LOG_WARNING(priv, FW_MSG,
+					"TOP DBG message is too long,"
+					"truncating...");
+			LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
+{
+	int i, pos, len;
+	for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
+		len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
+				i, logdefs[i]);
+		pos += len;
+	}
+	buf[pos-1] = '\n';
+	buf[pos] = '\0';
+
+	if (i < logdefsz)
+		return -1;
+	return 0;
+}
+
+int log_get_filter_str(char *buf, int size)
+{
+	return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
+}
+
+int log_get_fw_filter_str(char *buf, int size)
+{
+	return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
+}
+
+#define HEXADECIMAL_RADIX	16
+#define LOG_SRC_FORMAT		7 /* log level is in format of "0xXXXX," */
+
+ssize_t show_iwmct_log_level(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwmct_priv *priv = d->driver_data;
+	char *str_buf;
+	int buf_size;
+	ssize_t ret = -EAGAIN;
+
+	buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
+	str_buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!str_buf) {
+		LOG_ERROR(priv, DEBUGFS,
+			"failed to allocate %d bytes\n", buf_size);
+		goto exit;
+	}
+
+	if (log_get_filter_str(str_buf, buf_size) < 0)
+		goto exit;
+
+	ret = sprintf(buf, "%s", str_buf);
+
+exit:
+	kfree(str_buf);
+	return ret;
+}
+
+ssize_t store_iwmct_log_level(struct device *d,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct iwmct_priv *priv = d->driver_data;
+	char *token, *str_buf = NULL;
+	long val;
+	u8 src, mask;
+
+	if (!count)
+		goto err;
+
+	str_buf = kzalloc(count, GFP_KERNEL);
+	if (!str_buf) {
+		LOG_ERROR(priv, DEBUGFS,
+			"failed to allocate %zd bytes\n", count);
+		goto err;
+	}
+
+	memcpy(str_buf, buf, count);
+
+	while ((token = strsep(&str_buf, ",")) != NULL) {
+		while (isspace(*token))
+			++token;
+		if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+			LOG_ERROR(priv, DEBUGFS,
+				  "failed to convert string to long %s\n",
+				  token);
+			goto err;
+		}
+
+		mask  = val & 0xFF;
+		src = (val & 0XFF00) >> 8;
+		iwmct_log_set_filter(src, mask);
+	}
+
+	kfree(str_buf);
+	return count;
+
+err:
+	kfree(str_buf);
+	return -EAGAIN;
+}
+
+ssize_t show_iwmct_log_level_fw(struct device *d,
+			struct device_attribute *attr, char *buf)
+{
+	struct iwmct_priv *priv = d->driver_data;
+	char *str_buf;
+	int buf_size;
+	ssize_t ret = -EAGAIN;
+
+	buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
+
+	str_buf = kzalloc(buf_size, GFP_KERNEL);
+	if (!str_buf) {
+		LOG_ERROR(priv, DEBUGFS,
+			"failed to allocate %d bytes\n", buf_size);
+		goto exit;
+	}
+
+	if (log_get_fw_filter_str(str_buf, buf_size) < 0)
+		goto exit;
+
+	ret = sprintf(buf, "%s", str_buf);
+
+exit:
+	kfree(str_buf);
+	return ret;
+}
+
+ssize_t store_iwmct_log_level_fw(struct device *d,
+			struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct iwmct_priv *priv = d->driver_data;
+	char *token, *str_buf = NULL;
+	long val;
+	u8 src, mask;
+	struct top_msg cmd;
+	u16 cmdlen = 0;
+	int i, rc;
+
+	if (!count)
+		goto err;
+
+	str_buf = kzalloc(count, GFP_KERNEL);
+	if (!str_buf) {
+		LOG_ERROR(priv, DEBUGFS,
+			"failed to allocate %zd bytes\n", count);
+		goto err;
+	}
+
+	memcpy(str_buf, buf, count);
+
+	cmd.hdr.type = COMM_TYPE_H2D;
+	cmd.hdr.category = COMM_CATEGORY_DEBUG;
+	cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
+
+	for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
+		     (i < FW_LOG_SRC_MAX); i++) {
+
+		while (isspace(*token))
+			++token;
+
+		if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
+			LOG_ERROR(priv, DEBUGFS,
+				  "failed to convert string to long %s\n",
+				  token);
+			goto err;
+		}
+
+		mask  = val & 0xFF; /* LSB */
+		src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
+		iwmct_log_set_fw_filter(src, mask);
+
+		cmd.u.logdefs[i].logsource = src;
+		cmd.u.logdefs[i].sevmask = mask;
+	}
+
+	cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
+	cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
+
+	rc = iwmct_send_hcmd(priv, (u8 *) &cmd, cmdlen);
+	if (rc) {
+		LOG_ERROR(priv, DEBUGFS,
+			  "Failed to send %d bytes of fwcmd, rc=%d\n",
+			  cmdlen, rc);
+		goto err;
+	} else
+		LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
+
+	kfree(str_buf);
+	return count;
+
+err:
+	kfree(str_buf);
+	return -EAGAIN;
+}
+
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h
new file mode 100644
index 0000000..aba8121
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.h
@@ -0,0 +1,158 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/log.h
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#ifndef __LOG_H__
+#define __LOG_H__
+
+
+/* log severity:
+ * The log levels here match FW log levels
+ * so values need to stay as is */
+#define LOG_SEV_CRITICAL		0
+#define LOG_SEV_ERROR			1
+#define LOG_SEV_WARNING			2
+#define LOG_SEV_INFO			3
+#define LOG_SEV_INFOEX			4
+
+#define LOG_SEV_FILTER_ALL		\
+	(BIT(LOG_SEV_CRITICAL) |	\
+	 BIT(LOG_SEV_ERROR)    |	\
+	 BIT(LOG_SEV_WARNING)  | 	\
+	 BIT(LOG_SEV_INFO)     |	\
+	 BIT(LOG_SEV_INFOEX))
+
+/* log source */
+#define LOG_SRC_INIT			0
+#define LOG_SRC_DEBUGFS			1
+#define LOG_SRC_FW_DOWNLOAD		2
+#define LOG_SRC_FW_MSG			3
+#define LOG_SRC_TST			4
+#define LOG_SRC_IRQ			5
+
+#define	LOG_SRC_MAX			6
+#define	LOG_SRC_ALL			0xFF
+
+/**
+ * Default intitialization runtime log level
+ */
+#ifndef LOG_SEV_FILTER_RUNTIME
+#define LOG_SEV_FILTER_RUNTIME			\
+	(BIT(LOG_SEV_CRITICAL)	|		\
+	 BIT(LOG_SEV_ERROR)	|		\
+	 BIT(LOG_SEV_WARNING))
+#endif
+
+#ifndef FW_LOG_SEV_FILTER_RUNTIME
+#define FW_LOG_SEV_FILTER_RUNTIME	LOG_SEV_FILTER_ALL
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+/**
+ * Log macros
+ */
+
+#define priv2dev(priv) (&(priv->func)->dev)
+
+#define LOG_CRITICAL(priv, src, fmt, args...)				\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL))	\
+		dev_crit(priv2dev(priv), "%s %d: " fmt,			\
+			__func__, __LINE__, ##args);			\
+} while (0)
+
+#define LOG_ERROR(priv, src, fmt, args...)				\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR))	\
+		dev_err(priv2dev(priv), "%s %d: " fmt,			\
+			__func__, __LINE__, ##args);			\
+} while (0)
+
+#define LOG_WARNING(priv, src, fmt, args...)				\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING))	\
+		dev_warn(priv2dev(priv), "%s %d: " fmt,			\
+			 __func__, __LINE__, ##args);			\
+} while (0)
+
+#define LOG_INFO(priv, src, fmt, args...)				\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO))		\
+		dev_info(priv2dev(priv), "%s %d: " fmt,			\
+			 __func__, __LINE__, ##args);			\
+} while (0)
+
+#define LOG_INFOEX(priv, src, fmt, args...)				\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX))	\
+		dev_dbg(priv2dev(priv), "%s %d: " fmt,			\
+			 __func__, __LINE__, ##args);			\
+} while (0)
+
+#define LOG_HEXDUMP(src, ptr, len)					\
+do {									\
+	if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX))	\
+		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,	\
+				16, 1, ptr, len, false);		\
+} while (0)
+
+void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
+
+extern u8 iwmct_logdefs[];
+
+int iwmct_log_set_filter(u8 src, u8 logmask);
+int iwmct_log_set_fw_filter(u8 src, u8 logmask);
+
+ssize_t show_iwmct_log_level(struct device *d,
+			struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level(struct device *d,
+			struct device_attribute *attr,
+			const char *buf, size_t count);
+ssize_t show_iwmct_log_level_fw(struct device *d,
+			struct device_attribute *attr, char *buf);
+ssize_t store_iwmct_log_level_fw(struct device *d,
+			struct device_attribute *attr,
+			const char *buf, size_t count);
+
+#else
+
+#define LOG_CRITICAL(priv, src, fmt, args...)
+#define LOG_ERROR(priv, src, fmt, args...)
+#define LOG_WARNING(priv, src, fmt, args...)
+#define LOG_INFO(priv, src, fmt, args...)
+#define LOG_INFOEX(priv, src, fmt, args...)
+#define LOG_HEXDUMP(src, ptr, len)
+
+static inline void iwmct_log_top_message(struct iwmct_priv *priv,
+					 u8 *buf, int len) {}
+static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
+static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
+
+#endif /* CONFIG_IWMC3200TOP_DEBUG */
+
+int log_get_filter_str(char *buf, int size);
+int log_get_fw_filter_str(char *buf, int size);
+
+#endif /* __LOG_H__ */
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
new file mode 100644
index 0000000..09f8d06
--- /dev/null
+++ b/drivers/misc/iwmc3200top/main.c
@@ -0,0 +1,702 @@
+/*
+ * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
+ * drivers/misc/iwmc3200top/main.c
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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-1301, USA.
+ *
+ *
+ * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
+ *  -
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio.h>
+
+#include "iwmc3200top.h"
+#include "log.h"
+#include "fw-msg.h"
+#include "debugfs.h"
+
+
+#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver"
+#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation."
+
+#define IWMCT_VERSION "0.1.62"
+
+#ifdef REPOSITORY_LABEL
+#define RL REPOSITORY_LABEL
+#else
+#define RL ""
+#endif
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+#define VD "-d"
+#else
+#define VD
+#endif
+
+#define DRIVER_VERSION IWMCT_VERSION "-"  __stringify(RL) VD
+
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_COPYRIGHT);
+
+
+#ifndef SDIO_DEVICE_ID_INTEL_IWMC3200TOP
+#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP	0x1404
+#endif
+
+/*
+ * This workers main task is to wait for OP_OPR_ALIVE
+ * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
+ * When OP_OPR_ALIVE received it will issue
+ * a call to "bus_rescan_devices".
+ */
+static void iwmct_rescan_worker(struct work_struct *ws)
+{
+	struct iwmct_priv *priv;
+	int ret;
+
+	priv = container_of(ws, struct iwmct_priv, bus_rescan_worker);
+
+	LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n");
+
+	ret = bus_rescan_devices(priv->func->dev.bus);
+	if (ret < 0)
+		LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
+}
+
+static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
+{
+	switch (msg->hdr.opcode) {
+	case OP_OPR_ALIVE:
+		LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
+		queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
+		break;
+	default:
+		LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
+			msg->hdr.opcode);
+		break;
+	}
+}
+
+
+static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len)
+{
+	struct top_msg *msg;
+
+	msg = (struct top_msg *)buf;
+
+	if (msg->hdr.type != COMM_TYPE_D2H) {
+		LOG_ERROR(priv, FW_MSG,
+			"Message from TOP with invalid message type 0x%X\n",
+			msg->hdr.type);
+		return;
+	}
+
+	if (len < sizeof(msg->hdr)) {
+		LOG_ERROR(priv, FW_MSG,
+			"Message from TOP is too short for message header "
+			"received %d bytes, expected at least %zd bytes\n",
+			len, sizeof(msg->hdr));
+		return;
+	}
+
+	if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) {
+		LOG_ERROR(priv, FW_MSG,
+			"Message length (%d bytes) is shorter than "
+			"in header (%d bytes)\n",
+			len, le16_to_cpu(msg->hdr.length));
+		return;
+	}
+
+	switch (msg->hdr.category) {
+	case COMM_CATEGORY_OPERATIONAL:
+		op_top_message(priv, (struct top_msg *)buf);
+		break;
+
+	case COMM_CATEGORY_DEBUG:
+	case COMM_CATEGORY_TESTABILITY:
+	case COMM_CATEGORY_DIAGNOSTICS:
+		iwmct_log_top_message(priv, buf, len);
+		break;
+
+	default:
+		LOG_ERROR(priv, FW_MSG,
+			"Message from TOP with unknown category 0x%X\n",
+			msg->hdr.category);
+		break;
+	}
+}
+
+int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
+{
+	int ret;
+	u8 *buf;
+
+	LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
+
+	/* add padding to 256 for IWMC */
+	((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
+
+	LOG_HEXDUMP(FW_MSG, cmd, len);
+
+	if (len > FW_HCMD_BLOCK_SIZE) {
+		LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
+			  len, FW_HCMD_BLOCK_SIZE);
+		return -1;
+	}
+
+	buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
+	if (!buf) {
+		LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
+			  FW_HCMD_BLOCK_SIZE);
+		return -1;
+	}
+
+	memcpy(buf, cmd, len);
+
+	sdio_claim_host(priv->func);
+	ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
+			       FW_HCMD_BLOCK_SIZE);
+	sdio_release_host(priv->func);
+
+	kfree(buf);
+	return ret;
+}
+
+int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
+	void *src, int count)
+{
+	int ret;
+
+	sdio_claim_host(priv->func);
+	ret = sdio_memcpy_toio(priv->func, addr, src, count);
+	sdio_release_host(priv->func);
+
+	return ret;
+}
+
+static void iwmct_irq_read_worker(struct work_struct *ws)
+{
+	struct iwmct_priv *priv;
+	struct iwmct_work_struct *read_req;
+	__le32 *buf = NULL;
+	int ret, val, i;
+	int iosize;
+	u32 barker;
+
+	priv = container_of(ws, struct iwmct_priv, isr_worker);
+
+	LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
+
+	/* --------------------- Handshake with device -------------------- */
+	sdio_claim_host(priv->func);
+
+	/* all list manipulations have to be protected by
+	 * sdio_claim_host/sdio_release_host */
+	if (list_empty(&priv->read_req_list)) {
+		LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
+		goto exit_release;
+	}
+
+	read_req = list_entry(priv->read_req_list.next,
+			      struct iwmct_work_struct, list);
+
+	list_del(&read_req->list);
+	iosize = read_req->iosize;
+	kfree(read_req);
+
+	buf = kzalloc(iosize, GFP_KERNEL);
+	if (!buf) {
+		LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
+		goto exit_release;
+	}
+
+	LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
+				iosize, buf, priv->func->num);
+
+	/* read from device */
+	ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
+	if (ret) {
+		LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
+		goto exit_release;
+	}
+
+	LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);
+
+	barker = le32_to_cpu(buf[0]);
+	if (barker != IWMC_BARKER_ACK &&
+	   (barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
+		/* Handle Top Commhub message.
+		 * Current handling - treat all message as
+		 * logger messages and print the context as a string. */
+		sdio_release_host(priv->func);
+		handle_top_message(priv, (u8 *)buf, iosize);
+		goto exit;
+	}
+
+	/* verify basic barker sanity */
+	for (i = 1; i < 4; i++)
+		if (buf[i] != buf[0]) {
+			LOG_ERROR(priv, IRQ, "Corrupted barker,"
+					     "buf[%d]=%x buf[0]=%x\n",
+					     i, buf[i], buf[0]);
+			goto exit_release;
+		}
+
+	val = atomic_read(&priv->dev_sync);
+
+	switch (val) {
+	case 0:
+		/* we expect to recieve REBOOT BARKER */
+		if ((barker & BARKER_DNLOAD_BARKER_MSK) != IWMC_BARKER_REBOOT) {
+			LOG_ERROR(priv, IRQ, "Expecting for reboot barker %x,"
+					"but got %x\n",
+					IWMC_BARKER_REBOOT,
+					(barker & BARKER_DNLOAD_BARKER_MSK));
+			goto exit_release;
+		}
+
+		LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
+		priv->barker = barker;
+
+		if (barker & BARKER_DNLOAD_SYNC_MSK) {
+			/* Send the same barker back */
+			ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
+					       buf, iosize);
+			if (ret) {
+				LOG_ERROR(priv, IRQ,
+					 "error %d echoing barker\n", ret);
+				goto exit_release;
+			}
+			LOG_INFO(priv, IRQ, "Echoing barker to device\n");
+			atomic_inc(&priv->dev_sync);
+			goto exit_release;
+		}
+		break;
+
+	case 1:
+		/* we expect to recieve ACK BARKER */
+		if (barker != IWMC_BARKER_ACK) {
+			LOG_INFO(priv, IRQ, "Expecting for ACK barker[%x],"
+				 "got this instead %x\n",
+				 IWMC_BARKER_ACK, barker);
+			goto exit_release;
+		}
+		kfree(buf);
+		atomic_set(&priv->dev_sync, 0);
+		atomic_set(&priv->reset, 0);
+		break;
+
+	default:
+		LOG_INFO(priv, IRQ, "Wrong dev_sync %d\n", val);
+		break;
+	}
+
+	sdio_release_host(priv->func);
+
+
+	LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
+	LOG_INFO(priv, IRQ, "*******  Top FW %s requested ********\n",
+			(priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
+	LOG_INFO(priv, IRQ, "*******  GPS FW %s requested ********\n",
+			(priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
+	LOG_INFO(priv, IRQ, "*******  BT FW %s requested ********\n",
+			(priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
+
+	if (priv->dbg.fw_download)
+		iwmct_fw_load(priv);
+	else
+		LOG_ERROR(priv, IRQ, "FW download not allowed\n");
+
+	return;
+
+exit_release:
+	sdio_release_host(priv->func);
+exit:
+	kfree(buf);
+	LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
+}
+
+static void iwmct_irq(struct sdio_func *func)
+{
+	struct iwmct_priv *priv;
+	int val, ret;
+	int iosize;
+	int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
+	struct iwmct_work_struct *read_req;
+
+	priv = sdio_get_drvdata(func);
+
+	LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
+
+	/* read the function's status register */
+	val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
+
+	LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
+
+	if (!val) {
+		LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
+		goto exit_clear_intr;
+	}
+
+
+	/*
+	 * read 2 bytes of the transaction size
+	 * IMPORTANT: sdio transaction size has to be read before clearing
+	 * sdio interrupt!!!
+	 */
+	val = sdio_readb(priv->func, addr++, &ret);
+	iosize = val;
+	val = sdio_readb(priv->func, addr++, &ret);
+	iosize += val << 8;
+
+	LOG_INFO(priv, IRQ, "READ size %d\n", iosize);
+
+	if (iosize == 0) {
+		LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
+		goto exit_clear_intr;
+	}
+
+	/* allocate a work structure to pass iosize to the worker */
+	read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
+	if (!read_req) {
+		LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
+		goto exit_clear_intr;
+	}
+
+	INIT_LIST_HEAD(&read_req->list);
+	read_req->iosize = iosize;
+
+	list_add_tail(&priv->read_req_list, &read_req->list);
+
+	/* clear the function's interrupt request bit (write 1 to clear) */
+	sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+
+	queue_work(priv->wq, &priv->isr_worker);
+
+	LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
+
+	return;
+
+exit_clear_intr:
+	/* clear the function's interrupt request bit (write 1 to clear) */
+	sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
+}
+
+
+static int blocks;
+module_param(blocks, int, 0604);
+MODULE_PARM_DESC(blocks, "max_blocks_to_send");
+
+static int dump;
+module_param(dump, bool, 0604);
+MODULE_PARM_DESC(dump, "dump_hex_content");
+
+static int jump = 1;
+module_param(jump, bool, 0604);
+
+static int direct = 1;
+module_param(direct, bool, 0604);
+
+static int checksum = 1;
+module_param(checksum, bool, 0604);
+
+static int fw_download = 1;
+module_param(fw_download, bool, 0604);
+
+static int block_size = IWMC_SDIO_BLK_SIZE;
+module_param(block_size, int, 0404);
+
+static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
+module_param(download_trans_blks, int, 0604);
+
+static int rubbish_barker;
+module_param(rubbish_barker, bool, 0604);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static int log_level[LOG_SRC_MAX];
+static unsigned int log_level_argc;
+module_param_array(log_level, int, &log_level_argc, 0604);
+MODULE_PARM_DESC(log_level, "log_level");
+
+static int log_level_fw[FW_LOG_SRC_MAX];
+static unsigned int log_level_fw_argc;
+module_param_array(log_level_fw, int, &log_level_fw_argc, 0604);
+MODULE_PARM_DESC(log_level_fw, "log_level_fw");
+#endif
+
+void iwmct_dbg_init_params(struct iwmct_priv *priv)
+{
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+	int i;
+
+	for (i = 0; i < log_level_argc; i++) {
+		dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n",
+						i, log_level[i]);
+		iwmct_log_set_filter((log_level[i] >> 8) & 0xFF,
+			       log_level[i] & 0xFF);
+	}
+	for (i = 0; i < log_level_fw_argc; i++) {
+		dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n",
+						i, log_level_fw[i]);
+		iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF,
+				  log_level_fw[i] & 0xFF);
+	}
+#endif
+
+	priv->dbg.blocks = blocks;
+	LOG_INFO(priv, INIT, "blocks=%d\n", blocks);
+	priv->dbg.dump = (bool)dump;
+	LOG_INFO(priv, INIT, "dump=%d\n", dump);
+	priv->dbg.jump = (bool)jump;
+	LOG_INFO(priv, INIT, "jump=%d\n", jump);
+	priv->dbg.direct = (bool)direct;
+	LOG_INFO(priv, INIT, "direct=%d\n", direct);
+	priv->dbg.checksum = (bool)checksum;
+	LOG_INFO(priv, INIT, "checksum=%d\n", checksum);
+	priv->dbg.fw_download = (bool)fw_download;
+	LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download);
+	priv->dbg.block_size = block_size;
+	LOG_INFO(priv, INIT, "block_size=%d\n", block_size);
+	priv->dbg.download_trans_blks = download_trans_blks;
+	LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks);
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+static ssize_t show_iwmct_fw_version(struct device *d,
+				  struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n",
+		       ((struct iwmct_priv *)d->driver_data)->dbg.label_fw);
+}
+static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL);
+
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO,
+		   show_iwmct_log_level, store_iwmct_log_level);
+static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO,
+		   show_iwmct_log_level_fw, store_iwmct_log_level_fw);
+#endif
+
+static struct attribute *iwmct_sysfs_entries[] = {
+	&dev_attr_cc_label_fw.attr,
+#ifdef CONFIG_IWMC3200TOP_DEBUG
+	&dev_attr_log_level.attr,
+	&dev_attr_log_level_fw.attr,
+#endif
+	NULL
+};
+
+static struct attribute_group iwmct_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = iwmct_sysfs_entries,
+};
+
+
+static int iwmct_probe(struct sdio_func *func,
+			   const struct sdio_device_id *id)
+{
+	struct iwmct_priv *priv;
+	int ret;
+	int val = 1;
+	int addr = IWMC_SDIO_INTR_ENABLE_ADDR;
+
+	dev_info(&func->dev, "enter iwmct_probe\n");
+
+	dev_info(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
+		jiffies_to_msecs(2147483647), HZ);
+
+	priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&func->dev, "kzalloc error\n");
+		return -ENOMEM;
+	}
+	priv->func = func;
+	sdio_set_drvdata(func, priv);
+
+	LOG_INFO(priv, INIT, "HIDR supported\n");
+
+	/* create drivers work queue */
+	priv->wq = create_workqueue(DRV_NAME "_wq");
+	priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
+	INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
+	INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
+
+	init_waitqueue_head(&priv->wait_q);
+
+	sdio_claim_host(func);
+	/* FIXME: Remove after it is fixed in the Boot ROM upgrade */
+	func->enable_timeout = 10;
+
+	/* In our HW, setting the block size also wakes up the boot rom. */
+	ret = sdio_set_block_size(func, priv->dbg.block_size);
+	if (ret) {
+		LOG_ERROR(priv, INIT,
+			"sdio_set_block_size() failure: %d\n", ret);
+		goto error_sdio_enable;
+	}
+
+	ret = sdio_enable_func(func);
+	if (ret) {
+		LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret);
+		goto error_sdio_enable;
+	}
+
+	/* init reset and dev_sync states */
+	atomic_set(&priv->reset, 0);
+	atomic_set(&priv->dev_sync, 0);
+
+	/* init read req queue */
+	INIT_LIST_HEAD(&priv->read_req_list);
+
+	/* process configurable parameters */
+	iwmct_dbg_init_params(priv);
+	ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group);
+	if (ret) {
+		LOG_ERROR(priv, INIT, "Failed to register attributes and "
+			 "initialize module_params\n");
+		goto error_dev_attrs;
+	}
+
+	iwmct_dbgfs_register(priv, DRV_NAME);
+
+	if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) {
+		LOG_INFO(priv, INIT,
+			 "Reducing transaction to 8 blocks = 2K (from %d)\n",
+			 priv->dbg.download_trans_blks);
+		priv->dbg.download_trans_blks = 8;
+	}
+	priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size;
+	LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len);
+
+	ret = sdio_claim_irq(func, iwmct_irq);
+	if (ret) {
+		LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret);
+		goto error_claim_irq;
+	}
+
+
+	/* Enable function's interrupt */
+	sdio_writeb(priv->func, val, addr, &ret);
+	if (ret) {
+		LOG_ERROR(priv, INIT, "Failure writing to "
+			  "Interrupt Enable Register (%d): %d\n", addr, ret);
+		goto error_enable_int;
+	}
+
+	sdio_release_host(func);
+
+	LOG_INFO(priv, INIT, "exit iwmct_probe\n");
+
+	return ret;
+
+error_enable_int:
+	sdio_release_irq(func);
+error_claim_irq:
+	sdio_disable_func(func);
+error_dev_attrs:
+	iwmct_dbgfs_unregister(priv->dbgfs);
+	sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+error_sdio_enable:
+	sdio_release_host(func);
+	return ret;
+}
+
+static void iwmct_remove(struct sdio_func *func)
+{
+	struct iwmct_work_struct *read_req;
+	struct iwmct_priv *priv = sdio_get_drvdata(func);
+
+	priv = sdio_get_drvdata(func);
+
+	LOG_INFO(priv, INIT, "enter\n");
+
+	sdio_claim_host(func);
+	sdio_release_irq(func);
+	sdio_release_host(func);
+
+	/* Safely destroy osc workqueue */
+	destroy_workqueue(priv->bus_rescan_wq);
+	destroy_workqueue(priv->wq);
+
+	sdio_claim_host(func);
+	sdio_disable_func(func);
+	sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
+	iwmct_dbgfs_unregister(priv->dbgfs);
+	sdio_release_host(func);
+
+	/* free read requests */
+	while (!list_empty(&priv->read_req_list)) {
+		read_req = list_entry(priv->read_req_list.next,
+			struct iwmct_work_struct, list);
+
+		list_del(&read_req->list);
+		kfree(read_req);
+	}
+
+	kfree(priv);
+}
+
+
+static const struct sdio_device_id iwmct_ids[] = {
+	{ SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_INTEL_IWMC3200TOP)},
+	{ /* end: all zeroes */	},
+};
+
+MODULE_DEVICE_TABLE(sdio, iwmct_ids);
+
+static struct sdio_driver iwmct_driver = {
+	.probe		= iwmct_probe,
+	.remove		= iwmct_remove,
+	.name		= DRV_NAME,
+	.id_table	= iwmct_ids,
+};
+
+static int __init iwmct_init(void)
+{
+	int rc;
+
+	/* Default log filter settings */
+	iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
+	iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
+	iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
+
+	rc = sdio_register_driver(&iwmct_driver);
+
+	return rc;
+}
+
+static void __exit iwmct_exit(void)
+{
+	sdio_unregister_driver(&iwmct_driver);
+}
+
+module_init(iwmct_init);
+module_exit(iwmct_exit);
+
-- 
1.6.0.6

---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply related

* [PATCH 0/3 net] Add iwmc3200top driver
From: Tomas Winkler @ 2009-09-22 23:38 UTC (permalink / raw)
  To: davem, linville, netdev, linux-wireless, linux-mmc
  Cc: yi.zhu, inaky.perez-gonzalez, cindy.h.kao, guy.cohen,
	ron.rindjunsky

iwmc3200top: Add Intel Wireless MultiCom 3200 top driver.
iwmc3200wifi: select IWMC3200TOP in Kconfig
i2400m-sdio: select IWMC3200TOP in Kconfig

Add iwmc3200top driver. Imwc3200 is under drivers/misc driver but IMWC network 
drivers depends on it therefore submitted through netdev


---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


^ permalink raw reply

* Re: [RFC] nl80211: introduce NL80211_ATTR_SCAN_EXPIRE
From: Dan Williams @ 2009-09-22 23:29 UTC (permalink / raw)
  To: Holger Schurig
  Cc: Johannes Berg, linux-wireless@vger.kernel.org, John W Linville
In-Reply-To: <200909210946.19675.hs4233@mail.mn-solutions.de>

On Mon, 2009-09-21 at 09:46 +0200, Holger Schurig wrote:
> > It's not actually the same, and you didn't explain that well.
> > You care about the disappear case, but you made it sound like
> > you cared about the _reappear_ case.
> 
> Okay, sorry. I thought you read my other mails about 
> scan-life-time and that thus the context was/is clear.
> 
> 
> The base issue is: SCAN_TRIGGER does normally not a "clean scan", 
> it normally adds entries to the BSS list or updates existing 
> ones.
> 
> Entries in the BSS list are only deleted after 15 seconds.

So on the supplicant side, this weekend I was discussing with Jouni
about making the supplicant *not* trigger a completely new scan when
trying to associate if the scan list was current in the past 5 or 10
seconds.  The issue here is that NM requests a scan, figures out what AP
to start using, then tells the supplicant to associate with it.  Then
the supplicant throws away any scan results it has an does a full *new*
scan before associating.  That adds about 5 seconds to each NM
connection attempt that I'd like to get rid of.

Would that interfere with your forklift case?

BTW, 10 years ago I did a forklift deployment too with pre-802.11
Aironet equipment and Netware.  Wasn't that fun to get up and running.
This was at a paper company too, and guess what huge rolls of paper do?
They absorb radio waves quite well.  Suck.  And forklifts can go *fast*.

Dan

> 
> 
> However, in 15 seconds you can easily leave the range of AP_OLD 
> and be in the range of a completely AP_NEW. But it can also be 
> the case that the (now stale!) signal of AP_OLD is higher than 
> the (real) signal of AP_NEW. In this case wpa_supplicant tries 
> to associate to AP_OLD, which is out-of-sight. And that takes 
> unneeded time.
> 
> 
> I simple tried to mimick this scenario in the office, by 
> switching off an AP (just that I didn't really switch it off, 
> because the boot-times of Cisco-APs are soooooooo sloooooow).
> 
> About your "It's not actually the same": I think that my 
> laboratory experiment very well shows this behavior, e.g. see my 
> 2nd message with subject "Life-time of scan-results?":
> 
> 1253275108.958746: Trying to authenticate with 00:13:19:80:da:30 
> (SSID='MNHS' freq=2412 MHz)
> 
> Bit this is the "vanished" AP_OLD. With wireshark on a second 
> WLAN card I saw the attemps of mac80211 to associate to this 
> now-out-of-sight AP. This takes some tries from mac80211, then a 
> timeout on wpa_supplicant, than a new scan, then a new attempt. 
> All of those delays completely unnecessary if there would have 
> been a way to not get stale data via SCAN_DUMP.
> 
> 
> 
> So, clearly I have a visible problem and need to fix that.
> 
> I could fix that by making SCAN_TRIGGER always delete all stale 
> (cached) entries. Then I wouldn't need NL80211_ATTR_SCAN_EXPIRE.
> 
> However, a scan because "I want to look what is around" might be 
> different to a scan because "I need fresh data of APs around for 
> associating". And so I thought I make that configurable.
> 
> 
> I hope this now makes more sense.
> --
> 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


^ permalink raw reply

* Re: getting "ath5k phy0: noise floor calibration timeout"
From: Dan Williams @ 2009-09-22 23:29 UTC (permalink / raw)
  To: Holger Schurig; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <200909210902.23723.hs4233@mail.mn-solutions.de>

On Mon, 2009-09-21 at 09:02 +0200, Holger Schurig wrote:
> I kept my laptop the week-end on. The devices was unused during
> that time. I got a bunch output into my syslog:

I get that all the time, and have since 2.6.27 or earlier.  If it's a
real bug, we should fix it, but if it's just an informational message,
maybe we should silence it?

Dan

> Sep 18 17:30:03 laptop kernel: ##HS cfg80211_bss_expire:129 0
> Sep 18 17:30:03 laptop kernel: ##HS expire 00:1b:d4:44:35:90
> Sep 18 17:30:03 laptop kernel: ##HS expire 00:13:19:80:da:30
> Sep 18 17:30:03 laptop kernel: ##HS expire 00:1b:53:11:dc:40
> Sep 18 18:15:04 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 18 18:26:12 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 11:12:09 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 11:29:36 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 11:47:57 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 12:31:05 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 13:06:42 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 14:07:51 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 14:10:31 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 19 14:12:00 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 00:06:20 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 07:46:24 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 16:36:43 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 16:47:43 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 16:52:43 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 17:01:43 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 20 20:07:57 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:22:55 laptop last message repeated 2 times
> Sep 21 06:26:00 laptop last message repeated 2 times
> Sep 21 06:28:26 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:33:14 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:38:34 laptop last message repeated 2 times
> Sep 21 06:40:21 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:41:40 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:43:44 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 06:55:17 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 07:03:10 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 07:04:35 laptop last message repeated 2 times
> Sep 21 07:06:11 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 07:16:58 laptop kernel: ath5k phy0: noise floor calibration timeout (2412MHz)
> Sep 21 07:21:37 laptop last message repeated 2 times
> 
> Is this anything where I should care?  Or can I just
> ignore that?  If the latter is the case, should I add a
> patch that only three consecutive calibration timeouts
> produce a message, so that the log doesn't get "spammed" ?
> 


^ permalink raw reply

* Flush TX - wireless summit topic
From: Luis R. Rodriguez @ 2009-09-22 22:41 UTC (permalink / raw)
  To: Bob Copeland, Jouni.Malinen, Johannes Berg; +Cc: linux-wireless

Another thing we spoke about at the wireless summit was flushing TX
prior to changing channel / scan. Bob, remember the issue with ath5k
on the band not coinciding on received skbs since we don't do a DMA RX
flush prior to channel change? Well one theory discussed was that we
would see that issue disappear if we actually did a proper TX flush
prior to channel change since we expect we would not see further
incoming frames from our AP if we told it we were going to PS (sending
a null func frame). If we implement a proper TX flush then the theory
goes that we wouldn't need to do any sort of DMA flush as we would not
have any frames pending.

So a plan here would be to give that a shot.

  Luis

^ permalink raw reply

* Synching trees for BT 3.0 and a possible compat-bluetooth
From: Luis R. Rodriguez @ 2009-09-22 17:01 UTC (permalink / raw)
  To: John W. Linville, Marcel Holtmann, Jouni.Malinen, Johannes Berg
  Cc: Gaurav Jauhar, Senthil Balasubramanian, Jothikumar Mothilal,
	linux-wireless, Kevin Hayes

I forgot to poke about BT 3.0 synching at the summit. To work on
bluetooth 3.0 we'll need some synching of trees between
wireless-testing and Marcel's bluetooth tree. Also a compat-bluetooth
might be in order to accomplish the same as we do with
compat-wireless, only it would seem logical to consider tying to just
merge this with compat-wireless to get the features required for
bluetooth 3.0; to do this having one tree with both would be nice with
the added benefit of all the same compat-2.6.3x.[ch] files being
reused. Synching of the trees would be required only when a feature on
one tree is not yet available on the latest rc kernel (provided marcel
rebases on Linus' latest rc as well, not sure), this will probably be
important during initial implementation, not sure how much divergence
we should expect after this goes through a release through Linus.

So any thoughts on synching bluetooth and wireless-testing other than
doing so on a private tree for development purposes?

  Luis

^ permalink raw reply

* Re: [PATCH] b43: Implement RFKILL status for LP PHY
From: Michael Buesch @ 2009-09-22 12:51 UTC (permalink / raw)
  To: Larry Finger; +Cc: John Linville, Gábor Stefanik, wireless, Broadcom Linux
In-Reply-To: <4AB8054F.7080600@lwfinger.net>

On Tuesday 22 September 2009 00:59:27 Larry Finger wrote:
> The LP (and probably N) PHY has the same radio disabled bit as
> the higher-revision A and G PHYs.
> 
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>

ack

> ---
> 
> John,
> 
> Submission of this change for 2.6.32 would be nice, but not necessary.
> 
> Larry
> ---
> 
> Index: wireless-testing/drivers/net/wireless/b43/rfkill.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/b43/rfkill.c
> +++ wireless-testing/drivers/net/wireless/b43/rfkill.c
> @@ -28,7 +28,7 @@
>  /* Returns TRUE, if the radio is enabled in hardware. */
>  bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
>  {
> -	if (dev->phy.rev >= 3) {
> +	if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) {
>  		if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
>  		      & B43_MMIO_RADIO_HWENABLED_HI_MASK))
>  			return 1;
> 
> 
> 
> 



-- 
Greetings, Michael.

^ permalink raw reply

* [PATCH] drivers/net/wireless: Use usb_endpoint_dir_out
From: Julia Lawall @ 2009-09-22 11:45 UTC (permalink / raw)
  To: John W. Linville, Ulrich Kunitz, Daniel Drake, linux-wireless,
	netdev, linux-kernel, kernel-janitors

From: Julia Lawall <julia@diku.dk>

Use the usb_endpoint_dir_out API function.  Note that the use of
USB_TYPE_MASK in the original code is incorrect; it results in a test that
is always false.

The semantic patch that makes this change is as follows:
(http://coccinelle.lip6.fr/)

// <smpl>
@@
struct usb_endpoint_descriptor *endpoint;
expression E;
@@

- (endpoint->bEndpointAddress & E) == USB_DIR_OUT
+ usb_endpoint_dir_out(endpoint)
// </smpl>

Signed-off-by: Julia Lawall <julia@diku.dk>

---
 drivers/net/wireless/zd1211rw/zd_usb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff -u -p a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1070,7 +1070,7 @@ static int eject_installer(struct usb_in
 
 	/* Find bulk out endpoint */
 	endpoint = &iface_desc->endpoint[1].desc;
-	if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+	if (usb_endpoint_dir_out(endpoint) &&
 	    usb_endpoint_xfer_bulk(endpoint)) {
 		bulk_out_ep = endpoint->bEndpointAddress;
 	} else {

^ permalink raw reply

* Re: Comparison of wpa_supplicant with -Dnl80211 and -Dwext, WEP and WPA
From: Holger Schurig @ 2009-09-22 11:17 UTC (permalink / raw)
  To: hostap; +Cc: linux-wireless
In-Reply-To: <200909221258.44921.hs4233@mail.mn-solutions.de>

> However, I'm wondering: if several scan commands are
> ...

Ah, the analysis was correct, but not the conclusion. The -EBUSY
wasn't in cfg80211_wext_giwscan(), but in
cfg80211_wext_siwscan().


Hey, I'm talking too much to myself.

/me wishes, the people are back from PDX to normal work :-)

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: Comparison of wpa_supplicant with -Dnl80211 and -Dwext, WEP and WPA
From: Holger Schurig @ 2009-09-22 10:58 UTC (permalink / raw)
  To: hostap; +Cc: linux-wireless
In-Reply-To: <200909221118.04569.hs4233@mail.mn-solutions.de>

> wep_nl80211
> -----------
>  0.00000  0.00000: Initializing interface ...
>  0.03985  0.03985: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
>  0.03992  0.00007: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
>  0.03998  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
>  0.04004  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)

This is because of net/wireless/nl80211.c, function nl80211_key_allowed():

        switch (wdev->iftype) {
	...
        case NL80211_IFTYPE_STATION:
                if (wdev->sme_state != CFG80211_SME_CONNECTED)
                        return -ENOLINK;
                break;


> wep_wext
> --------
>  0.00000  0.00000: Initializing interface ...
>  0.08801  0.08801: Setting scan request: 0 sec 100000 usec
>  0.25167  0.16365: ioctl[SIOCGIWSCAN]: Resource temporarily unavailable

This is because wpa_supplicant very early - in
wpa_driver_wext_finish_drv_init() - calls
wpa_driver_wext_disconnect(). This in turn sets a random 32
character long ESSID, as a desparate means to disconnect.

Now that an essid is set, the calling chain in the kernel

   cfg80211_netdev_notifier_call(), case NETDEV_UP
   cfg80211_mgd_wext_connect()
   __cfg80211_connect()
  cfg80211_conn_scan(

get's executed. This starts a scan.

Later, when wpa_supplicant tries to get a scan result, it will
only get an -EBUSY because of net/wireless/scan.c, function
cfg80211_wext_siwscan():

        if (rdev->scan_req) {
                err = -EBUSY;
                goto out;
        }



However, I'm wondering: if several scan commands are
supposed to add up into the BSS list anyway (and each BSS list
entry by default pruned after 15 seconds), why is it an error
to access the current state of the BSS list while a scan is
in progress?

In other words, I think the following sequence should be ok:

Request Scan
scan finishes
get scan result (2 BSS entries)
request scan
get scan result (2 BSS entries)
scan finishes   (the scan is still in process)
get scan result (5 BSS entries)

If user-space ask for intermediate results, it should be
allowed to do so at any time. If user-space wants full
results, it can wait for the scan-done event.



This would mean that the BSS entries get individual locks
and that rdev->scan_req isn't used as an implicit lock.

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: BUG: can bring wpa_supplicant/mac80211 into a stuck state at will
From: Holger Schurig @ 2009-09-22  9:23 UTC (permalink / raw)
  To: hostap; +Cc: linux-wireless
In-Reply-To: <200909211259.45431.hs4233@mail.mn-solutions.de>

Another thing that might be related:


Start with freshly loaded modules (ath5k, mac80211, ath, cfg80211).

script -c "./wpa_supplicant -i eth1 -D wext -t -c mnfunk.conf -d" 1

Wait till "ping" works

script -c "./wpa_supplicant -i eth1 -D wext -t -c mnfunk.conf -d" 2


On the second try, it takes 15 seconds till
I'm connected and ping works again.

Maybe some state isn't clear at the implicit "ifdown XXX down"
that wpa_supplicant does when terminating?

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Comparison of wpa_supplicant with -Dnl80211 and -Dwext, WEP and WPA
From: Holger Schurig @ 2009-09-22  9:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: hostap

Management abstrace: NL80211 is now much butter then WEXT :-)


wireless-testing GIT with the "don't overwrite security" patch
and wpa_supplicant git.

I made logs with

script -c "./wpa_supplicant -i eth1 -D nl80211 -t -c wpa.conf -d" wext_nl80211
script -c "./wpa_supplicant -i eth1 -D nl80211 -t -c wpa.conf -d" wpa_nl8021
script -c "./wpa_supplicant -i eth1 -D wext    -t -c wep.conf -d" wep_wext
script -c "./wpa_supplicant -i eth1 -D wext    -t -c wep.conf -d" wep_wext


Then I wrote a little python script to sift throught the weeds,
extract interesting events and get me the time since start and
time since previous event.

Some of those "interesting" events are further marked as
"##ERROR" to stand out from the log.


wep_wext
--------
 0.00000  0.00000: Initializing interface ...
 0.08801  0.08801: Setting scan request: 0 sec 100000 usec
 0.25167  0.16365: ioctl[SIOCGIWSCAN]: Resource temporarily unavailable
 0.25171  0.00005: ##ERROR: Failed to get scan results
 0.25172  0.00001: ##ERROR: Failed to get scan results - try scanning again
 0.25173  0.00001: Setting scan request: 0 sec 0 usec
 0.25176  0.00003: ioctl[SIOCSIWSCAN]: Device or resource busy
 0.25179  0.00003: ##ERROR: Failed to initiate AP scan.
 0.25180  0.00001: Setting scan request: 10 sec 0 usec
 3.07458  2.82278: CTRL-EVENT-CONNECTED - Connection to 00:1b:d4:44:35:90 completed (auth) [id=0 id_str=]


wep_nl80211
-----------
 0.00000  0.00000: Initializing interface ...
 0.03985  0.03985: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.03992  0.00007: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.03998  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.04004  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.04008  0.00004: Setting scan request: 0 sec 100000 usec
 0.14061  0.10053: Received scan results (0 BSSes)
 0.14070  0.00009: Setting scan request: 0 sec 0 usec
 0.78813  0.64743: Received scan results (5 BSSes)
 0.78853  0.00040: Trying to authenticate with 00:1b:53:11:dc:40 (SSID='MNFUNK' freq=2412 MHz)
 0.78888  0.00034: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.96270  0.17382: SME: Authentication response: peer=00:1b:53:11:dc:40 auth_type=0 status_code=0


wpa_wext
--------
 0.00000  0.00000: Initializing interface ...
 0.07409  0.07409: Setting scan request: 0 sec 100000 usec
 0.24986  0.17576: ioctl[SIOCGIWSCAN]: Resource temporarily unavailable
 0.24990  0.00004: ##ERROR: Failed to get scan results
 0.24991  0.00001: ##ERROR: Failed to get scan results - try scanning again
 0.24991  0.00001: Setting scan request: 0 sec 0 usec
 0.24995  0.00003: ioctl[SIOCSIWSCAN]: Device or resource busy
 0.24998  0.00003: ##ERROR: Failed to initiate AP scan.
 0.24998  0.00001: Setting scan request: 10 sec 0 usec
 3.15609  2.90611: CTRL-EVENT-CONNECTED - Connection to 00:1b:d4:44:35:90 completed (auth) [id=0 id_str=]


wpa_nl80211
-----------
 0.00000  0.00000: Initializing interface ...
 0.07400  0.07400: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.07406  0.00007: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.07413  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.07419  0.00006: ##ERROR: nl80211: set_key failed; err=-67 Link has been severed)
 0.07424  0.00005: Setting scan request: 0 sec 100000 usec
 0.17475  0.10052: Received scan results (0 BSSes)
 0.17485  0.00009: Setting scan request: 0 sec 0 usec
 0.67432  0.49947: Received scan results (3 BSSes)
 0.67463  0.00032: Trying to authenticate with 00:1b:d4:44:35:90 (SSID='MNWPA' freq=2412 MHz)
 0.81141  0.13678: SME: Authentication response: peer=00:1b:d4:44:35:90 auth_type=0 status_code=0
 0.98805  0.17664: CTRL-EVENT-CONNECTED - Connection to 00:1b:d4:44:35:90 completed (auth) [id=0 id_str=]


For those tests, it was needed to rmmod mac80211 & friends
between those test, because otherwise connection could take up to
15 seconds.

We've quite a number of errors.

Also, NL80211 is usually faster connecting one than WEXT.

I can't say if this is a property of NL80211, it might also be
because COMPAT-WEXT has still some bugs and produces more errors,
making wpa_supplicant do excessive scanning.



-- 
http://www.holgerschurig.de

^ permalink raw reply

* BUGLET? cfg80211: .dumpit methods called twice
From: Holger Schurig @ 2009-09-22  7:33 UTC (permalink / raw)
  To: linux-wireless

I just noticed that all functions mentioned on .dumpit in 
net/wireless/nl80211.c are actually called twice.

For example, I've added

--- linux-wl.orig/net/wireless/nl80211.c        2009-09-18 
14:44:28.000000000 +0200
+++ linux-wl/net/wireless/nl80211.c     2009-09-18 
14:45:41.000000000 +0200
@@ -2919,6 +2919,8 @@ static int nl80211_trigger_scan(struct s
        enum ieee80211_band band;
        size_t ie_len;

+       printk("##HS %s:%d\n", __func__, __LINE__);
+
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;

and when I now issue one "iw eth1 scan dump" I get two logs of 
this printk in my dmesg.

AFAIK it doesn't cause any harm, but it's not that efficient and 
it might cause harm in the future if any of the .dumpit methods 
has the "right" side-effects.

-- 
http://www.holgerschurig.de

^ permalink raw reply

* Re: p54spi: dbm_antsignal value, is it RSSI or dbm?
From: Christian Lamparter @ 2009-09-22  1:46 UTC (permalink / raw)
  To: Andre K; +Cc: Gábor Stefanik, linux-wireless
In-Reply-To: <76516bfc0909211704iddf2ebcm9a8e12548c50fecd@mail.gmail.com>

On Tuesday 22 September 2009 02:04:32 Andre K wrote:
> I actually wouldn't mind investing some time to help sort this out,
> but I have no idea where to start.

stlc45xx gives you two clues:

a rough formula:
status.signal = data->rcpi / 2 - 110;
=> a rough formula

/* let's assume that maximum rcpi value is 140 (= -35 dBm) */
=> a _valid_ point (140 rssi => -35 dBm)

more bits can be retrieved from the original cx3110x driver and
maybe by comparing the signal/noise figures with other devices
in the same location.

> For now I think I'll have to revert to stlc45xx v1.3 and the calibration tool.

better start cracking! stlc45xx's end is near...

"stlc45xx Another wireless driver that no one seems to care about.
So sad. I guess no one will miss it when it goes away in .33."

http://www.kroah.com/log/linux/staging-status-09-2009.html

> On 9/21/09, Gábor Stefanik <netrolller.3d@gmail.com> wrote:
> > On Mon, Sep 21, 2009 at 9:04 PM, Christian Lamparter
> >>
> >> stlc45xx has a completely different phy/rf (longbow - rxhw = 5) and
> >> the specs are not a part of the freely available fw iface documentation.
> >>
> >> here's the relevant quote from a Nokia official: "
> >>> If this is so, what's so secret about the values that it needs a
> >>> binary-only tool and hidden storage area? Is there legal issues with
> >>> it (related to the radio device regulations)?
> >>
> >> Yes, this is because regulatory requirements. So thank FCC and ETSI
> >> for all this. This causes much grief for all wireless vendors, for
> >> example Intel had to do major changes in iwl3945 firmware for their
> >> mac80211 driver. "
> >> (ref:
> >> http://www.mail-archive.com/stlc45xx-devel@garage.maemo.org/msg00021.html
> >> )
> >
> > I've actually read somewhere (AFAIK on this list, but I am not sure)
> > that this is actually a misinterpretation of the FCC requirements...
AFAIK, the FCC changed the regulation wording some time ago?
But, other countries regulatory institutions (like ETSI, IC, MKK) 
might have a word, or two as well...

Regards,
	Chr

^ permalink raw reply

* Re: p54spi: dbm_antsignal value, is it RSSI or dbm?
From: Andre K @ 2009-09-22  0:04 UTC (permalink / raw)
  To: Gábor Stefanik; +Cc: Christian Lamparter, linux-wireless
In-Reply-To: <69e28c910909211325o271c471eydb9f37e20b9bd4c3@mail.gmail.com>

Thanks for the replies and the clarification.

I actually wouldn't mind investing some time to help sort this out,
but I have no idea where to start. For now I think I'll have to revert
to stlc45xx v1.3 and the calibration tool.

-Andre.

On 9/21/09, Gábor Stefanik <netrolller.3d@gmail.com> wrote:
> On Mon, Sep 21, 2009 at 9:04 PM, Christian Lamparter
> <chunkeey@googlemail.com> wrote:
>> On Monday 21 September 2009 20:19:35 Andre K wrote:
>>> Hi all,
>>>
>>> I've been using the new p54spi driver on a couple of n800s. Some
>>> specifics:
>>> Kernel : 2.6.29-omap1
>>> Wireless-compat: compat-wireless-2009-08-22
>>> OS: Maemo
>>> Options:  disabled CONFIG_RFKILL_BACKPORT_LEDS because it didn't compile
>>>
>>> The driver loads and functions normally. However, the values for the
>>> dbm_antsignal (from RadioTap header), are they RSSI or dbm? Initially
>>> I thought they were dbm since tcpdump showed negative values, which
>>> makes sense:
>>>
>>> Tcpdump:
>>> 14:08:25.312988 4469382526us tsft 2.0 Mb/s 2437 MHz (0x00a0) -49dB
>>> signal -41dB noise antenna 0 [0x0000000e] Acknowledgment
>>> RA:00:1d:e0:3d:5a:53 (oui Unknown)
>> heh, noise is higher than the signal.
>>
>>> 14:08:25.313903 4469383345us tsft 1.0 Mb/s 2437 MHz (0x00a0) 4dB
>>> signal -41dB noise antenna 0 [0x0000000e] 04:c2:08:00:07:07 (oui
>>> Unknown) Unknown SSAP 0x0a >
>>>
>>> Which shows up the first positive dbm value. Next I set up another
>>> n800 to broadcast ping packets (using hping3, since busybox's ping
>>> doesn't allow broadcast).
>>>
>>> 14:12:22.066192 13296010370us tsft 1.0 Mb/s 2437 MHz (0x00a0) 87dB
>>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>>> 192.168.10.255: ICMP echo request, id 6662, seq 40704, length 8
>>> 14:12:22.092376 13296036864us tsft 18.0 Mb/s 2437 MHz (0x00c0) 82dB
>>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>>> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
>>> 14:12:22.094787 13296037678us tsft 1.0 Mb/s 2437 MHz (0x00a0) 112dB
>>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>>> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
>>>
>>> I get strange dbm values, in the range of 50 - 100dbm, which doesn't
>>> make much sense.
>>>
>>> Does anyone have an idea what value is being returned and if there is
>>> an error in the dbm calculation?
>>>
>>
>> no, this has been on the TODO list for some time now.
>>
>> (drivers/net/wireless/p54/txrx.c)
>> static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
>> {
>>        int band = priv->hw->conf.channel->band;
>>
>>        if (priv->rxhw != 5)
>>                return ((rssi * priv->rssical_db[band].mul) / 64 +
>>                         priv->rssical_db[band].add) / 4;
>>        else
>>                /*
>>                 * TODO: find the correct formula
>>                 */
>>                return ((rssi * priv->rssical_db[band].mul) / 64 +
>>                         priv->rssical_db[band].add) / 4;
>> }
>>
>> the .mul & .add values can be retrieved from the p54spi_eeprom.h blob.
>>
>> 0x09, 0x00, 0xad, 0xde,         /* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM
>> */
>>        0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
>>        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>>
>> => translates into: (best viewed with a fixed-width font)
>> .mul           = 0x010a = 416 (base 10)
>> .add           = 0xfe72 = -398
>> .longbow_unkn1 = 0x001a = 26
>> .longbow_unkn2 = 0x0000 = 0
>>
>> ---
>>
>> stlc45xx has a completely different phy/rf (longbow - rxhw = 5) and
>> the specs are not a part of the freely available fw iface documentation.
>>
>> here's the relevant quote from a Nokia official: "
>>> If this is so, what's so secret about the values that it needs a
>>> binary-only tool and hidden storage area? Is there legal issues with
>>> it (related to the radio device regulations)?
>>
>> Yes, this is because regulatory requirements. So thank FCC and ETSI
>> for all this. This causes much grief for all wireless vendors, for
>> example Intel had to do major changes in iwl3945 firmware for their
>> mac80211 driver. "
>> (ref:
>> http://www.mail-archive.com/stlc45xx-devel@garage.maemo.org/msg00021.html
>> )
>
> I've actually read somewhere (AFAIK on this list, but I am not sure)
> that this is actually a misinterpretation of the FCC requirements...
>
>>
>> ---
>>
>> if you need real dBm reading for signal and noise, you have
>> to some "reverse engineering" on your own or find someone else
>> with the hardware and some spare time to burn.
>>
>> Regards,
>>        Chr
>> --
>> 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

* Re: [PATCH v2] mac80211: Fix [re]association power saving issue on AP side
From: Johannes Berg @ 2009-09-21 23:36 UTC (permalink / raw)
  To: Igor Perminov; +Cc: John W. Linville, Jouni Malinen, linux-wireless
In-Reply-To: <1253564744.4477.18.camel@sunlight>

[-- Attachment #1: Type: text/plain, Size: 195 bytes --]

On Tue, 2009-09-22 at 00:25 +0400, Igor Perminov wrote:
> Consider the following step-by step:

NACK this, we'll take care of it properly with the required cleanup as
mentioned.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* [PATCH] b43: Implement RFKILL status for LP PHY
From: Larry Finger @ 2009-09-21 22:59 UTC (permalink / raw)
  To: John Linville, Michael Buesch, Gábor Stefanik
  Cc: wireless, Broadcom Linux

The LP (and probably N) PHY has the same radio disabled bit as
the higher-revision A and G PHYs.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---

John,

Submission of this change for 2.6.32 would be nice, but not necessary.

Larry
---

Index: wireless-testing/drivers/net/wireless/b43/rfkill.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/rfkill.c
+++ wireless-testing/drivers/net/wireless/b43/rfkill.c
@@ -28,7 +28,7 @@
 /* Returns TRUE, if the radio is enabled in hardware. */
 bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
 {
-	if (dev->phy.rev >= 3) {
+	if (dev->phy.rev >= 3 || dev->phy.type == B43_PHYTYPE_LP) {
 		if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
 		      & B43_MMIO_RADIO_HWENABLED_HI_MASK))
 			return 1;



^ permalink raw reply

* [PATCH v2] mac80211: Fix [re]association power saving issue on AP side
From: Igor Perminov @ 2009-09-21 20:25 UTC (permalink / raw)
  To: John W. Linville; +Cc: Johannes Berg, Jouni Malinen, linux-wireless

Consider the following step-by step:
1. A STA authenticates and associates with the AP and exchanges
traffic.
2. The STA reports to the AP that it is going to PS state.
3. Some time later the STA device goes to the stand-by mode (not only
its wi-fi card, but the device itself) and drops the association state
without sending a disassociation frame.
4. The STA device wakes up and begins authentication with an
Auth frame as it hasn't been authenticated/associated previously.
 
At the step 4 the AP "remembers" the STA and considers it is still in
the PS state, so the AP buffers frames, which it has to send to the STA.
But the STA isn't actually in the PS state and so it neither checks
TIM bits nor reports to the AP that it isn't power saving.
Because of that authentication/[re]association fails.

To fix authentication/[re]association stage of this issue, Auth, Assoc
Resp and Reassoc Resp frames are transmitted disregarding of STA's power
saving state.

N.B. This patch doesn't fix further data frame exchange after
authentication/[re]association. A patch in hostapd is required to fix
that.

Signed-off-by: Igor Perminov <igor.perminov@inbox.ru>
---
 net/mac80211/tx.c       |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 10a1099..4d981e7 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -367,7 +367,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 	u32 staflags;
 
-	if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control)))
+	if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control)
+			|| ieee80211_is_auth(hdr->frame_control)
+			|| ieee80211_is_assoc_resp(hdr->frame_control)
+			|| ieee80211_is_reassoc_resp(hdr->frame_control)))
 		return TX_CONTINUE;
 
 	staflags = get_sta_flags(sta);



^ permalink raw reply related

* Re: p54spi: dbm_antsignal value, is it RSSI or dbm?
From: Gábor Stefanik @ 2009-09-21 20:25 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: Andre K, linux-wireless
In-Reply-To: <200909212104.28665.chunkeey@googlemail.com>

On Mon, Sep 21, 2009 at 9:04 PM, Christian Lamparter
<chunkeey@googlemail.com> wrote:
> On Monday 21 September 2009 20:19:35 Andre K wrote:
>> Hi all,
>>
>> I've been using the new p54spi driver on a couple of n800s. Some specifics:
>> Kernel : 2.6.29-omap1
>> Wireless-compat: compat-wireless-2009-08-22
>> OS: Maemo
>> Options:  disabled CONFIG_RFKILL_BACKPORT_LEDS because it didn't compile
>>
>> The driver loads and functions normally. However, the values for the
>> dbm_antsignal (from RadioTap header), are they RSSI or dbm? Initially
>> I thought they were dbm since tcpdump showed negative values, which
>> makes sense:
>>
>> Tcpdump:
>> 14:08:25.312988 4469382526us tsft 2.0 Mb/s 2437 MHz (0x00a0) -49dB
>> signal -41dB noise antenna 0 [0x0000000e] Acknowledgment RA:00:1d:e0:3d:5a:53 (oui Unknown)
> heh, noise is higher than the signal.
>
>> 14:08:25.313903 4469383345us tsft 1.0 Mb/s 2437 MHz (0x00a0) 4dB
>> signal -41dB noise antenna 0 [0x0000000e] 04:c2:08:00:07:07 (oui
>> Unknown) Unknown SSAP 0x0a >
>>
>> Which shows up the first positive dbm value. Next I set up another
>> n800 to broadcast ping packets (using hping3, since busybox's ping
>> doesn't allow broadcast).
>>
>> 14:12:22.066192 13296010370us tsft 1.0 Mb/s 2437 MHz (0x00a0) 87dB
>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>> 192.168.10.255: ICMP echo request, id 6662, seq 40704, length 8
>> 14:12:22.092376 13296036864us tsft 18.0 Mb/s 2437 MHz (0x00c0) 82dB
>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
>> 14:12:22.094787 13296037678us tsft 1.0 Mb/s 2437 MHz (0x00a0) 112dB
>> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
>> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
>>
>> I get strange dbm values, in the range of 50 - 100dbm, which doesn't
>> make much sense.
>>
>> Does anyone have an idea what value is being returned and if there is
>> an error in the dbm calculation?
>>
>
> no, this has been on the TODO list for some time now.
>
> (drivers/net/wireless/p54/txrx.c)
> static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
> {
>        int band = priv->hw->conf.channel->band;
>
>        if (priv->rxhw != 5)
>                return ((rssi * priv->rssical_db[band].mul) / 64 +
>                         priv->rssical_db[band].add) / 4;
>        else
>                /*
>                 * TODO: find the correct formula
>                 */
>                return ((rssi * priv->rssical_db[band].mul) / 64 +
>                         priv->rssical_db[band].add) / 4;
> }
>
> the .mul & .add values can be retrieved from the p54spi_eeprom.h blob.
>
> 0x09, 0x00, 0xad, 0xde,         /* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM */
>        0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
>        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>
> => translates into: (best viewed with a fixed-width font)
> .mul           = 0x010a = 416 (base 10)
> .add           = 0xfe72 = -398
> .longbow_unkn1 = 0x001a = 26
> .longbow_unkn2 = 0x0000 = 0
>
> ---
>
> stlc45xx has a completely different phy/rf (longbow - rxhw = 5) and
> the specs are not a part of the freely available fw iface documentation.
>
> here's the relevant quote from a Nokia official: "
>> If this is so, what's so secret about the values that it needs a
>> binary-only tool and hidden storage area? Is there legal issues with
>> it (related to the radio device regulations)?
>
> Yes, this is because regulatory requirements. So thank FCC and ETSI
> for all this. This causes much grief for all wireless vendors, for
> example Intel had to do major changes in iwl3945 firmware for their
> mac80211 driver. "
> (ref: http://www.mail-archive.com/stlc45xx-devel@garage.maemo.org/msg00021.html )

I've actually read somewhere (AFAIK on this list, but I am not sure)
that this is actually a misinterpretation of the FCC requirements...

>
> ---
>
> if you need real dBm reading for signal and noise, you have
> to some "reverse engineering" on your own or find someone else
> with the hardware and some spare time to burn.
>
> Regards,
>        Chr
> --
> 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

* Re: p54spi: dbm_antsignal value, is it RSSI or dbm?
From: Christian Lamparter @ 2009-09-21 19:04 UTC (permalink / raw)
  To: Andre K; +Cc: linux-wireless
In-Reply-To: <76516bfc0909211119i4362ca35k13fc1f87857fb393@mail.gmail.com>

On Monday 21 September 2009 20:19:35 Andre K wrote:
> Hi all,
> 
> I've been using the new p54spi driver on a couple of n800s. Some specifics:
> Kernel : 2.6.29-omap1
> Wireless-compat: compat-wireless-2009-08-22
> OS: Maemo
> Options:  disabled CONFIG_RFKILL_BACKPORT_LEDS because it didn't compile
> 
> The driver loads and functions normally. However, the values for the
> dbm_antsignal (from RadioTap header), are they RSSI or dbm? Initially
> I thought they were dbm since tcpdump showed negative values, which
> makes sense:
> 
> Tcpdump:
> 14:08:25.312988 4469382526us tsft 2.0 Mb/s 2437 MHz (0x00a0) -49dB
> signal -41dB noise antenna 0 [0x0000000e] Acknowledgment RA:00:1d:e0:3d:5a:53 (oui Unknown)
heh, noise is higher than the signal.

> 14:08:25.313903 4469383345us tsft 1.0 Mb/s 2437 MHz (0x00a0) 4dB
> signal -41dB noise antenna 0 [0x0000000e] 04:c2:08:00:07:07 (oui
> Unknown) Unknown SSAP 0x0a >
> 
> Which shows up the first positive dbm value. Next I set up another
> n800 to broadcast ping packets (using hping3, since busybox's ping
> doesn't allow broadcast).
>
> 14:12:22.066192 13296010370us tsft 1.0 Mb/s 2437 MHz (0x00a0) 87dB
> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
> 192.168.10.255: ICMP echo request, id 6662, seq 40704, length 8
> 14:12:22.092376 13296036864us tsft 18.0 Mb/s 2437 MHz (0x00c0) 82dB
> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
> 14:12:22.094787 13296037678us tsft 1.0 Mb/s 2437 MHz (0x00a0) 112dB
> signal -62dB noise antenna 0 [0x0000000e] IP 192.168.10.11 >
> 192.168.10.255: ICMP echo request, id 6662, seq 40960, length 8
> 
> I get strange dbm values, in the range of 50 - 100dbm, which doesn't
> make much sense.
> 
> Does anyone have an idea what value is being returned and if there is
> an error in the dbm calculation?
>

no, this has been on the TODO list for some time now.

(drivers/net/wireless/p54/txrx.c)
static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
{
        int band = priv->hw->conf.channel->band;

        if (priv->rxhw != 5)
                return ((rssi * priv->rssical_db[band].mul) / 64 +
                         priv->rssical_db[band].add) / 4;
        else
                /*
                 * TODO: find the correct formula
                 */
                return ((rssi * priv->rssical_db[band].mul) / 64 +
                         priv->rssical_db[band].add) / 4;
}

the .mul & .add values can be retrieved from the p54spi_eeprom.h blob.

0x09, 0x00, 0xad, 0xde,         /* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM */
        0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

=> translates into: (best viewed with a fixed-width font)
.mul           = 0x010a = 416 (base 10)
.add           = 0xfe72 = -398
.longbow_unkn1 = 0x001a = 26
.longbow_unkn2 = 0x0000 = 0

---

stlc45xx has a completely different phy/rf (longbow - rxhw = 5) and
the specs are not a part of the freely available fw iface documentation.

here's the relevant quote from a Nokia official: "
> If this is so, what's so secret about the values that it needs a
> binary-only tool and hidden storage area? Is there legal issues with
> it (related to the radio device regulations)?

Yes, this is because regulatory requirements. So thank FCC and ETSI
for all this. This causes much grief for all wireless vendors, for
example Intel had to do major changes in iwl3945 firmware for their
mac80211 driver. "
(ref: http://www.mail-archive.com/stlc45xx-devel@garage.maemo.org/msg00021.html )

---

if you need real dBm reading for signal and noise, you have
to some "reverse engineering" on your own or find someone else
with the hardware and some spare time to burn.

Regards,
	Chr

^ 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