Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Samuel Ortiz says:

====================
NFC 4.3 pull request

This is the NFC pull request for 4.3.
With this one we have:

- A new driver for Samsung's S3FWRN5 NFC chipset. In order to
properly support this driver, a few NCI core routines needed
to be exported. Future drivers like Intel's Fields Peak will
benefit from this.

- SPI support as a physical transport for STM st21nfcb.

- An additional netlink API for sending replies back to userspace
from vendor commands.

- 2 small fixes for TI's trf7970a

- A few st-nci fixes.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+2180 -61
+27
Documentation/devicetree/bindings/net/nfc/s3fwrn5.txt
··· 1 + * Samsung S3FWRN5 NCI NFC Controller 2 + 3 + Required properties: 4 + - compatible: Should be "samsung,s3fwrn5-i2c". 5 + - reg: address on the bus 6 + - interrupt-parent: phandle for the interrupt gpio controller 7 + - interrupts: GPIO interrupt to which the chip is connected 8 + - s3fwrn5,en-gpios: Output GPIO pin used for enabling/disabling the chip 9 + - s3fwrn5,fw-gpios: Output GPIO pin used to enter firmware mode and 10 + sleep/wakeup control 11 + 12 + Example: 13 + 14 + &hsi2c_4 { 15 + status = "okay"; 16 + s3fwrn5@27 { 17 + compatible = "samsung,s3fwrn5-i2c"; 18 + 19 + reg = <0x27>; 20 + 21 + interrupt-parent = <&gpa1>; 22 + interrupts = <3 0 0>; 23 + 24 + s3fwrn5,en-gpios = <&gpf1 4 0>; 25 + s3fwrn5,fw-gpios = <&gpj0 2 0>; 26 + }; 27 + };
+31
Documentation/devicetree/bindings/net/nfc/st-nci-spi.txt
··· 1 + * STMicroelectronics SAS. ST NCI NFC Controller 2 + 3 + Required properties: 4 + - compatible: Should be "st,st21nfcb-spi" 5 + - spi-max-frequency: Maximum SPI frequency (<= 10000000). 6 + - interrupt-parent: phandle for the interrupt gpio controller 7 + - interrupts: GPIO interrupt to which the chip is connected 8 + - reset-gpios: Output GPIO pin used to reset the ST21NFCB 9 + 10 + Optional SoC Specific Properties: 11 + - pinctrl-names: Contains only one value - "default". 12 + - pintctrl-0: Specifies the pin control groups used for this controller. 13 + 14 + Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4): 15 + 16 + &mcspi4 { 17 + 18 + status = "okay"; 19 + 20 + st21nfcb: st21nfcb@0 { 21 + 22 + compatible = "st,st21nfcb-spi"; 23 + 24 + clock-frequency = <4000000>; 25 + 26 + interrupt-parent = <&gpio5>; 27 + interrupts = <2 IRQ_TYPE_EDGE_RISING>; 28 + 29 + reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; 30 + }; 31 + };
Documentation/devicetree/bindings/net/nfc/st-nci.txt Documentation/devicetree/bindings/net/nfc/st-nci-i2c.txt
+6
MAINTAINERS
··· 8881 8881 S: Supported 8882 8882 F: drivers/media/i2c/s5k5baf.c 8883 8883 8884 + SAMSUNG S3FWRN5 NFC DRIVER 8885 + M: Robert Baldyga <r.baldyga@samsung.com> 8886 + L: linux-nfc@lists.01.org (moderated for non-subscribers) 8887 + S: Supported 8888 + F: drivers/nfc/s3fwrn5 8889 + 8884 8890 SAMSUNG SOC CLOCK DRIVERS 8885 8891 M: Sylwester Nawrocki <s.nawrocki@samsung.com> 8886 8892 M: Tomasz Figa <tomasz.figa@gmail.com>
+1
drivers/nfc/Kconfig
··· 74 74 source "drivers/nfc/st21nfca/Kconfig" 75 75 source "drivers/nfc/st-nci/Kconfig" 76 76 source "drivers/nfc/nxp-nci/Kconfig" 77 + source "drivers/nfc/s3fwrn5/Kconfig" 77 78 endmenu
+1
drivers/nfc/Makefile
··· 14 14 obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ 15 15 obj-$(CONFIG_NFC_ST_NCI) += st-nci/ 16 16 obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ 17 + obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/
+19
drivers/nfc/s3fwrn5/Kconfig
··· 1 + config NFC_S3FWRN5 2 + tristate 3 + ---help--- 4 + Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities 5 + of chip. It's intended to be used by PHYs to avoid duplicating lots 6 + of common code. 7 + 8 + config NFC_S3FWRN5_I2C 9 + tristate "Samsung S3FWRN5 I2C support" 10 + depends on NFC_NCI && I2C 11 + select NFC_S3FWRN5 12 + default n 13 + ---help--- 14 + This module adds support for an I2C interface to the S3FWRN5 chip. 15 + Select this if your platform is using the I2C bus. 16 + 17 + To compile this driver as a module, choose m here. The module will 18 + be called s3fwrn5_i2c.ko. 19 + Say N if unsure.
+11
drivers/nfc/s3fwrn5/Makefile
··· 1 + # 2 + # Makefile for Samsung S3FWRN5 NFC driver 3 + # 4 + 5 + s3fwrn5-objs = core.o firmware.o nci.o 6 + s3fwrn5_i2c-objs = i2c.o 7 + 8 + obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o 9 + obj-$(CONFIG_NFC_S3FWRN5_I2C) += s3fwrn5_i2c.o 10 + 11 + ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
+219
drivers/nfc/s3fwrn5/core.c
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/module.h> 21 + #include <net/nfc/nci_core.h> 22 + 23 + #include "s3fwrn5.h" 24 + #include "firmware.h" 25 + #include "nci.h" 26 + 27 + #define S3FWRN5_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ 28 + NFC_PROTO_MIFARE_MASK | \ 29 + NFC_PROTO_FELICA_MASK | \ 30 + NFC_PROTO_ISO14443_MASK | \ 31 + NFC_PROTO_ISO14443_B_MASK | \ 32 + NFC_PROTO_ISO15693_MASK) 33 + 34 + static int s3fwrn5_firmware_update(struct s3fwrn5_info *info) 35 + { 36 + bool need_update; 37 + int ret; 38 + 39 + s3fwrn5_fw_init(&info->fw_info, "sec_s3fwrn5_firmware.bin"); 40 + 41 + /* Update firmware */ 42 + 43 + s3fwrn5_set_wake(info, false); 44 + s3fwrn5_set_mode(info, S3FWRN5_MODE_FW); 45 + 46 + ret = s3fwrn5_fw_setup(&info->fw_info); 47 + if (ret < 0) 48 + return ret; 49 + 50 + need_update = s3fwrn5_fw_check_version(&info->fw_info, 51 + info->ndev->manufact_specific_info); 52 + if (!need_update) 53 + goto out; 54 + 55 + dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n"); 56 + 57 + ret = s3fwrn5_fw_download(&info->fw_info); 58 + if (ret < 0) 59 + goto out; 60 + 61 + /* Update RF configuration */ 62 + 63 + s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 64 + 65 + s3fwrn5_set_wake(info, true); 66 + ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin"); 67 + s3fwrn5_set_wake(info, false); 68 + 69 + out: 70 + s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 71 + s3fwrn5_fw_cleanup(&info->fw_info); 72 + return ret; 73 + } 74 + 75 + static int s3fwrn5_nci_open(struct nci_dev *ndev) 76 + { 77 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 78 + 79 + if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD) 80 + return -EBUSY; 81 + 82 + s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 83 + s3fwrn5_set_wake(info, true); 84 + 85 + return 0; 86 + } 87 + 88 + static int s3fwrn5_nci_close(struct nci_dev *ndev) 89 + { 90 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 91 + 92 + s3fwrn5_set_wake(info, false); 93 + s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 94 + 95 + return 0; 96 + } 97 + 98 + static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 99 + { 100 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 101 + int ret; 102 + 103 + mutex_lock(&info->mutex); 104 + 105 + if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) { 106 + mutex_unlock(&info->mutex); 107 + return -EINVAL; 108 + } 109 + 110 + ret = s3fwrn5_write(info, skb); 111 + if (ret < 0) 112 + kfree_skb(skb); 113 + 114 + mutex_unlock(&info->mutex); 115 + return ret; 116 + } 117 + 118 + static int s3fwrn5_nci_post_setup(struct nci_dev *ndev) 119 + { 120 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 121 + int ret; 122 + 123 + ret = s3fwrn5_firmware_update(info); 124 + if (ret < 0) 125 + goto out; 126 + 127 + /* NCI core reset */ 128 + 129 + s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 130 + s3fwrn5_set_wake(info, true); 131 + 132 + ret = nci_core_reset(info->ndev); 133 + if (ret < 0) 134 + goto out; 135 + 136 + ret = nci_core_init(info->ndev); 137 + 138 + out: 139 + return ret; 140 + } 141 + 142 + static struct nci_ops s3fwrn5_nci_ops = { 143 + .open = s3fwrn5_nci_open, 144 + .close = s3fwrn5_nci_close, 145 + .send = s3fwrn5_nci_send, 146 + .post_setup = s3fwrn5_nci_post_setup, 147 + }; 148 + 149 + int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev, 150 + struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload) 151 + { 152 + struct s3fwrn5_info *info; 153 + int ret; 154 + 155 + info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL); 156 + if (!info) 157 + return -ENOMEM; 158 + 159 + info->phy_id = phy_id; 160 + info->pdev = pdev; 161 + info->phy_ops = phy_ops; 162 + info->max_payload = max_payload; 163 + mutex_init(&info->mutex); 164 + 165 + s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 166 + 167 + s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops.prop_ops, 168 + &s3fwrn5_nci_ops.n_prop_ops); 169 + 170 + info->ndev = nci_allocate_device(&s3fwrn5_nci_ops, 171 + S3FWRN5_NFC_PROTOCOLS, 0, 0); 172 + if (!info->ndev) 173 + return -ENOMEM; 174 + 175 + nci_set_parent_dev(info->ndev, pdev); 176 + nci_set_drvdata(info->ndev, info); 177 + 178 + ret = nci_register_device(info->ndev); 179 + if (ret < 0) { 180 + nci_free_device(info->ndev); 181 + return ret; 182 + } 183 + 184 + info->fw_info.ndev = info->ndev; 185 + 186 + *ndev = info->ndev; 187 + 188 + return ret; 189 + } 190 + EXPORT_SYMBOL(s3fwrn5_probe); 191 + 192 + void s3fwrn5_remove(struct nci_dev *ndev) 193 + { 194 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 195 + 196 + s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 197 + 198 + nci_unregister_device(ndev); 199 + nci_free_device(ndev); 200 + } 201 + EXPORT_SYMBOL(s3fwrn5_remove); 202 + 203 + int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb, 204 + enum s3fwrn5_mode mode) 205 + { 206 + switch (mode) { 207 + case S3FWRN5_MODE_NCI: 208 + return nci_recv_frame(ndev, skb); 209 + case S3FWRN5_MODE_FW: 210 + return s3fwrn5_fw_recv_frame(ndev, skb); 211 + default: 212 + return -ENODEV; 213 + } 214 + } 215 + EXPORT_SYMBOL(s3fwrn5_recv_frame); 216 + 217 + MODULE_LICENSE("GPL"); 218 + MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver"); 219 + MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");
+511
drivers/nfc/s3fwrn5/firmware.c
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/completion.h> 21 + #include <linux/firmware.h> 22 + #include <linux/crypto.h> 23 + #include <crypto/sha.h> 24 + 25 + #include "s3fwrn5.h" 26 + #include "firmware.h" 27 + 28 + struct s3fwrn5_fw_version { 29 + __u8 major; 30 + __u8 build1; 31 + __u8 build2; 32 + __u8 target; 33 + }; 34 + 35 + static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info, 36 + struct sk_buff *msg, struct sk_buff **rsp) 37 + { 38 + struct s3fwrn5_info *info = 39 + container_of(fw_info, struct s3fwrn5_info, fw_info); 40 + long ret; 41 + 42 + reinit_completion(&fw_info->completion); 43 + 44 + ret = s3fwrn5_write(info, msg); 45 + if (ret < 0) 46 + return ret; 47 + 48 + ret = wait_for_completion_interruptible_timeout( 49 + &fw_info->completion, msecs_to_jiffies(1000)); 50 + if (ret < 0) 51 + return ret; 52 + else if (ret == 0) 53 + return -ENXIO; 54 + 55 + if (!fw_info->rsp) 56 + return -EINVAL; 57 + 58 + *rsp = fw_info->rsp; 59 + fw_info->rsp = NULL; 60 + 61 + return 0; 62 + } 63 + 64 + static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info, 65 + struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len) 66 + { 67 + struct s3fwrn5_fw_header hdr; 68 + struct sk_buff *skb; 69 + 70 + hdr.type = type | fw_info->parity; 71 + fw_info->parity ^= 0x80; 72 + hdr.code = code; 73 + hdr.len = len; 74 + 75 + skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL); 76 + if (!skb) 77 + return -ENOMEM; 78 + 79 + memcpy(skb_put(skb, S3FWRN5_FW_HDR_SIZE), &hdr, S3FWRN5_FW_HDR_SIZE); 80 + if (len) 81 + memcpy(skb_put(skb, len), data, len); 82 + 83 + *msg = skb; 84 + 85 + return 0; 86 + } 87 + 88 + static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info, 89 + struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo) 90 + { 91 + struct sk_buff *msg, *rsp = NULL; 92 + struct s3fwrn5_fw_header *hdr; 93 + int ret; 94 + 95 + /* Send GET_BOOTINFO command */ 96 + 97 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 98 + S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0); 99 + if (ret < 0) 100 + return ret; 101 + 102 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 103 + kfree_skb(msg); 104 + if (ret < 0) 105 + return ret; 106 + 107 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 108 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 109 + ret = -EINVAL; 110 + goto out; 111 + } 112 + 113 + memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10); 114 + 115 + out: 116 + kfree_skb(rsp); 117 + return ret; 118 + } 119 + 120 + static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info, 121 + const void *hash_data, u16 hash_size, 122 + const void *sig_data, u16 sig_size) 123 + { 124 + struct s3fwrn5_fw_cmd_enter_updatemode args; 125 + struct sk_buff *msg, *rsp = NULL; 126 + struct s3fwrn5_fw_header *hdr; 127 + int ret; 128 + 129 + /* Send ENTER_UPDATE_MODE command */ 130 + 131 + args.hashcode_size = hash_size; 132 + args.signature_size = sig_size; 133 + 134 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 135 + S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args)); 136 + if (ret < 0) 137 + return ret; 138 + 139 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 140 + kfree_skb(msg); 141 + if (ret < 0) 142 + return ret; 143 + 144 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 145 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 146 + ret = -EPROTO; 147 + goto out; 148 + } 149 + 150 + kfree_skb(rsp); 151 + 152 + /* Send hashcode data */ 153 + 154 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0, 155 + hash_data, hash_size); 156 + if (ret < 0) 157 + return ret; 158 + 159 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 160 + kfree_skb(msg); 161 + if (ret < 0) 162 + return ret; 163 + 164 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 165 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 166 + ret = -EPROTO; 167 + goto out; 168 + } 169 + 170 + kfree_skb(rsp); 171 + 172 + /* Send signature data */ 173 + 174 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0, 175 + sig_data, sig_size); 176 + if (ret < 0) 177 + return ret; 178 + 179 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 180 + kfree_skb(msg); 181 + if (ret < 0) 182 + return ret; 183 + 184 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 185 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) 186 + ret = -EPROTO; 187 + 188 + out: 189 + kfree_skb(rsp); 190 + return ret; 191 + } 192 + 193 + static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info, 194 + u32 base_addr, const void *data) 195 + { 196 + struct s3fwrn5_fw_cmd_update_sector args; 197 + struct sk_buff *msg, *rsp = NULL; 198 + struct s3fwrn5_fw_header *hdr; 199 + int ret, i; 200 + 201 + /* Send UPDATE_SECTOR command */ 202 + 203 + args.base_address = base_addr; 204 + 205 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 206 + S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args)); 207 + if (ret < 0) 208 + return ret; 209 + 210 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 211 + kfree_skb(msg); 212 + if (ret < 0) 213 + return ret; 214 + 215 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 216 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 217 + ret = -EPROTO; 218 + goto err; 219 + } 220 + 221 + kfree_skb(rsp); 222 + 223 + /* Send data split into 256-byte packets */ 224 + 225 + for (i = 0; i < 16; ++i) { 226 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, 227 + S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256); 228 + if (ret < 0) 229 + break; 230 + 231 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 232 + kfree_skb(msg); 233 + if (ret < 0) 234 + break; 235 + 236 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 237 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) { 238 + ret = -EPROTO; 239 + goto err; 240 + } 241 + 242 + kfree_skb(rsp); 243 + } 244 + 245 + return ret; 246 + 247 + err: 248 + kfree_skb(rsp); 249 + return ret; 250 + } 251 + 252 + static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info) 253 + { 254 + struct sk_buff *msg, *rsp = NULL; 255 + struct s3fwrn5_fw_header *hdr; 256 + int ret; 257 + 258 + /* Send COMPLETE_UPDATE_MODE command */ 259 + 260 + ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD, 261 + S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0); 262 + if (ret < 0) 263 + return ret; 264 + 265 + ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp); 266 + kfree_skb(msg); 267 + if (ret < 0) 268 + return ret; 269 + 270 + hdr = (struct s3fwrn5_fw_header *) rsp->data; 271 + if (hdr->code != S3FWRN5_FW_RET_SUCCESS) 272 + ret = -EPROTO; 273 + 274 + kfree_skb(rsp); 275 + 276 + return ret; 277 + } 278 + 279 + /* 280 + * Firmware header stucture: 281 + * 282 + * 0x00 - 0x0B : Date and time string (w/o NUL termination) 283 + * 0x10 - 0x13 : Firmware version 284 + * 0x14 - 0x17 : Signature address 285 + * 0x18 - 0x1B : Signature size 286 + * 0x1C - 0x1F : Firmware image address 287 + * 0x20 - 0x23 : Firmware sectors count 288 + * 0x24 - 0x27 : Custom signature address 289 + * 0x28 - 0x2B : Custom signature size 290 + */ 291 + 292 + #define S3FWRN5_FW_IMAGE_HEADER_SIZE 44 293 + 294 + static int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info) 295 + { 296 + struct s3fwrn5_fw_image *fw = &fw_info->fw; 297 + u32 sig_off; 298 + u32 image_off; 299 + u32 custom_sig_off; 300 + int ret; 301 + 302 + ret = request_firmware(&fw->fw, fw_info->fw_name, 303 + &fw_info->ndev->nfc_dev->dev); 304 + if (ret < 0) 305 + return ret; 306 + 307 + if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE) 308 + return -EINVAL; 309 + 310 + memcpy(fw->date, fw->fw->data + 0x00, 12); 311 + fw->date[12] = '\0'; 312 + 313 + memcpy(&fw->version, fw->fw->data + 0x10, 4); 314 + 315 + memcpy(&sig_off, fw->fw->data + 0x14, 4); 316 + fw->sig = fw->fw->data + sig_off; 317 + memcpy(&fw->sig_size, fw->fw->data + 0x18, 4); 318 + 319 + memcpy(&image_off, fw->fw->data + 0x1C, 4); 320 + fw->image = fw->fw->data + image_off; 321 + memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4); 322 + 323 + memcpy(&custom_sig_off, fw->fw->data + 0x24, 4); 324 + fw->custom_sig = fw->fw->data + custom_sig_off; 325 + memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4); 326 + 327 + return 0; 328 + } 329 + 330 + static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info) 331 + { 332 + release_firmware(fw_info->fw.fw); 333 + } 334 + 335 + static int s3fwrn5_fw_get_base_addr( 336 + struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr) 337 + { 338 + int i; 339 + struct { 340 + u8 version[4]; 341 + u32 base_addr; 342 + } match[] = { 343 + {{0x05, 0x00, 0x00, 0x00}, 0x00005000}, 344 + {{0x05, 0x00, 0x00, 0x01}, 0x00003000}, 345 + {{0x05, 0x00, 0x00, 0x02}, 0x00003000}, 346 + {{0x05, 0x00, 0x00, 0x03}, 0x00003000}, 347 + {{0x05, 0x00, 0x00, 0x05}, 0x00003000} 348 + }; 349 + 350 + for (i = 0; i < ARRAY_SIZE(match); ++i) 351 + if (bootinfo->hw_version[0] == match[i].version[0] && 352 + bootinfo->hw_version[1] == match[i].version[1] && 353 + bootinfo->hw_version[3] == match[i].version[3]) { 354 + *base_addr = match[i].base_addr; 355 + return 0; 356 + } 357 + 358 + return -EINVAL; 359 + } 360 + 361 + static inline bool 362 + s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo) 363 + { 364 + return !!bootinfo->hw_version[2]; 365 + } 366 + 367 + int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info) 368 + { 369 + struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo; 370 + int ret; 371 + 372 + /* Get firmware data */ 373 + 374 + ret = s3fwrn5_fw_request_firmware(fw_info); 375 + if (ret < 0) { 376 + dev_err(&fw_info->ndev->nfc_dev->dev, 377 + "Failed to get fw file, ret=%02x\n", ret); 378 + return ret; 379 + } 380 + 381 + /* Get bootloader info */ 382 + 383 + ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo); 384 + if (ret < 0) { 385 + dev_err(&fw_info->ndev->nfc_dev->dev, 386 + "Failed to get bootinfo, ret=%02x\n", ret); 387 + goto err; 388 + } 389 + 390 + /* Match hardware version to obtain firmware base address */ 391 + 392 + ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr); 393 + if (ret < 0) { 394 + dev_err(&fw_info->ndev->nfc_dev->dev, 395 + "Unknown hardware version\n"); 396 + goto err; 397 + } 398 + 399 + fw_info->sector_size = bootinfo.sector_size; 400 + 401 + fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ? 402 + fw_info->fw.custom_sig_size : fw_info->fw.sig_size; 403 + fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ? 404 + fw_info->fw.custom_sig : fw_info->fw.sig; 405 + 406 + return 0; 407 + 408 + err: 409 + s3fwrn5_fw_release_firmware(fw_info); 410 + return ret; 411 + } 412 + 413 + bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version) 414 + { 415 + struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version; 416 + struct s3fwrn5_fw_version *old = (void *) &version; 417 + 418 + if (new->major > old->major) 419 + return true; 420 + if (new->build1 > old->build1) 421 + return true; 422 + if (new->build2 > old->build2) 423 + return true; 424 + 425 + return false; 426 + } 427 + 428 + int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info) 429 + { 430 + struct s3fwrn5_fw_image *fw = &fw_info->fw; 431 + u8 hash_data[SHA1_DIGEST_SIZE]; 432 + struct scatterlist sg; 433 + struct hash_desc desc; 434 + u32 image_size, off; 435 + int ret; 436 + 437 + image_size = fw_info->sector_size * fw->image_sectors; 438 + 439 + /* Compute SHA of firmware data */ 440 + 441 + sg_init_one(&sg, fw->image, image_size); 442 + desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); 443 + crypto_hash_init(&desc); 444 + crypto_hash_update(&desc, &sg, image_size); 445 + crypto_hash_final(&desc, hash_data); 446 + crypto_free_hash(desc.tfm); 447 + 448 + /* Firmware update process */ 449 + 450 + dev_info(&fw_info->ndev->nfc_dev->dev, 451 + "Firmware update: %s\n", fw_info->fw_name); 452 + 453 + ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data, 454 + SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size); 455 + if (ret < 0) { 456 + dev_err(&fw_info->ndev->nfc_dev->dev, 457 + "Unable to enter update mode\n"); 458 + goto out; 459 + } 460 + 461 + for (off = 0; off < image_size; off += fw_info->sector_size) { 462 + ret = s3fwrn5_fw_update_sector(fw_info, 463 + fw_info->base_addr + off, fw->image + off); 464 + if (ret < 0) { 465 + dev_err(&fw_info->ndev->nfc_dev->dev, 466 + "Firmware update error (code=%d)\n", ret); 467 + goto out; 468 + } 469 + } 470 + 471 + ret = s3fwrn5_fw_complete_update_mode(fw_info); 472 + if (ret < 0) { 473 + dev_err(&fw_info->ndev->nfc_dev->dev, 474 + "Unable to complete update mode\n"); 475 + goto out; 476 + } 477 + 478 + dev_info(&fw_info->ndev->nfc_dev->dev, 479 + "Firmware update: success\n"); 480 + 481 + out: 482 + return ret; 483 + } 484 + 485 + void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name) 486 + { 487 + fw_info->parity = 0x00; 488 + fw_info->rsp = NULL; 489 + fw_info->fw.fw = NULL; 490 + strcpy(fw_info->fw_name, fw_name); 491 + init_completion(&fw_info->completion); 492 + } 493 + 494 + void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info) 495 + { 496 + s3fwrn5_fw_release_firmware(fw_info); 497 + } 498 + 499 + int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb) 500 + { 501 + struct s3fwrn5_info *info = nci_get_drvdata(ndev); 502 + struct s3fwrn5_fw_info *fw_info = &info->fw_info; 503 + 504 + BUG_ON(fw_info->rsp); 505 + 506 + fw_info->rsp = skb; 507 + 508 + complete(&fw_info->completion); 509 + 510 + return 0; 511 + }
+111
drivers/nfc/s3fwrn5/firmware.h
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef __LOCAL_S3FWRN5_FIRMWARE_H_ 21 + #define __LOCAL_S3FWRN5_FIRMWARE_H_ 22 + 23 + /* FW Message Types */ 24 + #define S3FWRN5_FW_MSG_CMD 0x00 25 + #define S3FWRN5_FW_MSG_RSP 0x01 26 + #define S3FWRN5_FW_MSG_DATA 0x02 27 + 28 + /* FW Return Codes */ 29 + #define S3FWRN5_FW_RET_SUCCESS 0x00 30 + #define S3FWRN5_FW_RET_MESSAGE_TYPE_INVALID 0x01 31 + #define S3FWRN5_FW_RET_COMMAND_INVALID 0x02 32 + #define S3FWRN5_FW_RET_PAGE_DATA_OVERFLOW 0x03 33 + #define S3FWRN5_FW_RET_SECT_DATA_OVERFLOW 0x04 34 + #define S3FWRN5_FW_RET_AUTHENTICATION_FAIL 0x05 35 + #define S3FWRN5_FW_RET_FLASH_OPERATION_FAIL 0x06 36 + #define S3FWRN5_FW_RET_ADDRESS_OUT_OF_RANGE 0x07 37 + #define S3FWRN5_FW_RET_PARAMETER_INVALID 0x08 38 + 39 + /* ---- FW Packet structures ---- */ 40 + #define S3FWRN5_FW_HDR_SIZE 4 41 + 42 + struct s3fwrn5_fw_header { 43 + __u8 type; 44 + __u8 code; 45 + __u16 len; 46 + }; 47 + 48 + #define S3FWRN5_FW_CMD_RESET 0x00 49 + 50 + #define S3FWRN5_FW_CMD_GET_BOOTINFO 0x01 51 + 52 + struct s3fwrn5_fw_cmd_get_bootinfo_rsp { 53 + __u8 hw_version[4]; 54 + __u16 sector_size; 55 + __u16 page_size; 56 + __u16 frame_max_size; 57 + __u16 hw_buffer_size; 58 + }; 59 + 60 + #define S3FWRN5_FW_CMD_ENTER_UPDATE_MODE 0x02 61 + 62 + struct s3fwrn5_fw_cmd_enter_updatemode { 63 + __u16 hashcode_size; 64 + __u16 signature_size; 65 + }; 66 + 67 + #define S3FWRN5_FW_CMD_UPDATE_SECTOR 0x04 68 + 69 + struct s3fwrn5_fw_cmd_update_sector { 70 + __u32 base_address; 71 + }; 72 + 73 + #define S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE 0x05 74 + 75 + struct s3fwrn5_fw_image { 76 + const struct firmware *fw; 77 + 78 + char date[13]; 79 + u32 version; 80 + const void *sig; 81 + u32 sig_size; 82 + const void *image; 83 + u32 image_sectors; 84 + const void *custom_sig; 85 + u32 custom_sig_size; 86 + }; 87 + 88 + struct s3fwrn5_fw_info { 89 + struct nci_dev *ndev; 90 + struct s3fwrn5_fw_image fw; 91 + char fw_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; 92 + 93 + const void *sig; 94 + u32 sig_size; 95 + u32 sector_size; 96 + u32 base_addr; 97 + 98 + struct completion completion; 99 + struct sk_buff *rsp; 100 + char parity; 101 + }; 102 + 103 + void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name); 104 + int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info); 105 + bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version); 106 + int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info); 107 + void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info); 108 + 109 + int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb); 110 + 111 + #endif /* __LOCAL_S3FWRN5_FIRMWARE_H_ */
+306
drivers/nfc/s3fwrn5/i2c.c
··· 1 + /* 2 + * I2C Link Layer for Samsung S3FWRN5 NCI based Driver 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/i2c.h> 21 + #include <linux/gpio.h> 22 + #include <linux/delay.h> 23 + #include <linux/of_gpio.h> 24 + #include <linux/of_irq.h> 25 + #include <linux/module.h> 26 + 27 + #include <net/nfc/nfc.h> 28 + 29 + #include "s3fwrn5.h" 30 + 31 + #define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c" 32 + 33 + #define S3FWRN5_I2C_MAX_PAYLOAD 32 34 + #define S3FWRN5_EN_WAIT_TIME 150 35 + 36 + struct s3fwrn5_i2c_phy { 37 + struct i2c_client *i2c_dev; 38 + struct nci_dev *ndev; 39 + 40 + unsigned int gpio_en; 41 + unsigned int gpio_fw_wake; 42 + 43 + struct mutex mutex; 44 + 45 + enum s3fwrn5_mode mode; 46 + unsigned int irq_skip:1; 47 + }; 48 + 49 + static void s3fwrn5_i2c_set_wake(void *phy_id, bool wake) 50 + { 51 + struct s3fwrn5_i2c_phy *phy = phy_id; 52 + 53 + mutex_lock(&phy->mutex); 54 + gpio_set_value(phy->gpio_fw_wake, wake); 55 + msleep(S3FWRN5_EN_WAIT_TIME/2); 56 + mutex_unlock(&phy->mutex); 57 + } 58 + 59 + static void s3fwrn5_i2c_set_mode(void *phy_id, enum s3fwrn5_mode mode) 60 + { 61 + struct s3fwrn5_i2c_phy *phy = phy_id; 62 + 63 + mutex_lock(&phy->mutex); 64 + 65 + if (phy->mode == mode) 66 + goto out; 67 + 68 + phy->mode = mode; 69 + 70 + gpio_set_value(phy->gpio_en, 1); 71 + gpio_set_value(phy->gpio_fw_wake, 0); 72 + if (mode == S3FWRN5_MODE_FW) 73 + gpio_set_value(phy->gpio_fw_wake, 1); 74 + 75 + if (mode != S3FWRN5_MODE_COLD) { 76 + msleep(S3FWRN5_EN_WAIT_TIME); 77 + gpio_set_value(phy->gpio_en, 0); 78 + msleep(S3FWRN5_EN_WAIT_TIME/2); 79 + } 80 + 81 + phy->irq_skip = true; 82 + 83 + out: 84 + mutex_unlock(&phy->mutex); 85 + } 86 + 87 + static enum s3fwrn5_mode s3fwrn5_i2c_get_mode(void *phy_id) 88 + { 89 + struct s3fwrn5_i2c_phy *phy = phy_id; 90 + enum s3fwrn5_mode mode; 91 + 92 + mutex_lock(&phy->mutex); 93 + 94 + mode = phy->mode; 95 + 96 + mutex_unlock(&phy->mutex); 97 + 98 + return mode; 99 + } 100 + 101 + static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) 102 + { 103 + struct s3fwrn5_i2c_phy *phy = phy_id; 104 + int ret; 105 + 106 + mutex_lock(&phy->mutex); 107 + 108 + phy->irq_skip = false; 109 + 110 + ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len); 111 + if (ret == -EREMOTEIO) { 112 + /* Retry, chip was in standby */ 113 + usleep_range(110000, 120000); 114 + ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len); 115 + } 116 + 117 + mutex_unlock(&phy->mutex); 118 + 119 + if (ret < 0) 120 + return ret; 121 + 122 + if (ret != skb->len) 123 + return -EREMOTEIO; 124 + 125 + return 0; 126 + } 127 + 128 + static struct s3fwrn5_phy_ops i2c_phy_ops = { 129 + .set_wake = s3fwrn5_i2c_set_wake, 130 + .set_mode = s3fwrn5_i2c_set_mode, 131 + .get_mode = s3fwrn5_i2c_get_mode, 132 + .write = s3fwrn5_i2c_write, 133 + }; 134 + 135 + static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) 136 + { 137 + struct sk_buff *skb; 138 + size_t hdr_size; 139 + size_t data_len; 140 + char hdr[4]; 141 + int ret; 142 + 143 + hdr_size = (phy->mode == S3FWRN5_MODE_NCI) ? 144 + NCI_CTRL_HDR_SIZE : S3FWRN5_FW_HDR_SIZE; 145 + ret = i2c_master_recv(phy->i2c_dev, hdr, hdr_size); 146 + if (ret < 0) 147 + return ret; 148 + 149 + if (ret < hdr_size) 150 + return -EBADMSG; 151 + 152 + data_len = (phy->mode == S3FWRN5_MODE_NCI) ? 153 + ((struct nci_ctrl_hdr *)hdr)->plen : 154 + ((struct s3fwrn5_fw_header *)hdr)->len; 155 + 156 + skb = alloc_skb(hdr_size + data_len, GFP_KERNEL); 157 + if (!skb) 158 + return -ENOMEM; 159 + 160 + memcpy(skb_put(skb, hdr_size), hdr, hdr_size); 161 + 162 + if (data_len == 0) 163 + goto out; 164 + 165 + ret = i2c_master_recv(phy->i2c_dev, skb_put(skb, data_len), data_len); 166 + if (ret != data_len) { 167 + kfree_skb(skb); 168 + return -EBADMSG; 169 + } 170 + 171 + out: 172 + return s3fwrn5_recv_frame(phy->ndev, skb, phy->mode); 173 + } 174 + 175 + static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id) 176 + { 177 + struct s3fwrn5_i2c_phy *phy = phy_id; 178 + int ret = 0; 179 + 180 + if (!phy || !phy->ndev) { 181 + WARN_ON_ONCE(1); 182 + return IRQ_NONE; 183 + } 184 + 185 + mutex_lock(&phy->mutex); 186 + 187 + if (phy->irq_skip) 188 + goto out; 189 + 190 + switch (phy->mode) { 191 + case S3FWRN5_MODE_NCI: 192 + case S3FWRN5_MODE_FW: 193 + ret = s3fwrn5_i2c_read(phy); 194 + break; 195 + case S3FWRN5_MODE_COLD: 196 + ret = -EREMOTEIO; 197 + break; 198 + } 199 + 200 + out: 201 + mutex_unlock(&phy->mutex); 202 + 203 + return IRQ_HANDLED; 204 + } 205 + 206 + static int s3fwrn5_i2c_parse_dt(struct i2c_client *client) 207 + { 208 + struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client); 209 + struct device_node *np = client->dev.of_node; 210 + 211 + if (!np) 212 + return -ENODEV; 213 + 214 + phy->gpio_en = of_get_named_gpio(np, "s3fwrn5,en-gpios", 0); 215 + if (!gpio_is_valid(phy->gpio_en)) 216 + return -ENODEV; 217 + 218 + phy->gpio_fw_wake = of_get_named_gpio(np, "s3fwrn5,fw-gpios", 0); 219 + if (!gpio_is_valid(phy->gpio_fw_wake)) 220 + return -ENODEV; 221 + 222 + return 0; 223 + } 224 + 225 + static int s3fwrn5_i2c_probe(struct i2c_client *client, 226 + const struct i2c_device_id *id) 227 + { 228 + struct s3fwrn5_i2c_phy *phy; 229 + int ret; 230 + 231 + phy = devm_kzalloc(&client->dev, sizeof(*phy), GFP_KERNEL); 232 + if (!phy) 233 + return -ENOMEM; 234 + 235 + mutex_init(&phy->mutex); 236 + phy->mode = S3FWRN5_MODE_COLD; 237 + phy->irq_skip = true; 238 + 239 + phy->i2c_dev = client; 240 + i2c_set_clientdata(client, phy); 241 + 242 + ret = s3fwrn5_i2c_parse_dt(client); 243 + if (ret < 0) 244 + return ret; 245 + 246 + ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, 247 + GPIOF_OUT_INIT_HIGH, "s3fwrn5_en"); 248 + if (ret < 0) 249 + return ret; 250 + 251 + ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw_wake, 252 + GPIOF_OUT_INIT_LOW, "s3fwrn5_fw_wake"); 253 + if (ret < 0) 254 + return ret; 255 + 256 + ret = s3fwrn5_probe(&phy->ndev, phy, &phy->i2c_dev->dev, &i2c_phy_ops, 257 + S3FWRN5_I2C_MAX_PAYLOAD); 258 + if (ret < 0) 259 + return ret; 260 + 261 + ret = request_threaded_irq(phy->i2c_dev->irq, NULL, 262 + s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 263 + S3FWRN5_I2C_DRIVER_NAME, phy); 264 + if (ret) 265 + s3fwrn5_remove(phy->ndev); 266 + 267 + return ret; 268 + } 269 + 270 + static int s3fwrn5_i2c_remove(struct i2c_client *client) 271 + { 272 + struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client); 273 + 274 + s3fwrn5_remove(phy->ndev); 275 + 276 + return 0; 277 + } 278 + 279 + static struct i2c_device_id s3fwrn5_i2c_id_table[] = { 280 + {S3FWRN5_I2C_DRIVER_NAME, 0}, 281 + {} 282 + }; 283 + MODULE_DEVICE_TABLE(i2c, s3fwrn5_i2c_id_table); 284 + 285 + static const struct of_device_id of_s3fwrn5_i2c_match[] = { 286 + { .compatible = "samsung,s3fwrn5-i2c", }, 287 + {} 288 + }; 289 + MODULE_DEVICE_TABLE(of, of_s3fwrn5_i2c_match); 290 + 291 + static struct i2c_driver s3fwrn5_i2c_driver = { 292 + .driver = { 293 + .owner = THIS_MODULE, 294 + .name = S3FWRN5_I2C_DRIVER_NAME, 295 + .of_match_table = of_match_ptr(of_s3fwrn5_i2c_match), 296 + }, 297 + .probe = s3fwrn5_i2c_probe, 298 + .remove = s3fwrn5_i2c_remove, 299 + .id_table = s3fwrn5_i2c_id_table, 300 + }; 301 + 302 + module_i2c_driver(s3fwrn5_i2c_driver); 303 + 304 + MODULE_LICENSE("GPL"); 305 + MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN5"); 306 + MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");
+165
drivers/nfc/s3fwrn5/nci.c
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/completion.h> 21 + #include <linux/firmware.h> 22 + 23 + #include "s3fwrn5.h" 24 + #include "nci.h" 25 + 26 + static int s3fwrn5_nci_prop_rsp(struct nci_dev *ndev, struct sk_buff *skb) 27 + { 28 + __u8 status = skb->data[0]; 29 + 30 + nci_req_complete(ndev, status); 31 + return 0; 32 + } 33 + 34 + static struct nci_prop_ops s3fwrn5_nci_prop_ops[] = { 35 + { 36 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 37 + NCI_PROP_AGAIN), 38 + .rsp = s3fwrn5_nci_prop_rsp, 39 + }, 40 + { 41 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 42 + NCI_PROP_GET_RFREG), 43 + .rsp = s3fwrn5_nci_prop_rsp, 44 + }, 45 + { 46 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 47 + NCI_PROP_SET_RFREG), 48 + .rsp = s3fwrn5_nci_prop_rsp, 49 + }, 50 + { 51 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 52 + NCI_PROP_GET_RFREG_VER), 53 + .rsp = s3fwrn5_nci_prop_rsp, 54 + }, 55 + { 56 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 57 + NCI_PROP_SET_RFREG_VER), 58 + .rsp = s3fwrn5_nci_prop_rsp, 59 + }, 60 + { 61 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 62 + NCI_PROP_START_RFREG), 63 + .rsp = s3fwrn5_nci_prop_rsp, 64 + }, 65 + { 66 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 67 + NCI_PROP_STOP_RFREG), 68 + .rsp = s3fwrn5_nci_prop_rsp, 69 + }, 70 + { 71 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 72 + NCI_PROP_FW_CFG), 73 + .rsp = s3fwrn5_nci_prop_rsp, 74 + }, 75 + { 76 + .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 77 + NCI_PROP_WR_RESET), 78 + .rsp = s3fwrn5_nci_prop_rsp, 79 + }, 80 + }; 81 + 82 + void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n) 83 + { 84 + *ops = s3fwrn5_nci_prop_ops; 85 + *n = ARRAY_SIZE(s3fwrn5_nci_prop_ops); 86 + } 87 + 88 + #define S3FWRN5_RFREG_SECTION_SIZE 252 89 + 90 + int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name) 91 + { 92 + const struct firmware *fw; 93 + struct nci_prop_fw_cfg_cmd fw_cfg; 94 + struct nci_prop_set_rfreg_cmd set_rfreg; 95 + struct nci_prop_stop_rfreg_cmd stop_rfreg; 96 + u32 checksum; 97 + int i, len; 98 + int ret; 99 + 100 + ret = request_firmware(&fw, fw_name, &info->ndev->nfc_dev->dev); 101 + if (ret < 0) 102 + return ret; 103 + 104 + /* Compute rfreg checksum */ 105 + 106 + checksum = 0; 107 + for (i = 0; i < fw->size; i += 4) 108 + checksum += *((u32 *)(fw->data+i)); 109 + 110 + /* Set default clock configuration for external crystal */ 111 + 112 + fw_cfg.clk_type = 0x01; 113 + fw_cfg.clk_speed = 0xff; 114 + fw_cfg.clk_req = 0xff; 115 + ret = nci_prop_cmd(info->ndev, NCI_PROP_FW_CFG, 116 + sizeof(fw_cfg), (__u8 *)&fw_cfg); 117 + if (ret < 0) 118 + goto out; 119 + 120 + /* Start rfreg configuration */ 121 + 122 + dev_info(&info->ndev->nfc_dev->dev, 123 + "rfreg configuration update: %s\n", fw_name); 124 + 125 + ret = nci_prop_cmd(info->ndev, NCI_PROP_START_RFREG, 0, NULL); 126 + if (ret < 0) { 127 + dev_err(&info->ndev->nfc_dev->dev, 128 + "Unable to start rfreg update\n"); 129 + goto out; 130 + } 131 + 132 + /* Update rfreg */ 133 + 134 + set_rfreg.index = 0; 135 + for (i = 0; i < fw->size; i += S3FWRN5_RFREG_SECTION_SIZE) { 136 + len = (fw->size - i < S3FWRN5_RFREG_SECTION_SIZE) ? 137 + (fw->size - i) : S3FWRN5_RFREG_SECTION_SIZE; 138 + memcpy(set_rfreg.data, fw->data+i, len); 139 + ret = nci_prop_cmd(info->ndev, NCI_PROP_SET_RFREG, 140 + len+1, (__u8 *)&set_rfreg); 141 + if (ret < 0) { 142 + dev_err(&info->ndev->nfc_dev->dev, 143 + "rfreg update error (code=%d)\n", ret); 144 + goto out; 145 + } 146 + set_rfreg.index++; 147 + } 148 + 149 + /* Finish rfreg configuration */ 150 + 151 + stop_rfreg.checksum = checksum & 0xffff; 152 + ret = nci_prop_cmd(info->ndev, NCI_PROP_STOP_RFREG, 153 + sizeof(stop_rfreg), (__u8 *)&stop_rfreg); 154 + if (ret < 0) { 155 + dev_err(&info->ndev->nfc_dev->dev, 156 + "Unable to stop rfreg update\n"); 157 + goto out; 158 + } 159 + 160 + dev_info(&info->ndev->nfc_dev->dev, 161 + "rfreg configuration update: success\n"); 162 + out: 163 + release_firmware(fw); 164 + return ret; 165 + }
+89
drivers/nfc/s3fwrn5/nci.h
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef __LOCAL_S3FWRN5_NCI_H_ 21 + #define __LOCAL_S3FWRN5_NCI_H_ 22 + 23 + #include "s3fwrn5.h" 24 + 25 + #define NCI_PROP_AGAIN 0x01 26 + 27 + #define NCI_PROP_GET_RFREG 0x21 28 + #define NCI_PROP_SET_RFREG 0x22 29 + 30 + struct nci_prop_set_rfreg_cmd { 31 + __u8 index; 32 + __u8 data[252]; 33 + }; 34 + 35 + struct nci_prop_set_rfreg_rsp { 36 + __u8 status; 37 + }; 38 + 39 + #define NCI_PROP_GET_RFREG_VER 0x24 40 + 41 + struct nci_prop_get_rfreg_ver_rsp { 42 + __u8 status; 43 + __u8 data[8]; 44 + }; 45 + 46 + #define NCI_PROP_SET_RFREG_VER 0x25 47 + 48 + struct nci_prop_set_rfreg_ver_cmd { 49 + __u8 data[8]; 50 + }; 51 + 52 + struct nci_prop_set_rfreg_ver_rsp { 53 + __u8 status; 54 + }; 55 + 56 + #define NCI_PROP_START_RFREG 0x26 57 + 58 + struct nci_prop_start_rfreg_rsp { 59 + __u8 status; 60 + }; 61 + 62 + #define NCI_PROP_STOP_RFREG 0x27 63 + 64 + struct nci_prop_stop_rfreg_cmd { 65 + __u16 checksum; 66 + }; 67 + 68 + struct nci_prop_stop_rfreg_rsp { 69 + __u8 status; 70 + }; 71 + 72 + #define NCI_PROP_FW_CFG 0x28 73 + 74 + struct nci_prop_fw_cfg_cmd { 75 + __u8 clk_type; 76 + __u8 clk_speed; 77 + __u8 clk_req; 78 + }; 79 + 80 + struct nci_prop_fw_cfg_rsp { 81 + __u8 status; 82 + }; 83 + 84 + #define NCI_PROP_WR_RESET 0x2f 85 + 86 + void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n); 87 + int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name); 88 + 89 + #endif /* __LOCAL_S3FWRN5_NCI_H_ */
+99
drivers/nfc/s3fwrn5/s3fwrn5.h
··· 1 + /* 2 + * NCI based driver for Samsung S3FWRN5 NFC chip 3 + * 4 + * Copyright (C) 2015 Samsung Electrnoics 5 + * Robert Baldyga <r.baldyga@samsung.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms and conditions of the GNU General Public License, 9 + * version 2 or later, as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef __LOCAL_S3FWRN5_H_ 21 + #define __LOCAL_S3FWRN5_H_ 22 + 23 + #include <linux/nfc.h> 24 + 25 + #include <net/nfc/nci_core.h> 26 + 27 + #include "firmware.h" 28 + 29 + enum s3fwrn5_mode { 30 + S3FWRN5_MODE_COLD, 31 + S3FWRN5_MODE_NCI, 32 + S3FWRN5_MODE_FW, 33 + }; 34 + 35 + struct s3fwrn5_phy_ops { 36 + void (*set_wake)(void *id, bool sleep); 37 + void (*set_mode)(void *id, enum s3fwrn5_mode); 38 + enum s3fwrn5_mode (*get_mode)(void *id); 39 + int (*write)(void *id, struct sk_buff *skb); 40 + }; 41 + 42 + struct s3fwrn5_info { 43 + struct nci_dev *ndev; 44 + void *phy_id; 45 + struct device *pdev; 46 + 47 + struct s3fwrn5_phy_ops *phy_ops; 48 + unsigned int max_payload; 49 + 50 + struct s3fwrn5_fw_info fw_info; 51 + 52 + struct mutex mutex; 53 + }; 54 + 55 + static inline int s3fwrn5_set_mode(struct s3fwrn5_info *info, 56 + enum s3fwrn5_mode mode) 57 + { 58 + if (!info->phy_ops->set_mode) 59 + return -ENOTSUPP; 60 + 61 + info->phy_ops->set_mode(info->phy_id, mode); 62 + 63 + return 0; 64 + } 65 + 66 + static inline enum s3fwrn5_mode s3fwrn5_get_mode(struct s3fwrn5_info *info) 67 + { 68 + if (!info->phy_ops->get_mode) 69 + return -ENOTSUPP; 70 + 71 + return info->phy_ops->get_mode(info->phy_id); 72 + } 73 + 74 + static inline int s3fwrn5_set_wake(struct s3fwrn5_info *info, bool wake) 75 + { 76 + if (!info->phy_ops->set_wake) 77 + return -ENOTSUPP; 78 + 79 + info->phy_ops->set_wake(info->phy_id, wake); 80 + 81 + return 0; 82 + } 83 + 84 + static inline int s3fwrn5_write(struct s3fwrn5_info *info, struct sk_buff *skb) 85 + { 86 + if (!info->phy_ops->write) 87 + return -ENOTSUPP; 88 + 89 + return info->phy_ops->write(info->phy_id, skb); 90 + } 91 + 92 + int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev, 93 + struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload); 94 + void s3fwrn5_remove(struct nci_dev *ndev); 95 + 96 + int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb, 97 + enum s3fwrn5_mode mode); 98 + 99 + #endif /* __LOCAL_S3FWRN5_H_ */
+11
drivers/nfc/st-nci/Kconfig
··· 21 21 22 22 If you choose to build a module, it'll be called st-nci_i2c. 23 23 Say N if unsure. 24 + 25 + config NFC_ST_NCI_SPI 26 + tristate "NFC ST NCI spi support" 27 + depends on NFC_ST_NCI && SPI 28 + ---help--- 29 + This module adds support for an SPI interface to the 30 + STMicroelectronics NFC NCI chips familly. 31 + Select this if your platform is using the spi bus. 32 + 33 + If you choose to build a module, it'll be called st-nci_spi. 34 + Say N if unsure.
+3
drivers/nfc/st-nci/Makefile
··· 7 7 8 8 st-nci_i2c-objs = i2c.o 9 9 obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o 10 + 11 + st-nci_spi-objs = spi.o 12 + obj-$(CONFIG_NFC_ST_NCI_SPI) += st-nci_spi.o
+9 -14
drivers/nfc/st-nci/i2c.c
··· 25 25 #include <linux/interrupt.h> 26 26 #include <linux/delay.h> 27 27 #include <linux/nfc.h> 28 - #include <linux/platform_data/st_nci.h> 28 + #include <linux/platform_data/st-nci.h> 29 29 30 30 #include "ndlc.h" 31 31 32 - #define DRIVER_DESC "NCI NFC driver for ST21NFCB" 32 + #define DRIVER_DESC "NCI NFC driver for ST_NCI" 33 33 34 34 /* ndlc header */ 35 - #define ST21NFCB_FRAME_HEADROOM 1 36 - #define ST21NFCB_FRAME_TAILROOM 0 35 + #define ST_NCI_FRAME_HEADROOM 1 36 + #define ST_NCI_FRAME_TAILROOM 0 37 37 38 38 #define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ 39 39 #define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ ··· 118 118 /* 119 119 * Reads an ndlc frame and returns it in a newly allocated sk_buff. 120 120 * returns: 121 - * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at 122 - * end of read) 123 - * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF 124 - * at end of read) 121 + * 0 : if received frame is complete 125 122 * -EREMOTEIO : i2c read error (fatal) 126 123 * -EBADMSG : frame was incorrect and discarded 127 - * (value returned from st_nci_i2c_repack) 128 - * -EIO : if no ST21NFCB_SOF_EOF is found after reaching 129 - * the read length end sequence 124 + * -ENOMEM : cannot allocate skb, frame dropped 130 125 */ 131 126 static int st_nci_i2c_read(struct st_nci_i2c_phy *phy, 132 127 struct sk_buff **skb) ··· 174 179 /* 175 180 * Reads an ndlc frame from the chip. 176 181 * 177 - * On ST21NFCB, IRQ goes in idle state when read starts. 182 + * On ST_NCI, IRQ goes in idle state when read starts. 178 183 */ 179 184 static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id) 180 185 { ··· 320 325 } 321 326 } else { 322 327 nfc_err(&client->dev, 323 - "st21nfcb platform resources not available\n"); 328 + "st_nci platform resources not available\n"); 324 329 return -ENODEV; 325 330 } 326 331 327 332 r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, 328 - ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, 333 + ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, 329 334 &phy->ndlc); 330 335 if (r < 0) { 331 336 nfc_err(&client->dev, "Unable to register ndlc layer\n");
+5 -2
drivers/nfc/st-nci/ndlc.c
··· 171 171 if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { 172 172 switch (pcb & PCB_SYNC_MASK) { 173 173 case PCB_SYNC_ACK: 174 + skb = skb_dequeue(&ndlc->ack_pending_q); 175 + kfree_skb(skb); 174 176 del_timer_sync(&ndlc->t1_timer); 175 177 del_timer_sync(&ndlc->t2_timer); 176 178 ndlc->t2_active = false; ··· 194 192 msecs_to_jiffies(NDLC_TIMER_T1_WAIT)); 195 193 break; 196 194 default: 197 - pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); 198 195 kfree_skb(skb); 199 196 break; 200 197 } 201 - } else { 198 + } else if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_DATAFRAME) { 202 199 nci_recv_frame(ndlc->ndev, skb); 200 + } else { 201 + kfree_skb(skb); 203 202 } 204 203 } 205 204 }
+392
drivers/nfc/st-nci/spi.c
··· 1 + /* 2 + * SPI Link Layer for ST NCI based Driver 3 + * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 4 + * 5 + * This program is free software; you can redistribute it and/or modify it 6 + * under the terms and conditions of the GNU General Public License, 7 + * version 2, as published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 + 20 + #include <linux/module.h> 21 + #include <linux/spi/spi.h> 22 + #include <linux/gpio.h> 23 + #include <linux/of_irq.h> 24 + #include <linux/of_gpio.h> 25 + #include <linux/interrupt.h> 26 + #include <linux/delay.h> 27 + #include <linux/nfc.h> 28 + #include <linux/platform_data/st-nci.h> 29 + 30 + #include "ndlc.h" 31 + 32 + #define DRIVER_DESC "NCI NFC driver for ST_NCI" 33 + 34 + /* ndlc header */ 35 + #define ST_NCI_FRAME_HEADROOM 1 36 + #define ST_NCI_FRAME_TAILROOM 0 37 + 38 + #define ST_NCI_SPI_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ 39 + #define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */ 40 + 41 + #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi" 42 + 43 + static struct spi_device_id st_nci_spi_id_table[] = { 44 + {ST_NCI_SPI_DRIVER_NAME, 0}, 45 + {} 46 + }; 47 + MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table); 48 + 49 + struct st_nci_spi_phy { 50 + struct spi_device *spi_dev; 51 + struct llt_ndlc *ndlc; 52 + 53 + unsigned int gpio_reset; 54 + unsigned int irq_polarity; 55 + }; 56 + 57 + #define SPI_DUMP_SKB(info, skb) \ 58 + do { \ 59 + pr_debug("%s:\n", info); \ 60 + print_hex_dump(KERN_DEBUG, "spi: ", DUMP_PREFIX_OFFSET, \ 61 + 16, 1, (skb)->data, (skb)->len, 0); \ 62 + } while (0) 63 + 64 + static int st_nci_spi_enable(void *phy_id) 65 + { 66 + struct st_nci_spi_phy *phy = phy_id; 67 + 68 + gpio_set_value(phy->gpio_reset, 0); 69 + usleep_range(10000, 15000); 70 + gpio_set_value(phy->gpio_reset, 1); 71 + usleep_range(80000, 85000); 72 + 73 + if (phy->ndlc->powered == 0) 74 + enable_irq(phy->spi_dev->irq); 75 + 76 + return 0; 77 + } 78 + 79 + static void st_nci_spi_disable(void *phy_id) 80 + { 81 + struct st_nci_spi_phy *phy = phy_id; 82 + 83 + disable_irq_nosync(phy->spi_dev->irq); 84 + } 85 + 86 + /* 87 + * Writing a frame must not return the number of written bytes. 88 + * It must return either zero for success, or <0 for error. 89 + * In addition, it must not alter the skb 90 + */ 91 + static int st_nci_spi_write(void *phy_id, struct sk_buff *skb) 92 + { 93 + int r; 94 + struct st_nci_spi_phy *phy = phy_id; 95 + struct spi_device *dev = phy->spi_dev; 96 + struct sk_buff *skb_rx; 97 + u8 buf[ST_NCI_SPI_MAX_SIZE]; 98 + struct spi_transfer spi_xfer = { 99 + .tx_buf = skb->data, 100 + .rx_buf = buf, 101 + .len = skb->len, 102 + }; 103 + 104 + SPI_DUMP_SKB("st_nci_spi_write", skb); 105 + 106 + if (phy->ndlc->hard_fault != 0) 107 + return phy->ndlc->hard_fault; 108 + 109 + r = spi_sync_transfer(dev, &spi_xfer, 1); 110 + /* 111 + * We may have received some valuable data on miso line. 112 + * Send them back in the ndlc state machine. 113 + */ 114 + if (!r) { 115 + skb_rx = alloc_skb(skb->len, GFP_KERNEL); 116 + if (!skb_rx) { 117 + r = -ENOMEM; 118 + goto exit; 119 + } 120 + 121 + skb_put(skb_rx, skb->len); 122 + memcpy(skb_rx->data, buf, skb->len); 123 + ndlc_recv(phy->ndlc, skb_rx); 124 + } 125 + 126 + exit: 127 + return r; 128 + } 129 + 130 + /* 131 + * Reads an ndlc frame and returns it in a newly allocated sk_buff. 132 + * returns: 133 + * 0 : if received frame is complete 134 + * -EREMOTEIO : i2c read error (fatal) 135 + * -EBADMSG : frame was incorrect and discarded 136 + * -ENOMEM : cannot allocate skb, frame dropped 137 + */ 138 + static int st_nci_spi_read(struct st_nci_spi_phy *phy, 139 + struct sk_buff **skb) 140 + { 141 + int r; 142 + u8 len; 143 + u8 buf[ST_NCI_SPI_MAX_SIZE]; 144 + struct spi_device *dev = phy->spi_dev; 145 + struct spi_transfer spi_xfer = { 146 + .rx_buf = buf, 147 + .len = ST_NCI_SPI_MIN_SIZE, 148 + }; 149 + 150 + r = spi_sync_transfer(dev, &spi_xfer, 1); 151 + if (r < 0) 152 + return -EREMOTEIO; 153 + 154 + len = be16_to_cpu(*(__be16 *) (buf + 2)); 155 + if (len > ST_NCI_SPI_MAX_SIZE) { 156 + nfc_err(&dev->dev, "invalid frame len\n"); 157 + phy->ndlc->hard_fault = 1; 158 + return -EBADMSG; 159 + } 160 + 161 + *skb = alloc_skb(ST_NCI_SPI_MIN_SIZE + len, GFP_KERNEL); 162 + if (*skb == NULL) 163 + return -ENOMEM; 164 + 165 + skb_reserve(*skb, ST_NCI_SPI_MIN_SIZE); 166 + skb_put(*skb, ST_NCI_SPI_MIN_SIZE); 167 + memcpy((*skb)->data, buf, ST_NCI_SPI_MIN_SIZE); 168 + 169 + if (!len) 170 + return 0; 171 + 172 + spi_xfer.len = len; 173 + r = spi_sync_transfer(dev, &spi_xfer, 1); 174 + if (r < 0) { 175 + kfree_skb(*skb); 176 + return -EREMOTEIO; 177 + } 178 + 179 + skb_put(*skb, len); 180 + memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len); 181 + 182 + SPI_DUMP_SKB("spi frame read", *skb); 183 + 184 + return 0; 185 + } 186 + 187 + /* 188 + * Reads an ndlc frame from the chip. 189 + * 190 + * On ST21NFCB, IRQ goes in idle state when read starts. 191 + */ 192 + static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id) 193 + { 194 + struct st_nci_spi_phy *phy = phy_id; 195 + struct spi_device *dev; 196 + struct sk_buff *skb = NULL; 197 + int r; 198 + 199 + if (!phy || !phy->ndlc || irq != phy->spi_dev->irq) { 200 + WARN_ON_ONCE(1); 201 + return IRQ_NONE; 202 + } 203 + 204 + dev = phy->spi_dev; 205 + dev_dbg(&dev->dev, "IRQ\n"); 206 + 207 + if (phy->ndlc->hard_fault) 208 + return IRQ_HANDLED; 209 + 210 + if (!phy->ndlc->powered) { 211 + st_nci_spi_disable(phy); 212 + return IRQ_HANDLED; 213 + } 214 + 215 + r = st_nci_spi_read(phy, &skb); 216 + if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG) 217 + return IRQ_HANDLED; 218 + 219 + ndlc_recv(phy->ndlc, skb); 220 + 221 + return IRQ_HANDLED; 222 + } 223 + 224 + static struct nfc_phy_ops spi_phy_ops = { 225 + .write = st_nci_spi_write, 226 + .enable = st_nci_spi_enable, 227 + .disable = st_nci_spi_disable, 228 + }; 229 + 230 + #ifdef CONFIG_OF 231 + static int st_nci_spi_of_request_resources(struct spi_device *dev) 232 + { 233 + struct st_nci_spi_phy *phy = spi_get_drvdata(dev); 234 + struct device_node *pp; 235 + int gpio; 236 + int r; 237 + 238 + pp = dev->dev.of_node; 239 + if (!pp) 240 + return -ENODEV; 241 + 242 + /* Get GPIO from device tree */ 243 + gpio = of_get_named_gpio(pp, "reset-gpios", 0); 244 + if (gpio < 0) { 245 + nfc_err(&dev->dev, 246 + "Failed to retrieve reset-gpios from device tree\n"); 247 + return gpio; 248 + } 249 + 250 + /* GPIO request and configuration */ 251 + r = devm_gpio_request_one(&dev->dev, gpio, 252 + GPIOF_OUT_INIT_HIGH, "clf_reset"); 253 + if (r) { 254 + nfc_err(&dev->dev, "Failed to request reset pin\n"); 255 + return r; 256 + } 257 + phy->gpio_reset = gpio; 258 + 259 + phy->irq_polarity = irq_get_trigger_type(dev->irq); 260 + 261 + return 0; 262 + } 263 + #else 264 + static int st_nci_spi_of_request_resources(struct spi_device *dev) 265 + { 266 + return -ENODEV; 267 + } 268 + #endif 269 + 270 + static int st_nci_spi_request_resources(struct spi_device *dev) 271 + { 272 + struct st_nci_nfc_platform_data *pdata; 273 + struct st_nci_spi_phy *phy = spi_get_drvdata(dev); 274 + int r; 275 + 276 + pdata = dev->dev.platform_data; 277 + if (pdata == NULL) { 278 + nfc_err(&dev->dev, "No platform data\n"); 279 + return -EINVAL; 280 + } 281 + 282 + /* store for later use */ 283 + phy->gpio_reset = pdata->gpio_reset; 284 + phy->irq_polarity = pdata->irq_polarity; 285 + 286 + r = devm_gpio_request_one(&dev->dev, 287 + phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset"); 288 + if (r) { 289 + pr_err("%s : reset gpio_request failed\n", __FILE__); 290 + return r; 291 + } 292 + 293 + return 0; 294 + } 295 + 296 + static int st_nci_spi_probe(struct spi_device *dev) 297 + { 298 + struct st_nci_spi_phy *phy; 299 + struct st_nci_nfc_platform_data *pdata; 300 + int r; 301 + 302 + dev_dbg(&dev->dev, "%s\n", __func__); 303 + dev_dbg(&dev->dev, "IRQ: %d\n", dev->irq); 304 + 305 + /* Check SPI platform functionnalities */ 306 + if (!dev) { 307 + pr_debug("%s: dev is NULL. Device is not accessible.\n", 308 + __func__); 309 + return -ENODEV; 310 + } 311 + 312 + phy = devm_kzalloc(&dev->dev, sizeof(struct st_nci_spi_phy), 313 + GFP_KERNEL); 314 + if (!phy) 315 + return -ENOMEM; 316 + 317 + phy->spi_dev = dev; 318 + 319 + spi_set_drvdata(dev, phy); 320 + 321 + pdata = dev->dev.platform_data; 322 + if (!pdata && dev->dev.of_node) { 323 + r = st_nci_spi_of_request_resources(dev); 324 + if (r) { 325 + nfc_err(&dev->dev, "No platform data\n"); 326 + return r; 327 + } 328 + } else if (pdata) { 329 + r = st_nci_spi_request_resources(dev); 330 + if (r) { 331 + nfc_err(&dev->dev, 332 + "Cannot get platform resources\n"); 333 + return r; 334 + } 335 + } else { 336 + nfc_err(&dev->dev, 337 + "st_nci platform resources not available\n"); 338 + return -ENODEV; 339 + } 340 + 341 + r = ndlc_probe(phy, &spi_phy_ops, &dev->dev, 342 + ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM, 343 + &phy->ndlc); 344 + if (r < 0) { 345 + nfc_err(&dev->dev, "Unable to register ndlc layer\n"); 346 + return r; 347 + } 348 + 349 + r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL, 350 + st_nci_irq_thread_fn, 351 + phy->irq_polarity | IRQF_ONESHOT, 352 + ST_NCI_SPI_DRIVER_NAME, phy); 353 + if (r < 0) 354 + nfc_err(&dev->dev, "Unable to register IRQ handler\n"); 355 + 356 + return r; 357 + } 358 + 359 + static int st_nci_spi_remove(struct spi_device *dev) 360 + { 361 + struct st_nci_spi_phy *phy = spi_get_drvdata(dev); 362 + 363 + dev_dbg(&dev->dev, "%s\n", __func__); 364 + 365 + ndlc_remove(phy->ndlc); 366 + 367 + return 0; 368 + } 369 + 370 + #ifdef CONFIG_OF 371 + static const struct of_device_id of_st_nci_spi_match[] = { 372 + { .compatible = "st,st21nfcb-spi", }, 373 + {} 374 + }; 375 + MODULE_DEVICE_TABLE(of, of_st_nci_spi_match); 376 + #endif 377 + 378 + static struct spi_driver st_nci_spi_driver = { 379 + .driver = { 380 + .owner = THIS_MODULE, 381 + .name = ST_NCI_SPI_DRIVER_NAME, 382 + .of_match_table = of_match_ptr(of_st_nci_spi_match), 383 + }, 384 + .probe = st_nci_spi_probe, 385 + .id_table = st_nci_spi_id_table, 386 + .remove = st_nci_spi_remove, 387 + }; 388 + 389 + module_spi_driver(st_nci_spi_driver); 390 + 391 + MODULE_LICENSE("GPL"); 392 + MODULE_DESCRIPTION(DRIVER_DESC);
+4 -4
drivers/nfc/st-nci/st-nci_se.c
··· 189 189 ST_NCI_DEVICE_MGNT_GATE, 190 190 ST_NCI_DEVICE_MGNT_PIPE); 191 191 if (r < 0) 192 - goto free_info; 192 + return r; 193 193 194 194 /* Get pipe list */ 195 195 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 196 196 ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list), 197 197 &skb_pipe_list); 198 198 if (r < 0) 199 - goto free_info; 199 + return r; 200 200 201 201 /* Complete the existing gate_pipe table */ 202 202 for (i = 0; i < skb_pipe_list->len; i++) { ··· 222 222 dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) { 223 223 pr_err("Unexpected apdu_reader pipe on host %x\n", 224 224 dm_pipe_info->src_host_id); 225 + kfree_skb(skb_pipe_info); 225 226 continue; 226 227 } 227 228 ··· 242 241 ndev->hci_dev->pipes[st_nci_gates[j].pipe].host = 243 242 dm_pipe_info->src_host_id; 244 243 } 244 + kfree_skb(skb_pipe_info); 245 245 } 246 246 247 247 memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, 248 248 sizeof(st_nci_gates)); 249 249 250 - free_info: 251 - kfree_skb(skb_pipe_info); 252 250 kfree_skb(skb_pipe_list); 253 251 return r; 254 252 }
+6 -5
drivers/nfc/st21nfca/st21nfca.c
··· 148 148 ST21NFCA_DEVICE_MGNT_GATE, 149 149 ST21NFCA_DEVICE_MGNT_PIPE); 150 150 if (r < 0) 151 - goto free_info; 151 + return r; 152 152 153 153 /* Get pipe list */ 154 154 r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, 155 155 ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list), 156 156 &skb_pipe_list); 157 157 if (r < 0) 158 - goto free_info; 158 + return r; 159 159 160 160 /* Complete the existing gate_pipe table */ 161 161 for (i = 0; i < skb_pipe_list->len; i++) { ··· 181 181 info->src_host_id != ST21NFCA_ESE_HOST_ID) { 182 182 pr_err("Unexpected apdu_reader pipe on host %x\n", 183 183 info->src_host_id); 184 + kfree_skb(skb_pipe_info); 184 185 continue; 185 186 } 186 187 ··· 201 200 hdev->pipes[st21nfca_gates[j].pipe].dest_host = 202 201 info->src_host_id; 203 202 } 203 + kfree_skb(skb_pipe_info); 204 204 } 205 205 206 206 /* ··· 216 214 st21nfca_gates[i].gate, 217 215 st21nfca_gates[i].pipe); 218 216 if (r < 0) 219 - goto free_info; 217 + goto free_list; 220 218 } 221 219 } 222 220 223 221 memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates)); 224 - free_info: 225 - kfree_skb(skb_pipe_info); 222 + free_list: 226 223 kfree_skb(skb_pipe_list); 227 224 return r; 228 225 }
+4 -2
drivers/nfc/trf7970a.c
··· 336 336 337 337 #define TRF7970A_NFC_TARGET_LEVEL_RFDET(v) ((v) & 0x07) 338 338 #define TRF7970A_NFC_TARGET_LEVEL_HI_RF BIT(3) 339 - #define TRF7970A_NFC_TARGET_LEVEL_SDD_EN BIT(3) 339 + #define TRF7970A_NFC_TARGET_LEVEL_SDD_EN BIT(5) 340 340 #define TRF7970A_NFC_TARGET_LEVEL_LD_S_4BYTES (0x0 << 6) 341 341 #define TRF7970A_NFC_TARGET_LEVEL_LD_S_7BYTES (0x1 << 6) 342 342 #define TRF7970A_NFC_TARGET_LEVEL_LD_S_10BYTES (0x2 << 6) ··· 629 629 } 630 630 631 631 if (trf->adjust_resp_len) { 632 - skb_trim(trf->rx_skb, trf->rx_skb->len - 1); 632 + if (trf->rx_skb) 633 + skb_trim(trf->rx_skb, trf->rx_skb->len - 1); 634 + 633 635 trf->adjust_resp_len = false; 634 636 } 635 637
-29
include/linux/platform_data/st_nci.h
··· 1 - /* 2 - * Driver include for ST NCI NFC chip family. 3 - * 4 - * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 5 - * 6 - * This program is free software; you can redistribute it and/or modify it 7 - * under the terms and conditions of the GNU General Public License, 8 - * version 2, as published by the Free Software Foundation. 9 - * 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 - * 15 - * You should have received a copy of the GNU General Public License 16 - * along with this program; if not, see <http://www.gnu.org/licenses/>. 17 - */ 18 - 19 - #ifndef _ST_NCI_H_ 20 - #define _ST_NCI_H_ 21 - 22 - #define ST_NCI_DRIVER_NAME "st_nci" 23 - 24 - struct st_nci_nfc_platform_data { 25 - unsigned int gpio_reset; 26 - unsigned int irq_polarity; 27 - }; 28 - 29 - #endif /* _ST_NCI_H_ */
+3
include/net/nfc/nci_core.h
··· 79 79 int (*close)(struct nci_dev *ndev); 80 80 int (*send)(struct nci_dev *ndev, struct sk_buff *skb); 81 81 int (*setup)(struct nci_dev *ndev); 82 + int (*post_setup)(struct nci_dev *ndev); 82 83 int (*fw_download)(struct nci_dev *ndev, const char *firmware_name); 83 84 __u32 (*get_rfprotocol)(struct nci_dev *ndev, __u8 rf_protocol); 84 85 int (*discover_se)(struct nci_dev *ndev); ··· 278 277 unsigned long opt), 279 278 unsigned long opt, __u32 timeout); 280 279 int nci_prop_cmd(struct nci_dev *ndev, __u8 oid, size_t len, __u8 *payload); 280 + int nci_core_reset(struct nci_dev *ndev); 281 + int nci_core_init(struct nci_dev *ndev); 281 282 282 283 int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb); 283 284 int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val);
+41
include/net/nfc/nfc.h
··· 203 203 int n_vendor_cmds; 204 204 205 205 struct nfc_ops *ops; 206 + struct genl_info *cur_cmd_info; 206 207 }; 207 208 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev) 208 209 ··· 317 316 dev->n_vendor_cmds = n_cmds; 318 317 319 318 return 0; 319 + } 320 + 321 + struct sk_buff *__nfc_alloc_vendor_cmd_reply_skb(struct nfc_dev *dev, 322 + enum nfc_attrs attr, 323 + u32 oui, u32 subcmd, 324 + int approxlen); 325 + int nfc_vendor_cmd_reply(struct sk_buff *skb); 326 + 327 + /** 328 + * nfc_vendor_cmd_alloc_reply_skb - allocate vendor command reply 329 + * @dev: nfc device 330 + * @oui: vendor oui 331 + * @approxlen: an upper bound of the length of the data that will 332 + * be put into the skb 333 + * 334 + * This function allocates and pre-fills an skb for a reply to 335 + * a vendor command. Since it is intended for a reply, calling 336 + * it outside of a vendor command's doit() operation is invalid. 337 + * 338 + * The returned skb is pre-filled with some identifying data in 339 + * a way that any data that is put into the skb (with skb_put(), 340 + * nla_put() or similar) will end up being within the 341 + * %NFC_ATTR_VENDOR_DATA attribute, so all that needs to be done 342 + * with the skb is adding data for the corresponding userspace tool 343 + * which can then read that data out of the vendor data attribute. 344 + * You must not modify the skb in any other way. 345 + * 346 + * When done, call nfc_vendor_cmd_reply() with the skb and return 347 + * its error code as the result of the doit() operation. 348 + * 349 + * Return: An allocated and pre-filled skb. %NULL if any errors happen. 350 + */ 351 + static inline struct sk_buff * 352 + nfc_vendor_cmd_alloc_reply_skb(struct nfc_dev *dev, 353 + u32 oui, u32 subcmd, int approxlen) 354 + { 355 + return __nfc_alloc_vendor_cmd_reply_skb(dev, 356 + NFC_ATTR_VENDOR_DATA, 357 + oui, 358 + subcmd, approxlen); 320 359 } 321 360 322 361 #endif /* __NET_NFC_H */
+18
net/nfc/nci/core.c
··· 351 351 } 352 352 EXPORT_SYMBOL(nci_prop_cmd); 353 353 354 + int nci_core_reset(struct nci_dev *ndev) 355 + { 356 + return __nci_request(ndev, nci_reset_req, 0, 357 + msecs_to_jiffies(NCI_RESET_TIMEOUT)); 358 + } 359 + EXPORT_SYMBOL(nci_core_reset); 360 + 361 + int nci_core_init(struct nci_dev *ndev) 362 + { 363 + return __nci_request(ndev, nci_init_req, 0, 364 + msecs_to_jiffies(NCI_INIT_TIMEOUT)); 365 + } 366 + EXPORT_SYMBOL(nci_core_init); 367 + 354 368 static int nci_open_device(struct nci_dev *ndev) 355 369 { 356 370 int rc = 0; ··· 400 386 if (!rc) { 401 387 rc = __nci_request(ndev, nci_init_req, 0, 402 388 msecs_to_jiffies(NCI_INIT_TIMEOUT)); 389 + } 390 + 391 + if (ndev->ops->post_setup) { 392 + rc = ndev->ops->post_setup(ndev); 403 393 } 404 394 405 395 if (!rc) {
+1 -1
net/nfc/nci/hci.c
··· 233 233 r = nci_request(ndev, nci_hci_send_data_req, (unsigned long)&data, 234 234 msecs_to_jiffies(NCI_DATA_TIMEOUT)); 235 235 236 - if (r == NCI_STATUS_OK) 236 + if (r == NCI_STATUS_OK && skb) 237 237 *skb = conn_info->rx_skb; 238 238 239 239 return r;
+87 -4
net/nfc/netlink.c
··· 63 63 [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, 64 64 .len = NFC_FIRMWARE_NAME_MAXSIZE }, 65 65 [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY }, 66 + [NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, 67 + 66 68 }; 67 69 68 70 static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { ··· 1505 1503 u32 dev_idx, vid, subcmd; 1506 1504 u8 *data; 1507 1505 size_t data_len; 1508 - int i; 1506 + int i, err; 1509 1507 1510 1508 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || 1511 1509 !info->attrs[NFC_ATTR_VENDOR_ID] || ··· 1520 1518 if (!dev || !dev->vendor_cmds || !dev->n_vendor_cmds) 1521 1519 return -ENODEV; 1522 1520 1523 - data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]); 1524 - if (data) { 1521 + if (info->attrs[NFC_ATTR_VENDOR_DATA]) { 1522 + data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]); 1525 1523 data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]); 1526 1524 if (data_len == 0) 1527 1525 return -EINVAL; 1528 1526 } else { 1527 + data = NULL; 1529 1528 data_len = 0; 1530 1529 } 1531 1530 ··· 1536 1533 if (cmd->vendor_id != vid || cmd->subcmd != subcmd) 1537 1534 continue; 1538 1535 1539 - return cmd->doit(dev, data, data_len); 1536 + dev->cur_cmd_info = info; 1537 + err = cmd->doit(dev, data, data_len); 1538 + dev->cur_cmd_info = NULL; 1539 + return err; 1540 1540 } 1541 1541 1542 1542 return -EOPNOTSUPP; 1543 1543 } 1544 + 1545 + /* message building helper */ 1546 + static inline void *nfc_hdr_put(struct sk_buff *skb, u32 portid, u32 seq, 1547 + int flags, u8 cmd) 1548 + { 1549 + /* since there is no private header just add the generic one */ 1550 + return genlmsg_put(skb, portid, seq, &nfc_genl_family, flags, cmd); 1551 + } 1552 + 1553 + static struct sk_buff * 1554 + __nfc_alloc_vendor_cmd_skb(struct nfc_dev *dev, int approxlen, 1555 + u32 portid, u32 seq, 1556 + enum nfc_attrs attr, 1557 + u32 oui, u32 subcmd, gfp_t gfp) 1558 + { 1559 + struct sk_buff *skb; 1560 + void *hdr; 1561 + 1562 + skb = nlmsg_new(approxlen + 100, gfp); 1563 + if (!skb) 1564 + return NULL; 1565 + 1566 + hdr = nfc_hdr_put(skb, portid, seq, 0, NFC_CMD_VENDOR); 1567 + if (!hdr) { 1568 + kfree_skb(skb); 1569 + return NULL; 1570 + } 1571 + 1572 + if (nla_put_u32(skb, NFC_ATTR_DEVICE_INDEX, dev->idx)) 1573 + goto nla_put_failure; 1574 + if (nla_put_u32(skb, NFC_ATTR_VENDOR_ID, oui)) 1575 + goto nla_put_failure; 1576 + if (nla_put_u32(skb, NFC_ATTR_VENDOR_SUBCMD, subcmd)) 1577 + goto nla_put_failure; 1578 + 1579 + ((void **)skb->cb)[0] = dev; 1580 + ((void **)skb->cb)[1] = hdr; 1581 + 1582 + return skb; 1583 + 1584 + nla_put_failure: 1585 + kfree_skb(skb); 1586 + return NULL; 1587 + } 1588 + 1589 + struct sk_buff *__nfc_alloc_vendor_cmd_reply_skb(struct nfc_dev *dev, 1590 + enum nfc_attrs attr, 1591 + u32 oui, u32 subcmd, 1592 + int approxlen) 1593 + { 1594 + if (WARN_ON(!dev->cur_cmd_info)) 1595 + return NULL; 1596 + 1597 + return __nfc_alloc_vendor_cmd_skb(dev, approxlen, 1598 + dev->cur_cmd_info->snd_portid, 1599 + dev->cur_cmd_info->snd_seq, attr, 1600 + oui, subcmd, GFP_KERNEL); 1601 + } 1602 + EXPORT_SYMBOL(__nfc_alloc_vendor_cmd_reply_skb); 1603 + 1604 + int nfc_vendor_cmd_reply(struct sk_buff *skb) 1605 + { 1606 + struct nfc_dev *dev = ((void **)skb->cb)[0]; 1607 + void *hdr = ((void **)skb->cb)[1]; 1608 + 1609 + /* clear CB data for netlink core to own from now on */ 1610 + memset(skb->cb, 0, sizeof(skb->cb)); 1611 + 1612 + if (WARN_ON(!dev->cur_cmd_info)) { 1613 + kfree_skb(skb); 1614 + return -EINVAL; 1615 + } 1616 + 1617 + genlmsg_end(skb, hdr); 1618 + return genlmsg_reply(skb, dev->cur_cmd_info); 1619 + } 1620 + EXPORT_SYMBOL(nfc_vendor_cmd_reply); 1544 1621 1545 1622 static const struct genl_ops nfc_genl_ops[] = { 1546 1623 {