diff options
Diffstat (limited to 'net/nfc/nci')
| -rw-r--r-- | net/nfc/nci/core.c | 42 | ||||
| -rw-r--r-- | net/nfc/nci/data.c | 3 | ||||
| -rw-r--r-- | net/nfc/nci/lib.c | 3 | ||||
| -rw-r--r-- | net/nfc/nci/ntf.c | 10 | ||||
| -rw-r--r-- | net/nfc/nci/rsp.c | 3 | ||||
| -rw-r--r-- | net/nfc/nci/spi.c | 240 |
6 files changed, 131 insertions, 170 deletions
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index b943d46a164..2b400e1a869 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ @@ -75,7 +74,7 @@ static int __nci_request(struct nci_dev *ndev, ndev->req_status = NCI_REQ_PEND; - init_completion(&ndev->req_completion); + reinit_completion(&ndev->req_completion); req(ndev, opt); completion_rc = wait_for_completion_interruptible_timeout(&ndev->req_completion, @@ -302,6 +301,9 @@ static int nci_open_device(struct nci_dev *ndev) rc = __nci_request(ndev, nci_reset_req, 0, msecs_to_jiffies(NCI_RESET_TIMEOUT)); + if (ndev->ops->setup) + ndev->ops->setup(ndev); + if (!rc) { rc = __nci_request(ndev, nci_init_req, 0, msecs_to_jiffies(NCI_INIT_TIMEOUT)); @@ -362,6 +364,8 @@ static int nci_close_device(struct nci_dev *ndev) msecs_to_jiffies(NCI_RESET_TIMEOUT)); clear_bit(NCI_INIT, &ndev->flags); + del_timer_sync(&ndev->cmd_timer); + /* Flush cmd wq */ flush_workqueue(ndev->cmd_wq); @@ -409,12 +413,26 @@ static int nci_dev_down(struct nfc_dev *nfc_dev) return nci_close_device(ndev); } +int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val) +{ + struct nci_set_config_param param; + + if (!val || !len) + return 0; + + param.id = id; + param.len = len; + param.val = val; + + return __nci_request(ndev, nci_set_config_req, (unsigned long)¶m, + msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); +} +EXPORT_SYMBOL(nci_set_config); + static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_set_config_param param; - __u8 local_gb[NFC_MAX_GT_LEN]; - int i; param.val = nfc_get_local_general_bytes(nfc_dev, ¶m.len); if ((param.val == NULL) || (param.len == 0)) @@ -423,11 +441,7 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) if (param.len > NFC_MAX_GT_LEN) return -EINVAL; - for (i = 0; i < param.len; i++) - local_gb[param.len-1-i] = param.val[i]; - param.id = NCI_PN_ATR_REQ_GEN_BYTES; - param.val = local_gb; return nci_request(ndev, nci_set_config_req, (unsigned long)¶m, msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT)); @@ -695,6 +709,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops, ndev->ops = ops; ndev->tx_headroom = tx_headroom; ndev->tx_tailroom = tx_tailroom; + init_completion(&ndev->req_completion); ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops, supported_protocols, @@ -846,6 +861,10 @@ static int nci_send_frame(struct nci_dev *ndev, struct sk_buff *skb) /* Get rid of skb owner, prior to sending to the driver. */ skb_orphan(skb); + /* Send copy to sniffer */ + nfc_send_to_raw_sock(ndev->nfc_dev, skb, + RAW_PAYLOAD_NCI, NFC_DIRECTION_TX); + return ndev->ops->send(ndev, skb); } @@ -920,6 +939,11 @@ static void nci_rx_work(struct work_struct *work) struct sk_buff *skb; while ((skb = skb_dequeue(&ndev->rx_q))) { + + /* Send copy to sniffer */ + nfc_send_to_raw_sock(ndev->nfc_dev, skb, + RAW_PAYLOAD_NCI, NFC_DIRECTION_RX); + /* Process frame */ switch (nci_mt(skb->data)) { case NCI_MT_RSP_PKT: diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 2a9399dd6c6..6c3aef85287 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6b7fd26c68d..ed774a2e989 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index b2aa98ef092..f8f6af23138 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ @@ -367,7 +366,6 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, struct nci_rf_intf_activated_ntf *ntf, __u8 *data) { struct activation_params_poll_nfc_dep *poll; - int i; switch (ntf->activation_rf_tech_and_mode) { case NCI_NFC_A_PASSIVE_POLL_MODE: @@ -375,10 +373,8 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev, poll = &ntf->activation_params.poll_nfc_dep; poll->atr_res_len = min_t(__u8, *data++, 63); pr_debug("atr_res_len %d\n", poll->atr_res_len); - if (poll->atr_res_len > 0) { - for (i = 0; i < poll->atr_res_len; i++) - poll->atr_res[poll->atr_res_len-1-i] = data[i]; - } + if (poll->atr_res_len > 0) + memcpy(poll->atr_res, data, poll->atr_res_len); break; default: diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index dd072f38ad0..041de51ccdb 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see <http://www.gnu.org/licenses/>. * */ diff --git a/net/nfc/nci/spi.c b/net/nfc/nci/spi.c index c7cf37ba729..ec250e77763 100644 --- a/net/nfc/nci/spi.c +++ b/net/nfc/nci/spi.c @@ -21,11 +21,8 @@ #include <linux/export.h> #include <linux/spi/spi.h> #include <linux/crc-ccitt.h> -#include <linux/nfc.h> #include <net/nfc/nci_core.h> -#define NCI_SPI_HDR_LEN 4 -#define NCI_SPI_CRC_LEN 2 #define NCI_SPI_ACK_SHIFT 6 #define NCI_SPI_MSB_PAYLOAD_MASK 0x3F @@ -41,54 +38,48 @@ #define CRC_INIT 0xFFFF -static int nci_spi_open(struct nci_dev *nci_dev) -{ - struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev); - - return ndev->ops->open(ndev); -} - -static int nci_spi_close(struct nci_dev *nci_dev) -{ - struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev); - - return ndev->ops->close(ndev); -} - -static int __nci_spi_send(struct nci_spi_dev *ndev, struct sk_buff *skb) +static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb, + int cs_change) { struct spi_message m; struct spi_transfer t; - t.tx_buf = skb->data; - t.len = skb->len; - t.cs_change = 0; - t.delay_usecs = ndev->xfer_udelay; + memset(&t, 0, sizeof(struct spi_transfer)); + /* a NULL skb means we just want the SPI chip select line to raise */ + if (skb) { + t.tx_buf = skb->data; + t.len = skb->len; + } else { + /* still set tx_buf non NULL to make the driver happy */ + t.tx_buf = &t; + t.len = 0; + } + t.cs_change = cs_change; + t.delay_usecs = nspi->xfer_udelay; spi_message_init(&m); spi_message_add_tail(&t, &m); - return spi_sync(ndev->spi, &m); + return spi_sync(nspi->spi, &m); } -static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb) +int nci_spi_send(struct nci_spi *nspi, + struct completion *write_handshake_completion, + struct sk_buff *skb) { - struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev); unsigned int payload_len = skb->len; unsigned char *hdr; int ret; long completion_rc; - ndev->ops->deassert_int(ndev); - /* add the NCI SPI header to the start of the buffer */ hdr = skb_push(skb, NCI_SPI_HDR_LEN); hdr[0] = NCI_SPI_DIRECT_WRITE; - hdr[1] = ndev->acknowledge_mode; + hdr[1] = nspi->acknowledge_mode; hdr[2] = payload_len >> 8; hdr[3] = payload_len & 0xFF; - if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) { + if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { u16 crc; crc = crc_ccitt(CRC_INIT, skb->data, skb->len); @@ -96,123 +87,78 @@ static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb) *skb_put(skb, 1) = crc & 0xFF; } - ret = __nci_spi_send(ndev, skb); + if (write_handshake_completion) { + /* Trick SPI driver to raise chip select */ + ret = __nci_spi_send(nspi, NULL, 1); + if (ret) + goto done; - kfree_skb(skb); - ndev->ops->assert_int(ndev); + /* wait for NFC chip hardware handshake to complete */ + if (wait_for_completion_timeout(write_handshake_completion, + msecs_to_jiffies(1000)) == 0) { + ret = -ETIME; + goto done; + } + } - if (ret != 0 || ndev->acknowledge_mode == NCI_SPI_CRC_DISABLED) + ret = __nci_spi_send(nspi, skb, 0); + if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED) goto done; - init_completion(&ndev->req_completion); - completion_rc = - wait_for_completion_interruptible_timeout(&ndev->req_completion, - NCI_SPI_SEND_TIMEOUT); + reinit_completion(&nspi->req_completion); + completion_rc = wait_for_completion_interruptible_timeout( + &nspi->req_completion, + NCI_SPI_SEND_TIMEOUT); - if (completion_rc <= 0 || ndev->req_result == ACKNOWLEDGE_NACK) + if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK) ret = -EIO; done: + kfree_skb(skb); + return ret; } - -static struct nci_ops nci_spi_ops = { - .open = nci_spi_open, - .close = nci_spi_close, - .send = nci_spi_send, -}; +EXPORT_SYMBOL_GPL(nci_spi_send); /* ---- Interface to NCI SPI drivers ---- */ /** - * nci_spi_allocate_device - allocate a new nci spi device + * nci_spi_allocate_spi - allocate a new nci spi * * @spi: SPI device - * @ops: device operations - * @supported_protocols: NFC protocols supported by the device - * @supported_se: NFC Secure Elements supported by the device - * @acknowledge_mode: Acknowledge mode used by the device + * @acknowledge_mode: Acknowledge mode used by the NFC device * @delay: delay between transactions in us + * @ndev: nci dev to send incoming nci frames to */ -struct nci_spi_dev *nci_spi_allocate_device(struct spi_device *spi, - struct nci_spi_ops *ops, - u32 supported_protocols, - u32 supported_se, - u8 acknowledge_mode, - unsigned int delay) +struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi, + u8 acknowledge_mode, unsigned int delay, + struct nci_dev *ndev) { - struct nci_spi_dev *ndev; - int tailroom = 0; + struct nci_spi *nspi; - if (!ops->open || !ops->close || !ops->assert_int || !ops->deassert_int) + nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL); + if (!nspi) return NULL; - if (!supported_protocols) - return NULL; - - ndev = devm_kzalloc(&spi->dev, sizeof(struct nci_dev), GFP_KERNEL); - if (!ndev) - return NULL; + nspi->acknowledge_mode = acknowledge_mode; + nspi->xfer_udelay = delay; - ndev->ops = ops; - ndev->acknowledge_mode = acknowledge_mode; - ndev->xfer_udelay = delay; + nspi->spi = spi; + nspi->ndev = ndev; + init_completion(&nspi->req_completion); - if (acknowledge_mode == NCI_SPI_CRC_ENABLED) - tailroom += NCI_SPI_CRC_LEN; - - ndev->nci_dev = nci_allocate_device(&nci_spi_ops, supported_protocols, - NCI_SPI_HDR_LEN, tailroom); - if (!ndev->nci_dev) - return NULL; - - nci_set_drvdata(ndev->nci_dev, ndev); - - return ndev; + return nspi; } -EXPORT_SYMBOL_GPL(nci_spi_allocate_device); +EXPORT_SYMBOL_GPL(nci_spi_allocate_spi); -/** - * nci_spi_free_device - deallocate nci spi device - * - * @ndev: The nci spi device to deallocate - */ -void nci_spi_free_device(struct nci_spi_dev *ndev) -{ - nci_free_device(ndev->nci_dev); -} -EXPORT_SYMBOL_GPL(nci_spi_free_device); - -/** - * nci_spi_register_device - register a nci spi device in the nfc subsystem - * - * @pdev: The nci spi device to register - */ -int nci_spi_register_device(struct nci_spi_dev *ndev) -{ - return nci_register_device(ndev->nci_dev); -} -EXPORT_SYMBOL_GPL(nci_spi_register_device); - -/** - * nci_spi_unregister_device - unregister a nci spi device in the nfc subsystem - * - * @dev: The nci spi device to unregister - */ -void nci_spi_unregister_device(struct nci_spi_dev *ndev) -{ - nci_unregister_device(ndev->nci_dev); -} -EXPORT_SYMBOL_GPL(nci_spi_unregister_device); - -static int send_acknowledge(struct nci_spi_dev *ndev, u8 acknowledge) +static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge) { struct sk_buff *skb; unsigned char *hdr; u16 crc; int ret; - skb = nci_skb_alloc(ndev->nci_dev, 0, GFP_KERNEL); + skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL); /* add the NCI SPI header to the start of the buffer */ hdr = skb_push(skb, NCI_SPI_HDR_LEN); @@ -225,14 +171,14 @@ static int send_acknowledge(struct nci_spi_dev *ndev, u8 acknowledge) *skb_put(skb, 1) = crc >> 8; *skb_put(skb, 1) = crc & 0xFF; - ret = __nci_spi_send(ndev, skb); + ret = __nci_spi_send(nspi, skb, 0); kfree_skb(skb); return ret; } -static struct sk_buff *__nci_spi_recv_frame(struct nci_spi_dev *ndev) +static struct sk_buff *__nci_spi_read(struct nci_spi *nspi) { struct sk_buff *skb; struct spi_message m; @@ -242,43 +188,49 @@ static struct sk_buff *__nci_spi_recv_frame(struct nci_spi_dev *ndev) int ret; spi_message_init(&m); + + memset(&tx, 0, sizeof(struct spi_transfer)); req[0] = NCI_SPI_DIRECT_READ; - req[1] = ndev->acknowledge_mode; + req[1] = nspi->acknowledge_mode; tx.tx_buf = req; tx.len = 2; tx.cs_change = 0; spi_message_add_tail(&tx, &m); + + memset(&rx, 0, sizeof(struct spi_transfer)); rx.rx_buf = resp_hdr; rx.len = 2; rx.cs_change = 1; spi_message_add_tail(&rx, &m); - ret = spi_sync(ndev->spi, &m); + ret = spi_sync(nspi->spi, &m); if (ret) return NULL; - if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) + if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) + resp_hdr[1] + NCI_SPI_CRC_LEN; else rx_len = (resp_hdr[0] << 8) | resp_hdr[1]; - skb = nci_skb_alloc(ndev->nci_dev, rx_len, GFP_KERNEL); + skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL); if (!skb) return NULL; spi_message_init(&m); + + memset(&rx, 0, sizeof(struct spi_transfer)); rx.rx_buf = skb_put(skb, rx_len); rx.len = rx_len; rx.cs_change = 0; - rx.delay_usecs = ndev->xfer_udelay; + rx.delay_usecs = nspi->xfer_udelay; spi_message_add_tail(&rx, &m); - ret = spi_sync(ndev->spi, &m); + ret = spi_sync(nspi->spi, &m); if (ret) goto receive_error; - if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) { + if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { *skb_push(skb, 1) = resp_hdr[1]; *skb_push(skb, 1) = resp_hdr[0]; } @@ -318,61 +270,53 @@ static u8 nci_spi_get_ack(struct sk_buff *skb) } /** - * nci_spi_recv_frame - receive frame from NCI SPI drivers + * nci_spi_read - read frame from NCI SPI drivers * - * @ndev: The nci spi device + * @nspi: The nci spi * Context: can sleep * * This call may only be used from a context that may sleep. The sleep * is non-interruptible, and has no timeout. * - * It returns zero on success, else a negative error code. + * It returns an allocated skb containing the frame on success, or NULL. */ -int nci_spi_recv_frame(struct nci_spi_dev *ndev) +struct sk_buff *nci_spi_read(struct nci_spi *nspi) { struct sk_buff *skb; - int ret = 0; - - ndev->ops->deassert_int(ndev); /* Retrieve frame from SPI */ - skb = __nci_spi_recv_frame(ndev); - if (!skb) { - ret = -EIO; + skb = __nci_spi_read(nspi); + if (!skb) goto done; - } - if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) { + if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { if (!nci_spi_check_crc(skb)) { - send_acknowledge(ndev, ACKNOWLEDGE_NACK); + send_acknowledge(nspi, ACKNOWLEDGE_NACK); goto done; } /* In case of acknowledged mode: if ACK or NACK received, * unblock completion of latest frame sent. */ - ndev->req_result = nci_spi_get_ack(skb); - if (ndev->req_result) - complete(&ndev->req_completion); + nspi->req_result = nci_spi_get_ack(skb); + if (nspi->req_result) + complete(&nspi->req_completion); } /* If there is no payload (ACK/NACK only frame), * free the socket buffer */ - if (skb->len == 0) { + if (!skb->len) { kfree_skb(skb); + skb = NULL; goto done; } - if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) - send_acknowledge(ndev, ACKNOWLEDGE_ACK); - - /* Forward skb to NCI core layer */ - ret = nci_recv_frame(ndev->nci_dev, skb); + if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) + send_acknowledge(nspi, ACKNOWLEDGE_ACK); done: - ndev->ops->assert_int(ndev); - return ret; + return skb; } -EXPORT_SYMBOL_GPL(nci_spi_recv_frame); +EXPORT_SYMBOL_GPL(nci_spi_read); |
