1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Proprietary commands extension for STMicroelectronics NFC Chip 4 * 5 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 6 */ 7 8 #include <net/genetlink.h> 9 #include <linux/module.h> 10 #include <linux/nfc.h> 11 #include <net/nfc/hci.h> 12 #include <net/nfc/llc.h> 13 14 #include "st21nfca.h" 15 16 #define ST21NFCA_HCI_DM_GETDATA 0x10 17 #define ST21NFCA_HCI_DM_PUTDATA 0x11 18 #define ST21NFCA_HCI_DM_LOAD 0x12 19 #define ST21NFCA_HCI_DM_GETINFO 0x13 20 #define ST21NFCA_HCI_DM_UPDATE_AID 0x20 21 #define ST21NFCA_HCI_DM_RESET 0x3e 22 23 #define ST21NFCA_HCI_DM_FIELD_GENERATOR 0x32 24 25 #define ST21NFCA_FACTORY_MODE_ON 1 26 #define ST21NFCA_FACTORY_MODE_OFF 0 27 28 #define ST21NFCA_EVT_POST_DATA 0x02 29 30 struct get_param_data { 31 u8 gate; 32 u8 data; 33 } __packed; 34 35 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data, 36 size_t data_len) 37 { 38 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 39 40 if (data_len != 1) 41 return -EINVAL; 42 43 pr_debug("factory mode: %x\n", ((u8 *)data)[0]); 44 45 switch (((u8 *)data)[0]) { 46 case ST21NFCA_FACTORY_MODE_ON: 47 test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks); 48 break; 49 case ST21NFCA_FACTORY_MODE_OFF: 50 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks); 51 break; 52 default: 53 return -EINVAL; 54 } 55 56 return 0; 57 } 58 59 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data, 60 size_t data_len) 61 { 62 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 63 64 return nfc_hci_disconnect_all_gates(hdev); 65 } 66 67 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data, 68 size_t data_len) 69 { 70 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 71 72 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, 73 ST21NFCA_HCI_DM_PUTDATA, data, 74 data_len, NULL); 75 } 76 77 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data, 78 size_t data_len) 79 { 80 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 81 82 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, 83 ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL); 84 } 85 86 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data, 87 size_t data_len) 88 { 89 int r; 90 struct sk_buff *msg, *skb; 91 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 92 93 r = nfc_hci_send_cmd(hdev, 94 ST21NFCA_DEVICE_MGNT_GATE, 95 ST21NFCA_HCI_DM_GETINFO, 96 data, data_len, &skb); 97 if (r) 98 goto exit; 99 100 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI, 101 HCI_DM_GET_INFO, skb->len); 102 if (!msg) { 103 r = -ENOMEM; 104 goto free_skb; 105 } 106 107 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 108 kfree_skb(msg); 109 r = -ENOBUFS; 110 goto free_skb; 111 } 112 113 r = nfc_vendor_cmd_reply(msg); 114 115 free_skb: 116 kfree_skb(skb); 117 exit: 118 return r; 119 } 120 121 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data, 122 size_t data_len) 123 { 124 int r; 125 struct sk_buff *msg, *skb; 126 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 127 128 r = nfc_hci_send_cmd(hdev, 129 ST21NFCA_DEVICE_MGNT_GATE, 130 ST21NFCA_HCI_DM_GETDATA, 131 data, data_len, &skb); 132 if (r) 133 goto exit; 134 135 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI, 136 HCI_DM_GET_DATA, skb->len); 137 if (!msg) { 138 r = -ENOMEM; 139 goto free_skb; 140 } 141 142 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 143 kfree_skb(msg); 144 r = -ENOBUFS; 145 goto free_skb; 146 } 147 148 r = nfc_vendor_cmd_reply(msg); 149 150 free_skb: 151 kfree_skb(skb); 152 exit: 153 return r; 154 } 155 156 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data, 157 size_t data_len) 158 { 159 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 160 161 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, 162 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL); 163 } 164 165 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data, 166 size_t data_len) 167 { 168 int r; 169 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 170 171 r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE, 172 ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL); 173 if (r < 0) 174 return r; 175 176 r = nfc_llc_stop(hdev->llc); 177 if (r < 0) 178 return r; 179 180 return nfc_llc_start(hdev->llc); 181 } 182 183 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data, 184 size_t data_len) 185 { 186 int r; 187 struct sk_buff *msg, *skb; 188 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 189 struct get_param_data *param = (struct get_param_data *)data; 190 191 if (data_len < sizeof(struct get_param_data)) 192 return -EPROTO; 193 194 r = nfc_hci_get_param(hdev, param->gate, param->data, &skb); 195 if (r) 196 goto exit; 197 198 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI, 199 HCI_GET_PARAM, skb->len); 200 if (!msg) { 201 r = -ENOMEM; 202 goto free_skb; 203 } 204 205 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 206 kfree_skb(msg); 207 r = -ENOBUFS; 208 goto free_skb; 209 } 210 211 r = nfc_vendor_cmd_reply(msg); 212 213 free_skb: 214 kfree_skb(skb); 215 exit: 216 return r; 217 } 218 219 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data, 220 size_t data_len) 221 { 222 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 223 224 return nfc_hci_send_cmd(hdev, 225 ST21NFCA_DEVICE_MGNT_GATE, 226 ST21NFCA_HCI_DM_FIELD_GENERATOR, 227 data, data_len, NULL); 228 } 229 230 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event, 231 struct sk_buff *skb) 232 { 233 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 234 235 switch (event) { 236 case ST21NFCA_EVT_POST_DATA: 237 info->vendor_info.rx_skb = skb; 238 break; 239 default: 240 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n"); 241 } 242 complete(&info->vendor_info.req_completion); 243 return 0; 244 } 245 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received); 246 247 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data, 248 size_t data_len) 249 { 250 int r; 251 struct sk_buff *msg; 252 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev); 253 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 254 255 if (data_len <= 0) 256 return -EPROTO; 257 258 reinit_completion(&info->vendor_info.req_completion); 259 info->vendor_info.rx_skb = NULL; 260 261 r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE, 262 ST21NFCA_EVT_POST_DATA, data, data_len); 263 if (r < 0) { 264 r = -EPROTO; 265 goto exit; 266 } 267 268 wait_for_completion_interruptible(&info->vendor_info.req_completion); 269 if (!info->vendor_info.rx_skb || 270 info->vendor_info.rx_skb->len != data_len) { 271 r = -EPROTO; 272 goto exit; 273 } 274 275 msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev, 276 ST21NFCA_VENDOR_OUI, 277 HCI_LOOPBACK, 278 info->vendor_info.rx_skb->len); 279 if (!msg) { 280 r = -ENOMEM; 281 goto free_skb; 282 } 283 284 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len, 285 info->vendor_info.rx_skb->data)) { 286 kfree_skb(msg); 287 r = -ENOBUFS; 288 goto free_skb; 289 } 290 291 r = nfc_vendor_cmd_reply(msg); 292 free_skb: 293 kfree_skb(info->vendor_info.rx_skb); 294 exit: 295 return r; 296 } 297 298 static const struct nfc_vendor_cmd st21nfca_vendor_cmds[] = { 299 { 300 .vendor_id = ST21NFCA_VENDOR_OUI, 301 .subcmd = FACTORY_MODE, 302 .doit = st21nfca_factory_mode, 303 }, 304 { 305 .vendor_id = ST21NFCA_VENDOR_OUI, 306 .subcmd = HCI_CLEAR_ALL_PIPES, 307 .doit = st21nfca_hci_clear_all_pipes, 308 }, 309 { 310 .vendor_id = ST21NFCA_VENDOR_OUI, 311 .subcmd = HCI_DM_PUT_DATA, 312 .doit = st21nfca_hci_dm_put_data, 313 }, 314 { 315 .vendor_id = ST21NFCA_VENDOR_OUI, 316 .subcmd = HCI_DM_UPDATE_AID, 317 .doit = st21nfca_hci_dm_update_aid, 318 }, 319 { 320 .vendor_id = ST21NFCA_VENDOR_OUI, 321 .subcmd = HCI_DM_GET_INFO, 322 .doit = st21nfca_hci_dm_get_info, 323 }, 324 { 325 .vendor_id = ST21NFCA_VENDOR_OUI, 326 .subcmd = HCI_DM_GET_DATA, 327 .doit = st21nfca_hci_dm_get_data, 328 }, 329 { 330 .vendor_id = ST21NFCA_VENDOR_OUI, 331 .subcmd = HCI_DM_LOAD, 332 .doit = st21nfca_hci_dm_load, 333 }, 334 { 335 .vendor_id = ST21NFCA_VENDOR_OUI, 336 .subcmd = HCI_DM_RESET, 337 .doit = st21nfca_hci_dm_reset, 338 }, 339 { 340 .vendor_id = ST21NFCA_VENDOR_OUI, 341 .subcmd = HCI_GET_PARAM, 342 .doit = st21nfca_hci_get_param, 343 }, 344 { 345 .vendor_id = ST21NFCA_VENDOR_OUI, 346 .subcmd = HCI_DM_FIELD_GENERATOR, 347 .doit = st21nfca_hci_dm_field_generator, 348 }, 349 { 350 .vendor_id = ST21NFCA_VENDOR_OUI, 351 .subcmd = HCI_LOOPBACK, 352 .doit = st21nfca_hci_loopback, 353 }, 354 }; 355 356 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev) 357 { 358 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); 359 360 init_completion(&info->vendor_info.req_completion); 361 return nfc_hci_set_vendor_cmds(hdev, st21nfca_vendor_cmds, 362 sizeof(st21nfca_vendor_cmds)); 363 } 364 EXPORT_SYMBOL(st21nfca_vendor_cmds_init); 365