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 (4762B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NCI based driver for Samsung S3FWRN5 NFC chip
      4 *
      5 * Copyright (C) 2015 Samsung Electrnoics
      6 * Robert Baldyga <r.baldyga@samsung.com>
      7 */
      8
      9#include <linux/module.h>
     10#include <net/nfc/nci_core.h>
     11
     12#include "s3fwrn5.h"
     13#include "firmware.h"
     14#include "nci.h"
     15
     16#define S3FWRN5_NFC_PROTOCOLS  (NFC_PROTO_JEWEL_MASK | \
     17				NFC_PROTO_MIFARE_MASK | \
     18				NFC_PROTO_FELICA_MASK | \
     19				NFC_PROTO_ISO14443_MASK | \
     20				NFC_PROTO_ISO14443_B_MASK | \
     21				NFC_PROTO_ISO15693_MASK)
     22
     23static int s3fwrn5_firmware_init(struct s3fwrn5_info *info)
     24{
     25	struct s3fwrn5_fw_info *fw_info = &info->fw_info;
     26	int ret;
     27
     28	s3fwrn5_fw_init(fw_info, "sec_s3fwrn5_firmware.bin");
     29
     30	/* Get firmware data */
     31	ret = s3fwrn5_fw_request_firmware(fw_info);
     32	if (ret < 0)
     33		dev_err(&fw_info->ndev->nfc_dev->dev,
     34			"Failed to get fw file, ret=%02x\n", ret);
     35	return ret;
     36}
     37
     38static int s3fwrn5_firmware_update(struct s3fwrn5_info *info)
     39{
     40	bool need_update;
     41	int ret;
     42
     43	/* Update firmware */
     44
     45	s3fwrn5_set_wake(info, false);
     46	s3fwrn5_set_mode(info, S3FWRN5_MODE_FW);
     47
     48	ret = s3fwrn5_fw_setup(&info->fw_info);
     49	if (ret < 0)
     50		return ret;
     51
     52	need_update = s3fwrn5_fw_check_version(&info->fw_info,
     53		info->ndev->manufact_specific_info);
     54	if (!need_update)
     55		goto out;
     56
     57	dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n");
     58
     59	ret = s3fwrn5_fw_download(&info->fw_info);
     60	if (ret < 0)
     61		goto out;
     62
     63	/* Update RF configuration */
     64
     65	s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
     66
     67	s3fwrn5_set_wake(info, true);
     68	ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin");
     69	s3fwrn5_set_wake(info, false);
     70
     71out:
     72	s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
     73	s3fwrn5_fw_cleanup(&info->fw_info);
     74	return ret;
     75}
     76
     77static int s3fwrn5_nci_open(struct nci_dev *ndev)
     78{
     79	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
     80
     81	if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD)
     82		return  -EBUSY;
     83
     84	s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
     85	s3fwrn5_set_wake(info, true);
     86
     87	return 0;
     88}
     89
     90static int s3fwrn5_nci_close(struct nci_dev *ndev)
     91{
     92	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
     93
     94	s3fwrn5_set_wake(info, false);
     95	s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
     96
     97	return 0;
     98}
     99
    100static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
    101{
    102	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
    103	int ret;
    104
    105	mutex_lock(&info->mutex);
    106
    107	if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) {
    108		mutex_unlock(&info->mutex);
    109		return -EINVAL;
    110	}
    111
    112	ret = s3fwrn5_write(info, skb);
    113	if (ret < 0)
    114		kfree_skb(skb);
    115
    116	mutex_unlock(&info->mutex);
    117	return ret;
    118}
    119
    120static int s3fwrn5_nci_post_setup(struct nci_dev *ndev)
    121{
    122	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
    123	int ret;
    124
    125	if (s3fwrn5_firmware_init(info)) {
    126		//skip bootloader mode
    127		return 0;
    128	}
    129
    130	ret = s3fwrn5_firmware_update(info);
    131	if (ret < 0)
    132		return ret;
    133
    134	/* NCI core reset */
    135
    136	s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
    137	s3fwrn5_set_wake(info, true);
    138
    139	ret = nci_core_reset(info->ndev);
    140	if (ret < 0)
    141		return ret;
    142
    143	return nci_core_init(info->ndev);
    144}
    145
    146static const struct nci_ops s3fwrn5_nci_ops = {
    147	.open = s3fwrn5_nci_open,
    148	.close = s3fwrn5_nci_close,
    149	.send = s3fwrn5_nci_send,
    150	.post_setup = s3fwrn5_nci_post_setup,
    151	.prop_ops = s3fwrn5_nci_prop_ops,
    152	.n_prop_ops = ARRAY_SIZE(s3fwrn5_nci_prop_ops),
    153};
    154
    155int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
    156	const struct s3fwrn5_phy_ops *phy_ops)
    157{
    158	struct s3fwrn5_info *info;
    159	int ret;
    160
    161	info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL);
    162	if (!info)
    163		return -ENOMEM;
    164
    165	info->phy_id = phy_id;
    166	info->pdev = pdev;
    167	info->phy_ops = phy_ops;
    168	mutex_init(&info->mutex);
    169
    170	s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
    171
    172	info->ndev = nci_allocate_device(&s3fwrn5_nci_ops,
    173		S3FWRN5_NFC_PROTOCOLS, 0, 0);
    174	if (!info->ndev)
    175		return -ENOMEM;
    176
    177	nci_set_parent_dev(info->ndev, pdev);
    178	nci_set_drvdata(info->ndev, info);
    179
    180	ret = nci_register_device(info->ndev);
    181	if (ret < 0) {
    182		nci_free_device(info->ndev);
    183		return ret;
    184	}
    185
    186	info->fw_info.ndev = info->ndev;
    187
    188	*ndev = info->ndev;
    189
    190	return ret;
    191}
    192EXPORT_SYMBOL(s3fwrn5_probe);
    193
    194void s3fwrn5_remove(struct nci_dev *ndev)
    195{
    196	struct s3fwrn5_info *info = nci_get_drvdata(ndev);
    197
    198	s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
    199
    200	nci_unregister_device(ndev);
    201	nci_free_device(ndev);
    202}
    203EXPORT_SYMBOL(s3fwrn5_remove);
    204
    205int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,
    206	enum s3fwrn5_mode mode)
    207{
    208	switch (mode) {
    209	case S3FWRN5_MODE_NCI:
    210		return nci_recv_frame(ndev, skb);
    211	case S3FWRN5_MODE_FW:
    212		return s3fwrn5_fw_recv_frame(ndev, skb);
    213	default:
    214		kfree_skb(skb);
    215		return -ENODEV;
    216	}
    217}
    218EXPORT_SYMBOL(s3fwrn5_recv_frame);
    219
    220MODULE_LICENSE("GPL");
    221MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
    222MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");