core.c (3858B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * NCI based Driver for STMicroelectronics NFC Chip 4 * 5 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 6 */ 7 8#include <linux/module.h> 9#include <linux/nfc.h> 10#include <net/nfc/nci.h> 11#include <net/nfc/nci_core.h> 12 13#include "st-nci.h" 14 15#define DRIVER_DESC "NCI NFC driver for ST_NCI" 16 17#define ST_NCI1_X_PROPRIETARY_ISO15693 0x83 18 19static int st_nci_init(struct nci_dev *ndev) 20{ 21 struct nci_mode_set_cmd cmd; 22 23 cmd.cmd_type = ST_NCI_SET_NFC_MODE; 24 cmd.mode = 1; 25 26 return nci_prop_cmd(ndev, ST_NCI_CORE_PROP, 27 sizeof(struct nci_mode_set_cmd), (__u8 *)&cmd); 28} 29 30static int st_nci_open(struct nci_dev *ndev) 31{ 32 struct st_nci_info *info = nci_get_drvdata(ndev); 33 int r; 34 35 if (test_and_set_bit(ST_NCI_RUNNING, &info->flags)) 36 return 0; 37 38 r = ndlc_open(info->ndlc); 39 if (r) 40 clear_bit(ST_NCI_RUNNING, &info->flags); 41 42 return r; 43} 44 45static int st_nci_close(struct nci_dev *ndev) 46{ 47 struct st_nci_info *info = nci_get_drvdata(ndev); 48 49 if (!test_bit(ST_NCI_RUNNING, &info->flags)) 50 return 0; 51 52 ndlc_close(info->ndlc); 53 54 clear_bit(ST_NCI_RUNNING, &info->flags); 55 56 return 0; 57} 58 59static int st_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 60{ 61 struct st_nci_info *info = nci_get_drvdata(ndev); 62 63 skb->dev = (void *)ndev; 64 65 if (!test_bit(ST_NCI_RUNNING, &info->flags)) 66 return -EBUSY; 67 68 return ndlc_send(info->ndlc, skb); 69} 70 71static __u32 st_nci_get_rfprotocol(struct nci_dev *ndev, 72 __u8 rf_protocol) 73{ 74 return rf_protocol == ST_NCI1_X_PROPRIETARY_ISO15693 ? 75 NFC_PROTO_ISO15693_MASK : 0; 76} 77 78static int st_nci_prop_rsp_packet(struct nci_dev *ndev, 79 struct sk_buff *skb) 80{ 81 __u8 status = skb->data[0]; 82 83 nci_req_complete(ndev, status); 84 return 0; 85} 86 87static const struct nci_driver_ops st_nci_prop_ops[] = { 88 { 89 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY, 90 ST_NCI_CORE_PROP), 91 .rsp = st_nci_prop_rsp_packet, 92 }, 93}; 94 95static const struct nci_ops st_nci_ops = { 96 .init = st_nci_init, 97 .open = st_nci_open, 98 .close = st_nci_close, 99 .send = st_nci_send, 100 .get_rfprotocol = st_nci_get_rfprotocol, 101 .discover_se = st_nci_discover_se, 102 .enable_se = st_nci_enable_se, 103 .disable_se = st_nci_disable_se, 104 .se_io = st_nci_se_io, 105 .hci_load_session = st_nci_hci_load_session, 106 .hci_event_received = st_nci_hci_event_received, 107 .hci_cmd_received = st_nci_hci_cmd_received, 108 .prop_ops = st_nci_prop_ops, 109 .n_prop_ops = ARRAY_SIZE(st_nci_prop_ops), 110}; 111 112int st_nci_probe(struct llt_ndlc *ndlc, int phy_headroom, 113 int phy_tailroom, struct st_nci_se_status *se_status) 114{ 115 struct st_nci_info *info; 116 int r; 117 u32 protocols; 118 119 info = devm_kzalloc(ndlc->dev, 120 sizeof(struct st_nci_info), GFP_KERNEL); 121 if (!info) 122 return -ENOMEM; 123 124 protocols = NFC_PROTO_JEWEL_MASK 125 | NFC_PROTO_MIFARE_MASK 126 | NFC_PROTO_FELICA_MASK 127 | NFC_PROTO_ISO14443_MASK 128 | NFC_PROTO_ISO14443_B_MASK 129 | NFC_PROTO_ISO15693_MASK 130 | NFC_PROTO_NFC_DEP_MASK; 131 132 BUILD_BUG_ON(ARRAY_SIZE(st_nci_prop_ops) > NCI_MAX_PROPRIETARY_CMD); 133 ndlc->ndev = nci_allocate_device(&st_nci_ops, protocols, 134 phy_headroom, phy_tailroom); 135 if (!ndlc->ndev) { 136 pr_err("Cannot allocate nfc ndev\n"); 137 return -ENOMEM; 138 } 139 info->ndlc = ndlc; 140 141 nci_set_drvdata(ndlc->ndev, info); 142 143 r = st_nci_vendor_cmds_init(ndlc->ndev); 144 if (r) { 145 pr_err("Cannot register proprietary vendor cmds\n"); 146 goto err_reg_dev; 147 } 148 149 r = nci_register_device(ndlc->ndev); 150 if (r) { 151 pr_err("Cannot register nfc device to nci core\n"); 152 goto err_reg_dev; 153 } 154 155 return st_nci_se_init(ndlc->ndev, se_status); 156 157err_reg_dev: 158 nci_free_device(ndlc->ndev); 159 return r; 160} 161EXPORT_SYMBOL_GPL(st_nci_probe); 162 163void st_nci_remove(struct nci_dev *ndev) 164{ 165 struct st_nci_info *info = nci_get_drvdata(ndev); 166 167 ndlc_close(info->ndlc); 168 169 nci_unregister_device(ndev); 170 nci_free_device(ndev); 171} 172EXPORT_SYMBOL_GPL(st_nci_remove); 173 174MODULE_LICENSE("GPL"); 175MODULE_DESCRIPTION(DRIVER_DESC);