diff options
-rw-r--r-- | include/net/nfc/digital.h | 199 | ||||
-rw-r--r-- | net/nfc/Kconfig | 12 | ||||
-rw-r--r-- | net/nfc/Makefile | 2 | ||||
-rw-r--r-- | net/nfc/digital.h | 27 | ||||
-rw-r--r-- | net/nfc/digital_core.c | 151 |
5 files changed, 391 insertions, 0 deletions
diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h new file mode 100644 index 00000000000..8e16b6e0265 --- /dev/null +++ b/include/net/nfc/digital.h @@ -0,0 +1,199 @@ +/* + * NFC Digital Protocol stack + * Copyright (c) 2013, Intel Corporation. + * + * 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 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 __NFC_DIGITAL_H +#define __NFC_DIGITAL_H + +#include <linux/skbuff.h> +#include <net/nfc/nfc.h> + +/** + * Configuration types for in_configure_hw and tg_configure_hw. + */ +enum { + NFC_DIGITAL_CONFIG_RF_TECH = 0, + NFC_DIGITAL_CONFIG_FRAMING, +}; + +/** + * RF technology values passed as param argument to in_configure_hw and + * tg_configure_hw for NFC_DIGITAL_CONFIG_RF_TECH configuration type. + */ +enum { + NFC_DIGITAL_RF_TECH_106A = 0, + NFC_DIGITAL_RF_TECH_212F, + NFC_DIGITAL_RF_TECH_424F, + + NFC_DIGITAL_RF_TECH_LAST, +}; + +/** + * Framing configuration passed as param argument to in_configure_hw and + * tg_configure_hw for NFC_DIGITAL_CONFIG_FRAMING configuration type. + */ +enum { + NFC_DIGITAL_FRAMING_NFCA_SHORT = 0, + NFC_DIGITAL_FRAMING_NFCA_STANDARD, + NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A, + + NFC_DIGITAL_FRAMING_NFCA_T1T, + NFC_DIGITAL_FRAMING_NFCA_T2T, + NFC_DIGITAL_FRAMING_NFCA_NFC_DEP, + + NFC_DIGITAL_FRAMING_NFCF, + NFC_DIGITAL_FRAMING_NFCF_T3T, + NFC_DIGITAL_FRAMING_NFCF_NFC_DEP, + NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED, + + NFC_DIGITAL_FRAMING_LAST, +}; + +#define DIGITAL_MDAA_NFCID1_SIZE 3 + +struct digital_tg_mdaa_params { + u16 sens_res; + u8 nfcid1[DIGITAL_MDAA_NFCID1_SIZE]; + u8 sel_res; + + u8 nfcid2[NFC_NFCID2_MAXSIZE]; + u16 sc; +}; + +struct nfc_digital_dev; + +/** + * nfc_digital_cmd_complete_t - Definition of command result callback + * + * @ddev: nfc_digital_device ref + * @arg: user data + * @resp: response data + * + * resp pointer can be an error code and will be checked with IS_ERR() macro. + * The callback is responsible for freeing resp sk_buff. + */ +typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev, + void *arg, struct sk_buff *resp); + +/** + * Device side NFC Digital operations + * + * Initiator mode: + * @in_configure_hw: Hardware configuration for RF technology and communication + * framing in initiator mode. This is a synchronous function. + * @in_send_cmd: Initiator mode data exchange using RF technology and framing + * previously set with in_configure_hw. The peer response is returned + * through callback cb. If an io error occurs or the peer didn't reply + * within the specified timeout (ms), the error code is passed back through + * the resp pointer. This is an asynchronous function. + * + * Target mode: Only NFC-DEP protocol is supported in target mode. + * @tg_configure_hw: Hardware configuration for RF technology and communication + * framing in target mode. This is a synchronous function. + * @tg_send_cmd: Target mode data exchange using RF technology and framing + * previously set with tg_configure_hw. The peer next command is returned + * through callback cb. If an io error occurs or the peer didn't reply + * within the specified timeout (ms), the error code is passed back through + * the resp pointer. This is an asynchronous function. + * @tg_listen: Put the device in listen mode waiting for data from the peer + * device. This is an asynchronous function. + * @tg_listen_mdaa: If supported, put the device in automatic listen mode with + * mode detection and automatic anti-collision. In this mode, the device + * automatically detects the RF technology and executes the anti-collision + * detection using the command responses specified in mdaa_params. The + * mdaa_params structure contains SENS_RES, NFCID1, and SEL_RES for 106A RF + * tech. NFCID2 and system code (sc) for 212F and 424F. The driver returns + * the NFC-DEP ATR_REQ command through cb. The digital stack deducts the RF + * tech by analyzing the SoD of the frame containing the ATR_REQ command. + * This is an asynchronous function. + * + * @switch_rf: Turns device radio on or off. The stack does not call explicitly + * switch_rf to turn the radio on. A call to in|tg_configure_hw must turn + * the device radio on. + * @abort_cmd: Discard the last sent command. + */ +struct nfc_digital_ops { + int (*in_configure_hw)(struct nfc_digital_dev *ddev, int type, + int param); + int (*in_send_cmd)(struct nfc_digital_dev *ddev, struct sk_buff *skb, + u16 timeout, nfc_digital_cmd_complete_t cb, + void *arg); + + int (*tg_configure_hw)(struct nfc_digital_dev *ddev, int type, + int param); + int (*tg_send_cmd)(struct nfc_digital_dev *ddev, struct sk_buff *skb, + u16 timeout, nfc_digital_cmd_complete_t cb, + void *arg); + int (*tg_listen)(struct nfc_digital_dev *ddev, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg); + int (*tg_listen_mdaa)(struct nfc_digital_dev *ddev, + struct digital_tg_mdaa_params *mdaa_params, + u16 timeout, nfc_digital_cmd_complete_t cb, + void *arg); + + int (*switch_rf)(struct nfc_digital_dev *ddev, bool on); + void (*abort_cmd)(struct nfc_digital_dev *ddev); +}; + +/** + * Driver capabilities - bit mask made of the following values + * + * @NFC_DIGITAL_DRV_CAPS_IN_CRC: The driver handles CRC calculation in initiator + * mode. + * @NFC_DIGITAL_DRV_CAPS_TG_CRC: The driver handles CRC calculation in target + * mode. + */ +#define NFC_DIGITAL_DRV_CAPS_IN_CRC 0x0001 +#define NFC_DIGITAL_DRV_CAPS_TG_CRC 0x0002 + +struct nfc_digital_dev { + struct nfc_dev *nfc_dev; + struct nfc_digital_ops *ops; + + u32 protocols; + + int tx_headroom; + int tx_tailroom; + + u32 driver_capabilities; + void *driver_data; +}; + +struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, + __u32 supported_protocols, + __u32 driver_capabilities, + int tx_headroom, + int tx_tailroom); +void nfc_digital_free_device(struct nfc_digital_dev *ndev); +int nfc_digital_register_device(struct nfc_digital_dev *ndev); +void nfc_digital_unregister_device(struct nfc_digital_dev *ndev); + +static inline void nfc_digital_set_parent_dev(struct nfc_digital_dev *ndev, + struct device *dev) +{ + nfc_set_parent_dev(ndev->nfc_dev, dev); +} + +static inline void nfc_digital_set_drvdata(struct nfc_digital_dev *dev, + void *data) +{ + dev->driver_data = data; +} + +static inline void *nfc_digital_get_drvdata(struct nfc_digital_dev *dev) +{ + return dev->driver_data; +} + +#endif /* __NFC_DIGITAL_H */ diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig index 5948b2fc72f..13e1237e1ea 100644 --- a/net/nfc/Kconfig +++ b/net/nfc/Kconfig @@ -14,6 +14,18 @@ menuconfig NFC To compile this support as a module, choose M here: the module will be called nfc. +config NFC_DIGITAL + depends on NFC + tristate "NFC Digital Protocol stack support" + default n + help + Say Y if you want to build NFC digital protocol stack support. + This is needed by NFC chipsets whose firmware only implement + the NFC analog layer. + + To compile this support as a module, choose M here: the module will + be called nfc_digital. + source "net/nfc/nci/Kconfig" source "net/nfc/hci/Kconfig" diff --git a/net/nfc/Makefile b/net/nfc/Makefile index a76f4533cb6..8e0cabd85e9 100644 --- a/net/nfc/Makefile +++ b/net/nfc/Makefile @@ -5,7 +5,9 @@ obj-$(CONFIG_NFC) += nfc.o obj-$(CONFIG_NFC_NCI) += nci/ obj-$(CONFIG_NFC_HCI) += hci/ +obj-$(CONFIG_NFC_DIGITAL) += nfc_digital.o nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \ llcp_sock.o +nfc_digital-objs := digital_core.o diff --git a/net/nfc/digital.h b/net/nfc/digital.h new file mode 100644 index 00000000000..8d91ed82091 --- /dev/null +++ b/net/nfc/digital.h @@ -0,0 +1,27 @@ +/* + * NFC Digital Protocol stack + * Copyright (c) 2013, Intel Corporation. + * + * 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 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 __DIGITAL_H +#define __DIGITAL_H + +#include <net/nfc/nfc.h> +#include <net/nfc/digital.h> + +#define PR_DBG(fmt, ...) pr_debug("%s: " fmt "\n", __func__, ##__VA_ARGS__) +#define PR_ERR(fmt, ...) pr_err("%s: " fmt "\n", __func__, ##__VA_ARGS__) +#define PROTOCOL_ERR(req) pr_err("%s:%d: NFC Digital Protocol error: %s\n", \ + __func__, __LINE__, req) + +#endif /* __DIGITAL_H */ diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c new file mode 100644 index 00000000000..471188a0d2e --- /dev/null +++ b/net/nfc/digital_core.c @@ -0,0 +1,151 @@ +/* + * NFC Digital Protocol stack + * Copyright (c) 2013, Intel Corporation. + * + * 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 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. + * + */ + +#include <linux/module.h> + +#include "digital.h" + +static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, + __u32 tm_protocols) +{ + return -EOPNOTSUPP; +} + +static void digital_stop_poll(struct nfc_dev *nfc_dev) +{ +} + +static int digital_dev_up(struct nfc_dev *nfc_dev) +{ + return -EOPNOTSUPP; +} + +static int digital_dev_down(struct nfc_dev *nfc_dev) +{ + return -EOPNOTSUPP; +} + +static int digital_dep_link_up(struct nfc_dev *nfc_dev, + struct nfc_target *target, + __u8 comm_mode, __u8 *gb, size_t gb_len) +{ + return -EOPNOTSUPP; +} + +static int digital_dep_link_down(struct nfc_dev *nfc_dev) +{ + return -EOPNOTSUPP; +} + +static int digital_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, __u32 protocol) +{ + return -EOPNOTSUPP; +} + +static void digital_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) +{ +} + +static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, + struct sk_buff *skb, data_exchange_cb_t cb, + void *cb_context) +{ + return -EOPNOTSUPP; +} + +static struct nfc_ops digital_nfc_ops = { + .dev_up = digital_dev_up, + .dev_down = digital_dev_down, + .start_poll = digital_start_poll, + .stop_poll = digital_stop_poll, + .dep_link_up = digital_dep_link_up, + .dep_link_down = digital_dep_link_down, + .activate_target = digital_activate_target, + .deactivate_target = digital_deactivate_target, + .tm_send = digital_tg_send, + .im_transceive = digital_in_send, +}; + +struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, + __u32 supported_protocols, + __u32 driver_capabilities, + int tx_headroom, int tx_tailroom) +{ + struct nfc_digital_dev *ddev; + + if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || + !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || + !ops->switch_rf) + return NULL; + + ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); + if (!ddev) { + PR_ERR("kzalloc failed"); + return NULL; + } + + ddev->driver_capabilities = driver_capabilities; + ddev->ops = ops; + + ddev->tx_headroom = tx_headroom; + ddev->tx_tailroom = tx_tailroom; + + ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols, + ddev->tx_headroom, + ddev->tx_tailroom); + if (!ddev->nfc_dev) { + PR_ERR("nfc_allocate_device failed"); + goto free_dev; + } + + nfc_set_drvdata(ddev->nfc_dev, ddev); + + return ddev; + +free_dev: + kfree(ddev); + + return NULL; +} +EXPORT_SYMBOL(nfc_digital_allocate_device); + +void nfc_digital_free_device(struct nfc_digital_dev *ddev) +{ + nfc_free_device(ddev->nfc_dev); + + kfree(ddev); +} +EXPORT_SYMBOL(nfc_digital_free_device); + +int nfc_digital_register_device(struct nfc_digital_dev *ddev) +{ + return nfc_register_device(ddev->nfc_dev); +} +EXPORT_SYMBOL(nfc_digital_register_device); + +void nfc_digital_unregister_device(struct nfc_digital_dev *ddev) +{ + nfc_unregister_device(ddev->nfc_dev); +} +EXPORT_SYMBOL(nfc_digital_unregister_device); + +MODULE_LICENSE("GPL"); |