Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: Intel PRO/Wireless 2100 Driver Firmware
From: Stanislav Yakovlev @ 2013-08-22 17:30 UTC (permalink / raw)
  To: Marcus Laitala; +Cc: wireless
In-Reply-To: <CA+7kRpWhLEKZYzGN-Eu4dPDM2+JQRkmJYWP1CJf0jzWSN=KVJA@mail.gmail.com>

Hi Marcus,

On 20 August 2013 17:44, Marcus Laitala <marcus.vitsar@gmail.com> wrote:
> I tried to download the Intel PRO/Wireless 2100 Driver Firmware
> from: http://ipw2100.sourceforge.net/firmware.php
>
> I only get the following error:
> This webpage is not available"
>
> As if the files/webpage is no longer there/online. I just wanted to
> tell who ever is in charge of those that those files are no longer
> downloadable.

Thank you for the information. The firmware can be downloaded from the
Fedora repository:
http://pkgs.fedoraproject.org/repo/pkgs/ipw2100-firmware/

Stanislav.

^ permalink raw reply

* [PATCH v3] mac80211: only respond to probe request with mesh ID
From: Chun-Yeow Yeoh @ 2013-08-22 17:28 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh

From: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>

Previously, the mesh STA responds to probe request from legacy STA
but now it will only respond to legacy STA if the legacy STA does include 
the specific mesh ID or wildcard mesh ID in the probe request.

The iw patch "iw: scan using meshid" can be used either by legacy STA
or by mesh STA to do active scanning by inserting the mesh ID in the 
probe request frame.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
Acked-by: Thomas Pedersen <thomas@cozybit.com>
Acked-by: Javier Cardona <javier@cozybit.com>
---
v2: modify comments (Thomas)
v3: style problem (Bob)

 net/mac80211/mesh.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 885a5f6..a660fb8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -832,6 +832,9 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
 
 	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
 
+	if (!elems.mesh_id)
+		return;
+
 	/* 802.11-2012 10.1.4.3.2 */
 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
 	     !is_broadcast_ether_addr(mgmt->da)) ||
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH v2] mac80211: only respond to probe request with mesh ID
From: Bob Copeland @ 2013-08-22 17:13 UTC (permalink / raw)
  To: Chun-Yeow Yeoh; +Cc: linux-wireless, johannes, linville, devel, distro11s
In-Reply-To: <1377190892-5328-1-git-send-email-yeohchunyeow@gmail.com>

On Thu, Aug 22, 2013 at 10:01:32AM -0700, Chun-Yeow Yeoh wrote:
> +	if(!elems.mesh_id)
> +		return;
> +

if (!elems.mesh_id)

(checkpatch will warn about that)

-- 
Bob Copeland %% www.bobcopeland.com

^ permalink raw reply

* [PATCH v2] mac80211: only respond to probe request with mesh ID
From: Chun-Yeow Yeoh @ 2013-08-22 17:01 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh

From: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>

Previously, the mesh STA responds to probe request from legacy STA
but now it will only respond to legacy STA if the legacy STA does include 
the specific mesh ID or wildcard mesh ID in the probe request.

The iw patch "iw: scan using meshid" can be used either by legacy STA
or by mesh STA to do active scanning by inserting the mesh ID in the 
probe request frame.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
Acked-by: Thomas Pedersen <thomas@cozybit.com>
Acked-by: Javier Cardona <javier@cozybit.com>
---
v2: modify comments (Thomas)

 net/mac80211/mesh.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 885a5f6..a660fb8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -832,6 +832,9 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
 
 	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
 
+	if(!elems.mesh_id)
+		return;
+
 	/* 802.11-2012 10.1.4.3.2 */
 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
 	     !is_broadcast_ether_addr(mgmt->da)) ||
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] mac80211: only respond to probe request with mesh ID
From: Chun-Yeow Yeoh @ 2013-08-22 16:44 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, linville, devel, distro11s, Chun-Yeow Yeoh

From: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>

Previously, the mesh STA responds to probe request from legacy STA
but now it will respond to legacy STA only if the legacy STA has
included the specific mesh ID or wildcard mesh ID in the probe request.

Signed-off-by: Chun-Yeow Yeoh <yeohchunyeow@cozybit.com>
Acked-by: Thomas Pedersen <thomas@cozybit.com>
Acked-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 885a5f6..a660fb8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -832,6 +832,9 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
 
 	ieee802_11_parse_elems(pos, len - baselen, false, &elems);
 
+	if(!elems.mesh_id)
+		return;
+
 	/* 802.11-2012 10.1.4.3.2 */
 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
 	     !is_broadcast_ether_addr(mgmt->da)) ||
-- 
1.7.9.5


^ permalink raw reply related

* Re: pull-request: mac80211 2013-08-21
From: John W. Linville @ 2013-08-22 15:39 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1377092661.15268.13.camel@jlt4.sipsolutions.net>

On Wed, Aug 21, 2013 at 03:44:21PM +0200, Johannes Berg wrote:
> John,
> 
> I have three more patches for the 3.11 stream: Felix's fix for the
> fairly visible brcmsmac crash, a fix from Simon for an IBSS join bug I
> found and a fix for a channel context bug in IBSS I'd introduced.
> 
> Let me know if there's any problem.
> 
> Thanks,
> johannes
> 
> The following changes since commit dee8a9732e713480075adbbca8eb220c5b8d1216:
> 
>   cfg80211: don't request disconnect if not connected (2013-08-14 14:00:19 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git for-john
> 
> for you to fetch changes up to 75a423f493ffdf741acae27bf179cd560f7813d7:
> 
>   mac80211: ibss: fix ignored channel parameter (2013-08-21 15:33:08 +0200)
> 
> ----------------------------------------------------------------
> Felix Fietkau (1):
>       mac80211: add a flag to indicate CCK support for HT clients
> 
> Johannes Berg (1):
>       mac80211: add missing channel context release
> 
> Simon Wunderlich (1):
>       mac80211: ibss: fix ignored channel parameter

Pulling now...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: [PATCH] mac80211: ignore obviously bogus ECSAs in probe response frames
From: Seth Forshee @ 2013-08-22 15:09 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John W. Linville
In-Reply-To: <20130822141011.GA24445@thinkpad-t410>

On Thu, Aug 22, 2013 at 09:10:11AM -0500, Seth Forshee wrote:
> On Thu, Aug 22, 2013 at 04:01:03PM +0200, Johannes Berg wrote:
> > On Thu, 2013-08-22 at 08:53 -0500, Seth Forshee wrote:
> > > The Netgear WNDAP360 sends invalid ECSA IEs in probe response
> > > frames
> > 
> > I think we shouldn't be checking probe response frames at all. That
> > seems like a mistake. Can you try this?
> 
> I had considered this, but the spec says that it's at least valid for
> the AP to be sending ECSAs in probe responses. IEEE 802.11-2012 section
> 10.3.3.2:
> 
>   ...an AP shall inform associated STAs that the AP is moving to a new
>   channel and/or operating class and maintain the association by
>   advertising the switch using Extended Channel Switch Announcement
>   elements in any transmitted Beacon frames, Probe Response frames, and
>   Extended Channel Switch Announcement frames until the intended channel
>   switch time.
> 
> Perhaps we can still ignore them though? I suppose we'd expect to
> receive some other frame with the ECSA before it actually happens.

Anyway, your fix also eliminates the disconnects, so whichever solution
you think best is fine. There is a build failure though.

+       ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+                                        elems, true);

Needs to be &elems here.

Thanks,
Seth

^ permalink raw reply

* [PATCH RFC] nfc: add a driver for pn532 connected on uart
From: Lars Poeschel @ 2013-08-22 14:28 UTC (permalink / raw)
  To: poeschel, lauro.venancio, aloisio.almeida, sameo, gregkh, jslaby,
	linux-kernel, linux-wireless, linux-nfc

From: Lars Poeschel <poeschel@lemonage.de>

This adds a driver for the nxp pn532 nfc chip.
It is not meant for merging. Instead it is meant to show that some
progress has been made and what the current state is and to help
testing.
Although I can do some basic things with this driver I expect it to
contain lots of bugs. Be aware!
This driver is heavily based on the pn533 driver and duplicates much
code. This has do be factored out some time.

Signed-off-by: Lars Poeschel <poeschel@lemonage.de>
---
 drivers/nfc/Kconfig      |    9 +
 drivers/nfc/Makefile     |    1 +
 drivers/nfc/pn532.c      | 2608 ++++++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/tty.h |    1 +
 4 files changed, 2619 insertions(+)
 create mode 100644 drivers/nfc/pn532.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index b0b64cc..e97303a 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -5,6 +5,15 @@
 menu "Near Field Communication (NFC) devices"
 	depends on NFC
 
+config NFC_PN532
+	tristate "NXP PN532 UART driver"
+	help
+	  NXP PN532 UART driver.
+	  This driver provides support for NFC NXP PN532 devices.
+
+	  Say Y here to compile support for PN532 devices into the
+	  kernel or say M to compile it as module (pn532).
+
 config NFC_PN533
 	tristate "NXP PN533 USB driver"
 	depends on USB
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index be7636a..a942734 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_NFC_PN544)		+= pn544/
 obj-$(CONFIG_NFC_MICROREAD)	+= microread/
+obj-$(CONFIG_NFC_PN532)		+= pn532.o
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
diff --git a/drivers/nfc/pn532.c b/drivers/nfc/pn532.c
new file mode 100644
index 0000000..7e0db46
--- /dev/null
+++ b/drivers/nfc/pn532.c
@@ -0,0 +1,2608 @@
+/*
+ * Copyright (C) 2013 Lemonage Software GmbH
+ *
+ * Author:
+ *    Lars Poeschel <poeschel@lemonage.de>
+ *
+ * Heavily based on the pn533 driver by:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#define DEBUG
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/nfc.h>
+#include <linux/netdevice.h>
+#include <net/nfc/nfc.h>
+
+#define DESCRIPTION "PN532 uart driver"
+#define PN532_MAX_DEVS		2
+
+#define PN532_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
+			     NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
+			     NFC_PROTO_NFC_DEP_MASK |\
+			     NFC_PROTO_ISO14443_B_MASK)
+
+#define PN532_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
+				   NFC_PROTO_MIFARE_MASK | \
+				   NFC_PROTO_FELICA_MASK | \
+				   NFC_PROTO_ISO14443_MASK | \
+				   NFC_PROTO_NFC_DEP_MASK)
+
+/* How much time we spend listening for initiators */
+#define PN532_LISTEN_TIME 2
+
+/* frame definitions */
+#define PN532_FRAME_HEADER_LEN (sizeof(struct pn532_frame) \
+					+ 2) /* data[0] TFI, data[1] CC */
+#define PN532_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
+
+/*
+ * Max extended frame payload len, excluding TFI and CC
+ * which are already in PN532_FRAME_HEADER_LEN.
+ */
+#define PN532_FRAME_MAX_PAYLOAD_LEN 263
+
+#define PN532_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+				  Postamble (1) */
+#define PN532_FRAME_CHECKSUM(f) (f->data[f->datalen])
+#define PN532_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
+
+/* start of frame */
+#define PN532_SOF 0x00FF
+
+/* frame identifier: in/out/error */
+#define PN532_FRAME_IDENTIFIER(f) (f->data[0])
+#define PN532_DIR_OUT 0xD4
+#define PN532_DIR_IN 0xD5
+
+/* PN532 Commands */
+#define PN532_FRAME_CMD(f) (f->data[1])
+
+#define PN532_CMD_GET_FIRMWARE_VERSION 0x02
+#define PN532_CMD_SAM_CONFIGURATION 0x14
+#define PN532_CMD_RF_CONFIGURATION 0x32
+#define PN532_CMD_IN_DATA_EXCHANGE 0x40
+#define PN532_CMD_IN_COMM_THRU     0x42
+#define PN532_CMD_IN_LIST_PASSIVE_TARGET 0x4A
+#define PN532_CMD_IN_ATR 0x50
+#define PN532_CMD_IN_RELEASE 0x52
+#define PN532_CMD_IN_JUMP_FOR_DEP 0x56
+#define PN532_CMD_IN_AUTOPOLL 0x60
+
+#define PN532_CMD_TG_INIT_AS_TARGET 0x8c
+#define PN532_CMD_TG_GET_DATA 0x86
+#define PN532_CMD_TG_SET_DATA 0x8e
+#define PN532_CMD_UNDEF 0xff
+
+#define PN532_CMD_RESPONSE(cmd) (cmd + 1)
+
+/* PN532 Return codes */
+#define PN532_CMD_RET_MASK 0x3F
+#define PN532_CMD_MI_MASK 0x40
+#define PN532_CMD_RET_SUCCESS 0x00
+
+struct pn532;
+
+typedef int (*pn532_cmd_complete_t) (struct pn532 *dev, void *arg, int status);
+
+typedef int (*pn532_send_async_complete_t) (struct pn532 *dev, void *arg,
+					struct sk_buff *resp);
+
+/* structs for pn532 commands */
+
+/* PN532_CMD_GET_FIRMWARE_VERSION */
+struct pn532_fw_version {
+	u8 ic;
+	u8 ver;
+	u8 rev;
+	u8 support;
+};
+
+/* PN532_CMD_RF_CONFIGURATION */
+#define PN532_CFGITEM_TIMING 0x02
+#define PN532_CFGITEM_MAX_RETRIES 0x05
+#define PN532_CFGITEM_PASORI 0x82
+
+#define PN532_CONFIG_TIMING_102 0xb
+#define PN532_CONFIG_TIMING_204 0xc
+#define PN532_CONFIG_TIMING_409 0xd
+#define PN532_CONFIG_TIMING_819 0xe
+
+#define PN532_CONFIG_MAX_RETRIES_NO_RETRY 0x00
+#define PN532_CONFIG_MAX_RETRIES_ENDLESS 0xFF
+
+struct pn532_config_max_retries {
+	u8 mx_rty_atr;
+	u8 mx_rty_psl;
+	u8 mx_rty_passive_act;
+} __packed;
+
+struct pn532_config_timing {
+	u8 rfu;
+	u8 atr_res_timeout;
+	u8 dep_timeout;
+} __packed;
+
+/* PN532_CMD_IN_LIST_PASSIVE_TARGET */
+
+/* felica commands opcode */
+#define PN532_FELICA_OPC_SENSF_REQ 0
+#define PN532_FELICA_OPC_SENSF_RES 1
+/* felica SENSF_REQ parameters */
+#define PN532_FELICA_SENSF_SC_ALL 0xFFFF
+#define PN532_FELICA_SENSF_RC_NO_SYSTEM_CODE 0
+#define PN532_FELICA_SENSF_RC_SYSTEM_CODE 1
+#define PN532_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2
+
+/* type B initiator_data values */
+#define PN532_TYPE_B_AFI_ALL_FAMILIES 0
+#define PN532_TYPE_B_POLL_METHOD_TIMESLOT 0
+#define PN532_TYPE_B_POLL_METHOD_PROBABILISTIC 1
+
+union pn532_cmd_poll_initdata {
+	struct {
+		u8 afi;
+		u8 polling_method;
+	} __packed type_b;
+	struct {
+		u8 opcode;
+		__be16 sc;
+		u8 rc;
+		u8 tsn;
+	} __packed felica;
+};
+
+/* Poll modulations */
+enum {
+	PN532_POLL_MOD_106KBPS_A,
+	PN532_POLL_MOD_212KBPS_FELICA,
+	PN532_POLL_MOD_424KBPS_FELICA,
+	PN532_POLL_MOD_106KBPS_JEWEL,
+	PN532_POLL_MOD_106KBPS_B,
+	PN532_LISTEN_MOD,
+
+	__PN532_POLL_MOD_AFTER_LAST,
+};
+#define PN532_POLL_MOD_MAX (__PN532_POLL_MOD_AFTER_LAST - 1)
+
+struct pn532_poll_modulations {
+	struct {
+		u8 maxtg;
+		u8 brty;
+		union pn532_cmd_poll_initdata initiator_data;
+	} __packed data;
+	u8 len;
+};
+
+static const struct pn532_poll_modulations poll_mod[] = {
+	[PN532_POLL_MOD_106KBPS_A] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 0,
+		},
+		.len = 2,
+	},
+	[PN532_POLL_MOD_212KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 1,
+			.initiator_data.felica = {
+				.opcode = PN532_FELICA_OPC_SENSF_REQ,
+				.sc = PN532_FELICA_SENSF_SC_ALL,
+				.rc = PN532_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		},
+		.len = 7,
+	},
+	[PN532_POLL_MOD_424KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 2,
+			.initiator_data.felica = {
+				.opcode = PN532_FELICA_OPC_SENSF_REQ,
+				.sc = PN532_FELICA_SENSF_SC_ALL,
+				.rc = PN532_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		 },
+		.len = 7,
+	},
+	[PN532_POLL_MOD_106KBPS_JEWEL] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 4,
+		},
+		.len = 2,
+	},
+	[PN532_POLL_MOD_106KBPS_B] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 3,
+			.initiator_data.type_b = {
+				.afi = PN532_TYPE_B_AFI_ALL_FAMILIES,
+				.polling_method =
+					PN532_TYPE_B_POLL_METHOD_TIMESLOT,
+			},
+		},
+		.len = 3,
+	},
+	[PN532_LISTEN_MOD] = {
+		.len = 0,
+	},
+};
+
+/* PN532_CMD_IN_ATR */
+
+struct pn532_cmd_activate_response {
+	u8 status;
+	u8 nfcid3t[10];
+	u8 didt;
+	u8 bst;
+	u8 brt;
+	u8 to;
+	u8 ppt;
+	/* optional */
+	u8 gt[];
+} __packed;
+
+struct pn532_cmd_jump_dep_response {
+	u8 status;
+	u8 tg;
+	u8 nfcid3t[10];
+	u8 didt;
+	u8 bst;
+	u8 brt;
+	u8 to;
+	u8 ppt;
+	/* optional */
+	u8 gt[];
+} __packed;
+
+/* PN532_CMD_IN_AUTOPOLL */
+#define PN532_AUTOPOLL_POLLNR_INFINITE	0xff
+#define PN532_AUTOPOLL_PERIOD		0x03 /* in units of 150 ms */
+
+#define PN532_AUTOPOLL_TYPE_GENERIC_106		0x00
+#define PN532_AUTOPOLL_TYPE_GENERIC_212		0x01
+#define PN532_AUTOPOLL_TYPE_GENERIC_424		0x02
+#define PN532_AUTOPOLL_TYPE_JEWEL		0x04
+#define PN532_AUTOPOLL_TYPE_MIFARE		0x10
+#define PN532_AUTOPOLL_TYPE_FELICA212		0x11
+#define PN532_AUTOPOLL_TYPE_FELICA424		0x12
+#define PN532_AUTOPOLL_TYPE_ISOA		0x20
+#define PN532_AUTOPOLL_TYPE_ISOB		0x23
+#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_106	0x40
+#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_212	0x41
+#define PN532_AUTOPOLL_TYPE_DEP_ACTIVE_424	0x42
+#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_106	0x80
+#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_212	0x81
+#define PN532_AUTOPOLL_TYPE_DEP_PASSIVE_424	0x82
+
+/* PN532_TG_INIT_AS_TARGET */
+#define PN532_INIT_TARGET_PASSIVE 0x1
+#define PN532_INIT_TARGET_DEP 0x2
+
+#define PN532_INIT_TARGET_RESP_FRAME_MASK 0x3
+#define PN532_INIT_TARGET_RESP_ACTIVE     0x1
+#define PN532_INIT_TARGET_RESP_DEP        0x4
+
+#define PN532_MAGIC		0x162f
+
+struct pn532_frame {
+	u8 preamble;
+	__be16 start_frame;
+	u8 datalen;
+	u8 datalen_checksum;
+	u8 data[];
+} __packed;
+
+typedef int (*pn532_recv_complete_t) (struct pn532 *dev,
+					struct pn532_frame *frame);
+
+struct pn532 {
+	int magic;
+	struct tty_struct *tty;
+	struct nfc_dev *nfc_dev;
+
+	/* These are pointers to the malloc()ed frame buffers. */
+	/*
+	unsigned char		rbuff[PN532_FRAME_HEADER_LEN +
+				      PN532_FRAME_MAX_PAYLOAD_LEN +
+				      PN532_FRAME_TAIL_LEN
+				     ];	*//* receiver buffer	     */
+	unsigned char *rbuf;
+	int rlen; /* length of receive buffer */
+	int rcount; /* received chars counter    */
+	pn532_recv_complete_t recv_complete;
+
+	/*
+	unsigned char		xbuff[PN532_FRAME_HEADER_LEN +
+				      PN532_FRAME_MAX_PAYLOAD_LEN +
+				      PN532_FRAME_TAIL_LEN
+				     ];	*//* transmitter buffer	     */
+	unsigned char *xbuf;
+	unsigned char		*xhead;         /* pointer to next XMIT byte */
+	int			xleft;          /* bytes left in XMIT queue  */
+	unsigned	wakeup;
+
+	struct sk_buff_head resp_q;
+
+	struct workqueue_struct	*wq;
+	struct workqueue_struct	*wq_deactivate_tgt;
+	struct workqueue_struct	*wq_conn_nfc;
+	struct work_struct cmd_work;
+	struct work_struct cmd_complete_work;
+	struct work_struct poll_work;
+	struct work_struct mi_work;
+	struct work_struct tg_work;
+	struct work_struct conn_nfc_work;
+	struct work_struct deactivate_tgt_work;
+	struct timer_list listen_timer;
+	int wq_in_error;
+	int cancel_listen;
+
+	pn532_cmd_complete_t cmd_complete;
+	void *cmd_complete_arg;
+	void *cmd_complete_mi_arg;
+	struct mutex cmd_lock; /* Lock for modifying the cmd_pending, cmd,
+				  cmd_complete, cmd_complete_arg and setting
+				  the buffer of this struct */
+	u8 cmd;
+
+	struct pn532_poll_modulations *poll_mod_active[PN532_POLL_MOD_MAX + 1];
+	u8 poll_mod_count;
+	u8 poll_mod_curr;
+	u32 poll_protocols;
+	u32 listen_protocols;
+
+	u8 *gb;
+	size_t gb_len;
+
+	u8 tgt_available_prots;
+	u8 tgt_active_prot;
+	u8 tgt_mode;
+
+	u32 device_type;
+
+	struct list_head cmd_queue;
+	u8 cmd_pending;
+
+	struct pn532_frame_ops *ops;
+};
+
+struct pn532_cmd {
+	struct list_head queue;
+	u8 cmd_code;
+	struct sk_buff *req;
+	struct sk_buff *resp;
+	int resp_len;
+	void *arg;
+};
+
+struct pn532_frame_ops {
+	void (*tx_frame_init)(void *frame, u8 cmd_code);
+	void (*tx_frame_finish)(void *frame);
+	void (*tx_update_payload_len)(void *frame, int len);
+	int tx_header_len;
+	int tx_tail_len;
+
+	bool (*rx_is_frame_valid)(void *frame);
+	int (*rx_frame_size)(void *frame);
+	int rx_header_len;
+	int rx_tail_len;
+
+	int max_payload_len;
+	u8 (*get_cmd_code)(void *frame);
+};
+
+/* The rule: value + checksum = 0 */
+static inline u8 pn532_checksum(u8 value)
+{
+	return ~value + 1;
+}
+
+/* The rule: sum(data elements) + checksum = 0 */
+static u8 pn532_data_checksum(u8 *data, int datalen)
+{
+	u8 sum = 0;
+	int i;
+
+	for (i = 0; i < datalen; i++)
+		sum += data[i];
+
+	return pn532_checksum(sum);
+}
+
+static void pn532_tx_frame_init(void *_frame, u8 cmd_code)
+{
+	struct pn532_frame *frame = _frame;
+
+	frame->preamble = 0;
+	frame->start_frame = cpu_to_be16(PN532_SOF);
+	PN532_FRAME_IDENTIFIER(frame) = PN532_DIR_OUT;
+	PN532_FRAME_CMD(frame) = cmd_code;
+	frame->datalen = 2;
+}
+
+static void pn532_tx_frame_finish(void *_frame)
+{
+	struct pn532_frame *frame = _frame;
+
+	frame->datalen_checksum = pn532_checksum(frame->datalen);
+
+	PN532_FRAME_CHECKSUM(frame) =
+		pn532_data_checksum(frame->data, frame->datalen);
+
+	PN532_FRAME_POSTAMBLE(frame) = 0;
+}
+
+static void pn532_tx_update_payload_len(void *_frame, int len)
+{
+	struct pn532_frame *frame = _frame;
+
+	frame->datalen += len;
+}
+
+static bool pn532_rx_frame_is_valid(void *_frame)
+{
+	u8 checksum;
+	struct pn532_frame *frame = _frame;
+
+	if (frame->start_frame != cpu_to_be16(PN532_SOF))
+		return false;
+
+	checksum = pn532_checksum(frame->datalen);
+	if (checksum != frame->datalen_checksum)
+		return false;
+
+	checksum = pn532_data_checksum(frame->data, frame->datalen);
+	if (checksum != PN532_FRAME_CHECKSUM(frame))
+		return false;
+
+	return true;
+}
+
+static bool pn532_rx_frame_is_ack(struct pn532_frame *frame)
+{
+	if (frame->start_frame != cpu_to_be16(PN532_SOF))
+		return false;
+
+	if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
+		return false;
+
+	return true;
+}
+
+static inline int pn532_rx_frame_size(void *frame)
+{
+	struct pn532_frame *f = frame;
+
+	return sizeof(struct pn532_frame) + f->datalen + PN532_FRAME_TAIL_LEN;
+}
+
+static u8 pn532_get_cmd_code(void *frame)
+{
+	struct pn532_frame *f = frame;
+
+	return PN532_FRAME_CMD(f);
+}
+
+static struct pn532_frame_ops pn532_std_frame_ops = {
+	.tx_frame_init = pn532_tx_frame_init,
+	.tx_frame_finish = pn532_tx_frame_finish,
+	.tx_update_payload_len = pn532_tx_update_payload_len,
+	.tx_header_len = PN532_FRAME_HEADER_LEN,
+	.tx_tail_len = PN532_FRAME_TAIL_LEN,
+
+	.rx_is_frame_valid = pn532_rx_frame_is_valid,
+	.rx_frame_size = pn532_rx_frame_size,
+	.rx_header_len = PN532_FRAME_HEADER_LEN,
+	.rx_tail_len = PN532_FRAME_TAIL_LEN,
+
+	.max_payload_len =  PN532_FRAME_MAX_PAYLOAD_LEN,
+	.get_cmd_code = pn532_get_cmd_code,
+};
+
+static bool pn532_rx_frame_is_cmd_response(struct pn532 *dev, void *frame)
+{
+	return (dev->ops->get_cmd_code(frame) == PN532_CMD_RESPONSE(dev->cmd));
+}
+
+
+static void pn532_wq_cmd_complete(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, cmd_complete_work);
+	int rc;
+
+	rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
+
+	nfc_dev_dbg(dev->tty->dev, "%s rc:%i", __func__, rc);
+	if (rc != -EINPROGRESS)
+		queue_work(dev->wq, &dev->cmd_work);
+}
+
+static int pn532_recv_response(struct pn532 *dev, struct pn532_frame *frame)
+{
+	nfc_dev_dbg(dev->tty->dev, "%s Received a frame.", __func__);
+	print_hex_dump(KERN_DEBUG, "PN532 RX: ", DUMP_PREFIX_NONE, 16, 1,
+		       frame, dev->ops->rx_frame_size(frame), false);
+
+	if (!dev->ops->rx_is_frame_valid(frame)) {
+		nfc_dev_err(dev->tty->dev, "Received an invalid frame");
+		dev->wq_in_error = -EIO;
+		goto sched_wq;
+	}
+
+	if (!pn532_rx_frame_is_cmd_response(dev, frame)) {
+		nfc_dev_err(dev->tty->dev,
+			    "It it not the response to the last command");
+		dev->wq_in_error = -EIO;
+		goto sched_wq;
+	}
+
+	dev->wq_in_error = 0;
+	queue_work(dev->wq, &dev->cmd_complete_work);
+	return 0;
+
+sched_wq:
+	queue_work(dev->wq, &dev->cmd_complete_work);
+	return -1;
+}
+
+
+static int pn532_recv_ack(struct pn532 *dev, struct pn532_frame *frame)
+{
+	if (!pn532_rx_frame_is_ack(frame)) {
+		nfc_dev_err(dev->tty->dev, "Received an invalid ack");
+		dev->wq_in_error = -EIO;
+		goto sched_wq;
+	}
+
+	dev->recv_complete = pn532_recv_response;
+
+	return 0;
+
+sched_wq:
+	queue_work(dev->wq, &dev->cmd_complete_work);
+	return -1;
+}
+
+static int pn532_send_ack(struct pn532 *dev, gfp_t flags)
+{
+	u8 ack[PN532_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+	/* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
+	int rc;
+
+	dev->xbuf = ack;
+
+	set_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
+	rc = dev->tty->ops->write(dev->tty, dev->xbuf, sizeof(ack));
+	dev->xleft = sizeof(ack) - rc;
+	dev->xhead = dev->xbuf + rc;
+
+	return 0;
+}
+
+static int __pn532_send_frame_async(struct pn532 *dev,
+					struct sk_buff *out,
+					struct sk_buff *in,
+					int in_len,
+					pn532_cmd_complete_t cmd_complete,
+					void *arg)
+{
+	int count;
+	unsigned char wakeup[] = {0x55, 0x55, 0x00, 0x00, 0x00, 0x00};
+
+	nfc_dev_dbg(dev->tty->dev, "%s wakeup:%i", __func__, dev->wakeup);
+
+	dev->cmd = dev->ops->get_cmd_code(out->data);
+	dev->cmd_complete = cmd_complete;
+	dev->cmd_complete_arg = arg;
+
+	dev->xbuf = out->data;
+	dev->rbuf = in->data;
+	dev->rlen = in_len;
+
+	print_hex_dump(KERN_DEBUG, "PN532 TX: ", DUMP_PREFIX_NONE, 16, 1,
+		       out->data, out->len, false);
+
+	if (dev->wakeup) {
+		dev->tty->ops->write(dev->tty, wakeup, sizeof(wakeup));
+		dev->wakeup = 0;
+	}
+	set_bit(TTY_DO_WRITE_WAKEUP, &dev->tty->flags);
+	count = dev->tty->ops->write(dev->tty, dev->xbuf, out->len);
+	dev->xleft = out->len - count;
+	dev->xhead = dev->xbuf + count;
+
+	nfc_dev_dbg(dev->tty->dev, "count:%i xleft:%i", count, dev->xleft);
+
+	dev->recv_complete = pn532_recv_ack;
+
+	return 0;
+}
+
+static void pn532_build_cmd_frame(struct pn532 *dev, u8 cmd_code,
+				  struct sk_buff *skb)
+{
+	/* payload is already there, just update datalen */
+	int payload_len = skb->len;
+	struct pn532_frame_ops *ops = dev->ops;
+
+
+	skb_push(skb, ops->tx_header_len);
+	skb_put(skb, ops->tx_tail_len);
+
+	ops->tx_frame_init(skb->data, cmd_code);
+	ops->tx_update_payload_len(skb->data, payload_len);
+	ops->tx_frame_finish(skb->data);
+}
+
+struct pn532_send_async_complete_arg {
+	pn532_send_async_complete_t  complete_cb;
+	void *complete_cb_context;
+	struct sk_buff *resp;
+	struct sk_buff *req;
+};
+
+static int pn532_send_async_complete(struct pn532 *dev, void *_arg, int status)
+{
+	struct pn532_send_async_complete_arg *arg = _arg;
+
+	struct sk_buff *req = arg->req;
+	struct sk_buff *resp = arg->resp;
+
+	int rc;
+
+	dev_kfree_skb(req);
+
+	if (status < 0) {
+		nfc_dev_dbg(dev->tty->dev, "%s error way status < 0", __func__);
+		arg->complete_cb(dev, arg->complete_cb_context,
+				 ERR_PTR(status));
+		dev_kfree_skb(resp);
+		kfree(arg);
+		return status;
+	}
+
+	skb_put(resp, dev->ops->rx_frame_size(resp->data));
+	skb_pull(resp, dev->ops->rx_header_len);
+	skb_trim(resp, resp->len - dev->ops->rx_tail_len);
+
+	rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+
+	kfree(arg);
+	return rc;
+}
+
+static int __pn532_send_async(struct pn532 *dev, u8 cmd_code,
+			      struct sk_buff *req, struct sk_buff *resp,
+			      int resp_len,
+			      pn532_send_async_complete_t complete_cb,
+			      void *complete_cb_context)
+{
+	struct pn532_cmd *cmd;
+	struct pn532_send_async_complete_arg *arg;
+	int rc = 0;
+
+	nfc_dev_dbg(dev->tty->dev, "%s Sending command 0x%x",
+			__func__, cmd_code);
+
+	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg)
+		return -ENOMEM;
+
+	arg->complete_cb = complete_cb;
+	arg->complete_cb_context = complete_cb_context;
+	arg->resp = resp;
+	arg->req = req;
+
+	pn532_build_cmd_frame(dev, cmd_code, req);
+
+	mutex_lock(&dev->cmd_lock);
+
+	if (!dev->cmd_pending) {
+		rc = __pn532_send_frame_async(dev, req, resp, resp_len,
+					      pn532_send_async_complete, arg);
+		if (rc)
+			goto error;
+
+		dev->cmd_pending = 1;
+		goto unlock;
+	}
+
+	nfc_dev_dbg(dev->tty->dev, "%s Queuing command 0x%x", __func__,
+		    cmd_code);
+
+	cmd = kzalloc(sizeof(struct pn532_cmd), GFP_KERNEL);
+	if (!cmd) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	INIT_LIST_HEAD(&cmd->queue);
+	cmd->cmd_code = cmd_code;
+	cmd->req = req;
+	cmd->resp = resp;
+	cmd->resp_len = resp_len;
+	cmd->arg = arg;
+
+	list_add_tail(&cmd->queue, &dev->cmd_queue);
+
+	goto unlock;
+
+error:
+	kfree(arg);
+unlock:
+	mutex_unlock(&dev->cmd_lock);
+	return rc;
+}
+
+static int pn532_send_data_async(struct pn532 *dev, u8 cmd_code,
+				 struct sk_buff *req,
+				 pn532_send_async_complete_t complete_cb,
+				 void *complete_cb_context)
+{
+	struct sk_buff *resp;
+	int rc;
+	int  resp_len = dev->ops->rx_header_len +
+			dev->ops->max_payload_len +
+			dev->ops->rx_tail_len;
+
+	resp = nfc_alloc_recv_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	rc = __pn532_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+				complete_cb_context);
+	if (rc)
+		dev_kfree_skb(resp);
+
+	return rc;
+}
+
+static int pn532_send_cmd_async(struct pn532 *dev, u8 cmd_code,
+				struct sk_buff *req,
+				pn532_send_async_complete_t complete_cb,
+				void *complete_cb_context)
+{
+	struct sk_buff *resp;
+	int rc;
+	int  resp_len = dev->ops->rx_header_len +
+			dev->ops->max_payload_len +
+			dev->ops->rx_tail_len;
+
+	resp = alloc_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	rc = __pn532_send_async(dev, cmd_code, req, resp, resp_len, complete_cb,
+				complete_cb_context);
+	if (rc)
+		dev_kfree_skb(resp);
+
+	return rc;
+}
+
+/*
+ * pn532_send_cmd_direct_async
+ *
+ * The function sends a piority cmd directly to the chip omiting the cmd
+ * queue. It's intended to be used by chaining mechanism of received responses
+ * where the host has to request every single chunk of data before scheduling
+ * next cmd from the queue.
+ */
+static int pn532_send_cmd_direct_async(struct pn532 *dev, u8 cmd_code,
+				       struct sk_buff *req,
+				       pn532_send_async_complete_t complete_cb,
+				       void *complete_cb_context)
+{
+	struct pn532_send_async_complete_arg *arg;
+	struct sk_buff *resp;
+	int rc;
+	int resp_len = dev->ops->rx_header_len +
+		       dev->ops->max_payload_len +
+		       dev->ops->rx_tail_len;
+
+	resp = alloc_skb(resp_len, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		dev_kfree_skb(resp);
+		return -ENOMEM;
+	}
+
+	arg->complete_cb = complete_cb;
+	arg->complete_cb_context = complete_cb_context;
+	arg->resp = resp;
+	arg->req = req;
+
+	pn532_build_cmd_frame(dev, cmd_code, req);
+
+	rc = __pn532_send_frame_async(dev, req, resp, resp_len,
+				      pn532_send_async_complete, arg);
+	if (rc < 0) {
+		dev_kfree_skb(resp);
+		kfree(arg);
+	}
+
+	return rc;
+}
+
+static void pn532_wq_cmd(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, cmd_work);
+	struct pn532_cmd *cmd;
+
+	mutex_lock(&dev->cmd_lock);
+
+	if (list_empty(&dev->cmd_queue)) {
+		dev->cmd_pending = 0;
+		mutex_unlock(&dev->cmd_lock);
+		return;
+	}
+
+	cmd = list_first_entry(&dev->cmd_queue, struct pn532_cmd, queue);
+
+	list_del(&cmd->queue);
+
+	mutex_unlock(&dev->cmd_lock);
+
+	__pn532_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
+				 pn532_send_async_complete, cmd->arg);
+
+	kfree(cmd);
+}
+
+struct pn532_sync_cmd_response {
+	struct sk_buff *resp;
+	struct completion done;
+};
+
+static int pn532_send_sync_complete(struct pn532 *dev, void *_arg,
+				    struct sk_buff *resp)
+{
+	struct pn532_sync_cmd_response *arg = _arg;
+
+	nfc_dev_dbg(dev->tty->dev, "%s arg:%p resp:%p", __func__, arg, resp);
+
+	arg->resp = resp;
+	nfc_dev_dbg(dev->tty->dev, "%s done:%p", __func__, &arg->done);
+	complete(&arg->done);
+
+	return 0;
+}
+
+/*  pn532_send_cmd_sync
+ *
+ *  Please note the req parameter is freed inside the function to
+ *  limit a number of return value interpretations by the caller.
+ *
+ *  1. negative in case of error during TX path -> req should be freed
+ *
+ *  2. negative in case of error during RX path -> req should not be freed
+ *     as it's been already freed at the beginning of RX path by
+ *     async_complete_cb.
+ *
+ *  3. valid pointer in case of successful RX path
+ *
+ *  A caller has to check a return value with IS_ERR macro. If the test pass,
+ *  the returned pointer is valid.
+ *
+ * */
+static struct sk_buff *pn532_send_cmd_sync(struct pn532 *dev, u8 cmd_code,
+					       struct sk_buff *req)
+{
+	int rc;
+	struct pn532_sync_cmd_response arg;
+
+	init_completion(&arg.done);
+
+	rc = pn532_send_cmd_async(dev, cmd_code, req,
+				  pn532_send_sync_complete, &arg);
+	if (rc) {
+		dev_kfree_skb(req);
+		return ERR_PTR(rc);
+	}
+
+	/* TODO den Timeout richtig einstellen */
+	rc = wait_for_completion_timeout(&arg.done, HZ);
+	if (rc <= 0)
+		return ERR_PTR(-ETIMEDOUT);
+
+	return arg.resp;
+}
+
+/*
+ * Allocates a skb and reserves space for the tx_header
+ */
+static struct sk_buff *pn532_alloc_skb(struct pn532 *dev, unsigned int size)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(dev->ops->tx_header_len +
+			size +
+			dev->ops->tx_tail_len, GFP_KERNEL);
+
+	if (skb)
+		skb_reserve(skb, dev->ops->tx_header_len);
+
+	return skb;
+}
+
+struct pn532_target_type_a {
+	__be16 sens_res;
+	u8 sel_res;
+	u8 nfcid_len;
+	u8 nfcid_data[];
+} __packed;
+
+
+#define PN532_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6))
+#define PN532_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0))
+#define PN532_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8))
+
+#define PN532_TYPE_A_SENS_RES_SSD_JEWEL 0x00
+#define PN532_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C
+
+#define PN532_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5)
+#define PN532_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2)
+
+#define PN532_TYPE_A_SEL_PROT_MIFARE 0
+#define PN532_TYPE_A_SEL_PROT_ISO14443 1
+#define PN532_TYPE_A_SEL_PROT_DEP 2
+#define PN532_TYPE_A_SEL_PROT_ISO14443_DEP 3
+
+static bool pn532_target_type_a_is_valid(struct pn532_target_type_a *type_a,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn532_target_type_a))
+		return false;
+
+	/* The lenght check of nfcid[] and ats[] are not being performed because
+	   the values are not being used */
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN532_TYPE_A_SENS_RES_SSD(type_a->sens_res);
+	platconf = PN532_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
+
+	if ((ssd == PN532_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf != PN532_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+	    (ssd != PN532_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf == PN532_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	/* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
+	if (PN532_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0)
+		return false;
+
+	return true;
+}
+
+static int pn532_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn532_target_type_a *tgt_type_a;
+
+	tgt_type_a = (struct pn532_target_type_a *)tgt_data;
+
+	if (!pn532_target_type_a_is_valid(tgt_type_a, tgt_data_len))
+		return -EPROTO;
+
+	switch (PN532_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) {
+	case PN532_TYPE_A_SEL_PROT_MIFARE:
+		pr_debug("mifare");
+		nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK;
+		break;
+	case PN532_TYPE_A_SEL_PROT_ISO14443:
+		pr_debug("iso14443");
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK;
+		break;
+	case PN532_TYPE_A_SEL_PROT_DEP:
+		pr_debug("dep");
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		break;
+	case PN532_TYPE_A_SEL_PROT_ISO14443_DEP:
+		pr_debug("iso dep");
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK |
+							NFC_PROTO_NFC_DEP_MASK;
+		break;
+	}
+
+	nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res);
+	nfc_tgt->sel_res = tgt_type_a->sel_res;
+	nfc_tgt->nfcid1_len = tgt_type_a->nfcid_len;
+	memcpy(nfc_tgt->nfcid1, tgt_type_a->nfcid_data, nfc_tgt->nfcid1_len);
+
+	return 0;
+}
+
+struct pn532_target_felica {
+	u8 pol_res;
+	u8 opcode;
+	u8 nfcid2[8];
+	u8 pad[8];
+	/* optional */
+	u8 syst_code[];
+} __packed;
+
+#define PN532_FELICA_SENSF_NFCID2_DEP_B1 0x01
+#define PN532_FELICA_SENSF_NFCID2_DEP_B2 0xFE
+
+static bool pn532_target_felica_is_valid(struct pn532_target_felica *felica,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn532_target_felica))
+		return false;
+
+	if (felica->opcode != PN532_FELICA_OPC_SENSF_RES)
+		return false;
+
+	return true;
+}
+
+static int pn532_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn532_target_felica *tgt_felica;
+
+	tgt_felica = (struct pn532_target_felica *)tgt_data;
+
+	if (!pn532_target_felica_is_valid(tgt_felica, tgt_data_len))
+		return -EPROTO;
+
+	if ((tgt_felica->nfcid2[0] == PN532_FELICA_SENSF_NFCID2_DEP_B1) &&
+	    (tgt_felica->nfcid2[1] == PN532_FELICA_SENSF_NFCID2_DEP_B2))
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+	else
+		nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
+
+	memcpy(nfc_tgt->sensf_res, &tgt_felica->opcode, 9);
+	nfc_tgt->sensf_res_len = 9;
+
+	return 0;
+}
+
+struct pn532_target_jewel {
+	__be16 sens_res;
+	u8 jewelid[4];
+} __packed;
+
+static bool pn532_target_jewel_is_valid(struct pn532_target_jewel *jewel,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn532_target_jewel))
+		return false;
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN532_TYPE_A_SENS_RES_SSD(jewel->sens_res);
+	platconf = PN532_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
+
+	if ((ssd == PN532_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf != PN532_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+	    (ssd != PN532_TYPE_A_SENS_RES_SSD_JEWEL &&
+	     platconf == PN532_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	return true;
+}
+
+static int pn532_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn532_target_jewel *tgt_jewel;
+
+	tgt_jewel = (struct pn532_target_jewel *)tgt_data;
+
+	if (!pn532_target_jewel_is_valid(tgt_jewel, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK;
+	nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res);
+	nfc_tgt->nfcid1_len = 4;
+	memcpy(nfc_tgt->nfcid1, tgt_jewel->jewelid, nfc_tgt->nfcid1_len);
+
+	return 0;
+}
+
+struct pn532_type_b_prot_info {
+	u8 bitrate;
+	u8 fsci_type;
+	u8 fwi_adc_fo;
+} __packed;
+
+#define PN532_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4)
+#define PN532_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0)
+#define PN532_TYPE_B_PROT_TYPE_RFU_MASK 0x8
+
+struct pn532_type_b_sens_res {
+	u8 opcode;
+	u8 nfcid[4];
+	u8 appdata[4];
+	struct pn532_type_b_prot_info prot_info;
+} __packed;
+
+#define PN532_TYPE_B_OPC_SENSB_RES 0x50
+
+struct pn532_target_type_b {
+	struct pn532_type_b_sens_res sensb_res;
+	u8 attrib_res_len;
+	u8 attrib_res[];
+} __packed;
+
+static bool pn532_target_type_b_is_valid(struct pn532_target_type_b *type_b,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn532_target_type_b))
+		return false;
+
+	if (type_b->sensb_res.opcode != PN532_TYPE_B_OPC_SENSB_RES)
+		return false;
+
+	if (PN532_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) &
+						PN532_TYPE_B_PROT_TYPE_RFU_MASK)
+		return false;
+
+	return true;
+}
+
+static int pn532_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn532_target_type_b *tgt_type_b;
+
+	tgt_type_b = (struct pn532_target_type_b *)tgt_data;
+
+	if (!pn532_target_type_b_is_valid(tgt_type_b, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
+
+	return 0;
+}
+
+static inline void pn532_poll_next_mod(struct pn532 *dev)
+{
+	dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+}
+
+static void pn532_poll_reset_mod_list(struct pn532 *dev)
+{
+	dev->poll_mod_count = 0;
+}
+
+struct pn532_autopoll_resp {
+	u8 type;
+	u8 ln;
+	u8 tg;
+	u8 tgdata[];
+};
+
+static int pn532_start_poll_complete(struct pn532 *dev, struct sk_buff *resp)
+{
+	u8 nbtg;
+	int rc;
+	struct pn532_autopoll_resp *pres;
+	struct nfc_target *nfc_tgt;
+
+	nbtg = resp->data[0];
+	if ((nbtg > 2) || (nbtg <= 0))
+		return -EAGAIN;
+
+	nfc_tgt = kzalloc(nbtg * sizeof(struct nfc_target), GFP_KERNEL);
+	if (!nfc_tgt)
+		return -ENOMEM;
+
+	pres = (struct pn532_autopoll_resp *)&resp->data[1];
+
+	while (nbtg--) {
+		nfc_dev_dbg(dev->tty->dev, "%s -type=0x%x tg=%d nbtg=%d ln=%d",
+			__func__, pres->type, pres->tg, nbtg, pres->ln);
+
+		if (pres->tg != 1)
+			return -EPROTO;
+
+		switch (pres->type) {
+		case PN532_AUTOPOLL_TYPE_ISOA:
+			nfc_dev_dbg(dev->tty->dev, "ISOA");
+			rc = pn532_target_found_type_a(nfc_tgt, pres->tgdata,
+						       pres->ln - 1);
+			break;
+		case PN532_AUTOPOLL_TYPE_FELICA212:
+		case PN532_AUTOPOLL_TYPE_FELICA424:
+			nfc_dev_dbg(dev->tty->dev, "FELICA");
+			rc = pn532_target_found_felica(nfc_tgt, pres->tgdata,
+						       pres->ln - 1);
+			break;
+		case PN532_AUTOPOLL_TYPE_JEWEL:
+			nfc_dev_dbg(dev->tty->dev, "JEWEL");
+			rc = pn532_target_found_jewel(nfc_tgt, pres->tgdata,
+						      pres->ln - 1);
+			break;
+		case PN532_AUTOPOLL_TYPE_ISOB:
+			nfc_dev_dbg(dev->tty->dev, "ISOB");
+			rc = pn532_target_found_type_b(nfc_tgt, pres->tgdata,
+						       pres->ln - 1);
+			break;
+		default:
+			nfc_dev_dbg(dev->tty->dev, "default");
+			nfc_dev_err(dev->tty->dev,
+				    "Unknown current poll modulation");
+			return -EPROTO;
+		}
+
+		nfc_dev_dbg(dev->tty->dev, "%s rc:%d", __func__, rc);
+
+		if (rc)
+			return rc;
+
+		if (!(nfc_tgt->supported_protocols & dev->poll_protocols)) {
+			nfc_dev_dbg(dev->tty->dev,
+				    "The Tg found doesn't have the desired protocol");
+			return -EAGAIN;
+		}
+
+		nfc_dev_dbg(dev->tty->dev,
+			    "Target found - supported protocols: 0x%x",
+			    nfc_tgt->supported_protocols);
+
+		dev->tgt_available_prots = nfc_tgt->supported_protocols;
+		pres = (struct pn532_autopoll_resp *)
+					(pres->tgdata + (pres->ln));
+	}
+	nfc_targets_found(dev->nfc_dev, nfc_tgt, resp->data[0]);
+
+	kfree(nfc_tgt);
+	return 0;
+}
+
+static struct sk_buff *pn532_alloc_poll_tg_frame(struct pn532 *dev)
+{
+	struct sk_buff *skb;
+	u8 *felica, *nfcid3, *gb;
+
+	u8 *gbytes = dev->gb;
+	size_t gbytes_len = dev->gb_len;
+
+	u8 felica_params[18] = {0x1, 0xfe, /* DEP */
+				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
+				0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+				0xff, 0xff}; /* System code */
+
+	u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
+			       0x0, 0x0, 0x0,
+			       0x40}; /* SEL_RES for DEP */
+
+	unsigned int skb_len = 36 + /* mode (1), mifare (6),
+				       felica (18), nfcid3 (10), gb_len (1) */
+			       gbytes_len +
+			       1;  /* len Tk*/
+
+	skb = pn532_alloc_skb(dev, skb_len);
+	if (!skb)
+		return NULL;
+
+	/* DEP support only */
+	*skb_put(skb, 1) = PN532_INIT_TARGET_DEP;
+
+	/* MIFARE params */
+	memcpy(skb_put(skb, 6), mifare_params, 6);
+
+	/* Felica params */
+	felica = skb_put(skb, 18);
+	memcpy(felica, felica_params, 18);
+	get_random_bytes(felica + 2, 6);
+
+	/* NFCID3 */
+	nfcid3 = skb_put(skb, 10);
+	memset(nfcid3, 0, 10);
+	memcpy(nfcid3, felica, 8);
+
+	/* General bytes */
+	*skb_put(skb, 1) = gbytes_len;
+
+	gb = skb_put(skb, gbytes_len);
+	memcpy(gb, gbytes, gbytes_len);
+
+	/* Len Tk */
+	*skb_put(skb, 1) = 0;
+
+	return skb;
+}
+
+#define PN532_CMD_DATAEXCH_HEAD_LEN 1
+#define PN532_CMD_DATAEXCH_DATA_MAXLEN 262
+static int pn532_tm_get_data_complete(struct pn532 *dev, void *arg,
+				      struct sk_buff *resp)
+{
+	u8 status;
+
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	status = resp->data[0];
+	skb_pull(resp, sizeof(status));
+
+	if (status != 0) {
+		nfc_tm_deactivated(dev->nfc_dev);
+		dev->tgt_mode = 0;
+		dev_kfree_skb(resp);
+		return 0;
+	}
+
+	return nfc_tm_data_received(dev->nfc_dev, resp);
+}
+
+static void pn532_wq_tg_get_data(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, tg_work);
+
+	struct sk_buff *skb;
+	int rc;
+
+	skb = pn532_alloc_skb(dev, 0);
+	if (!skb)
+		return;
+
+	rc = pn532_send_data_async(dev, PN532_CMD_TG_GET_DATA, skb,
+				   pn532_tm_get_data_complete, NULL);
+
+	if (rc < 0)
+		dev_kfree_skb(skb);
+
+	return;
+}
+
+static void pn532_listen_mode_timer(unsigned long data)
+{
+	struct pn532 *dev = (struct pn532 *)data;
+
+	nfc_dev_dbg(dev->tty->dev, "Listen mode timeout");
+
+	/* An ack will cancel the last issued command (poll) */
+	pn532_send_ack(dev, GFP_ATOMIC);
+
+	dev->cancel_listen = 1;
+
+	pn532_poll_next_mod(dev);
+
+	queue_work(dev->wq, &dev->poll_work);
+}
+
+static int pn532_poll_complete(struct pn532 *dev, void *arg,
+			       struct sk_buff *resp)
+{
+	int rc;
+
+	nfc_dev_dbg(dev->tty->dev, "%s", __func__);
+
+	if (IS_ERR(resp)) {
+		rc = PTR_ERR(resp);
+
+		nfc_dev_err(dev->tty->dev, "%s  Poll complete error %d",
+			    __func__, rc);
+
+		if (rc == -ENOENT) {
+			if (dev->poll_mod_count != 0)
+				return rc;
+			else
+				goto stop_poll;
+		} else if (rc < 0) {
+			nfc_dev_err(dev->tty->dev,
+				    "Error %d when running poll", rc);
+			goto stop_poll;
+		}
+	}
+
+	rc = pn532_start_poll_complete(dev, resp);
+	if (!rc)
+		goto done;
+
+done:
+	dev_kfree_skb(resp);
+	return rc;
+
+stop_poll:
+	nfc_dev_err(dev->tty->dev, "Polling operation has been stopped");
+
+	pn532_poll_reset_mod_list(dev);
+	dev->poll_protocols = 0;
+	return rc;
+}
+
+static struct sk_buff *pn532_alloc_poll_in_frame(struct pn532 *dev,
+					struct pn532_poll_modulations *mod)
+{
+	struct sk_buff *skb;
+
+	skb = pn532_alloc_skb(dev, mod->len);
+	if (!skb)
+		return NULL;
+
+	memcpy(skb_put(skb, mod->len), &mod->data, mod->len);
+
+	return skb;
+}
+
+static int pn532_send_poll_frame(struct pn532 *dev)
+{
+	struct pn532_poll_modulations *mod;
+	struct sk_buff *skb;
+	int rc;
+	u8 cmd_code;
+
+	mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	nfc_dev_dbg(dev->tty->dev, "%s mod len %d\n",
+		    __func__, mod->len);
+
+	if (mod->len == 0) {  /* Listen mode */
+		cmd_code = PN532_CMD_TG_INIT_AS_TARGET;
+		skb = pn532_alloc_poll_tg_frame(dev);
+	} else {  /* Polling mode */
+		cmd_code =  PN532_CMD_IN_AUTOPOLL;
+		skb = pn532_alloc_poll_in_frame(dev, mod);
+	}
+
+	if (!skb) {
+		nfc_dev_err(dev->tty->dev, "Failed to allocate skb.");
+		return -ENOMEM;
+	}
+
+	rc = pn532_send_cmd_async(dev, cmd_code, skb, pn532_poll_complete,
+				  NULL);
+	if (rc < 0) {
+		dev_kfree_skb(skb);
+		nfc_dev_err(dev->tty->dev, "Polling loop error %d", rc);
+	}
+
+	return rc;
+}
+
+static void pn532_wq_poll(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, poll_work);
+	struct pn532_poll_modulations *cur_mod;
+	int rc;
+
+	cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	nfc_dev_dbg(dev->tty->dev,
+		    "%s cancel_listen %d modulation len %d",
+		    __func__, dev->cancel_listen, cur_mod->len);
+
+	if (dev->cancel_listen == 1) {
+		dev->cancel_listen = 0;
+		/*
+		usb_kill_urb(dev->in_urb);
+		*/
+	}
+
+	rc = pn532_send_poll_frame(dev);
+	if (rc)
+		return;
+
+	if (cur_mod->len == 0 && dev->poll_mod_count > 1)
+		mod_timer(&dev->listen_timer, jiffies + PN532_LISTEN_TIME * HZ);
+
+	return;
+}
+
+static int pn532_start_auto_poll(struct nfc_dev *nfc_dev,
+			    u32 im_protocols, u32 tm_protocols)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+	u8	rc;
+	struct sk_buff *skb;
+
+	nfc_dev_dbg(dev->tty->dev,
+		    "%s: im protocols 0x%x tm protocols 0x%x",
+		    __func__, im_protocols, tm_protocols);
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(dev->tty->dev,
+			    "Cannot poll with a target already activated");
+		return -EBUSY;
+	}
+
+	if (dev->tgt_mode) {
+		nfc_dev_err(dev->tty->dev,
+			    "Cannot poll while already being activated");
+		return -EBUSY;
+	}
+
+	if (tm_protocols) {
+		dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
+		if (dev->gb == NULL)
+			tm_protocols = 0;
+	}
+
+	skb = pn532_alloc_skb(dev, 4 + 6);
+	if (!skb) {
+		nfc_dev_err(dev->tty->dev, "Failed to allocate skb.");
+		return -ENOMEM;
+	}
+
+	*skb_put(skb, 1) = PN532_AUTOPOLL_POLLNR_INFINITE;
+	*skb_put(skb, 1) = PN532_AUTOPOLL_PERIOD;
+
+	if ((im_protocols & NFC_PROTO_MIFARE_MASK) ||
+	    (im_protocols & NFC_PROTO_ISO14443_MASK) ||
+	    (im_protocols & NFC_PROTO_NFC_DEP_MASK))
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_ISOA;
+
+	if (im_protocols & NFC_PROTO_FELICA_MASK ||
+	    im_protocols & NFC_PROTO_NFC_DEP_MASK) {
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_FELICA212;
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_FELICA424;
+	}
+
+	if (im_protocols & NFC_PROTO_JEWEL_MASK)
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_JEWEL;
+
+	if (im_protocols & NFC_PROTO_ISO14443_B_MASK)
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_ISOB;
+
+	if (tm_protocols)
+		*skb_put(skb, 1) = PN532_AUTOPOLL_TYPE_DEP_PASSIVE_106;
+
+	rc = pn532_send_cmd_async(dev, PN532_CMD_IN_AUTOPOLL, skb,
+				  pn532_poll_complete, NULL);
+	if (rc < 0) {
+		dev_kfree_skb(skb);
+		nfc_dev_err(dev->tty->dev, "Error setting up autopoll %d", rc);
+	}
+	dev->poll_protocols = im_protocols;
+	dev->listen_protocols = tm_protocols;
+	return rc;
+}
+
+static void pn532_stop_poll(struct nfc_dev *nfc_dev)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+
+	del_timer(&dev->listen_timer);
+
+	if (!dev->poll_mod_count) {
+		nfc_dev_dbg(dev->tty->dev,
+			    "Polling operation was not running");
+		return;
+	}
+
+	/* An ack will cancel the last issued command (poll) */
+	pn532_send_ack(dev, GFP_KERNEL);
+
+	/* prevent pn532_start_poll_complete to issue a new poll meanwhile */
+	/*
+	dev->rbuf = NULL;
+	*/
+
+	pn532_poll_reset_mod_list(dev);
+}
+
+static int pn532_activate_target_nfcdep(struct pn532 *dev)
+{
+	struct pn532_cmd_activate_response *rsp;
+	u16 gt_len;
+	int rc;
+
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	skb = pn532_alloc_skb(dev, sizeof(u8) * 2); /*TG + Next*/
+	if (!skb)
+		return -ENOMEM;
+
+	*skb_put(skb, sizeof(u8)) = 1; /* TG */
+	*skb_put(skb, sizeof(u8)) = 0; /* Next */
+
+	resp = pn532_send_cmd_sync(dev, PN532_CMD_IN_ATR, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	rsp = (struct pn532_cmd_activate_response *)resp->data;
+	rc = rsp->status & PN532_CMD_RET_MASK;
+	if (rc != PN532_CMD_RET_SUCCESS) {
+		dev_kfree_skb(resp);
+		return -EIO;
+	}
+
+	/* ATR_RES general bytes are located at offset 16 */
+	gt_len = resp->len - 16;
+	rc = nfc_set_remote_general_bytes(dev->nfc_dev, rsp->gt, gt_len);
+
+	dev_kfree_skb(resp);
+	return rc;
+}
+
+static int pn532_activate_target(struct nfc_dev *nfc_dev,
+				 struct nfc_target *target, u32 protocol)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+	int rc;
+
+	nfc_dev_dbg(dev->tty->dev, "%s - protocol=%u", __func__,
+		    protocol);
+
+	if (dev->poll_mod_count) {
+		nfc_dev_err(dev->tty->dev,
+			    "Cannot activate while polling");
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(dev->tty->dev,
+			    "There is already an active target");
+		return -EBUSY;
+	}
+
+	if (!dev->tgt_available_prots) {
+		nfc_dev_err(dev->tty->dev,
+			    "There is no available target to activate");
+		return -EINVAL;
+	}
+
+	if (!(dev->tgt_available_prots & (1 << protocol))) {
+		nfc_dev_err(dev->tty->dev,
+			    "Target doesn't support requested proto %u",
+			    protocol);
+		return -EINVAL;
+	}
+
+	if (protocol == NFC_PROTO_NFC_DEP) {
+		rc = pn532_activate_target_nfcdep(dev);
+		if (rc) {
+			nfc_dev_err(dev->tty->dev,
+				    "Activating target with DEP failed %d", rc);
+			return rc;
+		}
+	}
+
+	dev->tgt_active_prot = protocol;
+	dev->tgt_available_prots = 0;
+
+	return 0;
+}
+
+static void pn532_wq_deactivate_tgt(struct work_struct *work)
+{
+	struct pn532 *dev =
+		container_of(work, struct pn532, deactivate_tgt_work);
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	int rc;
+
+	if (!dev->tgt_active_prot) {
+		nfc_dev_err(dev->tty->dev, "There is no active target");
+		return;
+	}
+
+	dev->tgt_active_prot = 0;
+	skb_queue_purge(&dev->resp_q);
+
+	skb = pn532_alloc_skb(dev, sizeof(u8));
+	if (!skb)
+		return;
+
+	*skb_put(skb, 1) = 1; /* TG*/
+
+	resp = pn532_send_cmd_sync(dev, PN532_CMD_IN_RELEASE, skb);
+	if (IS_ERR(resp))
+		return;
+
+	rc = resp->data[0] & PN532_CMD_RET_MASK;
+	if (rc != PN532_CMD_RET_SUCCESS)
+		nfc_dev_err(dev->tty->dev,
+			    "Error 0x%x when releasing the target", rc);
+
+	dev_kfree_skb(resp);
+	return;
+}
+
+static void pn532_deactivate_target(struct nfc_dev *nfc_dev,
+				    struct nfc_target *target)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+
+	queue_work(dev->wq_deactivate_tgt, &dev->deactivate_tgt_work);
+}
+
+
+static int pn532_in_dep_link_up_complete(struct pn532 *dev, void *arg,
+					 struct sk_buff *resp)
+{
+	struct pn532_cmd_jump_dep_response *rsp;
+	u8 target_gt_len;
+	int rc;
+	u8 active = *(u8 *)arg;
+
+	kfree(arg);
+
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	if (dev->tgt_available_prots &&
+	    !(dev->tgt_available_prots & (1 << NFC_PROTO_NFC_DEP))) {
+		nfc_dev_err(dev->tty->dev,
+			    "The target does not support DEP");
+		rc =  -EINVAL;
+		goto error;
+	}
+
+	rsp = (struct pn532_cmd_jump_dep_response *)resp->data;
+
+	rc = rsp->status & PN532_CMD_RET_MASK;
+	if (rc != PN532_CMD_RET_SUCCESS) {
+		nfc_dev_err(dev->tty->dev,
+			    "Bringing DEP link up failed %d", rc);
+		goto error;
+	}
+
+	if (!dev->tgt_available_prots) {
+		struct nfc_target nfc_target;
+
+		nfc_dev_dbg(dev->tty->dev, "Creating new target");
+
+		nfc_target.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		nfc_target.nfcid1_len = 10;
+		memcpy(nfc_target.nfcid1, rsp->nfcid3t, nfc_target.nfcid1_len);
+		rc = nfc_targets_found(dev->nfc_dev, &nfc_target, 1);
+		if (rc)
+			goto error;
+
+		dev->tgt_available_prots = 0;
+	}
+
+	dev->tgt_active_prot = NFC_PROTO_NFC_DEP;
+
+	/* ATR_RES general bytes are located at offset 17 */
+	target_gt_len = resp->len - 17;
+	rc = nfc_set_remote_general_bytes(dev->nfc_dev,
+					  rsp->gt, target_gt_len);
+	if (rc == 0)
+		rc = nfc_dep_link_is_up(dev->nfc_dev,
+					dev->nfc_dev->targets[0].idx,
+					!active, NFC_RF_INITIATOR);
+
+error:
+	dev_kfree_skb(resp);
+	return rc;
+}
+
+static int pn532_mod_to_baud(struct pn532 *dev)
+{
+	switch (dev->poll_mod_curr) {
+	case PN532_POLL_MOD_106KBPS_A:
+		return 0;
+	case PN532_POLL_MOD_212KBPS_FELICA:
+		return 1;
+	case PN532_POLL_MOD_424KBPS_FELICA:
+		return 2;
+	default:
+		return -EINVAL;
+	}
+}
+
+#define PASSIVE_DATA_LEN 5
+static int pn532_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
+			     u8 comm_mode, u8 *gb, size_t gb_len)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+	struct sk_buff *skb;
+	int rc, baud, skb_len;
+	u8 *next, *arg;
+
+	u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
+
+	if (dev->poll_mod_count) {
+		nfc_dev_err(dev->tty->dev,
+			    "Cannot bring the DEP link up while polling");
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		nfc_dev_err(dev->tty->dev,
+			    "There is already an active target");
+		return -EBUSY;
+	}
+
+	baud = pn532_mod_to_baud(dev);
+	if (baud < 0) {
+		nfc_dev_err(dev->tty->dev,
+			    "Invalid curr modulation %d", dev->poll_mod_curr);
+		return baud;
+	}
+
+	skb_len = 3 + gb_len; /* ActPass + BR + Next */
+	if (comm_mode == NFC_COMM_PASSIVE)
+		skb_len += PASSIVE_DATA_LEN;
+
+	skb = pn532_alloc_skb(dev, skb_len);
+	if (!skb)
+		return -ENOMEM;
+
+	*skb_put(skb, 1) = !comm_mode;  /* ActPass */
+	*skb_put(skb, 1) = baud;  /* Baud rate */
+
+	next = skb_put(skb, 1);  /* Next */
+	*next = 0;
+
+	if (comm_mode == NFC_COMM_PASSIVE && baud > 0) {
+		memcpy(skb_put(skb, PASSIVE_DATA_LEN), passive_data,
+		       PASSIVE_DATA_LEN);
+		*next |= 1;
+	}
+
+	if (gb != NULL && gb_len > 0) {
+		memcpy(skb_put(skb, gb_len), gb, gb_len);
+		*next |= 4; /* We have some Gi */
+	} else {
+		*next = 0;
+	}
+
+	arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		dev_kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	*arg = !comm_mode;
+
+	rc = pn532_send_cmd_async(dev, PN532_CMD_IN_JUMP_FOR_DEP, skb,
+				  pn532_in_dep_link_up_complete, arg);
+
+	if (rc < 0) {
+		dev_kfree_skb(skb);
+		kfree(arg);
+	}
+
+	return rc;
+}
+
+static int pn532_dep_link_down(struct nfc_dev *nfc_dev)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+
+	pn532_poll_reset_mod_list(dev);
+
+	if (dev->tgt_mode || dev->tgt_active_prot) {
+		pn532_send_ack(dev, GFP_KERNEL);
+		dev->rbuf = NULL;
+	}
+
+	dev->tgt_active_prot = 0;
+	dev->tgt_mode = 0;
+
+	skb_queue_purge(&dev->resp_q);
+
+	return 0;
+}
+
+struct pn532_data_exchange_arg {
+	data_exchange_cb_t cb;
+	void *cb_context;
+};
+
+static struct sk_buff *pn532_build_response(struct pn532 *dev)
+{
+	struct sk_buff *skb, *tmp, *t;
+	unsigned int skb_len = 0, tmp_len = 0;
+
+	if (skb_queue_empty(&dev->resp_q))
+		return NULL;
+
+	if (skb_queue_len(&dev->resp_q) == 1) {
+		skb = skb_dequeue(&dev->resp_q);
+		goto out;
+	}
+
+	skb_queue_walk_safe(&dev->resp_q, tmp, t)
+		skb_len += tmp->len;
+
+	skb = alloc_skb(skb_len, GFP_KERNEL);
+	if (skb == NULL)
+		goto out;
+
+	skb_put(skb, skb_len);
+
+	skb_queue_walk_safe(&dev->resp_q, tmp, t) {
+		memcpy(skb->data + tmp_len, tmp->data, tmp->len);
+		tmp_len += tmp->len;
+	}
+
+out:
+	skb_queue_purge(&dev->resp_q);
+
+	return skb;
+}
+
+static int pn532_data_exchange_complete(struct pn532 *dev, void *_arg,
+					struct sk_buff *resp)
+{
+	struct pn532_data_exchange_arg *arg = _arg;
+	struct sk_buff *skb;
+	int rc = 0;
+	u8 status, ret, mi;
+
+	if (IS_ERR(resp)) {
+		rc = PTR_ERR(resp);
+		goto _error;
+	}
+
+	status = resp->data[0];
+	ret = status & PN532_CMD_RET_MASK;
+	mi = status & PN532_CMD_MI_MASK;
+
+	skb_pull(resp, sizeof(status));
+
+	if (ret != PN532_CMD_RET_SUCCESS) {
+		nfc_dev_err(dev->tty->dev,
+			    "PN532 reported error %d when exchanging data",
+			    ret);
+		rc = -EIO;
+		goto error;
+	}
+
+	skb_queue_tail(&dev->resp_q, resp);
+
+	if (mi) {
+		dev->cmd_complete_mi_arg = arg;
+		queue_work(dev->wq, &dev->mi_work);
+		return -EINPROGRESS;
+	}
+
+	skb = pn532_build_response(dev);
+	if (!skb)
+		goto error;
+
+	arg->cb(arg->cb_context, skb, 0);
+	kfree(arg);
+	return 0;
+
+error:
+	dev_kfree_skb(resp);
+_error:
+	skb_queue_purge(&dev->resp_q);
+	arg->cb(arg->cb_context, NULL, rc);
+	kfree(arg);
+	return rc;
+}
+
+static int pn532_transceive(struct nfc_dev *nfc_dev,
+			    struct nfc_target *target, struct sk_buff *skb,
+			    data_exchange_cb_t cb, void *cb_context)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn532_data_exchange_arg *arg = NULL;
+	int rc;
+
+	nfc_dev_dbg(dev->tty->dev, "%s", __func__);
+
+	if (skb->len > PN532_CMD_DATAEXCH_DATA_MAXLEN) {
+		/* TODO: Implement support to multi-part data exchange */
+		nfc_dev_err(dev->tty->dev,
+			    "Data length greater than the max allowed: %d",
+			    PN532_CMD_DATAEXCH_DATA_MAXLEN);
+		rc = -ENOSYS;
+		goto error;
+	}
+
+	if (!dev->tgt_active_prot) {
+		nfc_dev_err(dev->tty->dev,
+			    "Can't exchange data if there is no active target");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	arg = kmalloc(sizeof(*arg), GFP_KERNEL);
+	if (!arg) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	arg->cb = cb;
+	arg->cb_context = cb_context;
+
+	*skb_push(skb, sizeof(u8)) =  1; /*TG*/
+
+	rc = pn532_send_data_async(dev, PN532_CMD_IN_DATA_EXCHANGE,
+				   skb, pn532_data_exchange_complete,
+				   arg);
+
+	if (rc < 0) /* rc from send_async */
+		goto error;
+
+	return 0;
+
+error:
+	kfree(arg);
+	dev_kfree_skb(skb);
+	return rc;
+}
+
+static int pn532_tm_send_complete(struct pn532 *dev, void *arg,
+				  struct sk_buff *resp)
+{
+	u8 status;
+
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	status = resp->data[0];
+
+	dev_kfree_skb(resp);
+
+	if (status != 0) {
+		nfc_tm_deactivated(dev->nfc_dev);
+
+		dev->tgt_mode = 0;
+
+		return 0;
+	}
+
+	queue_work(dev->wq, &dev->tg_work);
+
+	return 0;
+}
+
+static int pn532_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+	struct pn532 *dev = nfc_get_drvdata(nfc_dev);
+	int rc;
+
+	if (skb->len > PN532_CMD_DATAEXCH_DATA_MAXLEN) {
+		nfc_dev_err(dev->tty->dev,
+			    "Data length greater than the max allowed: %d",
+			    PN532_CMD_DATAEXCH_DATA_MAXLEN);
+		return -ENOSYS;
+	}
+
+	rc = pn532_send_data_async(dev, PN532_CMD_TG_SET_DATA, skb,
+				   pn532_tm_send_complete, NULL);
+	if (rc < 0)
+		dev_kfree_skb(skb);
+
+	return rc;
+}
+
+static void pn532_wq_mi_recv(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, mi_work);
+
+	struct sk_buff *skb;
+	int rc;
+
+	skb = pn532_alloc_skb(dev, PN532_CMD_DATAEXCH_HEAD_LEN);
+	if (!skb)
+		goto error;
+
+	*skb_put(skb, sizeof(u8)) =  1; /*TG*/
+
+	rc = pn532_send_cmd_direct_async(dev,
+					 PN532_CMD_IN_DATA_EXCHANGE,
+					 skb,
+					 pn532_data_exchange_complete,
+					 dev->cmd_complete_mi_arg);
+
+	if (rc == 0) /* success */
+		return;
+
+	nfc_dev_err(dev->tty->dev,
+		    "Error %d when trying to perform data_exchange", rc);
+
+	dev_kfree_skb(skb);
+	kfree(dev->cmd_complete_arg);
+
+error:
+	pn532_send_ack(dev, GFP_KERNEL);
+	queue_work(dev->wq, &dev->cmd_work);
+}
+
+static int pn532_set_configuration(struct pn532 *dev, u8 cfgitem, u8 *cfgdata,
+								u8 cfgdata_len)
+{
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	int skb_len;
+
+	skb_len = sizeof(cfgitem) + cfgdata_len; /* cfgitem + cfgdata */
+
+	skb = pn532_alloc_skb(dev, skb_len);
+	if (!skb)
+		return -ENOMEM;
+
+	*skb_put(skb, sizeof(cfgitem)) = cfgitem;
+	memcpy(skb_put(skb, cfgdata_len), cfgdata, cfgdata_len);
+
+	resp = pn532_send_cmd_sync(dev, PN532_CMD_RF_CONFIGURATION, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	dev_kfree_skb(resp);
+	return 0;
+}
+
+static int pn532_get_firmware_version(struct pn532 *dev,
+				      struct pn532_fw_version *fv)
+{
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	skb = pn532_alloc_skb(dev, 0);
+	if (!skb)
+		return -ENOMEM;
+
+	resp = pn532_send_cmd_sync(dev, PN532_CMD_GET_FIRMWARE_VERSION, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	fv->ic = resp->data[0];
+	fv->ver = resp->data[1];
+	fv->rev = resp->data[2];
+	fv->support = resp->data[3];
+
+	dev_kfree_skb(resp);
+	return 0;
+}
+
+static int pn532_sam_configuration(struct pn532 *dev)
+{
+	struct sk_buff *skb;
+	struct sk_buff *resp;
+
+	skb = pn532_alloc_skb(dev, sizeof(u8));
+	if (!skb)
+		return -ENOMEM;
+
+	*skb_put(skb, sizeof(u8)) = 0x01; /* Mode(timeout and IRQ left out) */
+
+	resp = pn532_send_cmd_sync(dev, PN532_CMD_SAM_CONFIGURATION, skb);
+	if (IS_ERR(resp))
+		return PTR_ERR(resp);
+
+	dev_kfree_skb(resp);
+
+	return 0;
+}
+
+static struct nfc_ops pn532_nfc_ops = {
+	/* TODO implement dev_up und dev_down */
+	.dev_up = NULL,
+	.dev_down = NULL,
+	.dep_link_up = pn532_dep_link_up,
+	.dep_link_down = pn532_dep_link_down,
+	.start_poll = pn532_start_auto_poll,
+	.stop_poll = pn532_stop_poll,
+	.activate_target = pn532_activate_target,
+	.deactivate_target = pn532_deactivate_target,
+	.im_transceive = pn532_transceive,
+	.tm_send = pn532_tm_send,
+};
+
+static int pn532_setup(struct pn532 *dev)
+{
+	struct pn532_config_max_retries max_retries;
+	struct pn532_config_timing timing;
+	int rc;
+
+	max_retries.mx_rty_atr = PN532_CONFIG_MAX_RETRIES_ENDLESS;
+	max_retries.mx_rty_psl = 2;
+	max_retries.mx_rty_passive_act = PN532_CONFIG_MAX_RETRIES_NO_RETRY;
+
+	timing.rfu = PN532_CONFIG_TIMING_102;
+	timing.atr_res_timeout = PN532_CONFIG_TIMING_204;
+	timing.dep_timeout = PN532_CONFIG_TIMING_409;
+
+	rc = pn532_set_configuration(dev, PN532_CFGITEM_MAX_RETRIES,
+				     (u8 *)&max_retries, sizeof(max_retries));
+	if (rc) {
+		nfc_dev_err(dev->tty->dev,
+			    "Error on setting MAX_RETRIES config");
+		return rc;
+	}
+
+
+	rc = pn532_set_configuration(dev, PN532_CFGITEM_TIMING,
+				     (u8 *)&timing, sizeof(timing));
+	if (rc) {
+		nfc_dev_err(dev->tty->dev,
+			    "Error on setting RF timings");
+		return rc;
+	}
+
+	return 0;
+}
+
+static void pn532_connect_nfc(struct work_struct *work)
+{
+	struct pn532 *dev = container_of(work, struct pn532, conn_nfc_work);
+	struct pn532_fw_version fw_ver;
+	int rc = -ENOMEM;
+
+	if (dev == NULL || dev->tty == NULL || dev->tty->dev == NULL)
+		return;
+
+	mutex_init(&dev->cmd_lock);
+
+	INIT_WORK(&dev->cmd_work, pn532_wq_cmd);
+	INIT_WORK(&dev->cmd_complete_work, pn532_wq_cmd_complete);
+	INIT_WORK(&dev->mi_work, pn532_wq_mi_recv);
+	INIT_WORK(&dev->tg_work, pn532_wq_tg_get_data);
+	INIT_WORK(&dev->poll_work, pn532_wq_poll);
+	INIT_WORK(&dev->deactivate_tgt_work, pn532_wq_deactivate_tgt);
+	dev->wq = alloc_ordered_workqueue("pn532", 0);
+	if (dev->wq == NULL)
+		return;
+
+	dev->wq_deactivate_tgt = alloc_workqueue("pn532_add", 0, 0);
+	if (dev->wq_deactivate_tgt == NULL) {
+		destroy_workqueue(dev->wq);
+		return;
+	}
+
+	init_timer(&dev->listen_timer);
+	dev->listen_timer.data = (unsigned long) dev;
+	dev->listen_timer.function = pn532_listen_mode_timer;
+
+	skb_queue_head_init(&dev->resp_q);
+
+	INIT_LIST_HEAD(&dev->cmd_queue);
+
+	dev->ops = &pn532_std_frame_ops;
+
+	dev->wakeup = 1;
+	rc = pn532_sam_configuration(dev);
+
+	if (rc < 0) {
+		destroy_workqueue(dev->wq_deactivate_tgt);
+		destroy_workqueue(dev->wq);
+		return;
+	}
+
+	memset(&fw_ver, 0, sizeof(fw_ver));
+	rc = pn532_get_firmware_version(dev, &fw_ver);
+	if (rc < 0) {
+		destroy_workqueue(dev->wq_deactivate_tgt);
+		destroy_workqueue(dev->wq);
+		return;
+	}
+
+	nfc_dev_info(dev->tty->dev,
+		     "NXP PN532 firmware ver %d.%d now attached",
+		     fw_ver.ver, fw_ver.rev);
+
+
+	dev->nfc_dev = nfc_allocate_device(&pn532_nfc_ops, PN532_ALL_PROTOCOLS,
+					   dev->ops->tx_header_len +
+					   PN532_CMD_DATAEXCH_HEAD_LEN,
+					   dev->ops->tx_tail_len);
+	if (!dev->nfc_dev) {
+		destroy_workqueue(dev->wq_deactivate_tgt);
+		destroy_workqueue(dev->wq);
+		return;
+	}
+
+	nfc_set_parent_dev(dev->nfc_dev, dev->tty->dev);
+	nfc_set_drvdata(dev->nfc_dev, dev);
+
+	rc = nfc_register_device(dev->nfc_dev);
+	if (rc)
+		goto free_nfc_dev;
+
+	rc = pn532_setup(dev);
+	if (rc)
+		goto unregister_nfc_dev;
+
+	destroy_workqueue(dev->wq_conn_nfc);
+	return;
+
+unregister_nfc_dev:
+	nfc_unregister_device(dev->nfc_dev);
+
+free_nfc_dev:
+	nfc_free_device(dev->nfc_dev);
+}
+
+/*
+ * line discipline
+ */
+
+/*
+ * scans the buffer if it contains a pn532 frame. It is not checked if it is
+ * valid. This could be done with pn532_rx_frame_is_valid. It therefore does
+ * not require, that the frame starts at the beginning of the buffer.
+ * This is useful for malformed or errornous transmitted frames. Returns the
+ * bufferposition where the frame starts.
+ */
+static struct pn532_frame *pn532_rx_is_frame(unsigned char *buf, u8 buf_len)
+{
+	int i;
+	u16 frame_len;
+	u16 *flp;
+
+	/* minimal frame length = 5 */
+	for (i = 0; i + 4 < buf_len; i++) {
+		/* search start code */
+		if (buf[i] == 0x00 &&
+			buf[i + 1] == 0x00 &&
+			buf[i + 2] == 0xff) {
+			/* type */
+			switch (buf[i + 3]) {
+			case 0x00: /* ACK frame ? */
+				if (buf[i + 4] == 0xff)
+					return (struct pn532_frame *) &buf[i];
+				break;
+			case 0x01: /* error frame */
+				if ((buf[i + 4] == 0xff) &&
+					(buf_len >= 6))
+					return (struct pn532_frame *) &buf[i];
+				break;
+			case 0xff: /* extended frame ?*/
+				flp = (u16 *)&buf[i + 5];
+				frame_len = be16_to_cpu(*flp);
+				if (buf_len >= frame_len + 9)
+					return (struct pn532_frame *) &buf[i];
+				break;
+			default: /* normal information frame */
+				frame_len = buf[i + 3];
+				if (buf_len >= frame_len + 6)
+					return (struct pn532_frame *) &buf[i];
+				break;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+static void pn532_receive_buf(struct tty_struct *tty,
+			      const unsigned char *cp, char *fp, int count)
+{
+	struct pn532_frame *frame;
+	struct pn532 *dev = (struct pn532 *)tty->disc_data;
+	unsigned char c;
+
+	nfc_dev_dbg(dev->tty->dev, "count:%i rbuf:%p rlen:%i rcount:%i",
+		count, dev->rbuf, dev->rlen, dev->rcount);
+
+	print_hex_dump(KERN_DEBUG, "frischRX: ", DUMP_PREFIX_NONE, 16, 1,
+		       cp, count, false);
+
+	if (!dev || dev->magic != PN532_MAGIC || dev->rbuf == NULL)
+		return;
+
+	while (count-- && (dev->rlen - dev->rcount > 0)) {
+		if (fp && *fp++) {
+			/*
+			if (!test_and_set_bit(PN532_ERROR, &dev->flags))
+			{
+				// TODO handle error
+			}
+			*/
+			cp++;
+			continue;
+		}
+		c = *cp++;
+		/*
+		if (c != 0)
+			continue;
+		*/
+
+		dev->rbuf[dev->rcount] = c;
+		frame = pn532_rx_is_frame(dev->rbuf, dev->rcount++);
+
+		if (frame != NULL)
+			if (!dev->recv_complete(dev, frame))
+				dev->rcount = 0;
+	}
+}
+
+static void pn532_write_wakeup(struct tty_struct *tty)
+{
+	int actual;
+	struct pn532 *pn532 = (struct pn532 *)tty->disc_data;
+
+	if (!pn532 || pn532->magic != PN532_MAGIC)
+		return;
+
+	if (pn532->xleft <= 0) {
+		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+		return;
+	}
+
+	actual = tty->ops->write(tty, pn532->xhead, pn532->xleft);
+	pn532->xleft -= actual;
+	pn532->xhead += actual;
+}
+
+static int pn532_open(struct tty_struct *tty)
+{
+	struct pn532 *pn532;
+	int err;
+
+	if (tty->ops->write == NULL)
+		return -EOPNOTSUPP;
+
+	/*
+	mutex_lock();
+	*/
+
+	pn532 = tty->disc_data;
+
+	err = -EEXIST;
+	/* First make sure we're not already connected. */
+	if (pn532 && pn532->magic == PN532_MAGIC)
+		goto err_exit;
+
+	err = -ENFILE;
+	pn532 = kzalloc(sizeof(*pn532), GFP_KERNEL);
+	if (pn532 == NULL)
+		goto err_exit;
+
+	pn532->tty = tty;
+
+	INIT_WORK(&pn532->conn_nfc_work, pn532_connect_nfc);
+	pn532->wq_conn_nfc = alloc_workqueue("pn532_connect_nfc", 0, 0);
+	if (pn532->wq_conn_nfc == NULL)
+		goto err_free;
+
+	tty->disc_data = pn532;
+
+	/* Done.  We have linked the TTY line to a channel. */
+	/*
+	mutex_unlock();
+	*/
+	tty->receive_room = 65536;	/* We don't flow control */
+
+	queue_work(pn532->wq_conn_nfc, &pn532->conn_nfc_work);
+	pn532->magic = PN532_MAGIC;
+	/* TTY layer expects 0 on success */
+	return 0;
+
+err_free:
+	kfree(pn532);
+err_exit:
+	/*
+	mutex_unlock();
+	*/
+
+	/* Count references from TTY module */
+	return err;
+}
+
+static void pn532_close(struct tty_struct *tty)
+{
+	struct pn532 *pn532 = (struct pn532 *) tty->disc_data;
+	struct pn532_cmd *cmd, *n;
+
+	/* First make sure we're connected. */
+	if (!pn532 || pn532->magic != PN532_MAGIC || pn532->tty != tty)
+		return;
+
+	if (pn532->nfc_dev) {
+		destroy_workqueue(pn532->wq_deactivate_tgt);
+		destroy_workqueue(pn532->wq);
+
+		nfc_unregister_device(pn532->nfc_dev);
+		nfc_free_device(pn532->nfc_dev);
+
+		skb_queue_purge(&pn532->resp_q);
+
+		del_timer(&pn532->listen_timer);
+
+		list_for_each_entry_safe(cmd, n, &pn532->cmd_queue, queue) {
+			list_del(&cmd->queue);
+			kfree(cmd);
+		}
+		nfc_dev_info(pn532->tty->dev, "NXP PN532 NFC device disconnected");
+	}
+	tty->disc_data = NULL;
+
+	kfree(pn532);
+}
+
+static int pn532_hangup(struct tty_struct *tty)
+{
+	pn532_close(tty);
+	return 0;
+}
+
+/* Perform I/O control on an active SLCAN channel. */
+static int pn532_ioctl(struct tty_struct *tty, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	struct pn532 *pn532 = (struct pn532 *) tty->disc_data;
+	unsigned int tmp;
+
+	/* First make sure we're connected. */
+	if (!pn532 || pn532->magic != PN532_MAGIC)
+		return -EINVAL;
+
+	switch (cmd) {
+	case SIOCGIFNAME:
+		if (!pn532->nfc_dev)
+			return -EINVAL;
+		tmp = strlen(nfc_device_name(pn532->nfc_dev)) + 1;
+		if (copy_to_user((void __user *)arg,
+					nfc_device_name(pn532->nfc_dev), tmp))
+			return -EFAULT;
+		return 0;
+
+	case SIOCSIFHWADDR:
+		return -EINVAL;
+
+	default:
+		return tty_mode_ioctl(tty, file, cmd, arg);
+	}
+}
+
+static struct tty_ldisc_ops pn532_ldisc = {
+	.owner		= THIS_MODULE,
+	.magic		= TTY_LDISC_MAGIC,
+	.name		= "pn532",
+	.open		= pn532_open,
+	.close		= pn532_close,
+	.hangup		= pn532_hangup,
+	.ioctl		= pn532_ioctl,
+	.receive_buf	= pn532_receive_buf,
+	.write_wakeup	= pn532_write_wakeup,
+};
+
+static int __init pn532_init(void)
+{
+	int ret;
+
+	ret = tty_register_ldisc(N_PN532, &pn532_ldisc);
+	if (ret)
+		pr_err("pn532: can not register line discipline\n");
+
+	return ret;
+}
+
+static void __exit pn532_exit(void)
+{
+	int ret;
+
+	ret = tty_unregister_ldisc(N_PN532);
+	if (ret)
+		pr_err("pn532: can not unregister ldisc (err %d)\n", ret);
+}
+
+module_init(pn532_init);
+module_exit(pn532_exit);
+
+MODULE_ALIAS_LDISC(N_PN532);
+MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
+MODULE_DESCRIPTION(DESCRIPTION);
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/tty.h b/include/uapi/linux/tty.h
index dac199a..e6b6d77 100644
--- a/include/uapi/linux/tty.h
+++ b/include/uapi/linux/tty.h
@@ -34,5 +34,6 @@
 #define N_TI_WL		22	/* for TI's WL BT, FM, GPS combo chips */
 #define N_TRACESINK	23	/* Trace data routing for MIPI P1149.7 */
 #define N_TRACEROUTER	24	/* Trace data routing for MIPI P1149.7 */
+#define N_PN532		25	/* NXP PN532 NFC chip */
 
 #endif /* _UAPI_LINUX_TTY_H */
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH] mac80211: ignore obviously bogus ECSAs in probe response frames
From: Seth Forshee @ 2013-08-22 14:10 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John W. Linville
In-Reply-To: <1377180063.14110.23.camel@jlt4.sipsolutions.net>

On Thu, Aug 22, 2013 at 04:01:03PM +0200, Johannes Berg wrote:
> On Thu, 2013-08-22 at 08:53 -0500, Seth Forshee wrote:
> > The Netgear WNDAP360 sends invalid ECSA IEs in probe response
> > frames
> 
> I think we shouldn't be checking probe response frames at all. That
> seems like a mistake. Can you try this?

I had considered this, but the spec says that it's at least valid for
the AP to be sending ECSAs in probe responses. IEEE 802.11-2012 section
10.3.3.2:

  ...an AP shall inform associated STAs that the AP is moving to a new
  channel and/or operating class and maintain the association by
  advertising the switch using Extended Channel Switch Announcement
  elements in any transmitted Beacon frames, Probe Response frames, and
  Extended Channel Switch Announcement frames until the intended channel
  switch time.

Perhaps we can still ignore them though? I suppose we'd expect to
receive some other frame with the ECSA before it actually happens.

Seth

^ permalink raw reply

* Re: [PATCH] mac80211: ignore obviously bogus ECSAs in probe response frames
From: Johannes Berg @ 2013-08-22 14:01 UTC (permalink / raw)
  To: Seth Forshee; +Cc: linux-wireless, John W. Linville
In-Reply-To: <1377179613-26591-1-git-send-email-seth.forshee@canonical.com>

On Thu, 2013-08-22 at 08:53 -0500, Seth Forshee wrote:
> The Netgear WNDAP360 sends invalid ECSA IEs in probe response
> frames

I think we shouldn't be checking probe response frames at all. That
seems like a mistake. Can you try this?

http://p.sipsolutions.net/015f7b799f19426a.txt

johannes



^ permalink raw reply

* [PATCH] mac80211: ignore obviously bogus ECSAs in probe response frames
From: Seth Forshee @ 2013-08-22 13:53 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, John W. Linville

The Netgear WNDAP360 sends invalid ECSA IEs in probe response
frames which have the operating class and channel number fields
set to 0, even when no channel switch is pending. mac80211
responds to invalid ECSAs by disconnecting. The result is that
every scan when associated to one of these APs triggers a
disconnect.

Since these ECSAs are obviously bogus, ignore them in probe
response and beacon frames. Do not disconnect.

Cc: <stable@vger.kernel.org> # 3.10+
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 net/mac80211/mlme.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cc9e02d..f921b67 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1054,6 +1054,13 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 		if (!ieee80211_operating_class_to_band(
 				elems->ext_chansw_ie->new_operating_class,
 				&new_band)) {
+			/*
+			 * Some APs send invalid ECSA IEs in probe response
+			 * frames, so check for these and ignore them.
+			 */
+			if (beacon && elems->ext_chansw_ie->new_ch_num == 0 &&
+			    elems->ext_chansw_ie->new_operating_class == 0)
+				return;
 			sdata_info(sdata,
 				   "cannot understand ECSA IE operating class %d, disconnecting\n",
 				   elems->ext_chansw_ie->new_operating_class);
-- 
1.8.1.2


^ permalink raw reply related

* Fwd: ipw2200: Fix race condition in the command completion acknowledge
From: Stan G @ 2013-08-22 11:00 UTC (permalink / raw)
  To: linux-wireless, linux-kernel
In-Reply-To: <CAOMQbqHRkF4_gK=GA587LDghkYtd1hRQhLObV+Tbe9zEDbS5-Q@mail.gmail.com>

---------- Forwarded message ----------
From: Stan G <stangoesagain@gmail.com>
Date: Wed, Aug 21, 2013 at 3:16 PM
Subject: ipw2200: Fix race condition in the command completion acknowledge
To: stas.yakovlev@gmail.com
Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org


Hi,

This is regarding kernel patch history:

>>>>

commit dd447319895d0c0af423e483d9b63f84f3f8869a
Author: Stanislav Yakovlev <stas.yakovlev@gmail.com>
Date: Thu Apr 19 15:55:09 2012 -0400
ipw2200: Fix race condition in the command completion acknowledge

Driver incorrectly validates command completion: instead of waiting
for a command to be acknowledged it continues execution. Most of the
time driver gets acknowledge of the command completion in a tasklet
before it executes the next one. But sometimes it sends the next
command before it gets acknowledge for the previous one. In such a
case one of the following error messages appear in the log:

Failed to send SYSTEM_CONFIG: Already sending a command.
Failed to send ASSOCIATE: Already sending a command.
Failed to send TX_POWER: Already sending a command.

After that you need to reload the driver to get it working again.

This bug occurs during roaming (reported by Sam Varshavchik)
https://bugzilla.redhat.com/show_bug.cgi?id=738508
and machine booting (reported by Tom Gundersen and Mads Kiilerich)
https://bugs.archlinux.org/task/28097
https://bugzilla.redhat.com/show_bug.cgi?id=802106

This patch doesn't fix the delay issue during firmware load.
But at least device now works as usual after boot.

Cc: stable@kernel.org
Signed-off-by: Stanislav Yakovlev <stas.yakovlev@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

>>>>

I am having intermittent problems with dropping wifi network while the
 AP is still visible and dmesg produces this:

      [26617.864791] ipw2200: Failed to send ASSOCIATE: Already
sending a command.


I'm on OpenSuse 12.3 with 3.7.10-1.16

The whole story of this problem can be viewed here:

https://forums.opensuse.org/english/get-technical-help-here/network-internet/489371-wifi-up-access-point-visible-but-network-goes-down.html

where at the end I was advised to contact you, guys.

Reloading driver restores network as expected.

Can anything be done regarding this issue or is the driver too old to be fixed?

Would updating to the latest kernel solve the problem?

Stan

^ permalink raw reply

* Re: [PATCH 0/3] ath10k: fixes
From: Michal Kazior @ 2013-08-22 10:05 UTC (permalink / raw)
  To: ath10k; +Cc: linux-wireless, Michal Kazior
In-Reply-To: <1377066854-13981-1-git-send-email-michal.kazior@tieto.com>

On 21 August 2013 08:34, Michal Kazior <michal.kazior@tieto.com> wrote:
> Hi,
>
> This patchset addresses some throughput issues.
>
>
> Pozdrawiam / Best regards,
> Michal Kazior.
>
>
> Michal Kazior (3):
>   ath10k: make the workqueue multithreaded
>   ath10k: move htt rx processing to worker
>   ath10k: fix issues on non-preemptible systems
>
>  drivers/net/wireless/ath/ath10k/core.c   |    4 ++-
>  drivers/net/wireless/ath/ath10k/core.h   |    7 ++++
>  drivers/net/wireless/ath/ath10k/htc.c    |    4 +++
>  drivers/net/wireless/ath/ath10k/htt.h    |    3 ++
>  drivers/net/wireless/ath/ath10k/htt_rx.c |   58 ++++++++++++++++++++++++++----
>  drivers/net/wireless/ath/ath10k/wmi.c    |    4 +++
>  6 files changed, 72 insertions(+), 8 deletions(-)

Drop this patchset for now, please, There are some minor issues I'd
like to address first. Nevertheless, feel free to comment the patchset
if you see any issues.


Pozdrawiam / Best regards,
Michał Kazior.

^ permalink raw reply

* Re: [RFT V2 02/13] brcmsmac: change pa_gain for bcm4313 iPA
From: Arend van Spriel @ 2013-08-22  8:08 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: linux-wireless, Jonas Gorski, David Herrmann,
	Maximilian Engelhardt, David Costa
In-Reply-To: <52151297.5010706@hauke-m.de>

On 08/21/2013 09:18 PM, Hauke Mehrtens wrote:
> Hi Arend,
>
> when you send a new patch please fix this typo.

Got it covered already:

http://mid.gmane.org/1377007246-9957-3-git-send-email-arend@broadcom.com

Regards,
Arend

> Hauke
>
> On 08/13/2013 10:03 PM, Arend van Spriel wrote:
>> The function wlc_lcnphy_load_tx_gain_table() has a target PA
>> gain specified for the iPA variant of the bcm4313. This gain
>> value is reduced to avoid PA distortion. The if-statement is
>> removed because it was rather redundant in the first place.
>> Please not that this patch does not provide full iPA support.
>           ^^^
>           note
>
>
>



^ permalink raw reply

* [PATCH] mac80211: minstrel_ht: don't use control.flags in TX status path
From: Johannes Berg @ 2013-08-22  6:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: Sujith Manoharan, Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

Sujith reports that my commit af61a165187bb94b1dc7628ef815c23d0eacf40b
("mac80211: add control port protocol TX control flag") broke ath9k
(aggregation). The reason is that I made minstrel_ht use the flag in
the TX status path, where it can have been overwritten by the driver.
Since we have no more space in info->flags, revert that part of the
change for now, until we can reshuffle the flags or so.

Reported-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/rc80211_minstrel_ht.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 9eff382..c397ff5 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -439,13 +439,12 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	u16 tid;
 
 	if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
 		return;
 
-	if (unlikely(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
+	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
 		return;
 
 	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
-- 
1.8.4.rc2


^ permalink raw reply related

* [PATCH V3] cfg80211: vlan priority handling in WMM
From: cedric.voncken @ 2013-08-21 13:48 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: cedric Voncken

From: cedric Voncken <cedric.voncken@acksys.fr>

If the VLAN tci is set in skb->vlan_tci use the priority field to determine the WMM priority.

Signed-off-by: cedric Voncken <cedric.voncken@acksys.fr>
---
 net/wireless/util.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

V2 modifications:
	Fix indentation
	Use symbolic constant
	include the header linux/if_vlan.h

V3 modifications:
	Check the vlan_tci validity with macro vlan_tx_tag_present
	Get the vlan_tci field value with macro vlan_tx_tag_get
	Request to netdev mailling list to know if the VLAN priority value 0 must be treated as no priority request. I add the Ben Hutchings reply below:
	IEEE 802.1q refers to the definition in 802.1d:

	> The user_priority parameter is the priority requested by the
	> originating service user. The value of this parameter is in the range
	> 0 through 7.
	>
	> NOTE -- The default user_priority value is 0. Values 1 through 7 form an
	> ordered sequence of user_priorities, with 1 being the lowest value and
	> 7 the highest. See 7.7.3 and Annex G (informative) for further
	> explanation of the use of user_priority values.

	So a value of 0 should be treated as no priority request, same as for an untagged frame.

diff --git a/net/wireless/util.c b/net/wireless/util.c
index ce090c1..9e4cac2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -10,6 +10,7 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
+#include <linux/if_vlan.h>
 #include "core.h"
 #include "rdev-ops.h"
 
@@ -691,6 +692,7 @@ EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 {
 	unsigned int dscp;
+	unsigned char vlan_priority;
 
 	/* skb->priority values from 256->263 are magic values to
 	 * directly indicate a specific 802.1d priority.  This is used
@@ -700,6 +702,12 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 	if (skb->priority >= 256 && skb->priority <= 263)
 		return skb->priority - 256;
 
+	if(vlan_tx_tag_present(skb)) {
+		vlan_priority = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+		if (vlan_priority > 0)
+			return vlan_priority;
+	}
+
 	switch (skb->protocol) {
 	case htons(ETH_P_IP):
 		dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
-- 
1.7.2.5


^ permalink raw reply related

* [PATCH 2/2] staging: vt6656: rxtx.c: s_uGetDataDuration  Drop argument byDurType.
From: Malcolm Priestley @ 2013-08-21 21:16 UTC (permalink / raw)
  To: gregkh; +Cc: linux-wireless

When byDurType == DATADUR_B then byPktType == PK_TYPE_11B

Drop argument byDurType and filter on byPktType == PK_TYPE_11B.

Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
---
 drivers/staging/vt6656/rxtx.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 1d0611e..d4b9b60 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -132,7 +132,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
 	void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
 	struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
 
-static u16 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
 	u8 byPktType, int bNeedAck);
 
 static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
@@ -383,13 +383,13 @@ static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
 }
 
 //byFreqType 0: 5GHz, 1:2.4Ghz
-static u16 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
-	u8 byPktType, int bNeedAck)
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+					u8 byPktType, int bNeedAck)
 {
 	u32 uAckTime = 0;
 
 	if (bNeedAck) {
-		if (byDurType == DATADUR_B)
+		if (byPktType == PK_TYPE_11B)
 			uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
 				byPktType, 14, pDevice->byTopCCKBasicRate);
 		else
@@ -507,9 +507,9 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength,
 			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-		pBuf->wDuration_a = s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice,
 							byPktType, bNeedAck);
-		pBuf->wDuration_b = s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice,
 							PK_TYPE_11B, bNeedAck);
 
                 pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
@@ -525,14 +525,14 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength,
 			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-		pBuf->wDuration_a = s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice,
 							byPktType, bNeedAck);
-		pBuf->wDuration_b = s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice,
 							PK_TYPE_11B, bNeedAck);
 		pBuf->wDuration_a_f0 = s_uGetDataDuration(pDevice,
-					DATADUR_A_F0, byPktType, bNeedAck);
+							byPktType, bNeedAck);
 		pBuf->wDuration_a_f1 = s_uGetDataDuration(pDevice,
-					DATADUR_A_F1, byPktType, bNeedAck);
+							byPktType, bNeedAck);
                 pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
                 pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
                 return (pBuf->wDuration_a);
@@ -546,12 +546,12 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->a);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
 					byPktType, bNeedAck);
 		pBuf->wDuration_f0 = s_uGetDataDuration(pDevice,
-				DATADUR_A_F0, byPktType, bNeedAck);
+					byPktType, bNeedAck);
 		pBuf->wDuration_f1 = s_uGetDataDuration(pDevice,
-				DATADUR_A_F1, byPktType, bNeedAck);
+							byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
             return (pBuf->wDuration);
         } else {
@@ -561,7 +561,7 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
 				byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 
@@ -575,7 +575,7 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
 				byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 
@@ -1806,7 +1806,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
 							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
 	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
-					DATADUR_A, PK_TYPE_11A, false);
+						PK_TYPE_11A, false);
         pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     } else {
@@ -1819,7 +1819,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
 							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
 	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
-					DATADUR_B, PK_TYPE_11B, false);
+						PK_TYPE_11B, false);
         pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     }
-- 
1.8.1.2



^ permalink raw reply related

* Re: [PATCH] mac80211: move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into drivers
From: Luciano Coelho @ 2013-08-21 20:57 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Johannes Berg
In-Reply-To: <1377077275-19429-1-git-send-email-johannes@sipsolutions.net>

On Wed, 2013-08-21 at 11:27 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
> 
> mac80211 currently sets WIPHY_FLAG_SUPPORTS_SCHED_SCAN based on whether
> the start_sched_scan operation is supported or not, but that will not
> be correct for all drivers, we're adding scheduled scan to the iwlmvm
> driver but it depends on firmware support.
> 
> Therefore, move setting WIPHY_FLAG_SUPPORTS_SCHED_SCAN into the drivers
> so that they can control it regardless of implementing the operation.
> 
> This currently only affects the TI drivers since they're the only ones
> implementing scheduled scan (in a mac80211 driver.)
> 
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---

For the wlcore part:

Acked-by: Luciano Coelho <luca@coelho.fi>


^ permalink raw reply

* [PATCH 1/2] staging: vt6656: rxtx.c s_uGetDataDuration return endian corrected u16.
From: Malcolm Priestley @ 2013-08-21 20:58 UTC (permalink / raw)
  To: gregkh; +Cc: linux-wireless

The return always be u16 endian corrected. For the
large part this is missing.

Fix uGetDataDuration to return u16 endian corrected.

Signed-off-by: Malcolm Priestley <tvboxspy@gmail.com>
---
 drivers/staging/vt6656/rxtx.c | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 05e82ec..1d0611e 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -132,7 +132,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
 	void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
 	struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
 
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
+static u16 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
 	u8 byPktType, int bNeedAck);
 
 static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
@@ -383,7 +383,7 @@ static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
 }
 
 //byFreqType 0: 5GHz, 1:2.4Ghz
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
+static u16 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
 	u8 byPktType, int bNeedAck)
 {
 	u32 uAckTime = 0;
@@ -395,7 +395,7 @@ static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
 		else
 			uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
 				byPktType, 14, pDevice->byTopOFDMBasicRate);
-		return pDevice->uSIFS + uAckTime;
+		return cpu_to_le16((u16)(pDevice->uSIFS + uAckTime));
 	}
 
 	return 0;
@@ -507,9 +507,9 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength,
 			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-		pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice, DATADUR_A,
 							byPktType, bNeedAck);
-		pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice, DATADUR_B,
 							PK_TYPE_11B, bNeedAck);
 
                 pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
@@ -525,13 +525,13 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength,
 			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-		pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice, DATADUR_A,
 							byPktType, bNeedAck);
-		pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice, DATADUR_B,
 							PK_TYPE_11B, bNeedAck);
-		pBuf->wDuration_a_f0 = (u16)s_uGetDataDuration(pDevice,
+		pBuf->wDuration_a_f0 = s_uGetDataDuration(pDevice,
 					DATADUR_A_F0, byPktType, bNeedAck);
-		pBuf->wDuration_a_f1 = (u16)s_uGetDataDuration(pDevice,
+		pBuf->wDuration_a_f1 = s_uGetDataDuration(pDevice,
 					DATADUR_A_F1, byPktType, bNeedAck);
                 pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
                 pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
@@ -546,11 +546,11 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->a);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_A,
 					byPktType, bNeedAck);
-		pBuf->wDuration_f0 = (u16)s_uGetDataDuration(pDevice,
+		pBuf->wDuration_f0 = s_uGetDataDuration(pDevice,
 				DATADUR_A_F0, byPktType, bNeedAck);
-		pBuf->wDuration_f1 = (u16)s_uGetDataDuration(pDevice,
+		pBuf->wDuration_f1 = s_uGetDataDuration(pDevice,
 				DATADUR_A_F1, byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
             return (pBuf->wDuration);
@@ -561,7 +561,7 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A,
+		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_A,
 				byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 
@@ -575,7 +575,7 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
 		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
 			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-		pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_B,
+		pBuf->wDuration = s_uGetDataDuration(pDevice, DATADUR_B,
 				byPktType, bNeedAck);
                 pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 
@@ -1805,8 +1805,8 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
 	BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
 							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
-	pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice,
-				DATADUR_A, PK_TYPE_11A, false));
+	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+					DATADUR_A, PK_TYPE_11A, false);
         pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     } else {
@@ -1818,8 +1818,8 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
 	BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
 							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
-	pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice,
-				DATADUR_B, PK_TYPE_11B, false));
+	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+					DATADUR_B, PK_TYPE_11B, false);
         pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
 	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     }
-- 
1.8.1.2



^ permalink raw reply related

* [RFC] mac80211: fix locking with ieee80211_resume_disconnect()
From: Johannes Berg @ 2013-08-21 20:35 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg

From: Johannes Berg <johannes.berg@intel.com>

If it is needed to disconnect multiple virtual interfaces after
(WoWLAN-) suspend, the most obvious approach would be to iterate
all interfaces by calling ieee80211_iterate_active_interfaces()
and then call ieee80211_resume_disconnect() for each one. This
is what the iwlmvm driver does.

Unfortunately, this causes a locking dependency from mac80211's
iflist_mtx to the key_mtx. This is problematic as the former is
intentionally never held while calling any driver operation to
allow drivers to iterate with their own locks held. The key_mtx
is held while installing a key into the driver though, so this
new lock dependency means drivers implementing the logic above
can no longer hold their own lock while iterating.

To fix this, modify the ieee80211_resume_disconnect() API to do
the iteration in there (using RCU) while holding the key_mtx so
there's no new lock dependency, and let the driver device which
interface should be disconnected by passing a decision function
that returns true/false.

This also adjusts users accordingly, the iwldvm one introduces
a behavioural change (previously only a single interface would
have been disconnected) but this is acceptable since it only
supports a single one for WoWLAN, so the other one would have
been disconnected by the AP while sleeping anyway. For iwlmvm
this fixes the bug described above.

The decision-making callback would therefore not be necessary
right now, but I'm working on a future patch to keep a single
connection in iwlmvm open, at which point that one should not
be disconnected, though all other ones should, so the API is
prepared for that change already.

Change-Id: I9b578c7dacefbb818b4113da12770aec9d0b06c4
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/iwlwifi/dvm/mac80211.c |  2 +-
 drivers/net/wireless/iwlwifi/mvm/d3.c       | 12 +----------
 include/net/mac80211.h                      | 24 ++++++++++++++--------
 net/mac80211/util.c                         | 31 ++++++++++++++++-------------
 4 files changed, 35 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 4bd2ca9..1810b23 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -571,7 +571,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
 	mutex_unlock(&priv->mutex);
 	IWL_DEBUG_MAC80211(priv, "leave\n");
 
-	ieee80211_resume_disconnect(vif);
+	ieee80211_resume_disconnect(priv->hw, NULL, NULL);
 
 	return 1;
 }
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 5585538..29a7192 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -1362,13 +1362,6 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
 #endif
 }
 
-static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
-				       struct ieee80211_vif *vif)
-{
-	if (vif->type == NL80211_IFTYPE_STATION)
-		ieee80211_resume_disconnect(vif);
-}
-
 static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
 	struct iwl_d3_iter_data resume_iter_data = {
@@ -1411,10 +1404,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 
  out:
 	if (!test)
-		ieee80211_iterate_active_interfaces(mvm->hw,
-						    IEEE80211_IFACE_ITER_NORMAL,
-						    iwl_mvm_d3_disconnect_iter,
-						    NULL);
+		ieee80211_resume_disconnect(mvm->hw, NULL, NULL);
 
 	/* return 1 to reconfigure the device */
 	set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cb5eba8..194efe7 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4104,13 +4104,18 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif);
 /**
  * ieee80211_resume_disconnect - disconnect from AP after resume
  *
- * @vif: &struct ieee80211_vif pointer from the add_interface callback.
- *
- * Instructs mac80211 to disconnect from the AP after resume.
- * Drivers can use this after WoWLAN if they know that the
- * connection cannot be kept up, for example because keys were
- * used while the device was asleep but the replay counters or
- * similar cannot be retrieved from the device during resume.
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @decision: decision function, return %true if the interface should be
+ *	disconnected, only interfaces of type %NL80211_IFTYPE_STATION
+ *	(P2P and non-P2P) will be passed for decision-making. May be %NULL
+ *	which is equivalent to always returning %true.
+ *
+ * Instructs mac80211 to disconnect from the AP after resume for those
+ * interfaces where the decision-making function returned %true. Drivers
+ * can use this after WoWLAN if they know that the connection cannot be
+ * kept up, for example because keys were used while the device was asleep
+ * but the replay counters or similar cannot be retrieved from the device
+ * during resume.
  *
  * Note that due to implementation issues, if the driver uses
  * the reconfiguration functionality during resume the interface
@@ -4122,7 +4127,10 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif);
  * calls this function, or at least not any locks it needs in the
  * key configuration paths (if it supports HW crypto).
  */
-void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
+void ieee80211_resume_disconnect(struct ieee80211_hw *hw,
+				 bool (*decision)(struct ieee80211_vif *vif,
+						  void *data),
+				 void *decision_data);
 
 /**
  * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d23c5a7..ba85533 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1753,29 +1753,32 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 	return 0;
 }
 
-void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
+void ieee80211_resume_disconnect(struct ieee80211_hw *hw,
+				 bool (*decision)(struct ieee80211_vif *vif,
+						  void *data),
+				 void *decision_data)
 {
+	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_local *local;
 	struct ieee80211_key *key;
 
-	if (WARN_ON(!vif))
-		return;
-
-	sdata = vif_to_sdata(vif);
-	local = sdata->local;
-
 	if (WARN_ON(!local->resuming))
 		return;
 
-	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
-		return;
+	mutex_lock(&local->key_mtx);
+	rcu_read_lock();
 
-	sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (sdata->vif.type != NL80211_IFTYPE_STATION)
+			continue;
+		if (decision && !decision(&sdata->vif, decision_data))
+			continue;
+		sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
+		list_for_each_entry(key, &sdata->key_list, list)
+			key->flags |= KEY_FLAG_TAINTED;
+	}
 
-	mutex_lock(&local->key_mtx);
-	list_for_each_entry(key, &sdata->key_list, list)
-		key->flags |= KEY_FLAG_TAINTED;
+	rcu_read_unlock();
 	mutex_unlock(&local->key_mtx);
 }
 EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
-- 
1.8.4.rc2


^ permalink raw reply related

* Re: [RFT V2 02/13] brcmsmac: change pa_gain for bcm4313 iPA
From: Hauke Mehrtens @ 2013-08-21 19:18 UTC (permalink / raw)
  To: Arend van Spriel
  Cc: linux-wireless, Jonas Gorski, David Herrmann,
	Maximilian Engelhardt, David Costa
In-Reply-To: <1376424220-10765-3-git-send-email-arend@broadcom.com>

Hi Arend,

when you send a new patch please fix this typo.

Hauke

On 08/13/2013 10:03 PM, Arend van Spriel wrote:
> The function wlc_lcnphy_load_tx_gain_table() has a target PA
> gain specified for the iPA variant of the bcm4313. This gain
> value is reduced to avoid PA distortion. The if-statement is
> removed because it was rather redundant in the first place.
> Please not that this patch does not provide full iPA support.
         ^^^
         note



^ permalink raw reply

* Re: [RFT 00/13] brcmsmac: bcm4313 iPA related patches
From: Arend van Spriel @ 2013-08-21 19:00 UTC (permalink / raw)
  To: Maximilian Engelhardt; +Cc: linux-wireless
In-Reply-To: <7288564.kdgq91zD8T@eisbaer>

On 08/21/13 18:17, Maximilian Engelhardt wrote:
> On Tuesday 13 August 2013 22:03:27 Arend van Spriel wrote:
>> This series replaces the patch "[PATCH 12/12] brcmsmac: support 4313iPA"
>> with Message-ID:<1376130450-29746-13-git-send-email-arend@broadcom.com>.
>>
>> It has been split up into individual patches. Please test this series
>> especially if you had issues with the original commit b6fc28a that was
>> reverted.
>>
>> Cc: Jonas Gorski<jogo@openwrt.org>
>> Cc: David Herrmann<dh.herrmann@gmail.com>
>> Cc: Maximilian Engelhardt<maxi@daemonizer.de>
>> Cc: David Costa<david@zarel.net>
>>
>> Arend van Spriel (13):
>>    brcmsmac: cosmetic change in phy_lcn.c
>>    brcmsmac: change pa_gain for bcm4313 iPA
>>    brcmsmac: use ARRAY_SIZE in phytbl_lcn.c
>>    brcmsmac: add switch control table for BCM4313 iPA BT-combo cards
>>    brcmsmac: add debug info message providing phy and radio info
>>    brcmsmac: update transmit gain table for lcn phy
>>    brcmsmac: change lcnphy receive i/q calibration routine
>>    brcmsmac: fix TSSI idle estimation
>>    brcmsmac: avoid calling set_txpwr_by_index() twice
>>    brcmsmac: rework switch control table init including iPA BT-combo
>>    brcmsmac: correct phy registers for TSSI-based power control
>>    brcmsmac: reinitialize TSSI power control upon channel switch
>>    brcmsmac: add support for BCM4313 iPA variant
>>
>>   drivers/net/wireless/brcm80211/brcmsmac/main.c     |    4 +-
>>   .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c  |  397
>> +++++++++++-------- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c   |
>> 405 +++++++++++--------- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h
>> |    1 +
>>   4 files changed, 475 insertions(+), 332 deletions(-)
>
> Hello Arend,
>
> I finally had some time to test your patches.
>
> On my hardware I couldn't find any regressions with these patches. I also
> verified that the reception problems I had with my card are fixed by these
> patches.
>
> I did test the patches on top of 3.10.5 as they did apply without any
> problems.

Appreciated. I did send the patches for wireless-next already, ie. for 
v3.12 kernel. Good to know that they apply to 3.10 as is.

Regards,
Arend


^ permalink raw reply

* Re: Tunneable mesh channels
From: Francisco Cuesta @ 2013-08-21 19:00 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <CANMvdA-SDgbL7p0xbXfOoWpgjf9viVKYwErHd8K-VBGZotLA1A@mail.gmail.com>

Hello,

 I was wondering a question concerning to channel selection on mesh
networks, in my previous version of compat-wirelessI disabled some
channels, but now in the new version(2013-06-27) they're back again.
So I would like to ensure that whether the channel is listed by iw phy
phyo info that channel can be used by the kernel when setting up the
mesh node or not; since as far as I know, if it does not show up after
issuing the command then that channel for sure cannot be used at all.

 Am I mistaken?

 Thanks in advance,

 Regards!

^ permalink raw reply

* Re: [PATCH v2 3/6] rt2x00: rt2800: serialize shared memory access
From: Gabor Juhos @ 2013-08-21 16:42 UTC (permalink / raw)
  To: Helmut Schaa; +Cc: John W. Linville, linux-wireless, rt2x00 Users List
In-Reply-To: <CAGXE3d-q3-HNtdp5jq94nCcLzCW1-oO+HTt+=yOFEE+fL8kbtA@mail.gmail.com>

Hi Helmut,

> On Mon, Aug 19, 2013 at 3:11 PM, Gabor Juhos <juhosg@openwrt.org> wrote:
>> The shared memory of the rt2800 devices is accessible
>> through the register offset range between 0x4000 and
>> 0x8000. The size of this range is 16KB only and on
>> devices which have more than 16KB of shared memory either
>> the low or the high part of the memory is accessible at a
>> time.
>>
> 
>> Serialize all accesses to the shared memory by a mutex,
>> in order to avoid concurrent use of that.
>>
>> Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
>> ---
> 
> [...]
> 
> 
>> @@ -993,8 +1001,11 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
>>         }
>>
>>         beacon_base = HW_BEACON_BASE(entry->entry_idx);
>> +
>> +       rt2800_shared_mem_lock(rt2x00dev);
>>         rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
>>                                    entry->skb->len + padding_len);
>> +       rt2800_shared_mem_unlock(rt2x00dev);
>>
>>         /*
>>          * Enable beaconing again.
> 
> Beacons on PCI devices are updated from pre_tbtt or beacon_done tasklet.
> Looks like this will fail for pci then ...

Hm, you are right:

BUG: sleeping function called from invalid context at kernel/mutex.c:619
in_atomic(): 1, irqs_disabled(): 0, pid: 0, name: swapper
INFO: lockdep is turned off.
CPU: 0 PID: 0 Comm: swapper Tainted: G           O 3.11.0-rc6-wl #627
Stack : 00000000 00000000 80745dbe 00000045 00000000 80439ca0 803f097c 80723a50
        8043da78 8043d7c7 001f0640 80439ca0 83dfee20 803f0000 00000006 8035c3dc
        00000000 80031558 80745dbc 00000000 803f42b8 80439b9c 80439b9c 803f097c
        c01ba400 00000000 00000000 00000000 00000000 00000000 00000000 00000000
        00000000 00000000 00000000 00000000 00000000 00000000 00000000 80439b30
          ...
Call Trace:
[<8000d328>] show_stack+0x64/0x7c
[<80361ca0>] mutex_lock_nested+0x4c/0x484
[<c01ba458>] rt2800_write_beacon+0x300/0x460 [rt2800lib]
[<c016dc24>] rt2x00queue_update_beacon_locked+0xc0/0xe4 [rt2x00lib]
[<8033fa30>] ieee80211_iterate_active_interfaces_atomic+0x180/0x188
[<c01cbb18>] 0xc01cbb18


In an early version of the patch, I have used a spinlock but that was not
suitable for USB devices. I have to rethink that how can I resolve this.

Thank you for the review!

-Gabor

^ permalink raw reply

* Re: [RFT 00/13] brcmsmac: bcm4313 iPA related patches
From: Maximilian Engelhardt @ 2013-08-21 16:17 UTC (permalink / raw)
  To: Arend van Spriel; +Cc: linux-wireless
In-Reply-To: <1376424220-10765-1-git-send-email-arend@broadcom.com>

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

On Tuesday 13 August 2013 22:03:27 Arend van Spriel wrote:
> This series replaces the patch "[PATCH 12/12] brcmsmac: support 4313iPA"
> with Message-ID: <1376130450-29746-13-git-send-email-arend@broadcom.com>.
> 
> It has been split up into individual patches. Please test this series
> especially if you had issues with the original commit b6fc28a that was
> reverted.
> 
> Cc: Jonas Gorski <jogo@openwrt.org>
> Cc: David Herrmann <dh.herrmann@gmail.com>
> Cc: Maximilian Engelhardt <maxi@daemonizer.de>
> Cc: David Costa <david@zarel.net>
> 
> Arend van Spriel (13):
>   brcmsmac: cosmetic change in phy_lcn.c
>   brcmsmac: change pa_gain for bcm4313 iPA
>   brcmsmac: use ARRAY_SIZE in phytbl_lcn.c
>   brcmsmac: add switch control table for BCM4313 iPA BT-combo cards
>   brcmsmac: add debug info message providing phy and radio info
>   brcmsmac: update transmit gain table for lcn phy
>   brcmsmac: change lcnphy receive i/q calibration routine
>   brcmsmac: fix TSSI idle estimation
>   brcmsmac: avoid calling set_txpwr_by_index() twice
>   brcmsmac: rework switch control table init including iPA BT-combo
>   brcmsmac: correct phy registers for TSSI-based power control
>   brcmsmac: reinitialize TSSI power control upon channel switch
>   brcmsmac: add support for BCM4313 iPA variant
> 
>  drivers/net/wireless/brcm80211/brcmsmac/main.c     |    4 +-
>  .../net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c  |  397
> +++++++++++-------- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c   | 
> 405 +++++++++++--------- .../wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h  
> |    1 +
>  4 files changed, 475 insertions(+), 332 deletions(-)

Hello Arend,

I finally had some time to test your patches.

On my hardware I couldn't find any regressions with these patches. I also 
verified that the reception problems I had with my card are fixed by these 
patches.

I did test the patches on top of 3.10.5 as they did apply without any 
problems.

Greetings,
Maxi

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

^ 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