提交 82740b9a 编写于 作者: D David S. Miller

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

Samuel Ortiz says:

====================
NFC: 4.1 pull request

This is the NFC pull request for 4.1.

This is a shorter one than usual, as the Intel Field Peak NFC
driver could not make it in time.

We have:

- A new driver for NXP NCI based chipsets, like e.g. the NPC100 or
  the PN7150. It currently only supports an i2c physical layer, but
  could easily be extended to work on top of e.g. SPI.
  This driver also includes support for user space triggered firmware
  updates.

- A few minor st21nfc[ab] fixes, cleanups, and comments improvements.

- A pn533 error return fix.

- A few NFC related logs formatting cleanups.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
* NXP Semiconductors NXP NCI NFC Controllers
Required properties:
- compatible: Should be "nxp,nxp-nci-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- enable-gpios: Output GPIO pin used for enabling/disabling the chip
- firmware-gpios: Output GPIO pin used to enter firmware download mode
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2):
&i2c2 {
status = "okay";
npc100: npc100@29 {
compatible = "nxp,nxp-nci-i2c";
reg = <0x29>;
clock-frequency = <100000>;
interrupt-parent = <&gpio1>;
interrupts = <29 GPIO_ACTIVE_HIGH>;
enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>;
};
};
......@@ -6944,6 +6944,13 @@ S: Supported
F: drivers/block/nvme*
F: include/linux/nvme.h
NXP-NCI NFC DRIVER
M: Clément Perrochaud <clement.perrochaud@effinnov.com>
R: Charles Gorand <charles.gorand@effinnov.com>
L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Supported
F: drivers/nfc/nxp-nci
NXP TDA998X DRM DRIVER
M: Russell King <rmk+kernel@arm.linux.org.uk>
S: Supported
......
......@@ -73,4 +73,5 @@ source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
source "drivers/nfc/st21nfcb/Kconfig"
source "drivers/nfc/nxp-nci/Kconfig"
endmenu
......@@ -13,5 +13,6 @@ obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
......@@ -286,7 +286,7 @@ static int microread_i2c_probe(struct i2c_client *client,
if (r < 0)
goto err_irq;
nfc_info(&client->dev, "Probed");
nfc_info(&client->dev, "Probed\n");
return 0;
......
......@@ -111,7 +111,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
if (!priv->ndev) {
nfc_err(dev, "nci_allocate_device failed");
nfc_err(dev, "nci_allocate_device failed\n");
rc = -ENOMEM;
goto error;
}
......@@ -120,7 +120,7 @@ struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
rc = nci_register_device(priv->ndev);
if (rc) {
nfc_err(dev, "nci_register_device failed %d", rc);
nfc_err(dev, "nci_register_device failed %d\n", rc);
nci_free_device(priv->ndev);
goto error;
}
......
......@@ -80,7 +80,7 @@ static void nfcmrvl_bulk_complete(struct urb *urb)
if (!urb->status) {
if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
urb->actual_length) < 0)
nfc_err(&drv_data->udev->dev, "corrupted Rx packet");
nfc_err(&drv_data->udev->dev, "corrupted Rx packet\n");
}
if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
......@@ -96,7 +96,7 @@ static void nfcmrvl_bulk_complete(struct urb *urb)
*/
if (err != -EPERM && err != -ENODEV)
nfc_err(&drv_data->udev->dev,
"urb %p failed to resubmit (%d)", urb, -err);
"urb %p failed to resubmit (%d)\n", urb, -err);
usb_unanchor_urb(urb);
}
}
......@@ -137,7 +137,7 @@ nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
if (err) {
if (err != -EPERM && err != -ENODEV)
nfc_err(&drv_data->udev->dev,
"urb %p submission failed (%d)", urb, -err);
"urb %p submission failed (%d)\n", urb, -err);
usb_unanchor_urb(urb);
}
......@@ -153,7 +153,7 @@ static void nfcmrvl_tx_complete(struct urb *urb)
struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
nfc_info(priv->dev, "urb %p status %d count %d",
nfc_info(priv->dev, "urb %p status %d count %d\n",
urb, urb->status, urb->actual_length);
spin_lock(&drv_data->txlock);
......@@ -253,7 +253,7 @@ static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
if (err) {
if (err != -EPERM && err != -ENODEV)
nfc_err(&drv_data->udev->dev,
"urb %p submission failed (%d)", urb, -err);
"urb %p submission failed (%d)\n", urb, -err);
kfree(urb->setup_packet);
usb_unanchor_urb(urb);
} else {
......@@ -293,7 +293,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
int i;
struct usb_device *udev = interface_to_usbdev(intf);
nfc_info(&udev->dev, "intf %p id %p", intf, id);
nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
......@@ -348,7 +348,7 @@ static void nfcmrvl_disconnect(struct usb_interface *intf)
if (!drv_data)
return;
nfc_info(&drv_data->udev->dev, "intf %p", intf);
nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
nfcmrvl_nci_unregister_dev(drv_data->priv);
......@@ -360,7 +360,7 @@ static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
{
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
nfc_info(&drv_data->udev->dev, "intf %p", intf);
nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
if (drv_data->suspend_count++)
return 0;
......@@ -401,7 +401,7 @@ static int nfcmrvl_resume(struct usb_interface *intf)
struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
int err = 0;
nfc_info(&drv_data->udev->dev, "intf %p", intf);
nfc_info(&drv_data->udev->dev, "intf %p\n", intf);
if (--drv_data->suspend_count)
return 0;
......
config NFC_NXP_NCI
tristate "NXP-NCI NFC driver"
depends on NFC_NCI
default n
---help---
Generic core driver for NXP NCI chips such as the NPC100
or PN7150 families.
This is a driver based on the NCI NFC kernel layers and
will thus not work with NXP libnfc library.
To compile this driver as a module, choose m here. The module will
be called nxp_nci.
Say N if unsure.
config NFC_NXP_NCI_I2C
tristate "NXP-NCI I2C support"
depends on NFC_NXP_NCI && I2C
---help---
This module adds support for an I2C interface to the NXP NCI
chips.
Select this if your platform is using the I2C bus.
To compile this driver as a module, choose m here. The module will
be called nxp_nci_i2c.
Say Y if unsure.
#
# Makefile for NXP-NCI NFC driver
#
nxp-nci-objs = core.o firmware.o
nxp-nci_i2c-objs = i2c.o
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o
obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
/*
* Generic driver for NXP NCI NFC chips
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/nfc.h>
#include <linux/platform_data/nxp-nci.h>
#include <net/nfc/nci_core.h>
#include "nxp-nci.h"
#define NXP_NCI_HDR_LEN 4
#define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
NFC_PROTO_MIFARE_MASK | \
NFC_PROTO_FELICA_MASK | \
NFC_PROTO_ISO14443_MASK | \
NFC_PROTO_ISO14443_B_MASK | \
NFC_PROTO_NFC_DEP_MASK)
static int nxp_nci_open(struct nci_dev *ndev)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
int r = 0;
mutex_lock(&info->info_lock);
if (info->mode != NXP_NCI_MODE_COLD) {
r = -EBUSY;
goto open_exit;
}
if (info->phy_ops->set_mode)
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI);
info->mode = NXP_NCI_MODE_NCI;
open_exit:
mutex_unlock(&info->info_lock);
return r;
}
static int nxp_nci_close(struct nci_dev *ndev)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
int r = 0;
mutex_lock(&info->info_lock);
if (info->phy_ops->set_mode)
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
info->mode = NXP_NCI_MODE_COLD;
mutex_unlock(&info->info_lock);
return r;
}
static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
int r;
if (!info->phy_ops->write) {
r = -ENOTSUPP;
goto send_exit;
}
if (info->mode != NXP_NCI_MODE_NCI) {
r = -EINVAL;
goto send_exit;
}
r = info->phy_ops->write(info->phy_id, skb);
if (r < 0)
kfree_skb(skb);
send_exit:
return r;
}
static struct nci_ops nxp_nci_ops = {
.open = nxp_nci_open,
.close = nxp_nci_close,
.send = nxp_nci_send,
.fw_download = nxp_nci_fw_download,
};
int nxp_nci_probe(void *phy_id, struct device *pdev,
struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload,
struct nci_dev **ndev)
{
struct nxp_nci_info *info;
int r;
info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
if (!info) {
r = -ENOMEM;
goto probe_exit;
}
info->phy_id = phy_id;
info->pdev = pdev;
info->phy_ops = phy_ops;
info->max_payload = max_payload;
INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
init_completion(&info->fw_info.cmd_completion);
mutex_init(&info->info_lock);
if (info->phy_ops->set_mode) {
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
if (r < 0)
goto probe_exit;
}
info->mode = NXP_NCI_MODE_COLD;
info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
NXP_NCI_HDR_LEN, 0);
if (!info->ndev) {
r = -ENOMEM;
goto probe_exit;
}
nci_set_parent_dev(info->ndev, pdev);
nci_set_drvdata(info->ndev, info);
r = nci_register_device(info->ndev);
if (r < 0)
goto probe_exit_free_nci;
*ndev = info->ndev;
goto probe_exit;
probe_exit_free_nci:
nci_free_device(info->ndev);
probe_exit:
return r;
}
EXPORT_SYMBOL(nxp_nci_probe);
void nxp_nci_remove(struct nci_dev *ndev)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
if (info->mode == NXP_NCI_MODE_FW)
nxp_nci_fw_work_complete(info, -ESHUTDOWN);
cancel_work_sync(&info->fw_info.work);
mutex_lock(&info->info_lock);
if (info->phy_ops->set_mode)
info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
nci_unregister_device(ndev);
nci_free_device(ndev);
mutex_unlock(&info->info_lock);
}
EXPORT_SYMBOL(nxp_nci_remove);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("NXP NCI NFC driver");
MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
/*
* Generic driver for NXP NCI NFC chips
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
*
* Author: Clément Perrochaud <clement.perrochaud@nxp.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/completion.h>
#include <linux/firmware.h>
#include <linux/nfc.h>
#include <linux/unaligned/access_ok.h>
#include "nxp-nci.h"
/* Crypto operations can take up to 30 seconds */
#define NXP_NCI_FW_ANSWER_TIMEOUT msecs_to_jiffies(30000)
#define NXP_NCI_FW_CMD_RESET 0xF0
#define NXP_NCI_FW_CMD_GETVERSION 0xF1
#define NXP_NCI_FW_CMD_CHECKINTEGRITY 0xE0
#define NXP_NCI_FW_CMD_WRITE 0xC0
#define NXP_NCI_FW_CMD_READ 0xA2
#define NXP_NCI_FW_CMD_GETSESSIONSTATE 0xF2
#define NXP_NCI_FW_CMD_LOG 0xA7
#define NXP_NCI_FW_CMD_FORCE 0xD0
#define NXP_NCI_FW_CMD_GET_DIE_ID 0xF4
#define NXP_NCI_FW_CHUNK_FLAG 0x0400
#define NXP_NCI_FW_RESULT_OK 0x00
#define NXP_NCI_FW_RESULT_INVALID_ADDR 0x01
#define NXP_NCI_FW_RESULT_GENERIC_ERROR 0x02
#define NXP_NCI_FW_RESULT_UNKNOWN_CMD 0x0B
#define NXP_NCI_FW_RESULT_ABORTED_CMD 0x0C
#define NXP_NCI_FW_RESULT_PLL_ERROR 0x0D
#define NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR 0x1E
#define NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR 0x1F
#define NXP_NCI_FW_RESULT_MEM_BSY 0x20
#define NXP_NCI_FW_RESULT_SIGNATURE_ERROR 0x21
#define NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR 0x24
#define NXP_NCI_FW_RESULT_PROTOCOL_ERROR 0x28
#define NXP_NCI_FW_RESULT_SFWU_DEGRADED 0x2A
#define NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK 0x2D
#define NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK 0x2E
#define NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5 0xC5
void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result)
{
struct nxp_nci_fw_info *fw_info = &info->fw_info;
int r;
if (info->phy_ops->set_mode) {
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
if (r < 0 && result == 0)
result = -r;
}
info->mode = NXP_NCI_MODE_COLD;
if (fw_info->fw) {
release_firmware(fw_info->fw);
fw_info->fw = NULL;
}
nfc_fw_download_done(info->ndev->nfc_dev, fw_info->name, (u32) -result);
}
/* crc_ccitt cannot be used since it is computed MSB first and not LSB first */
static u16 nxp_nci_fw_crc(u8 const *buffer, size_t len)
{
u16 crc = 0xffff;
while (len--) {
crc = ((crc >> 8) | (crc << 8)) ^ *buffer++;
crc ^= (crc & 0xff) >> 4;
crc ^= (crc & 0xff) << 12;
crc ^= (crc & 0xff) << 5;
}
return crc;
}
static int nxp_nci_fw_send_chunk(struct nxp_nci_info *info)
{
struct nxp_nci_fw_info *fw_info = &info->fw_info;
u16 header, crc;
struct sk_buff *skb;
size_t chunk_len;
size_t remaining_len;
int r;
skb = nci_skb_alloc(info->ndev, info->max_payload, GFP_KERNEL);
if (!skb) {
r = -ENOMEM;
goto chunk_exit;
}
chunk_len = info->max_payload - NXP_NCI_FW_HDR_LEN - NXP_NCI_FW_CRC_LEN;
remaining_len = fw_info->frame_size - fw_info->written;
if (remaining_len > chunk_len) {
header = NXP_NCI_FW_CHUNK_FLAG;
} else {
chunk_len = remaining_len;
header = 0x0000;
}
header |= chunk_len & NXP_NCI_FW_FRAME_LEN_MASK;
put_unaligned_be16(header, skb_put(skb, NXP_NCI_FW_HDR_LEN));
memcpy(skb_put(skb, chunk_len), fw_info->data + fw_info->written,
chunk_len);
crc = nxp_nci_fw_crc(skb->data, chunk_len + NXP_NCI_FW_HDR_LEN);
put_unaligned_be16(crc, skb_put(skb, NXP_NCI_FW_CRC_LEN));
r = info->phy_ops->write(info->phy_id, skb);
if (r >= 0)
r = chunk_len;
kfree_skb(skb);
chunk_exit:
return r;
}
static int nxp_nci_fw_send(struct nxp_nci_info *info)
{
struct nxp_nci_fw_info *fw_info = &info->fw_info;
long completion_rc;
int r;
reinit_completion(&fw_info->cmd_completion);
if (fw_info->written == 0) {
fw_info->frame_size = get_unaligned_be16(fw_info->data) &
NXP_NCI_FW_FRAME_LEN_MASK;
fw_info->data += NXP_NCI_FW_HDR_LEN;
fw_info->size -= NXP_NCI_FW_HDR_LEN;
}
if (fw_info->frame_size > fw_info->size)
return -EMSGSIZE;
r = nxp_nci_fw_send_chunk(info);
if (r < 0)
return r;
fw_info->written += r;
if (*fw_info->data == NXP_NCI_FW_CMD_RESET) {
fw_info->cmd_result = 0;
if (fw_info->fw)
schedule_work(&fw_info->work);
} else {
completion_rc = wait_for_completion_interruptible_timeout(
&fw_info->cmd_completion, NXP_NCI_FW_ANSWER_TIMEOUT);
if (completion_rc == 0)
return -ETIMEDOUT;
}
return 0;
}
void nxp_nci_fw_work(struct work_struct *work)
{
struct nxp_nci_info *info;
struct nxp_nci_fw_info *fw_info;
int r;
fw_info = container_of(work, struct nxp_nci_fw_info, work);
info = container_of(fw_info, struct nxp_nci_info, fw_info);
mutex_lock(&info->info_lock);
r = fw_info->cmd_result;
if (r < 0)
goto exit_work;
if (fw_info->written == fw_info->frame_size) {
fw_info->data += fw_info->frame_size;
fw_info->size -= fw_info->frame_size;
fw_info->written = 0;
}
if (fw_info->size > 0)
r = nxp_nci_fw_send(info);
exit_work:
if (r < 0 || fw_info->size == 0)
nxp_nci_fw_work_complete(info, r);
mutex_unlock(&info->info_lock);
}
int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
struct nxp_nci_fw_info *fw_info = &info->fw_info;
int r;
mutex_lock(&info->info_lock);
if (!info->phy_ops->set_mode || !info->phy_ops->write) {
r = -ENOTSUPP;
goto fw_download_exit;
}
if (!firmware_name || firmware_name[0] == '\0') {
r = -EINVAL;
goto fw_download_exit;
}
strcpy(fw_info->name, firmware_name);
r = request_firmware(&fw_info->fw, firmware_name,
ndev->nfc_dev->dev.parent);
if (r < 0)
goto fw_download_exit;
r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_FW);
if (r < 0) {
release_firmware(fw_info->fw);
goto fw_download_exit;
}
info->mode = NXP_NCI_MODE_FW;
fw_info->data = fw_info->fw->data;
fw_info->size = fw_info->fw->size;
fw_info->written = 0;
fw_info->frame_size = 0;
fw_info->cmd_result = 0;
schedule_work(&fw_info->work);
fw_download_exit:
mutex_unlock(&info->info_lock);
return r;
}
static int nxp_nci_fw_read_status(u8 stat)
{
switch (stat) {
case NXP_NCI_FW_RESULT_OK:
return 0;
case NXP_NCI_FW_RESULT_INVALID_ADDR:
return -EINVAL;
case NXP_NCI_FW_RESULT_UNKNOWN_CMD:
return -EINVAL;
case NXP_NCI_FW_RESULT_ABORTED_CMD:
return -EMSGSIZE;
case NXP_NCI_FW_RESULT_ADDR_RANGE_OFL_ERROR:
return -EADDRNOTAVAIL;
case NXP_NCI_FW_RESULT_BUFFER_OFL_ERROR:
return -ENOBUFS;
case NXP_NCI_FW_RESULT_MEM_BSY:
return -ENOKEY;
case NXP_NCI_FW_RESULT_SIGNATURE_ERROR:
return -EKEYREJECTED;
case NXP_NCI_FW_RESULT_FIRMWARE_VERSION_ERROR:
return -EALREADY;
case NXP_NCI_FW_RESULT_PROTOCOL_ERROR:
return -EPROTO;
case NXP_NCI_FW_RESULT_SFWU_DEGRADED:
return -EHWPOISON;
case NXP_NCI_FW_RESULT_PH_STATUS_FIRST_CHUNK:
return 0;
case NXP_NCI_FW_RESULT_PH_STATUS_NEXT_CHUNK:
return 0;
case NXP_NCI_FW_RESULT_PH_STATUS_INTERNAL_ERROR_5:
return -EINVAL;
default:
return -EIO;
}
}
static u16 nxp_nci_fw_check_crc(struct sk_buff *skb)
{
u16 crc, frame_crc;
size_t len = skb->len - NXP_NCI_FW_CRC_LEN;
crc = nxp_nci_fw_crc(skb->data, len);
frame_crc = get_unaligned_be16(skb->data + len);
return (crc ^ frame_crc);
}
void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
{
struct nxp_nci_info *info = nci_get_drvdata(ndev);
struct nxp_nci_fw_info *fw_info = &info->fw_info;
complete(&fw_info->cmd_completion);
if (skb) {
if (nxp_nci_fw_check_crc(skb) != 0x00)
fw_info->cmd_result = -EBADMSG;
else
fw_info->cmd_result = nxp_nci_fw_read_status(
*skb_pull(skb, NXP_NCI_FW_HDR_LEN));
kfree_skb(skb);
} else {
fw_info->cmd_result = -EIO;
}
if (fw_info->fw)
schedule_work(&fw_info->work);
}
EXPORT_SYMBOL(nxp_nci_fw_recv_frame);
/*
* I2C link layer for the NXP NCI driver
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/nfc.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/platform_data/nxp-nci.h>
#include <linux/unaligned/access_ok.h>
#include <net/nfc/nfc.h>
#include "nxp-nci.h"
#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c"
#define NXP_NCI_I2C_MAX_PAYLOAD 32
struct nxp_nci_i2c_phy {
struct i2c_client *i2c_dev;
struct nci_dev *ndev;
unsigned int gpio_en;
unsigned int gpio_fw;
int hard_fault; /*
* < 0 if hardware error occurred (e.g. i2c err)
* and prevents normal operation.
*/
};
static int nxp_nci_i2c_set_mode(void *phy_id,
enum nxp_nci_mode mode)
{
struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id;
gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0);
gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0);
usleep_range(10000, 15000);
if (mode == NXP_NCI_MODE_COLD)
phy->hard_fault = 0;
return 0;
}
static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
{
int r;
struct nxp_nci_i2c_phy *phy = phy_id;
struct i2c_client *client = phy->i2c_dev;
if (phy->hard_fault != 0)
return phy->hard_fault;
r = i2c_master_send(client, skb->data, skb->len);
if (r == -EREMOTEIO) {
/* Retry, chip was in standby */
usleep_range(110000, 120000);
r = i2c_master_send(client, skb->data, skb->len);
}
if (r < 0) {
nfc_err(&client->dev, "Error %d on I2C send\n", r);
} else if (r != skb->len) {
nfc_err(&client->dev,
"Invalid length sent: %u (expected %u)\n",
r, skb->len);
r = -EREMOTEIO;
} else {
/* Success but return 0 and not number of bytes */
r = 0;
}
return r;
}
static struct nxp_nci_phy_ops i2c_phy_ops = {
.set_mode = nxp_nci_i2c_set_mode,
.write = nxp_nci_i2c_write,
};
static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy,
struct sk_buff **skb)
{
struct i2c_client *client = phy->i2c_dev;
u16 header;
size_t frame_len;
int r;
r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN);
if (r < 0) {
goto fw_read_exit;
} else if (r != NXP_NCI_FW_HDR_LEN) {
nfc_err(&client->dev, "Incorrect header length: %u\n", r);
r = -EBADMSG;
goto fw_read_exit;
}
frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) +
NXP_NCI_FW_CRC_LEN;
*skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL);
if (*skb == NULL) {
r = -ENOMEM;
goto fw_read_exit;
}
memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN);
r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len);
if (r != frame_len) {
nfc_err(&client->dev,
"Invalid frame length: %u (expected %zu)\n",
r, frame_len);
r = -EBADMSG;
goto fw_read_exit_free_skb;
}
return 0;
fw_read_exit_free_skb:
kfree_skb(*skb);
fw_read_exit:
return r;
}
static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy,
struct sk_buff **skb)
{
struct nci_ctrl_hdr header; /* May actually be a data header */
struct i2c_client *client = phy->i2c_dev;
int r;
r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE);
if (r < 0) {
goto nci_read_exit;
} else if (r != NCI_CTRL_HDR_SIZE) {
nfc_err(&client->dev, "Incorrect header length: %u\n", r);
r = -EBADMSG;
goto nci_read_exit;
}
*skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL);
if (*skb == NULL) {
r = -ENOMEM;
goto nci_read_exit;
}
memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header,
NCI_CTRL_HDR_SIZE);
r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen);
if (r != header.plen) {
nfc_err(&client->dev,
"Invalid frame payload length: %u (expected %u)\n",
r, header.plen);
r = -EBADMSG;
goto nci_read_exit_free_skb;
}
return 0;
nci_read_exit_free_skb:
kfree_skb(*skb);
nci_read_exit:
return r;
}
static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id)
{
struct nxp_nci_i2c_phy *phy = phy_id;
struct i2c_client *client;
struct nxp_nci_info *info;
struct sk_buff *skb = NULL;
int r = 0;
if (!phy || !phy->ndev)
goto exit_irq_none;
client = phy->i2c_dev;
if (!client || irq != client->irq)
goto exit_irq_none;
info = nci_get_drvdata(phy->ndev);
if (!info)
goto exit_irq_none;
mutex_lock(&info->info_lock);
if (phy->hard_fault != 0)
goto exit_irq_handled;
switch (info->mode) {
case NXP_NCI_MODE_NCI:
r = nxp_nci_i2c_nci_read(phy, &skb);
break;
case NXP_NCI_MODE_FW:
r = nxp_nci_i2c_fw_read(phy, &skb);
break;
case NXP_NCI_MODE_COLD:
r = -EREMOTEIO;
break;
}
if (r == -EREMOTEIO) {
phy->hard_fault = r;
skb = NULL;
} else if (r < 0) {
nfc_err(&client->dev, "Read failed with error %d\n", r);
goto exit_irq_handled;
}
switch (info->mode) {
case NXP_NCI_MODE_NCI:
nci_recv_frame(phy->ndev, skb);
break;
case NXP_NCI_MODE_FW:
nxp_nci_fw_recv_frame(phy->ndev, skb);
break;
case NXP_NCI_MODE_COLD:
break;
}
exit_irq_handled:
mutex_unlock(&info->info_lock);
return IRQ_HANDLED;
exit_irq_none:
WARN_ON_ONCE(1);
return IRQ_NONE;
}
#ifdef CONFIG_OF
static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
{
struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
struct device_node *pp;
int r;
pp = client->dev.of_node;
if (!pp)
return -ENODEV;
r = of_get_named_gpio(pp, "enable-gpios", 0);
if (r == -EPROBE_DEFER)
r = of_get_named_gpio(pp, "enable-gpios", 0);
if (r < 0) {
nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r);
return r;
}
phy->gpio_en = r;
r = of_get_named_gpio(pp, "firmware-gpios", 0);
if (r == -EPROBE_DEFER)
r = of_get_named_gpio(pp, "firmware-gpios", 0);
if (r < 0) {
nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r);
return r;
}
phy->gpio_fw = r;
r = irq_of_parse_and_map(pp, 0);
if (r < 0) {
nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
return r;
}
client->irq = r;
return 0;
}
#else
static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
{
return -ENODEV;
}
#endif
static int nxp_nci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct nxp_nci_i2c_phy *phy;
struct nxp_nci_nfc_platform_data *pdata;
int r;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
r = -ENODEV;
goto probe_exit;
}
phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy),
GFP_KERNEL);
if (!phy) {
r = -ENOMEM;
goto probe_exit;
}
phy->i2c_dev = client;
i2c_set_clientdata(client, phy);
pdata = client->dev.platform_data;
if (!pdata && client->dev.of_node) {
r = nxp_nci_i2c_parse_devtree(client);
if (r < 0) {
nfc_err(&client->dev, "Failed to get DT data\n");
goto probe_exit;
}
} else if (pdata) {
phy->gpio_en = pdata->gpio_en;
phy->gpio_fw = pdata->gpio_fw;
client->irq = pdata->irq;
} else {
nfc_err(&client->dev, "No platform data\n");
r = -EINVAL;
goto probe_exit;
}
r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en,
GPIOF_OUT_INIT_LOW, "nxp_nci_en");
if (r < 0)
goto probe_exit;
r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw,
GPIOF_OUT_INIT_LOW, "nxp_nci_fw");
if (r < 0)
goto probe_exit;
r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops,
NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev);
if (r < 0)
goto probe_exit;
r = request_threaded_irq(client->irq, NULL,
nxp_nci_i2c_irq_thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
NXP_NCI_I2C_DRIVER_NAME, phy);
if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n");
probe_exit:
return r;
}
static int nxp_nci_i2c_remove(struct i2c_client *client)
{
struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
nxp_nci_remove(phy->ndev);
free_irq(client->irq, phy);
return 0;
}
static struct i2c_device_id nxp_nci_i2c_id_table[] = {
{"nxp-nci_i2c", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
static const struct of_device_id of_nxp_nci_i2c_match[] = {
{ .compatible = "nxp,nxp-nci-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
static struct i2c_driver nxp_nci_i2c_driver = {
.driver = {
.name = NXP_NCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
},
.probe = nxp_nci_i2c_probe,
.id_table = nxp_nci_i2c_id_table,
.remove = nxp_nci_i2c_remove,
};
module_i2c_driver(nxp_nci_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers");
MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");
/*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
*
* Derived from PN544 device driver:
* Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LOCAL_NXP_NCI_H_
#define __LOCAL_NXP_NCI_H_
#include <linux/completion.h>
#include <linux/firmware.h>
#include <linux/nfc.h>
#include <linux/platform_data/nxp-nci.h>
#include <net/nfc/nci_core.h>
#define NXP_NCI_FW_HDR_LEN 2
#define NXP_NCI_FW_CRC_LEN 2
#define NXP_NCI_FW_FRAME_LEN_MASK 0x03FF
enum nxp_nci_mode {
NXP_NCI_MODE_COLD,
NXP_NCI_MODE_NCI,
NXP_NCI_MODE_FW
};
struct nxp_nci_phy_ops {
int (*set_mode)(void *id, enum nxp_nci_mode mode);
int (*write)(void *id, struct sk_buff *skb);
};
struct nxp_nci_fw_info {
char name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
const struct firmware *fw;
size_t size;
size_t written;
const u8 *data;
size_t frame_size;
struct work_struct work;
struct completion cmd_completion;
int cmd_result;
};
struct nxp_nci_info {
struct nci_dev *ndev;
void *phy_id;
struct device *pdev;
enum nxp_nci_mode mode;
struct nxp_nci_phy_ops *phy_ops;
unsigned int max_payload;
struct mutex info_lock;
struct nxp_nci_fw_info fw_info;
};
int nxp_nci_fw_download(struct nci_dev *ndev, const char *firmware_name);
void nxp_nci_fw_work(struct work_struct *work);
void nxp_nci_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
void nxp_nci_fw_work_complete(struct nxp_nci_info *info, int result);
int nxp_nci_probe(void *phy_id, struct device *pdev,
struct nxp_nci_phy_ops *phy_ops, unsigned int max_payload,
struct nci_dev **ndev);
void nxp_nci_remove(struct nci_dev *ndev);
#endif /* __LOCAL_NXP_NCI_H_ */
......@@ -1820,7 +1820,7 @@ static int pn533_rf_complete(struct pn533 *dev, void *arg,
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
nfc_err(&dev->interface->dev, "RF setting error %d", rc);
nfc_err(&dev->interface->dev, "RF setting error %d\n", rc);
return rc;
}
......@@ -2554,8 +2554,10 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
}
skb = pn533_build_response(dev);
if (!skb)
if (!skb) {
rc = -ENOMEM;
goto error;
}
arg->cb(arg->cb_context, skb, 0);
kfree(arg);
......
......@@ -953,7 +953,7 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
}
nfc_info(dev, "GPIO resource, no:%d irq:%d\n",
desc_to_gpio(gpiod_irq), ret);
desc_to_gpio(gpiod_irq), ret);
client->irq = ret;
return 0;
......@@ -1062,11 +1062,8 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
GFP_KERNEL);
if (!phy) {
nfc_err(&client->dev,
"Cannot allocate memory for pn544 i2c phy.\n");
if (!phy)
return -ENOMEM;
}
INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work);
phy->fw_work_state = FW_WORK_STATE_IDLE;
......
......@@ -604,11 +604,11 @@ static void port100_recv_response(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
nfc_err(&dev->interface->dev,
"The urb has been canceled (status %d)", urb->status);
"The urb has been canceled (status %d)\n", urb->status);
goto sched_wq;
case -ESHUTDOWN:
default:
nfc_err(&dev->interface->dev, "Urb failure (status %d)",
nfc_err(&dev->interface->dev, "Urb failure (status %d)\n",
urb->status);
goto sched_wq;
}
......@@ -616,7 +616,7 @@ static void port100_recv_response(struct urb *urb)
in_frame = dev->in_urb->transfer_buffer;
if (!port100_rx_frame_is_valid(in_frame)) {
nfc_err(&dev->interface->dev, "Received an invalid frame");
nfc_err(&dev->interface->dev, "Received an invalid frame\n");
cmd->status = -EIO;
goto sched_wq;
}
......@@ -626,7 +626,7 @@ static void port100_recv_response(struct urb *urb)
if (!port100_rx_frame_is_cmd_response(dev, in_frame)) {
nfc_err(&dev->interface->dev,
"It's not the response to the last command");
"It's not the response to the last command\n");
cmd->status = -EIO;
goto sched_wq;
}
......@@ -657,11 +657,11 @@ static void port100_recv_ack(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
nfc_err(&dev->interface->dev,
"The urb has been stopped (status %d)", urb->status);
"The urb has been stopped (status %d)\n", urb->status);
goto sched_wq;
case -ESHUTDOWN:
default:
nfc_err(&dev->interface->dev, "Urb failure (status %d)",
nfc_err(&dev->interface->dev, "Urb failure (status %d)\n",
urb->status);
goto sched_wq;
}
......@@ -669,7 +669,7 @@ static void port100_recv_ack(struct urb *urb)
in_frame = dev->in_urb->transfer_buffer;
if (!port100_rx_frame_is_ack(in_frame)) {
nfc_err(&dev->interface->dev, "Received an invalid ack");
nfc_err(&dev->interface->dev, "Received an invalid ack\n");
cmd->status = -EIO;
goto sched_wq;
}
......@@ -677,7 +677,7 @@ static void port100_recv_ack(struct urb *urb)
rc = port100_submit_urb_for_response(dev, GFP_ATOMIC);
if (rc) {
nfc_err(&dev->interface->dev,
"usb_submit_urb failed with result %d", rc);
"usb_submit_urb failed with result %d\n", rc);
cmd->status = rc;
goto sched_wq;
}
......@@ -873,11 +873,11 @@ static void port100_send_complete(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
nfc_err(&dev->interface->dev,
"The urb has been stopped (status %d)", urb->status);
"The urb has been stopped (status %d)\n", urb->status);
break;
case -ESHUTDOWN:
default:
nfc_err(&dev->interface->dev, "Urb failure (status %d)",
nfc_err(&dev->interface->dev, "Urb failure (status %d)\n",
urb->status);
}
}
......@@ -1094,7 +1094,7 @@ static void port100_in_comm_rf_complete(struct port100 *dev, void *arg,
if (resp->len < 4) {
nfc_err(&dev->interface->dev,
"Invalid packet length received.\n");
"Invalid packet length received\n");
rc = -EIO;
goto error;
}
......@@ -1250,7 +1250,7 @@ static bool port100_tg_target_activated(struct port100 *dev, u8 tgt_activated)
PORT100_MDAA_TGT_WAS_ACTIVATED_MASK;
break;
default:
nfc_err(&dev->interface->dev, "Unknonwn command type.\n");
nfc_err(&dev->interface->dev, "Unknown command type\n");
return false;
}
......@@ -1481,7 +1481,7 @@ static int port100_probe(struct usb_interface *interface,
cmd_type_mask = port100_get_command_type_mask(dev);
if (!cmd_type_mask) {
nfc_err(&interface->dev,
"Could not get supported command types.\n");
"Could not get supported command types\n");
rc = -ENODEV;
goto error;
}
......@@ -1494,7 +1494,7 @@ static int port100_probe(struct usb_interface *interface,
rc = port100_set_command_type(dev, dev->cmd_type);
if (rc) {
nfc_err(&interface->dev,
"The device does not support command type %u.\n",
"The device does not support command type %u\n",
dev->cmd_type);
goto error;
}
......@@ -1502,7 +1502,7 @@ static int port100_probe(struct usb_interface *interface,
fw_version = port100_get_firmware_version(dev);
if (!fw_version)
nfc_err(&interface->dev,
"Could not get device firmware version.\n");
"Could not get device firmware version\n");
nfc_info(&interface->dev,
"Sony NFC Port-100 Series attached (firmware v%x.%02x)\n",
......@@ -1515,7 +1515,7 @@ static int port100_probe(struct usb_interface *interface,
dev->skb_tailroom);
if (!dev->nfc_digital_dev) {
nfc_err(&interface->dev,
"Could not allocate nfc_digital_dev.\n");
"Could not allocate nfc_digital_dev\n");
rc = -ENOMEM;
goto error;
}
......@@ -1526,7 +1526,7 @@ static int port100_probe(struct usb_interface *interface,
rc = nfc_digital_register_device(dev->nfc_digital_dev);
if (rc) {
nfc_err(&interface->dev,
"Could not register digital device.\n");
"Could not register digital device\n");
goto free_nfc_dev;
}
......@@ -1562,7 +1562,7 @@ static void port100_disconnect(struct usb_interface *interface)
kfree(dev->cmd);
nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected");
nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected\n");
}
static struct usb_driver port100_driver = {
......
......@@ -572,7 +572,7 @@ static int st21nfca_get_iso14443_3_sak(struct nfc_hci_dev *hdev, u8 *sak)
return r;
}
static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *gate,
static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *uid,
int *len)
{
int r;
......@@ -588,7 +588,7 @@ static int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *gate,
goto exit;
}
gate = uid_skb->data;
memcpy(uid, uid_skb->data, uid_skb->len);
*len = uid_skb->len;
exit:
kfree_skb(uid_skb);
......
......@@ -310,6 +310,13 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
case ST21NFCA_EVT_CONNECTIVITY:
break;
case ST21NFCA_EVT_TRANSACTION:
/*
* According to specification etsi 102 622
* 11.2.2.4 EVT_TRANSACTION Table 52
* Description Tag Length
* AID 81 5 to 16
* PARAMETERS 82 0 to 255
*/
if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
return -EPROTO;
......@@ -318,8 +325,10 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
skb->len - 2, GFP_KERNEL);
transaction->aid_len = skb->data[1];
memcpy(transaction->aid, &skb->data[2], skb->data[1]);
memcpy(transaction->aid, &skb->data[2],
transaction->aid_len);
/* Check next byte is PARAMETERS tag (82) */
if (skb->data[transaction->aid_len + 2] !=
NFC_EVT_TRANSACTION_PARAMS_TAG)
return -EPROTO;
......
......@@ -109,7 +109,7 @@ static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
return phy->ndlc->hard_fault;
r = i2c_master_send(client, skb->data, skb->len);
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
if (r < 0) { /* Retry, chip was in standby */
usleep_range(1000, 4000);
r = i2c_master_send(client, skb->data, skb->len);
}
......@@ -148,7 +148,7 @@ static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
struct i2c_client *client = phy->i2c_dev;
r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
if (r == -EREMOTEIO) { /* Retry, chip was in standby */
if (r < 0) { /* Retry, chip was in standby */
usleep_range(1000, 4000);
r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
}
......@@ -313,11 +313,8 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy),
GFP_KERNEL);
if (!phy) {
nfc_err(&client->dev,
"Cannot allocate memory for st21nfcb i2c phy.\n");
if (!phy)
return -ENOMEM;
}
phy->i2c_dev = client;
......
......@@ -256,10 +256,9 @@ int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
struct llt_ndlc *ndlc;
ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL);
if (!ndlc) {
nfc_err(dev, "Cannot allocate memory for ndlc.\n");
if (!ndlc)
return -ENOMEM;
}
ndlc->ops = phy_ops;
ndlc->phy_id = phy_id;
ndlc->dev = dev;
......
......@@ -321,6 +321,12 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
break;
case ST21NFCB_EVT_TRANSACTION:
/* According to specification etsi 102 622
* 11.2.2.4 EVT_TRANSACTION Table 52
* Description Tag Length
* AID 81 5 to 16
* PARAMETERS 82 0 to 255
*/
if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
return -EPROTO;
......@@ -329,8 +335,9 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
skb->len - 2, GFP_KERNEL);
transaction->aid_len = skb->data[1];
memcpy(transaction->aid, &skb->data[2], skb->data[1]);
memcpy(transaction->aid, &skb->data[2], transaction->aid_len);
/* Check next byte is PARAMETERS tag (82) */
if (skb->data[transaction->aid_len + 2] !=
NFC_EVT_TRANSACTION_PARAMS_TAG)
return -EPROTO;
......@@ -340,6 +347,7 @@ static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
transaction->aid_len + 4, transaction->params_len);
r = nfc_se_transaction(ndev->nfc_dev, host, transaction);
break;
default:
return 1;
}
......@@ -542,14 +550,12 @@ static int st21nfcb_hci_network_init(struct nci_dev *ndev)
r = nci_hci_dev_session_init(ndev);
if (r != NCI_HCI_ANY_OK)
goto exit;
goto free_dest_params;
r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
NCI_NFCEE_ENABLE);
if (r != NCI_STATUS_OK)
goto exit;
return 0;
goto free_dest_params;
free_dest_params:
kfree(dest_params);
......
/*
* Generic platform data for the NXP NCI NFC chips.
*
* Copyright (C) 2014 NXP Semiconductors All rights reserved.
*
* Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
*
* 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.
*/
#ifndef _NXP_NCI_H_
#define _NXP_NCI_H_
struct nxp_nci_nfc_platform_data {
unsigned int gpio_en;
unsigned int gpio_fw;
unsigned int irq;
};
#endif /* _NXP_NCI_H_ */
......@@ -83,6 +83,10 @@ struct nfc_hci_pipe {
};
#define NFC_HCI_MAX_CUSTOM_GATES 50
/*
* According to specification 102 622 chapter 4.4 Pipes,
* the pipe identifier is 7 bits long.
*/
#define NFC_HCI_MAX_PIPES 127
struct nfc_hci_init_data {
u8 gate_count;
......
......@@ -71,6 +71,7 @@ struct nci_ops {
int (*close)(struct nci_dev *ndev);
int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
int (*setup)(struct nci_dev *ndev);
int (*fw_download)(struct nci_dev *ndev, const char *firmware_name);
__u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol);
int (*discover_se)(struct nci_dev *ndev);
int (*disable_se)(struct nci_dev *ndev, u32 se_idx);
......@@ -137,6 +138,10 @@ struct nci_conn_info {
#define NCI_HCI_INVALID_HOST 0x80
#define NCI_HCI_MAX_CUSTOM_GATES 50
/*
* According to specification 102 622 chapter 4.4 Pipes,
* the pipe identifier is 7 bits long.
*/
#define NCI_HCI_MAX_PIPES 127
struct nci_hci_gate {
......
......@@ -157,7 +157,7 @@ struct nfc_evt_transaction {
u32 aid_len;
u8 aid[NFC_MAX_AID_LENGTH];
u8 params_len;
u8 params[NFC_MAX_PARAMS_LENGTH];
u8 params[0];
} __packed;
struct nfc_genl_data {
......
......@@ -907,6 +907,16 @@ static int nci_se_io(struct nfc_dev *nfc_dev, u32 se_idx,
return 0;
}
static int nci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
if (!ndev->ops->fw_download)
return -ENOTSUPP;
return ndev->ops->fw_download(ndev, firmware_name);
}
static struct nfc_ops nci_nfc_ops = {
.dev_up = nci_dev_up,
.dev_down = nci_dev_down,
......@@ -922,6 +932,7 @@ static struct nfc_ops nci_nfc_ops = {
.disable_se = nci_disable_se,
.discover_se = nci_discover_se,
.se_io = nci_se_io,
.fw_download = nci_fw_download,
};
/* ---- Interface to NCI drivers ---- */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册