cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core.c (3589B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Generic driver for NXP NCI NFC chips
      4 *
      5 * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
      6 *
      7 * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
      8 *
      9 * Derived from PN544 device driver:
     10 * Copyright (C) 2012  Intel Corporation. All rights reserved.
     11 */
     12
     13#include <linux/delay.h>
     14#include <linux/module.h>
     15#include <linux/nfc.h>
     16
     17#include <net/nfc/nci_core.h>
     18
     19#include "nxp-nci.h"
     20
     21#define NXP_NCI_HDR_LEN	4
     22
     23#define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
     24			       NFC_PROTO_MIFARE_MASK | \
     25			       NFC_PROTO_FELICA_MASK | \
     26			       NFC_PROTO_ISO14443_MASK | \
     27			       NFC_PROTO_ISO14443_B_MASK | \
     28			       NFC_PROTO_NFC_DEP_MASK)
     29
     30static int nxp_nci_open(struct nci_dev *ndev)
     31{
     32	struct nxp_nci_info *info = nci_get_drvdata(ndev);
     33	int r = 0;
     34
     35	mutex_lock(&info->info_lock);
     36
     37	if (info->mode != NXP_NCI_MODE_COLD) {
     38		r = -EBUSY;
     39		goto open_exit;
     40	}
     41
     42	if (info->phy_ops->set_mode)
     43		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI);
     44
     45	info->mode = NXP_NCI_MODE_NCI;
     46
     47open_exit:
     48	mutex_unlock(&info->info_lock);
     49	return r;
     50}
     51
     52static int nxp_nci_close(struct nci_dev *ndev)
     53{
     54	struct nxp_nci_info *info = nci_get_drvdata(ndev);
     55	int r = 0;
     56
     57	mutex_lock(&info->info_lock);
     58
     59	if (info->phy_ops->set_mode)
     60		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
     61
     62	info->mode = NXP_NCI_MODE_COLD;
     63
     64	mutex_unlock(&info->info_lock);
     65	return r;
     66}
     67
     68static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
     69{
     70	struct nxp_nci_info *info = nci_get_drvdata(ndev);
     71	int r;
     72
     73	if (!info->phy_ops->write)
     74		return -EOPNOTSUPP;
     75
     76	if (info->mode != NXP_NCI_MODE_NCI)
     77		return -EINVAL;
     78
     79	r = info->phy_ops->write(info->phy_id, skb);
     80	if (r < 0)
     81		kfree_skb(skb);
     82
     83	return r;
     84}
     85
     86static const struct nci_ops nxp_nci_ops = {
     87	.open = nxp_nci_open,
     88	.close = nxp_nci_close,
     89	.send = nxp_nci_send,
     90	.fw_download = nxp_nci_fw_download,
     91};
     92
     93int nxp_nci_probe(void *phy_id, struct device *pdev,
     94		  const struct nxp_nci_phy_ops *phy_ops,
     95		  unsigned int max_payload,
     96		  struct nci_dev **ndev)
     97{
     98	struct nxp_nci_info *info;
     99	int r;
    100
    101	info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
    102	if (!info)
    103		return -ENOMEM;
    104
    105	info->phy_id = phy_id;
    106	info->pdev = pdev;
    107	info->phy_ops = phy_ops;
    108	info->max_payload = max_payload;
    109	INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
    110	init_completion(&info->fw_info.cmd_completion);
    111	mutex_init(&info->info_lock);
    112
    113	if (info->phy_ops->set_mode) {
    114		r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
    115		if (r < 0)
    116			return r;
    117	}
    118
    119	info->mode = NXP_NCI_MODE_COLD;
    120
    121	info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
    122					 NXP_NCI_HDR_LEN, 0);
    123	if (!info->ndev)
    124		return -ENOMEM;
    125
    126	nci_set_parent_dev(info->ndev, pdev);
    127	nci_set_drvdata(info->ndev, info);
    128	r = nci_register_device(info->ndev);
    129	if (r < 0) {
    130		nci_free_device(info->ndev);
    131		return r;
    132	}
    133
    134	*ndev = info->ndev;
    135	return r;
    136}
    137EXPORT_SYMBOL(nxp_nci_probe);
    138
    139void nxp_nci_remove(struct nci_dev *ndev)
    140{
    141	struct nxp_nci_info *info = nci_get_drvdata(ndev);
    142
    143	if (info->mode == NXP_NCI_MODE_FW)
    144		nxp_nci_fw_work_complete(info, -ESHUTDOWN);
    145	cancel_work_sync(&info->fw_info.work);
    146
    147	mutex_lock(&info->info_lock);
    148
    149	if (info->phy_ops->set_mode)
    150		info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
    151
    152	nci_unregister_device(ndev);
    153	nci_free_device(ndev);
    154
    155	mutex_unlock(&info->info_lock);
    156}
    157EXPORT_SYMBOL(nxp_nci_remove);
    158
    159MODULE_LICENSE("GPL");
    160MODULE_DESCRIPTION("NXP NCI NFC driver");
    161MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");