Commit 197bbf0a authored by John W. Linville's avatar John W. Linville

Merge tag 'nfc-next-3.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next

Samuel Ortiz <sameo@linux.intel.com> says:

"This is the 2nd NFC pull request for 3.10.

With this one we have:

- A major pn533 update. The pn533 framing support has been changed in order to
  easily support all pn533 derivatives. For example we now support the ACR122
  USB dongle.

- An NFC MEI physical layer code factorization through the mei_phy NFC API.
  Both the microread and the pn544 drivers now use it.

- LLCP aggregation support. This allows NFC p2p devices to send aggregated
  frames containing all sort of LLCP frames except SYMM and aggregation
  frames.

- More LLCP socket options for getting the remote device link parameters.

- Fixes for the LLCP socket option code added with the first pull request for
  3.10.

- Some support for LLCP corner cases like 0 length SDUs and general DISC
  (tagged with a 0,0 dsap ssap couple) handling.

- RFKILL support for NFC."
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parents 9b383672 bb03dceb
...@@ -26,6 +26,16 @@ config NFC_WILINK ...@@ -26,6 +26,16 @@ config NFC_WILINK
Say Y here to compile support for Texas Instrument's NFC WiLink driver Say Y here to compile support for Texas Instrument's NFC WiLink driver
into the kernel or say M to compile it as module. into the kernel or say M to compile it as module.
config NFC_MEI_PHY
tristate "MEI bus NFC device support"
depends on INTEL_MEI_BUS_NFC && NFC_HCI
help
This adds support to use an mei bus nfc device. Select this if you
will use an HCI NFC driver for an NFC chip connected behind an
Intel's Management Engine chip.
If unsure, say N.
source "drivers/nfc/pn544/Kconfig" source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig" source "drivers/nfc/microread/Kconfig"
......
...@@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544) += pn544/ ...@@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544) += pn544/
obj-$(CONFIG_NFC_MICROREAD) += microread/ obj-$(CONFIG_NFC_MICROREAD) += microread/
obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
/*
* MEI Library for mei bus nfc device access
*
* Copyright (C) 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/nfc.h>
#include "mei_phy.h"
struct mei_nfc_hdr {
u8 cmd;
u8 status;
u16 req_id;
u32 reserved;
u16 data_size;
} __attribute__((packed));
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
#define MEI_DUMP_SKB_IN(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, false); \
} while (0)
#define MEI_DUMP_SKB_OUT(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, false); \
} while (0)
int nfc_mei_phy_enable(void *phy_id)
{
int r;
struct nfc_mei_phy *phy = phy_id;
pr_info("%s\n", __func__);
if (phy->powered == 1)
return 0;
r = mei_cl_enable_device(phy->device);
if (r < 0) {
pr_err("MEI_PHY: Could not enable device\n");
return r;
}
phy->powered = 1;
return 0;
}
EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
void nfc_mei_phy_disable(void *phy_id)
{
struct nfc_mei_phy *phy = phy_id;
pr_info("%s\n", __func__);
mei_cl_disable_device(phy->device);
phy->powered = 0;
}
EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
/*
* Writing a frame must not return the number of written bytes.
* It must return either zero for success, or <0 for error.
* In addition, it must not alter the skb
*/
static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
{
struct nfc_mei_phy *phy = phy_id;
int r;
MEI_DUMP_SKB_OUT("mei frame sent", skb);
r = mei_cl_send(phy->device, skb->data, skb->len);
if (r > 0)
r = 0;
return r;
}
void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
{
struct nfc_mei_phy *phy = context;
if (phy->hard_fault != 0)
return;
if (events & BIT(MEI_CL_EVENT_RX)) {
struct sk_buff *skb;
int reply_size;
skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
if (!skb)
return;
reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
if (reply_size < MEI_NFC_HEADER_SIZE) {
kfree(skb);
return;
}
skb_put(skb, reply_size);
skb_pull(skb, MEI_NFC_HEADER_SIZE);
MEI_DUMP_SKB_IN("mei frame read", skb);
nfc_hci_recv_frame(phy->hdev, skb);
}
}
EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
struct nfc_phy_ops mei_phy_ops = {
.write = nfc_mei_phy_write,
.enable = nfc_mei_phy_enable,
.disable = nfc_mei_phy_disable,
};
EXPORT_SYMBOL_GPL(mei_phy_ops);
struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
{
struct nfc_mei_phy *phy;
phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
if (!phy)
return NULL;
phy->device = device;
mei_cl_set_drvdata(device, phy);
return phy;
}
EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
void nfc_mei_phy_free(struct nfc_mei_phy *phy)
{
kfree(phy);
}
EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("mei bus NFC device interface");
#ifndef __LOCAL_MEI_PHY_H_
#define __LOCAL_MEI_PHY_H_
#include <linux/mei_cl_bus.h>
#include <net/nfc/hci.h>
#define MEI_NFC_HEADER_SIZE 10
#define MEI_NFC_MAX_HCI_PAYLOAD 300
struct nfc_mei_phy {
struct mei_cl_device *device;
struct nfc_hci_dev *hdev;
int powered;
int hard_fault; /*
* < 0 if hardware error occured
* and prevents normal operation.
*/
};
extern struct nfc_phy_ops mei_phy_ops;
int nfc_mei_phy_enable(void *phy_id);
void nfc_mei_phy_disable(void *phy_id);
void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
void nfc_mei_phy_free(struct nfc_mei_phy *phy);
#endif /* __LOCAL_MEI_PHY_H_ */
...@@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C ...@@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C
config NFC_MICROREAD_MEI config NFC_MICROREAD_MEI
tristate "NFC Microread MEI support" tristate "NFC Microread MEI support"
depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC depends on NFC_MICROREAD && NFC_MEI_PHY
---help--- ---help---
This module adds support for the mei interface of adapters using This module adds support for the mei interface of adapters using
Inside microread chipsets. Select this if your microread chipset Inside microread chipsets. Select this if your microread chipset
......
...@@ -19,151 +19,31 @@ ...@@ -19,151 +19,31 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/mei_cl_bus.h>
#include <linux/nfc.h> #include <linux/nfc.h>
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include <net/nfc/llc.h> #include <net/nfc/llc.h>
#include "../mei_phy.h"
#include "microread.h" #include "microread.h"
#define MICROREAD_DRIVER_NAME "microread" #define MICROREAD_DRIVER_NAME "microread"
struct mei_nfc_hdr {
u8 cmd;
u8 status;
u16 req_id;
u32 reserved;
u16 data_size;
} __attribute__((packed));
#define MEI_NFC_HEADER_SIZE 10
#define MEI_NFC_MAX_HCI_PAYLOAD 300
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
struct microread_mei_phy {
struct mei_cl_device *device;
struct nfc_hci_dev *hdev;
int powered;
int hard_fault; /*
* < 0 if hardware error occured (e.g. i2c err)
* and prevents normal operation.
*/
};
#define MEI_DUMP_SKB_IN(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
#define MEI_DUMP_SKB_OUT(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
static int microread_mei_enable(void *phy_id)
{
struct microread_mei_phy *phy = phy_id;
pr_info(DRIVER_DESC ": %s\n", __func__);
phy->powered = 1;
return 0;
}
static void microread_mei_disable(void *phy_id)
{
struct microread_mei_phy *phy = phy_id;
pr_info(DRIVER_DESC ": %s\n", __func__);
phy->powered = 0;
}
/*
* Writing a frame must not return the number of written bytes.
* It must return either zero for success, or <0 for error.
* In addition, it must not alter the skb
*/
static int microread_mei_write(void *phy_id, struct sk_buff *skb)
{
struct microread_mei_phy *phy = phy_id;
int r;
MEI_DUMP_SKB_OUT("mei frame sent", skb);
r = mei_cl_send(phy->device, skb->data, skb->len);
if (r > 0)
r = 0;
return r;
}
static void microread_event_cb(struct mei_cl_device *device, u32 events,
void *context)
{
struct microread_mei_phy *phy = context;
if (phy->hard_fault != 0)
return;
if (events & BIT(MEI_CL_EVENT_RX)) {
struct sk_buff *skb;
int reply_size;
skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
if (!skb)
return;
reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
if (reply_size < MEI_NFC_HEADER_SIZE) {
kfree(skb);
return;
}
skb_put(skb, reply_size);
skb_pull(skb, MEI_NFC_HEADER_SIZE);
MEI_DUMP_SKB_IN("mei frame read", skb);
nfc_hci_recv_frame(phy->hdev, skb);
}
}
static struct nfc_phy_ops mei_phy_ops = {
.write = microread_mei_write,
.enable = microread_mei_enable,
.disable = microread_mei_disable,
};
static int microread_mei_probe(struct mei_cl_device *device, static int microread_mei_probe(struct mei_cl_device *device,
const struct mei_cl_device_id *id) const struct mei_cl_device_id *id)
{ {
struct microread_mei_phy *phy; struct nfc_mei_phy *phy;
int r; int r;
pr_info("Probing NFC microread\n"); pr_info("Probing NFC microread\n");
phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL); phy = nfc_mei_phy_alloc(device);
if (!phy) { if (!phy) {
pr_err("Cannot allocate memory for microread mei phy.\n"); pr_err("Cannot allocate memory for microread mei phy.\n");
return -ENOMEM; return -ENOMEM;
} }
phy->device = device; r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
mei_cl_set_drvdata(device, phy);
r = mei_cl_register_event_cb(device, microread_event_cb, phy);
if (r) { if (r) {
pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
goto err_out; goto err_out;
...@@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device, ...@@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device,
return 0; return 0;
err_out: err_out:
kfree(phy); nfc_mei_phy_free(phy);
return r; return r;
} }
static int microread_mei_remove(struct mei_cl_device *device) static int microread_mei_remove(struct mei_cl_device *device)
{ {
struct microread_mei_phy *phy = mei_cl_get_drvdata(device); struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
pr_info("Removing microread\n"); pr_info("Removing microread\n");
microread_remove(phy->hdev); microread_remove(phy->hdev);
if (phy->powered) nfc_mei_phy_disable(phy);
microread_mei_disable(phy);
kfree(phy); nfc_mei_phy_free(phy);
return 0; return 0;
} }
......
/* /*
* Copyright (C) 2011 Instituto Nokia de Tecnologia * Copyright (C) 2011 Instituto Nokia de Tecnologia
* * Copyright (C) 2012-2013 Tieto Poland
* Authors:
* 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -30,7 +27,7 @@ ...@@ -30,7 +27,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <net/nfc/nfc.h> #include <net/nfc/nfc.h>
#define VERSION "0.1" #define VERSION "0.2"
#define PN533_VENDOR_ID 0x4CC #define PN533_VENDOR_ID 0x4CC
#define PN533_PRODUCT_ID 0x2533 #define PN533_PRODUCT_ID 0x2533
...@@ -41,8 +38,12 @@ ...@@ -41,8 +38,12 @@
#define SONY_VENDOR_ID 0x054c #define SONY_VENDOR_ID 0x054c
#define PASORI_PRODUCT_ID 0x02e1 #define PASORI_PRODUCT_ID 0x02e1
#define ACS_VENDOR_ID 0x072f
#define ACR122U_PRODUCT_ID 0x2200
#define PN533_DEVICE_STD 0x1 #define PN533_DEVICE_STD 0x1
#define PN533_DEVICE_PASORI 0x2 #define PN533_DEVICE_PASORI 0x2
#define PN533_DEVICE_ACR122U 0x3
#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
...@@ -71,6 +72,11 @@ static const struct usb_device_id pn533_table[] = { ...@@ -71,6 +72,11 @@ static const struct usb_device_id pn533_table[] = {
.idProduct = PASORI_PRODUCT_ID, .idProduct = PASORI_PRODUCT_ID,
.driver_info = PN533_DEVICE_PASORI, .driver_info = PN533_DEVICE_PASORI,
}, },
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = ACS_VENDOR_ID,
.idProduct = ACR122U_PRODUCT_ID,
.driver_info = PN533_DEVICE_ACR122U,
},
{ } { }
}; };
MODULE_DEVICE_TABLE(usb, pn533_table); MODULE_DEVICE_TABLE(usb, pn533_table);
...@@ -78,32 +84,47 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -78,32 +84,47 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
/* How much time we spend listening for initiators */ /* How much time we spend listening for initiators */
#define PN533_LISTEN_TIME 2 #define PN533_LISTEN_TIME 2
/* frame definitions */ /* Standard pn533 frame definitions */
#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \ #define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \
+ 2) /* data[0] TFI, data[1] CC */ + 2) /* data[0] TFI, data[1] CC */
#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/ #define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
/* /*
* Max extended frame payload len, excluding TFI and CC * Max extended frame payload len, excluding TFI and CC
* which are already in PN533_FRAME_HEADER_LEN. * which are already in PN533_FRAME_HEADER_LEN.
*/ */
#define PN533_FRAME_MAX_PAYLOAD_LEN 263 #define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263
#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2), #define PN533_STD_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
Postamble (1) */ Postamble (1) */
#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen]) #define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1]) #define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
/* start of frame */ /* start of frame */
#define PN533_SOF 0x00FF #define PN533_STD_FRAME_SOF 0x00FF
/* frame identifier: in/out/error */ /* standard frame identifier: in/out/error */
#define PN533_FRAME_IDENTIFIER(f) (f->data[0]) #define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */
#define PN533_DIR_OUT 0xD4 #define PN533_STD_FRAME_DIR_OUT 0xD4
#define PN533_DIR_IN 0xD5 #define PN533_STD_FRAME_DIR_IN 0xD5
/* ACS ACR122 pn533 frame definitions */
#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \
+ 2)
#define PN533_ACR122_TX_FRAME_TAIL_LEN 0
#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \
+ 2)
#define PN533_ACR122_RX_FRAME_TAIL_LEN 2
#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN
/* CCID messages types */
#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62
#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B
#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
/* PN533 Commands */ /* PN533 Commands */
#define PN533_FRAME_CMD(f) (f->data[1]) #define PN533_STD_FRAME_CMD(f) (f->data[1])
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02 #define PN533_CMD_GET_FIRMWARE_VERSION 0x02
#define PN533_CMD_RF_CONFIGURATION 0x32 #define PN533_CMD_RF_CONFIGURATION 0x32
...@@ -128,8 +149,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table); ...@@ -128,8 +149,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
struct pn533; struct pn533;
typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg, typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
struct sk_buff *resp); struct sk_buff *resp);
...@@ -144,10 +163,14 @@ struct pn533_fw_version { ...@@ -144,10 +163,14 @@ struct pn533_fw_version {
}; };
/* PN533_CMD_RF_CONFIGURATION */ /* PN533_CMD_RF_CONFIGURATION */
#define PN533_CFGITEM_RF_FIELD 0x01
#define PN533_CFGITEM_TIMING 0x02 #define PN533_CFGITEM_TIMING 0x02
#define PN533_CFGITEM_MAX_RETRIES 0x05 #define PN533_CFGITEM_MAX_RETRIES 0x05
#define PN533_CFGITEM_PASORI 0x82 #define PN533_CFGITEM_PASORI 0x82
#define PN533_CFGITEM_RF_FIELD_ON 0x1
#define PN533_CFGITEM_RF_FIELD_OFF 0x0
#define PN533_CONFIG_TIMING_102 0xb #define PN533_CONFIG_TIMING_102 0xb
#define PN533_CONFIG_TIMING_204 0xc #define PN533_CONFIG_TIMING_204 0xc
#define PN533_CONFIG_TIMING_409 0xd #define PN533_CONFIG_TIMING_409 0xd
...@@ -313,10 +336,17 @@ struct pn533_cmd_jump_dep_response { ...@@ -313,10 +336,17 @@ struct pn533_cmd_jump_dep_response {
#define PN533_INIT_TARGET_RESP_ACTIVE 0x1 #define PN533_INIT_TARGET_RESP_ACTIVE 0x1
#define PN533_INIT_TARGET_RESP_DEP 0x4 #define PN533_INIT_TARGET_RESP_DEP 0x4
enum pn533_protocol_type {
PN533_PROTO_REQ_ACK_RESP = 0,
PN533_PROTO_REQ_RESP
};
struct pn533 { struct pn533 {
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *interface; struct usb_interface *interface;
struct nfc_dev *nfc_dev; struct nfc_dev *nfc_dev;
u32 device_type;
enum pn533_protocol_type protocol_type;
struct urb *out_urb; struct urb *out_urb;
struct urb *in_urb; struct urb *in_urb;
...@@ -329,21 +359,21 @@ struct pn533 { ...@@ -329,21 +359,21 @@ struct pn533 {
struct work_struct poll_work; struct work_struct poll_work;
struct work_struct mi_work; struct work_struct mi_work;
struct work_struct tg_work; struct work_struct tg_work;
struct timer_list listen_timer;
int wq_in_error;
int cancel_listen;
pn533_cmd_complete_t cmd_complete; struct list_head cmd_queue;
void *cmd_complete_arg; struct pn533_cmd *cmd;
u8 cmd_pending;
struct mutex cmd_lock; /* protects cmd queue */
void *cmd_complete_mi_arg; void *cmd_complete_mi_arg;
struct mutex cmd_lock;
u8 cmd;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count; u8 poll_mod_count;
u8 poll_mod_curr; u8 poll_mod_curr;
u32 poll_protocols; u32 poll_protocols;
u32 listen_protocols; u32 listen_protocols;
struct timer_list listen_timer;
int cancel_listen;
u8 *gb; u8 *gb;
size_t gb_len; size_t gb_len;
...@@ -352,24 +382,21 @@ struct pn533 { ...@@ -352,24 +382,21 @@ struct pn533 {
u8 tgt_active_prot; u8 tgt_active_prot;
u8 tgt_mode; u8 tgt_mode;
u32 device_type;
struct list_head cmd_queue;
u8 cmd_pending;
struct pn533_frame_ops *ops; struct pn533_frame_ops *ops;
}; };
struct pn533_cmd { struct pn533_cmd {
struct list_head queue; struct list_head queue;
u8 cmd_code; u8 code;
int status;
struct sk_buff *req; struct sk_buff *req;
struct sk_buff *resp; struct sk_buff *resp;
int resp_len; int resp_len;
void *arg; pn533_send_async_complete_t complete_cb;
void *complete_cb_context;
}; };
struct pn533_frame { struct pn533_std_frame {
u8 preamble; u8 preamble;
__be16 start_frame; __be16 start_frame;
u8 datalen; u8 datalen;
...@@ -393,14 +420,124 @@ struct pn533_frame_ops { ...@@ -393,14 +420,124 @@ struct pn533_frame_ops {
u8 (*get_cmd_code)(void *frame); u8 (*get_cmd_code)(void *frame);
}; };
struct pn533_acr122_ccid_hdr {
u8 type;
u32 datalen;
u8 slot;
u8 seq;
u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific
byte for reposnse msg */
u8 data[]; /* payload */
} __packed;
struct pn533_acr122_apdu_hdr {
u8 class;
u8 ins;
u8 p1;
u8 p2;
} __packed;
struct pn533_acr122_tx_frame {
struct pn533_acr122_ccid_hdr ccid;
struct pn533_acr122_apdu_hdr apdu;
u8 datalen;
u8 data[]; /* pn533 frame: TFI ... */
} __packed;
struct pn533_acr122_rx_frame {
struct pn533_acr122_ccid_hdr ccid;
u8 data[]; /* pn533 frame : TFI ... */
} __packed;
static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code)
{
struct pn533_acr122_tx_frame *frame = _frame;
frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE;
frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) +
sizeof(datalen) */
frame->ccid.slot = 0;
frame->ccid.seq = 0;
frame->ccid.params[0] = 0;
frame->ccid.params[1] = 0;
frame->ccid.params[2] = 0;
frame->data[0] = PN533_STD_FRAME_DIR_OUT;
frame->data[1] = cmd_code;
frame->datalen = 2; /* data[0] + data[1] */
frame->apdu.class = 0xFF;
frame->apdu.ins = 0;
frame->apdu.p1 = 0;
frame->apdu.p2 = 0;
}
static void pn533_acr122_tx_frame_finish(void *_frame)
{
struct pn533_acr122_tx_frame *frame = _frame;
frame->ccid.datalen += frame->datalen;
}
static void pn533_acr122_tx_update_payload_len(void *_frame, int len)
{
struct pn533_acr122_tx_frame *frame = _frame;
frame->datalen += len;
}
static bool pn533_acr122_is_rx_frame_valid(void *_frame)
{
struct pn533_acr122_rx_frame *frame = _frame;
if (frame->ccid.type != 0x83)
return false;
if (frame->data[frame->ccid.datalen - 2] == 0x63)
return false;
return true;
}
static int pn533_acr122_rx_frame_size(void *frame)
{
struct pn533_acr122_rx_frame *f = frame;
/* f->ccid.datalen already includes tail length */
return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen;
}
static u8 pn533_acr122_get_cmd_code(void *frame)
{
struct pn533_acr122_rx_frame *f = frame;
return PN533_STD_FRAME_CMD(f);
}
static struct pn533_frame_ops pn533_acr122_frame_ops = {
.tx_frame_init = pn533_acr122_tx_frame_init,
.tx_frame_finish = pn533_acr122_tx_frame_finish,
.tx_update_payload_len = pn533_acr122_tx_update_payload_len,
.tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN,
.tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN,
.rx_is_frame_valid = pn533_acr122_is_rx_frame_valid,
.rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN,
.rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN,
.rx_frame_size = pn533_acr122_rx_frame_size,
.max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN,
.get_cmd_code = pn533_acr122_get_cmd_code,
};
/* The rule: value + checksum = 0 */ /* The rule: value + checksum = 0 */
static inline u8 pn533_checksum(u8 value) static inline u8 pn533_std_checksum(u8 value)
{ {
return ~value + 1; return ~value + 1;
} }
/* The rule: sum(data elements) + checksum = 0 */ /* The rule: sum(data elements) + checksum = 0 */
static u8 pn533_data_checksum(u8 *data, int datalen) static u8 pn533_std_data_checksum(u8 *data, int datalen)
{ {
u8 sum = 0; u8 sum = 0;
int i; int i;
...@@ -408,61 +545,61 @@ static u8 pn533_data_checksum(u8 *data, int datalen) ...@@ -408,61 +545,61 @@ static u8 pn533_data_checksum(u8 *data, int datalen)
for (i = 0; i < datalen; i++) for (i = 0; i < datalen; i++)
sum += data[i]; sum += data[i];
return pn533_checksum(sum); return pn533_std_checksum(sum);
} }
static void pn533_tx_frame_init(void *_frame, u8 cmd_code) static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code)
{ {
struct pn533_frame *frame = _frame; struct pn533_std_frame *frame = _frame;
frame->preamble = 0; frame->preamble = 0;
frame->start_frame = cpu_to_be16(PN533_SOF); frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF);
PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT; PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT;
PN533_FRAME_CMD(frame) = cmd_code; PN533_STD_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2; frame->datalen = 2;
} }
static void pn533_tx_frame_finish(void *_frame) static void pn533_std_tx_frame_finish(void *_frame)
{ {
struct pn533_frame *frame = _frame; struct pn533_std_frame *frame = _frame;
frame->datalen_checksum = pn533_checksum(frame->datalen); frame->datalen_checksum = pn533_std_checksum(frame->datalen);
PN533_FRAME_CHECKSUM(frame) = PN533_STD_FRAME_CHECKSUM(frame) =
pn533_data_checksum(frame->data, frame->datalen); pn533_std_data_checksum(frame->data, frame->datalen);
PN533_FRAME_POSTAMBLE(frame) = 0; PN533_STD_FRAME_POSTAMBLE(frame) = 0;
} }
static void pn533_tx_update_payload_len(void *_frame, int len) static void pn533_std_tx_update_payload_len(void *_frame, int len)
{ {
struct pn533_frame *frame = _frame; struct pn533_std_frame *frame = _frame;
frame->datalen += len; frame->datalen += len;
} }
static bool pn533_rx_frame_is_valid(void *_frame) static bool pn533_std_rx_frame_is_valid(void *_frame)
{ {
u8 checksum; u8 checksum;
struct pn533_frame *frame = _frame; struct pn533_std_frame *frame = _frame;
if (frame->start_frame != cpu_to_be16(PN533_SOF)) if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
return false; return false;
checksum = pn533_checksum(frame->datalen); checksum = pn533_std_checksum(frame->datalen);
if (checksum != frame->datalen_checksum) if (checksum != frame->datalen_checksum)
return false; return false;
checksum = pn533_data_checksum(frame->data, frame->datalen); checksum = pn533_std_data_checksum(frame->data, frame->datalen);
if (checksum != PN533_FRAME_CHECKSUM(frame)) if (checksum != PN533_STD_FRAME_CHECKSUM(frame))
return false; return false;
return true; return true;
} }
static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) static bool pn533_std_rx_frame_is_ack(struct pn533_std_frame *frame)
{ {
if (frame->start_frame != cpu_to_be16(PN533_SOF)) if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
return false; return false;
if (frame->datalen != 0 || frame->datalen_checksum != 0xFF) if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
...@@ -471,57 +608,51 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame) ...@@ -471,57 +608,51 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
return true; return true;
} }
static inline int pn533_rx_frame_size(void *frame) static inline int pn533_std_rx_frame_size(void *frame)
{ {
struct pn533_frame *f = frame; struct pn533_std_frame *f = frame;
return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN; return sizeof(struct pn533_std_frame) + f->datalen +
PN533_STD_FRAME_TAIL_LEN;
} }
static u8 pn533_get_cmd_code(void *frame) static u8 pn533_std_get_cmd_code(void *frame)
{ {
struct pn533_frame *f = frame; struct pn533_std_frame *f = frame;
return PN533_FRAME_CMD(f); return PN533_STD_FRAME_CMD(f);
} }
static struct pn533_frame_ops pn533_std_frame_ops = { static struct pn533_frame_ops pn533_std_frame_ops = {
.tx_frame_init = pn533_tx_frame_init, .tx_frame_init = pn533_std_tx_frame_init,
.tx_frame_finish = pn533_tx_frame_finish, .tx_frame_finish = pn533_std_tx_frame_finish,
.tx_update_payload_len = pn533_tx_update_payload_len, .tx_update_payload_len = pn533_std_tx_update_payload_len,
.tx_header_len = PN533_FRAME_HEADER_LEN, .tx_header_len = PN533_STD_FRAME_HEADER_LEN,
.tx_tail_len = PN533_FRAME_TAIL_LEN, .tx_tail_len = PN533_STD_FRAME_TAIL_LEN,
.rx_is_frame_valid = pn533_rx_frame_is_valid, .rx_is_frame_valid = pn533_std_rx_frame_is_valid,
.rx_frame_size = pn533_rx_frame_size, .rx_frame_size = pn533_std_rx_frame_size,
.rx_header_len = PN533_FRAME_HEADER_LEN, .rx_header_len = PN533_STD_FRAME_HEADER_LEN,
.rx_tail_len = PN533_FRAME_TAIL_LEN, .rx_tail_len = PN533_STD_FRAME_TAIL_LEN,
.max_payload_len = PN533_FRAME_MAX_PAYLOAD_LEN, .max_payload_len = PN533_STD_FRAME_MAX_PAYLOAD_LEN,
.get_cmd_code = pn533_get_cmd_code, .get_cmd_code = pn533_std_get_cmd_code,
}; };
static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame) static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
{ {
return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd)); return (dev->ops->get_cmd_code(frame) ==
} PN533_CMD_RESPONSE(dev->cmd->code));
static void pn533_wq_cmd_complete(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
int rc;
rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
if (rc != -EINPROGRESS)
queue_work(dev->wq, &dev->cmd_work);
} }
static void pn533_recv_response(struct urb *urb) static void pn533_recv_response(struct urb *urb)
{ {
struct pn533 *dev = urb->context; struct pn533 *dev = urb->context;
struct pn533_cmd *cmd = dev->cmd;
u8 *in_frame; u8 *in_frame;
cmd->status = urb->status;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
break; /* success */ break; /* success */
...@@ -530,37 +661,33 @@ static void pn533_recv_response(struct urb *urb) ...@@ -530,37 +661,33 @@ static void pn533_recv_response(struct urb *urb)
nfc_dev_dbg(&dev->interface->dev, nfc_dev_dbg(&dev->interface->dev,
"The urb has been canceled (status %d)", "The urb has been canceled (status %d)",
urb->status); urb->status);
dev->wq_in_error = urb->status;
goto sched_wq; goto sched_wq;
case -ESHUTDOWN: case -ESHUTDOWN:
default: default:
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"Urb failure (status %d)", urb->status); "Urb failure (status %d)", urb->status);
dev->wq_in_error = urb->status;
goto sched_wq; goto sched_wq;
} }
in_frame = dev->in_urb->transfer_buffer; in_frame = dev->in_urb->transfer_buffer;
nfc_dev_dbg(&dev->interface->dev, "Received a frame."); nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame,
in_frame, dev->ops->rx_frame_size(in_frame), false); dev->ops->rx_frame_size(in_frame), false);
if (!dev->ops->rx_is_frame_valid(in_frame)) { if (!dev->ops->rx_is_frame_valid(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid frame"); nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
dev->wq_in_error = -EIO; cmd->status = -EIO;
goto sched_wq; goto sched_wq;
} }
if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) { if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"It it not the response to the last command"); "It it not the response to the last command");
dev->wq_in_error = -EIO; cmd->status = -EIO;
goto sched_wq; goto sched_wq;
} }
dev->wq_in_error = 0;
sched_wq: sched_wq:
queue_work(dev->wq, &dev->cmd_complete_work); queue_work(dev->wq, &dev->cmd_complete_work);
} }
...@@ -575,9 +702,12 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) ...@@ -575,9 +702,12 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
static void pn533_recv_ack(struct urb *urb) static void pn533_recv_ack(struct urb *urb)
{ {
struct pn533 *dev = urb->context; struct pn533 *dev = urb->context;
struct pn533_frame *in_frame; struct pn533_cmd *cmd = dev->cmd;
struct pn533_std_frame *in_frame;
int rc; int rc;
cmd->status = urb->status;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
break; /* success */ break; /* success */
...@@ -586,21 +716,19 @@ static void pn533_recv_ack(struct urb *urb) ...@@ -586,21 +716,19 @@ static void pn533_recv_ack(struct urb *urb)
nfc_dev_dbg(&dev->interface->dev, nfc_dev_dbg(&dev->interface->dev,
"The urb has been stopped (status %d)", "The urb has been stopped (status %d)",
urb->status); urb->status);
dev->wq_in_error = urb->status;
goto sched_wq; goto sched_wq;
case -ESHUTDOWN: case -ESHUTDOWN:
default: default:
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"Urb failure (status %d)", urb->status); "Urb failure (status %d)", urb->status);
dev->wq_in_error = urb->status;
goto sched_wq; goto sched_wq;
} }
in_frame = dev->in_urb->transfer_buffer; in_frame = dev->in_urb->transfer_buffer;
if (!pn533_rx_frame_is_ack(in_frame)) { if (!pn533_std_rx_frame_is_ack(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid ack"); nfc_dev_err(&dev->interface->dev, "Received an invalid ack");
dev->wq_in_error = -EIO; cmd->status = -EIO;
goto sched_wq; goto sched_wq;
} }
...@@ -608,7 +736,7 @@ static void pn533_recv_ack(struct urb *urb) ...@@ -608,7 +736,7 @@ static void pn533_recv_ack(struct urb *urb)
if (rc) { if (rc) {
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"usb_submit_urb failed with result %d", rc); "usb_submit_urb failed with result %d", rc);
dev->wq_in_error = rc; cmd->status = rc;
goto sched_wq; goto sched_wq;
} }
...@@ -627,7 +755,7 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) ...@@ -627,7 +755,7 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
static int pn533_send_ack(struct pn533 *dev, gfp_t flags) static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
{ {
u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00}; u8 ack[PN533_STD_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
/* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */ /* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
int rc; int rc;
...@@ -643,32 +771,34 @@ static int pn533_send_ack(struct pn533 *dev, gfp_t flags) ...@@ -643,32 +771,34 @@ static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
static int __pn533_send_frame_async(struct pn533 *dev, static int __pn533_send_frame_async(struct pn533 *dev,
struct sk_buff *out, struct sk_buff *out,
struct sk_buff *in, struct sk_buff *in,
int in_len, int in_len)
pn533_cmd_complete_t cmd_complete,
void *arg)
{ {
int rc; int rc;
dev->cmd = dev->ops->get_cmd_code(out->data);
dev->cmd_complete = cmd_complete;
dev->cmd_complete_arg = arg;
dev->out_urb->transfer_buffer = out->data; dev->out_urb->transfer_buffer = out->data;
dev->out_urb->transfer_buffer_length = out->len; dev->out_urb->transfer_buffer_length = out->len;
dev->in_urb->transfer_buffer = in->data; dev->in_urb->transfer_buffer = in->data;
dev->in_urb->transfer_buffer_length = in_len; dev->in_urb->transfer_buffer_length = in_len;
print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1, print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
out->data, out->len, false); out->data, out->len, false);
rc = usb_submit_urb(dev->out_urb, GFP_KERNEL); rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
if (rc) if (rc)
return rc; return rc;
if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
/* request for response for sent packet directly */
rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
if (rc)
goto error;
} else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) {
/* request for ACK if that's the case */
rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL); rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
if (rc) if (rc)
goto error; goto error;
}
return 0; return 0;
...@@ -693,39 +823,34 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code, ...@@ -693,39 +823,34 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
ops->tx_frame_finish(skb->data); ops->tx_frame_finish(skb->data);
} }
struct pn533_send_async_complete_arg { static int pn533_send_async_complete(struct pn533 *dev)
pn533_send_async_complete_t complete_cb;
void *complete_cb_context;
struct sk_buff *resp;
struct sk_buff *req;
};
static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
{ {
struct pn533_send_async_complete_arg *arg = _arg; struct pn533_cmd *cmd = dev->cmd;
int status = cmd->status;
struct sk_buff *req = arg->req; struct sk_buff *req = cmd->req;
struct sk_buff *resp = arg->resp; struct sk_buff *resp = cmd->resp;
int rc; int rc;
dev_kfree_skb(req); dev_kfree_skb(req);
if (status < 0) { if (status < 0) {
arg->complete_cb(dev, arg->complete_cb_context, rc = cmd->complete_cb(dev, cmd->complete_cb_context,
ERR_PTR(status)); ERR_PTR(status));
dev_kfree_skb(resp); dev_kfree_skb(resp);
kfree(arg); goto done;
return status;
} }
skb_put(resp, dev->ops->rx_frame_size(resp->data)); skb_put(resp, dev->ops->rx_frame_size(resp->data));
skb_pull(resp, dev->ops->rx_header_len); skb_pull(resp, dev->ops->rx_header_len);
skb_trim(resp, resp->len - dev->ops->rx_tail_len); skb_trim(resp, resp->len - dev->ops->rx_tail_len);
rc = arg->complete_cb(dev, arg->complete_cb_context, resp); rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp);
kfree(arg); done:
kfree(cmd);
dev->cmd = NULL;
return rc; return rc;
} }
...@@ -736,56 +861,45 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code, ...@@ -736,56 +861,45 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
void *complete_cb_context) void *complete_cb_context)
{ {
struct pn533_cmd *cmd; struct pn533_cmd *cmd;
struct pn533_send_async_complete_arg *arg;
int rc = 0; int rc = 0;
nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code); nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
arg = kzalloc(sizeof(*arg), GFP_KERNEL); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!arg) if (!cmd)
return -ENOMEM; return -ENOMEM;
arg->complete_cb = complete_cb; cmd->code = cmd_code;
arg->complete_cb_context = complete_cb_context; cmd->req = req;
arg->resp = resp; cmd->resp = resp;
arg->req = req; cmd->resp_len = resp_len;
cmd->complete_cb = complete_cb;
cmd->complete_cb_context = complete_cb_context;
pn533_build_cmd_frame(dev, cmd_code, req); pn533_build_cmd_frame(dev, cmd_code, req);
mutex_lock(&dev->cmd_lock); mutex_lock(&dev->cmd_lock);
if (!dev->cmd_pending) { if (!dev->cmd_pending) {
rc = __pn533_send_frame_async(dev, req, resp, resp_len, rc = __pn533_send_frame_async(dev, req, resp, resp_len);
pn533_send_async_complete, arg);
if (rc) if (rc)
goto error; goto error;
dev->cmd_pending = 1; dev->cmd_pending = 1;
dev->cmd = cmd;
goto unlock; goto unlock;
} }
nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__, nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
cmd_code); cmd_code);
cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
if (!cmd) {
rc = -ENOMEM;
goto error;
}
INIT_LIST_HEAD(&cmd->queue); 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); list_add_tail(&cmd->queue, &dev->cmd_queue);
goto unlock; goto unlock;
error: error:
kfree(arg); kfree(cmd);
unlock: unlock:
mutex_unlock(&dev->cmd_lock); mutex_unlock(&dev->cmd_lock);
return rc; return rc;
...@@ -850,8 +964,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, ...@@ -850,8 +964,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
pn533_send_async_complete_t complete_cb, pn533_send_async_complete_t complete_cb,
void *complete_cb_context) void *complete_cb_context)
{ {
struct pn533_send_async_complete_arg *arg;
struct sk_buff *resp; struct sk_buff *resp;
struct pn533_cmd *cmd;
int rc; int rc;
int resp_len = dev->ops->rx_header_len + int resp_len = dev->ops->rx_header_len +
dev->ops->max_payload_len + dev->ops->max_payload_len +
...@@ -861,33 +975,47 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code, ...@@ -861,33 +975,47 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
if (!resp) if (!resp)
return -ENOMEM; return -ENOMEM;
arg = kzalloc(sizeof(*arg), GFP_KERNEL); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!arg) { if (!cmd) {
dev_kfree_skb(resp); dev_kfree_skb(resp);
return -ENOMEM; return -ENOMEM;
} }
arg->complete_cb = complete_cb; cmd->code = cmd_code;
arg->complete_cb_context = complete_cb_context; cmd->req = req;
arg->resp = resp; cmd->resp = resp;
arg->req = req; cmd->resp_len = resp_len;
cmd->complete_cb = complete_cb;
cmd->complete_cb_context = complete_cb_context;
pn533_build_cmd_frame(dev, cmd_code, req); pn533_build_cmd_frame(dev, cmd_code, req);
rc = __pn533_send_frame_async(dev, req, resp, resp_len, rc = __pn533_send_frame_async(dev, req, resp, resp_len);
pn533_send_async_complete, arg);
if (rc < 0) { if (rc < 0) {
dev_kfree_skb(resp); dev_kfree_skb(resp);
kfree(arg); kfree(cmd);
} else {
dev->cmd = cmd;
} }
return rc; return rc;
} }
static void pn533_wq_cmd_complete(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
int rc;
rc = pn533_send_async_complete(dev);
if (rc != -EINPROGRESS)
queue_work(dev->wq, &dev->cmd_work);
}
static void pn533_wq_cmd(struct work_struct *work) static void pn533_wq_cmd(struct work_struct *work)
{ {
struct pn533 *dev = container_of(work, struct pn533, cmd_work); struct pn533 *dev = container_of(work, struct pn533, cmd_work);
struct pn533_cmd *cmd; struct pn533_cmd *cmd;
int rc;
mutex_lock(&dev->cmd_lock); mutex_lock(&dev->cmd_lock);
...@@ -903,10 +1031,15 @@ static void pn533_wq_cmd(struct work_struct *work) ...@@ -903,10 +1031,15 @@ static void pn533_wq_cmd(struct work_struct *work)
mutex_unlock(&dev->cmd_lock); mutex_unlock(&dev->cmd_lock);
__pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len, rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len);
pn533_send_async_complete, cmd->arg); if (rc < 0) {
dev_kfree_skb(cmd->req);
dev_kfree_skb(cmd->resp);
kfree(cmd); kfree(cmd);
return;
}
dev->cmd = cmd;
} }
struct pn533_sync_cmd_response { struct pn533_sync_cmd_response {
...@@ -982,6 +1115,23 @@ static void pn533_send_complete(struct urb *urb) ...@@ -982,6 +1115,23 @@ static void pn533_send_complete(struct urb *urb)
} }
} }
static void pn533_abort_cmd(struct pn533 *dev, gfp_t flags)
{
/* ACR122U does not support any command which aborts last
* issued command i.e. as ACK for standard PN533. Additionally,
* it behaves stange, sending broken or incorrect responses,
* when we cancel urb before the chip will send response.
*/
if (dev->device_type == PN533_DEVICE_ACR122U)
return;
/* An ack will cancel the last issued command */
pn533_send_ack(dev, flags);
/* cancel the urb request */
usb_kill_urb(dev->in_urb);
}
static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size) static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1500,9 +1650,6 @@ static void pn533_listen_mode_timer(unsigned long data) ...@@ -1500,9 +1650,6 @@ static void pn533_listen_mode_timer(unsigned long data)
nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout"); nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
/* An ack will cancel the last issued command (poll) */
pn533_send_ack(dev, GFP_ATOMIC);
dev->cancel_listen = 1; dev->cancel_listen = 1;
pn533_poll_next_mod(dev); pn533_poll_next_mod(dev);
...@@ -1549,6 +1696,11 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg, ...@@ -1549,6 +1696,11 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
if (!rc) if (!rc)
goto done; goto done;
if (!dev->poll_mod_count) {
nfc_dev_dbg(&dev->interface->dev, "Polling has been stoped.");
goto done;
}
pn533_poll_next_mod(dev); pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work); queue_work(dev->wq, &dev->poll_work);
...@@ -1627,7 +1779,7 @@ static void pn533_wq_poll(struct work_struct *work) ...@@ -1627,7 +1779,7 @@ static void pn533_wq_poll(struct work_struct *work)
if (dev->cancel_listen == 1) { if (dev->cancel_listen == 1) {
dev->cancel_listen = 0; dev->cancel_listen = 0;
usb_kill_urb(dev->in_urb); pn533_abort_cmd(dev, GFP_ATOMIC);
} }
rc = pn533_send_poll_frame(dev); rc = pn533_send_poll_frame(dev);
...@@ -1689,12 +1841,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev) ...@@ -1689,12 +1841,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
return; return;
} }
/* An ack will cancel the last issued command (poll) */ pn533_abort_cmd(dev, GFP_KERNEL);
pn533_send_ack(dev, GFP_KERNEL);
/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
usb_kill_urb(dev->in_urb);
pn533_poll_reset_mod_list(dev); pn533_poll_reset_mod_list(dev);
} }
...@@ -1723,6 +1870,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) ...@@ -1723,6 +1870,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
rsp = (struct pn533_cmd_activate_response *)resp->data; rsp = (struct pn533_cmd_activate_response *)resp->data;
rc = rsp->status & PN533_CMD_RET_MASK; rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) { if (rc != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev,
"Target activation failed (error 0x%x)", rc);
dev_kfree_skb(resp); dev_kfree_skb(resp);
return -EIO; return -EIO;
} }
...@@ -1850,7 +1999,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, ...@@ -1850,7 +1999,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
rc = rsp->status & PN533_CMD_RET_MASK; rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) { if (rc != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"Bringing DEP link up failed %d", rc); "Bringing DEP link up failed (error 0x%x)", rc);
goto error; goto error;
} }
...@@ -1985,10 +2134,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev) ...@@ -1985,10 +2134,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
pn533_poll_reset_mod_list(dev); pn533_poll_reset_mod_list(dev);
if (dev->tgt_mode || dev->tgt_active_prot) { if (dev->tgt_mode || dev->tgt_active_prot)
pn533_send_ack(dev, GFP_KERNEL); pn533_abort_cmd(dev, GFP_KERNEL);
usb_kill_urb(dev->in_urb);
}
dev->tgt_active_prot = 0; dev->tgt_active_prot = 0;
dev->tgt_mode = 0; dev->tgt_mode = 0;
...@@ -2064,8 +2211,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, ...@@ -2064,8 +2211,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
if (ret != PN533_CMD_RET_SUCCESS) { if (ret != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev, nfc_dev_err(&dev->interface->dev,
"PN533 reported error %d when exchanging data", "Exchanging data failed (error 0x%x)", ret);
ret);
rc = -EIO; rc = -EIO;
goto error; goto error;
} }
...@@ -2253,7 +2399,7 @@ static void pn533_wq_mi_recv(struct work_struct *work) ...@@ -2253,7 +2399,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
"Error %d when trying to perform data_exchange", rc); "Error %d when trying to perform data_exchange", rc);
dev_kfree_skb(skb); dev_kfree_skb(skb);
kfree(dev->cmd_complete_arg); kfree(dev->cmd_complete_mi_arg);
error: error:
pn533_send_ack(dev, GFP_KERNEL); pn533_send_ack(dev, GFP_KERNEL);
...@@ -2310,7 +2456,7 @@ static int pn533_get_firmware_version(struct pn533 *dev, ...@@ -2310,7 +2456,7 @@ static int pn533_get_firmware_version(struct pn533 *dev,
return 0; return 0;
} }
static int pn533_fw_reset(struct pn533 *dev) static int pn533_pasori_fw_reset(struct pn533 *dev)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *resp; struct sk_buff *resp;
...@@ -2332,9 +2478,102 @@ static int pn533_fw_reset(struct pn533 *dev) ...@@ -2332,9 +2478,102 @@ static int pn533_fw_reset(struct pn533 *dev)
return 0; return 0;
} }
struct pn533_acr122_poweron_rdr_arg {
int rc;
struct completion done;
};
static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
{
struct pn533_acr122_poweron_rdr_arg *arg = urb->context;
nfc_dev_dbg(&urb->dev->dev, "%s", __func__);
print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
urb->transfer_buffer, urb->transfer_buffer_length,
false);
arg->rc = urb->status;
complete(&arg->done);
}
static int pn533_acr122_poweron_rdr(struct pn533 *dev)
{
/* Power on th reader (CCID cmd) */
u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON,
0, 0, 0, 0, 0, 0, 3, 0, 0};
u8 buf[255];
int rc;
void *cntx;
struct pn533_acr122_poweron_rdr_arg arg;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
init_completion(&arg.done);
cntx = dev->in_urb->context; /* backup context */
dev->in_urb->transfer_buffer = buf;
dev->in_urb->transfer_buffer_length = 255;
dev->in_urb->complete = pn533_acr122_poweron_rdr_resp;
dev->in_urb->context = &arg;
dev->out_urb->transfer_buffer = cmd;
dev->out_urb->transfer_buffer_length = sizeof(cmd);
print_hex_dump(KERN_ERR, "ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
cmd, sizeof(cmd), false);
rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Reader power on cmd error %d", rc);
return rc;
}
rc = usb_submit_urb(dev->in_urb, GFP_KERNEL);
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Can't submit for reader power on cmd response %d",
rc);
return rc;
}
wait_for_completion(&arg.done);
dev->in_urb->context = cntx; /* restore context */
return arg.rc;
}
static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
u8 rf_field = !!rf;
int rc;
rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD,
(u8 *)&rf_field, 1);
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Error on setting RF field");
return rc;
}
return rc;
}
int pn533_dev_up(struct nfc_dev *nfc_dev)
{
return pn533_rf_field(nfc_dev, 1);
}
int pn533_dev_down(struct nfc_dev *nfc_dev)
{
return pn533_rf_field(nfc_dev, 0);
}
static struct nfc_ops pn533_nfc_ops = { static struct nfc_ops pn533_nfc_ops = {
.dev_up = NULL, .dev_up = pn533_dev_up,
.dev_down = NULL, .dev_down = pn533_dev_down,
.dep_link_up = pn533_dep_link_up, .dep_link_up = pn533_dep_link_up,
.dep_link_down = pn533_dep_link_down, .dep_link_down = pn533_dep_link_down,
.start_poll = pn533_start_poll, .start_poll = pn533_start_poll,
...@@ -2366,6 +2605,7 @@ static int pn533_setup(struct pn533 *dev) ...@@ -2366,6 +2605,7 @@ static int pn533_setup(struct pn533 *dev)
break; break;
case PN533_DEVICE_PASORI: case PN533_DEVICE_PASORI:
case PN533_DEVICE_ACR122U:
max_retries.mx_rty_atr = 0x2; max_retries.mx_rty_atr = 0x2;
max_retries.mx_rty_psl = 0x1; max_retries.mx_rty_psl = 0x1;
max_retries.mx_rty_passive_act = max_retries.mx_rty_passive_act =
...@@ -2405,7 +2645,7 @@ static int pn533_setup(struct pn533 *dev) ...@@ -2405,7 +2645,7 @@ static int pn533_setup(struct pn533 *dev)
break; break;
case PN533_DEVICE_PASORI: case PN533_DEVICE_PASORI:
pn533_fw_reset(dev); pn533_pasori_fw_reset(dev);
rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI,
pasori_cfg, 3); pasori_cfg, 3);
...@@ -2415,7 +2655,7 @@ static int pn533_setup(struct pn533 *dev) ...@@ -2415,7 +2655,7 @@ static int pn533_setup(struct pn533 *dev)
return rc; return rc;
} }
pn533_fw_reset(dev); pn533_pasori_fw_reset(dev);
break; break;
} }
...@@ -2496,6 +2736,7 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2496,6 +2736,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->ops = &pn533_std_frame_ops; dev->ops = &pn533_std_frame_ops;
dev->protocol_type = PN533_PROTO_REQ_ACK_RESP;
dev->device_type = id->driver_info; dev->device_type = id->driver_info;
switch (dev->device_type) { switch (dev->device_type) {
case PN533_DEVICE_STD: case PN533_DEVICE_STD:
...@@ -2506,6 +2747,20 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2506,6 +2747,20 @@ static int pn533_probe(struct usb_interface *interface,
protocols = PN533_NO_TYPE_B_PROTOCOLS; protocols = PN533_NO_TYPE_B_PROTOCOLS;
break; break;
case PN533_DEVICE_ACR122U:
protocols = PN533_NO_TYPE_B_PROTOCOLS;
dev->ops = &pn533_acr122_frame_ops;
dev->protocol_type = PN533_PROTO_REQ_RESP,
rc = pn533_acr122_poweron_rdr(dev);
if (rc < 0) {
nfc_dev_err(&dev->interface->dev,
"Couldn't poweron the reader (error %d)",
rc);
goto destroy_wq;
}
break;
default: default:
nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n",
dev->device_type); dev->device_type);
...@@ -2555,6 +2810,7 @@ static int pn533_probe(struct usb_interface *interface, ...@@ -2555,6 +2810,7 @@ static int pn533_probe(struct usb_interface *interface,
error: error:
usb_free_urb(dev->in_urb); usb_free_urb(dev->in_urb);
usb_free_urb(dev->out_urb); usb_free_urb(dev->out_urb);
usb_put_dev(dev->udev);
kfree(dev); kfree(dev);
return rc; return rc;
} }
...@@ -2600,8 +2856,9 @@ static struct usb_driver pn533_driver = { ...@@ -2600,8 +2856,9 @@ static struct usb_driver pn533_driver = {
module_usb_driver(pn533_driver); module_usb_driver(pn533_driver);
MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>," MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
" Aloisio Almeida Jr <aloisio.almeida@openbossa.org>"); MODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
MODULE_AUTHOR("Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>");
MODULE_DESCRIPTION("PN533 usb driver ver " VERSION); MODULE_DESCRIPTION("PN533 usb driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -21,3 +21,14 @@ config NFC_PN544_I2C ...@@ -21,3 +21,14 @@ config NFC_PN544_I2C
If you choose to build a module, it'll be called pn544_i2c. If you choose to build a module, it'll be called pn544_i2c.
Say N if unsure. Say N if unsure.
config NFC_PN544_MEI
tristate "NFC PN544 MEI support"
depends on NFC_PN544 && NFC_MEI_PHY
---help---
This module adds support for the mei interface of adapters using
NXP pn544 chipsets. Select this if your pn544 chipset
is handled by Intel's Management Engine Interface on your platform.
If you choose to build a module, it'll be called pn544_mei.
Say N if unsure.
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# #
pn544_i2c-objs = i2c.o pn544_i2c-objs = i2c.o
pn544_mei-objs = mei.o
obj-$(CONFIG_NFC_PN544) += pn544.o obj-$(CONFIG_NFC_PN544) += pn544.o
obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
obj-$(CONFIG_NFC_PN544_MEI) += pn544_mei.o
/*
* HCI based Driver for NXP pn544 NFC Chip
*
* Copyright (C) 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/nfc.h>
#include <net/nfc/hci.h>
#include <net/nfc/llc.h>
#include "../mei_phy.h"
#include "pn544.h"
#define PN544_DRIVER_NAME "pn544"
static int pn544_mei_probe(struct mei_cl_device *device,
const struct mei_cl_device_id *id)
{
struct nfc_mei_phy *phy;
int r;
pr_info("Probing NFC pn544\n");
phy = nfc_mei_phy_alloc(device);
if (!phy) {
pr_err("Cannot allocate memory for pn544 mei phy.\n");
return -ENOMEM;
}
r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
if (r) {
pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
goto err_out;
}
r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
&phy->hdev);
if (r < 0)
goto err_out;
return 0;
err_out:
nfc_mei_phy_free(phy);
return r;
}
static int pn544_mei_remove(struct mei_cl_device *device)
{
struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
pr_info("Removing pn544\n");
pn544_hci_remove(phy->hdev);
nfc_mei_phy_disable(phy);
nfc_mei_phy_free(phy);
return 0;
}
static struct mei_cl_device_id pn544_mei_tbl[] = {
{ PN544_DRIVER_NAME },
/* required last entry */
{ }
};
MODULE_DEVICE_TABLE(mei, pn544_mei_tbl);
static struct mei_cl_driver pn544_driver = {
.id_table = pn544_mei_tbl,
.name = PN544_DRIVER_NAME,
.probe = pn544_mei_probe,
.remove = pn544_mei_remove,
};
static int pn544_mei_init(void)
{
int r;
pr_debug(DRIVER_DESC ": %s\n", __func__);
r = mei_cl_driver_register(&pn544_driver);
if (r) {
pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
return r;
}
return 0;
}
static void pn544_mei_exit(void)
{
mei_cl_driver_unregister(&pn544_driver);
}
module_init(pn544_mei_init);
module_exit(pn544_mei_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);
...@@ -122,6 +122,8 @@ struct nfc_dev { ...@@ -122,6 +122,8 @@ struct nfc_dev {
bool shutting_down; bool shutting_down;
struct rfkill *rfkill;
struct nfc_ops *ops; struct nfc_ops *ops;
}; };
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
......
...@@ -235,5 +235,8 @@ struct sockaddr_nfc_llcp { ...@@ -235,5 +235,8 @@ struct sockaddr_nfc_llcp {
/* socket option names */ /* socket option names */
#define NFC_LLCP_RW 0 #define NFC_LLCP_RW 0
#define NFC_LLCP_MIUX 1 #define NFC_LLCP_MIUX 1
#define NFC_LLCP_REMOTE_MIU 2
#define NFC_LLCP_REMOTE_LTO 3
#define NFC_LLCP_REMOTE_RW 4
#endif /*__LINUX_NFC_H */ #endif /*__LINUX_NFC_H */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device. * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
* @RFKILL_TYPE_GPS: switch is on a GPS device. * @RFKILL_TYPE_GPS: switch is on a GPS device.
* @RFKILL_TYPE_FM: switch is on a FM radio device. * @RFKILL_TYPE_FM: switch is on a FM radio device.
* @RFKILL_TYPE_NFC: switch is on an NFC device.
* @NUM_RFKILL_TYPES: number of defined rfkill types * @NUM_RFKILL_TYPES: number of defined rfkill types
*/ */
enum rfkill_type { enum rfkill_type {
...@@ -48,6 +49,7 @@ enum rfkill_type { ...@@ -48,6 +49,7 @@ enum rfkill_type {
RFKILL_TYPE_WWAN, RFKILL_TYPE_WWAN,
RFKILL_TYPE_GPS, RFKILL_TYPE_GPS,
RFKILL_TYPE_FM, RFKILL_TYPE_FM,
RFKILL_TYPE_NFC,
NUM_RFKILL_TYPES, NUM_RFKILL_TYPES,
}; };
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rfkill.h>
#include <linux/nfc.h> #include <linux/nfc.h>
#include <net/genetlink.h> #include <net/genetlink.h>
...@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev) ...@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
device_lock(&dev->dev); device_lock(&dev->dev);
if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
rc = -ERFKILL;
goto error;
}
if (!device_is_registered(&dev->dev)) { if (!device_is_registered(&dev->dev)) {
rc = -ENODEV; rc = -ENODEV;
goto error; goto error;
...@@ -117,6 +123,24 @@ int nfc_dev_down(struct nfc_dev *dev) ...@@ -117,6 +123,24 @@ int nfc_dev_down(struct nfc_dev *dev)
return rc; return rc;
} }
static int nfc_rfkill_set_block(void *data, bool blocked)
{
struct nfc_dev *dev = data;
pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
if (!blocked)
return 0;
nfc_dev_down(dev);
return 0;
}
static const struct rfkill_ops nfc_rfkill_ops = {
.set_block = nfc_rfkill_set_block,
};
/** /**
* nfc_start_poll - start polling for nfc targets * nfc_start_poll - start polling for nfc targets
* *
...@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols) ...@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
goto error; goto error;
} }
if (!dev->dev_up) {
rc = -ENODEV;
goto error;
}
if (dev->polling) { if (dev->polling) {
rc = -EBUSY; rc = -EBUSY;
goto error; goto error;
...@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev) ...@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
pr_debug("The userspace won't be notified that the device %s was added\n", pr_debug("The userspace won't be notified that the device %s was added\n",
dev_name(&dev->dev)); dev_name(&dev->dev));
dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
if (dev->rfkill) {
if (rfkill_register(dev->rfkill) < 0) {
rfkill_destroy(dev->rfkill);
dev->rfkill = NULL;
}
}
return 0; return 0;
} }
EXPORT_SYMBOL(nfc_register_device); EXPORT_SYMBOL(nfc_register_device);
...@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev) ...@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
id = dev->idx; id = dev->idx;
if (dev->rfkill) {
rfkill_unregister(dev->rfkill);
rfkill_destroy(dev->rfkill);
}
if (dev->ops->check_presence) { if (dev->ops->check_presence) {
device_lock(&dev->dev); device_lock(&dev->dev);
dev->shutting_down = true; dev->shutting_down = true;
......
...@@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) ...@@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
} }
/* If the socket parameters are not set, use the local ones */ /* If the socket parameters are not set, use the local ones */
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
local->miux : sock->miux;
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
...@@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) ...@@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
return -ENODEV; return -ENODEV;
/* If the socket parameters are not set, use the local ones */ /* If the socket parameters are not set, use the local ones */
miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
local->miux : sock->miux;
rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
...@@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, ...@@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
struct nfc_llcp_local *local; struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len; size_t frag_len = 0, remaining_len;
u8 *msg_data, *msg_ptr; u8 *msg_data, *msg_ptr;
u16 remote_miu;
pr_debug("Send I frame len %zd\n", len); pr_debug("Send I frame len %zd\n", len);
...@@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, ...@@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len = len; remaining_len = len;
msg_ptr = msg_data; msg_ptr = msg_data;
while (remaining_len > 0) { do {
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : sock->remote_miu;
frag_len = min_t(size_t, sock->remote_miu, remaining_len); frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd", pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len); frag_len, remaining_len);
...@@ -706,6 +711,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, ...@@ -706,6 +711,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
skb_put(pdu, LLCP_SEQUENCE_SIZE); skb_put(pdu, LLCP_SEQUENCE_SIZE);
if (likely(frag_len > 0))
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
skb_queue_tail(&sock->tx_queue, pdu); skb_queue_tail(&sock->tx_queue, pdu);
...@@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, ...@@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len -= frag_len; remaining_len -= frag_len;
msg_ptr += frag_len; msg_ptr += frag_len;
} } while (remaining_len > 0);
kfree(msg_data); kfree(msg_data);
...@@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, ...@@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
struct nfc_llcp_local *local; struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len; size_t frag_len = 0, remaining_len;
u8 *msg_ptr, *msg_data; u8 *msg_ptr, *msg_data;
u16 remote_miu;
int err; int err;
pr_debug("Send UI frame len %zd\n", len); pr_debug("Send UI frame len %zd\n", len);
...@@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, ...@@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
remaining_len = len; remaining_len = len;
msg_ptr = msg_data; msg_ptr = msg_data;
while (remaining_len > 0) { do {
remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : sock->remote_miu;
frag_len = min_t(size_t, sock->remote_miu, remaining_len); frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd", pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len); frag_len, remaining_len);
...@@ -768,6 +777,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, ...@@ -768,6 +777,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
if (likely(frag_len > 0))
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
/* No need to check for the peer RW for UI frames */ /* No need to check for the peer RW for UI frames */
...@@ -775,7 +785,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, ...@@ -775,7 +785,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
remaining_len -= frag_len; remaining_len -= frag_len;
msg_ptr += frag_len; msg_ptr += frag_len;
} } while (remaining_len > 0);
kfree(msg_data); kfree(msg_data);
......
...@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d}; ...@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
static struct list_head llcp_devices; static struct list_head llcp_devices;
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk) void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
{ {
write_lock(&l->lock); write_lock(&l->lock);
...@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) ...@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
write_unlock(&l->lock); write_unlock(&l->lock);
} }
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock)
{
sock->remote_rw = LLCP_DEFAULT_RW;
sock->remote_miu = LLCP_MAX_MIU + 1;
}
static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
{ {
struct nfc_llcp_local *local = sock->local; struct nfc_llcp_local *local = sock->local;
...@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) ...@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
} }
} }
static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
int err) int err)
{ {
struct sock *sk; struct sock *sk;
...@@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, ...@@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(accept_sk); bh_unlock_sock(accept_sk);
} }
if (listen == true) {
bh_unlock_sock(sk);
continue;
}
}
/*
* If we have a connection less socket bound, we keep it alive
* if the device is still present.
*/
if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
listen == true) {
bh_unlock_sock(sk);
continue;
} }
if (err) if (err)
...@@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, ...@@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
write_unlock(&local->sockets.lock); write_unlock(&local->sockets.lock);
/* /* If we still have a device, we keep the RAW sockets alive */
* If we want to keep the listening sockets alive, if (device == true)
* we don't touch the RAW ones.
*/
if (listen == true)
return; return;
write_lock(&local->raw_sockets.lock); write_lock(&local->raw_sockets.lock);
...@@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) ...@@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
return local; return local;
} }
static void local_cleanup(struct nfc_llcp_local *local, bool listen) static void local_cleanup(struct nfc_llcp_local *local)
{ {
nfc_llcp_socket_release(local, listen, ENXIO); nfc_llcp_socket_release(local, false, ENXIO);
del_timer_sync(&local->link_timer); del_timer_sync(&local->link_timer);
skb_queue_purge(&local->tx_queue); skb_queue_purge(&local->tx_queue);
cancel_work_sync(&local->tx_work); cancel_work_sync(&local->tx_work);
...@@ -194,7 +184,7 @@ static void local_release(struct kref *ref) ...@@ -194,7 +184,7 @@ static void local_release(struct kref *ref)
local = container_of(ref, struct nfc_llcp_local, ref); local = container_of(ref, struct nfc_llcp_local, ref);
list_del(&local->list); list_del(&local->list);
local_cleanup(local, false); local_cleanup(local);
kfree(local); kfree(local);
} }
...@@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, ...@@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
dsap = nfc_llcp_dsap(skb); dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb); ssap = nfc_llcp_ssap(skb);
if ((dsap == 0) && (ssap == 0)) {
pr_debug("Connection termination");
nfc_dep_link_down(local->dev);
return;
}
llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
if (llcp_sock == NULL) { if (llcp_sock == NULL) {
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN); nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
...@@ -1349,19 +1345,54 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, ...@@ -1349,19 +1345,54 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
} }
static void nfc_llcp_rx_work(struct work_struct *work) static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
{ {
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, u8 ptype;
rx_work); u16 pdu_len;
u8 dsap, ssap, ptype; struct sk_buff *new_skb;
struct sk_buff *skb;
skb = local->rx_pending; if (skb->len <= LLCP_HEADER_SIZE) {
if (skb == NULL) { pr_err("Malformed AGF PDU\n");
pr_debug("No pending SKB\n"); return;
}
skb_pull(skb, LLCP_HEADER_SIZE);
while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
pdu_len = skb->data[0] << 8 | skb->data[1];
skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
pr_err("Malformed AGF PDU\n");
return; return;
} }
ptype = nfc_llcp_ptype(skb);
if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
goto next;
new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
if (new_skb == NULL) {
pr_err("Could not allocate PDU\n");
return;
}
memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
nfc_llcp_rx_skb(local, new_skb);
kfree_skb(new_skb);
next:
skb_pull(skb, pdu_len);
}
}
static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
{
u8 dsap, ssap, ptype;
ptype = nfc_llcp_ptype(skb); ptype = nfc_llcp_ptype(skb);
dsap = nfc_llcp_dsap(skb); dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb); ssap = nfc_llcp_ssap(skb);
...@@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work) ...@@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, true); 16, 1, skb->data, skb->len, true);
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
switch (ptype) { switch (ptype) {
case LLCP_PDU_SYMM: case LLCP_PDU_SYMM:
pr_debug("SYMM\n"); pr_debug("SYMM\n");
...@@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work) ...@@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work)
nfc_llcp_recv_hdlc(local, skb); nfc_llcp_recv_hdlc(local, skb);
break; break;
case LLCP_PDU_AGF:
pr_debug("AGF frame\n");
nfc_llcp_recv_agf(local, skb);
break;
} }
}
static void nfc_llcp_rx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
rx_work);
struct sk_buff *skb;
skb = local->rx_pending;
if (skb == NULL) {
pr_debug("No pending SKB\n");
return;
}
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
nfc_llcp_rx_skb(local, skb);
schedule_work(&local->tx_work); schedule_work(&local->tx_work);
kfree_skb(local->rx_pending); kfree_skb(local->rx_pending);
...@@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) ...@@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
if (local == NULL) if (local == NULL)
return; return;
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
/* Close and purge all existing sockets */ /* Close and purge all existing sockets */
nfc_llcp_socket_release(local, true, 0); nfc_llcp_socket_release(local, true, 0);
} }
...@@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) ...@@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
return; return;
} }
local_cleanup(local, false); local_cleanup(local);
nfc_llcp_local_put(local); nfc_llcp_local_put(local);
} }
......
...@@ -31,6 +31,7 @@ enum llcp_state { ...@@ -31,6 +31,7 @@ enum llcp_state {
#define LLCP_MAX_LTO 0xff #define LLCP_MAX_LTO 0xff
#define LLCP_MAX_RW 15 #define LLCP_MAX_RW 15
#define LLCP_MAX_MIUX 0x7ff #define LLCP_MAX_MIUX 0x7ff
#define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128)
#define LLCP_WKS_NUM_SAP 16 #define LLCP_WKS_NUM_SAP 16
#define LLCP_SDP_NUM_SAP 16 #define LLCP_SDP_NUM_SAP 16
...@@ -124,7 +125,7 @@ struct nfc_llcp_sock { ...@@ -124,7 +125,7 @@ struct nfc_llcp_sock {
char *service_name; char *service_name;
size_t service_name_len; size_t service_name_len;
u8 rw; u8 rw;
u16 miux; __be16 miux;
/* Remote link parameters */ /* Remote link parameters */
...@@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb { ...@@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb {
#define LLCP_HEADER_SIZE 2 #define LLCP_HEADER_SIZE 2
#define LLCP_SEQUENCE_SIZE 1 #define LLCP_SEQUENCE_SIZE 1
#define LLCP_AGF_PDU_HEADER_SIZE 2
/* LLCP versions: 1.1 is 1.0 plus SDP */ /* LLCP versions: 1.1 is 1.0 plus SDP */
#define LLCP_VERSION_10 0x10 #define LLCP_VERSION_10 0x10
...@@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb { ...@@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb {
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s); void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s); void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local); struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
int nfc_llcp_local_put(struct nfc_llcp_local *local); int nfc_llcp_local_put(struct nfc_llcp_local *local);
......
...@@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, ...@@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
break; break;
} }
llcp_sock->miux = (u16) opt; llcp_sock->miux = cpu_to_be16((u16) opt);
break; break;
...@@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, ...@@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
struct nfc_llcp_local *local;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
int len, err = 0; int len, err = 0;
u16 miux, remote_miu;
u8 rw;
pr_debug("%p optname %d\n", sk, optname); pr_debug("%p optname %d\n", sk, optname);
...@@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, ...@@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; return -EFAULT;
local = llcp_sock->local;
if (!local)
return -ENODEV;
len = min_t(u32, len, sizeof(u32)); len = min_t(u32, len, sizeof(u32));
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
case NFC_LLCP_RW: case NFC_LLCP_RW:
if (put_user(llcp_sock->rw, (u32 __user *) optval)) rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
if (put_user(rw, (u32 __user *) optval))
err = -EFAULT; err = -EFAULT;
break; break;
case NFC_LLCP_MIUX: case NFC_LLCP_MIUX:
if (put_user(llcp_sock->miux, (u32 __user *) optval)) miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
if (put_user(miux, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_MIU:
remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
local->remote_miu : llcp_sock->remote_miu;
if (put_user(remote_miu, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_LTO:
if (put_user(local->remote_lto / 10, (u32 __user *) optval))
err = -EFAULT;
break;
case NFC_LLCP_REMOTE_RW:
if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
err = -EFAULT; err = -EFAULT;
break; break;
...@@ -921,13 +953,12 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) ...@@ -921,13 +953,12 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
llcp_sock->ssap = 0; llcp_sock->ssap = 0;
llcp_sock->dsap = LLCP_SAP_SDP; llcp_sock->dsap = LLCP_SAP_SDP;
llcp_sock->rw = LLCP_MAX_RW + 1; llcp_sock->rw = LLCP_MAX_RW + 1;
llcp_sock->miux = LLCP_MAX_MIUX + 1; llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
llcp_sock->remote_rw = LLCP_DEFAULT_RW;
llcp_sock->remote_miu = LLCP_DEFAULT_MIU;
llcp_sock->send_n = llcp_sock->send_ack_n = 0; llcp_sock->send_n = llcp_sock->send_ack_n = 0;
llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
llcp_sock->remote_ready = 1; llcp_sock->remote_ready = 1;
llcp_sock->reserved_ssap = LLCP_SAP_MAX; llcp_sock->reserved_ssap = LLCP_SAP_MAX;
nfc_llcp_socket_remote_param_init(llcp_sock);
skb_queue_head_init(&llcp_sock->tx_queue); skb_queue_head_init(&llcp_sock->tx_queue);
skb_queue_head_init(&llcp_sock->tx_pending_queue); skb_queue_head_init(&llcp_sock->tx_pending_queue);
INIT_LIST_HEAD(&llcp_sock->accept_queue); INIT_LIST_HEAD(&llcp_sock->accept_queue);
......
...@@ -587,7 +587,7 @@ static ssize_t rfkill_name_show(struct device *dev, ...@@ -587,7 +587,7 @@ static ssize_t rfkill_name_show(struct device *dev,
static const char *rfkill_get_type_str(enum rfkill_type type) static const char *rfkill_get_type_str(enum rfkill_type type)
{ {
BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1); BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
switch (type) { switch (type) {
case RFKILL_TYPE_WLAN: case RFKILL_TYPE_WLAN:
...@@ -604,6 +604,8 @@ static const char *rfkill_get_type_str(enum rfkill_type type) ...@@ -604,6 +604,8 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
return "gps"; return "gps";
case RFKILL_TYPE_FM: case RFKILL_TYPE_FM:
return "fm"; return "fm";
case RFKILL_TYPE_NFC:
return "nfc";
default: default:
BUG(); BUG();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment