1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Proprietary commands extension for STMicroelectronics NFC NCI 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 <linux/delay.h> 12 #include <net/nfc/nci_core.h> 13 14 #include "st-nci.h" 15 16 #define ST_NCI_HCI_DM_GETDATA 0x10 17 #define ST_NCI_HCI_DM_PUTDATA 0x11 18 #define ST_NCI_HCI_DM_LOAD 0x12 19 #define ST_NCI_HCI_DM_GETINFO 0x13 20 #define ST_NCI_HCI_DM_FWUPD_START 0x14 21 #define ST_NCI_HCI_DM_FWUPD_STOP 0x15 22 #define ST_NCI_HCI_DM_UPDATE_AID 0x20 23 #define ST_NCI_HCI_DM_RESET 0x3e 24 25 #define ST_NCI_HCI_DM_FIELD_GENERATOR 0x32 26 #define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE 0x33 27 #define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON 0x34 28 29 #define ST_NCI_FACTORY_MODE_ON 1 30 #define ST_NCI_FACTORY_MODE_OFF 0 31 32 #define ST_NCI_EVT_POST_DATA 0x02 33 34 struct get_param_data { 35 u8 gate; 36 u8 data; 37 } __packed; 38 39 static int st_nci_factory_mode(struct nfc_dev *dev, void *data, 40 size_t data_len) 41 { 42 struct nci_dev *ndev = nfc_get_drvdata(dev); 43 struct st_nci_info *info = nci_get_drvdata(ndev); 44 45 if (data_len != 1) 46 return -EINVAL; 47 48 pr_debug("factory mode: %x\n", ((u8 *)data)[0]); 49 50 switch (((u8 *)data)[0]) { 51 case ST_NCI_FACTORY_MODE_ON: 52 test_and_set_bit(ST_NCI_FACTORY_MODE, &info->flags); 53 break; 54 case ST_NCI_FACTORY_MODE_OFF: 55 clear_bit(ST_NCI_FACTORY_MODE, &info->flags); 56 break; 57 default: 58 return -EINVAL; 59 } 60 61 return 0; 62 } 63 64 static int st_nci_hci_clear_all_pipes(struct nfc_dev *dev, void *data, 65 size_t data_len) 66 { 67 struct nci_dev *ndev = nfc_get_drvdata(dev); 68 69 return nci_hci_clear_all_pipes(ndev); 70 } 71 72 static int st_nci_hci_dm_put_data(struct nfc_dev *dev, void *data, 73 size_t data_len) 74 { 75 struct nci_dev *ndev = nfc_get_drvdata(dev); 76 77 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 78 ST_NCI_HCI_DM_PUTDATA, data, 79 data_len, NULL); 80 } 81 82 static int st_nci_hci_dm_update_aid(struct nfc_dev *dev, void *data, 83 size_t data_len) 84 { 85 struct nci_dev *ndev = nfc_get_drvdata(dev); 86 87 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 88 ST_NCI_HCI_DM_UPDATE_AID, data, data_len, NULL); 89 } 90 91 static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data, 92 size_t data_len) 93 { 94 int r; 95 struct sk_buff *msg, *skb; 96 struct nci_dev *ndev = nfc_get_drvdata(dev); 97 98 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO, 99 data, data_len, &skb); 100 if (r) 101 goto exit; 102 103 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 104 HCI_DM_GET_INFO, skb->len); 105 if (!msg) { 106 r = -ENOMEM; 107 goto free_skb; 108 } 109 110 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 111 kfree_skb(msg); 112 r = -ENOBUFS; 113 goto free_skb; 114 } 115 116 r = nfc_vendor_cmd_reply(msg); 117 118 free_skb: 119 kfree_skb(skb); 120 exit: 121 return r; 122 } 123 124 static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data, 125 size_t data_len) 126 { 127 int r; 128 struct sk_buff *msg, *skb; 129 struct nci_dev *ndev = nfc_get_drvdata(dev); 130 131 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA, 132 data, data_len, &skb); 133 if (r) 134 goto exit; 135 136 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 137 HCI_DM_GET_DATA, skb->len); 138 if (!msg) { 139 r = -ENOMEM; 140 goto free_skb; 141 } 142 143 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 144 kfree_skb(msg); 145 r = -ENOBUFS; 146 goto free_skb; 147 } 148 149 r = nfc_vendor_cmd_reply(msg); 150 151 free_skb: 152 kfree_skb(skb); 153 exit: 154 return r; 155 } 156 157 static int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data, 158 size_t data_len) 159 { 160 int r; 161 struct nci_dev *ndev = nfc_get_drvdata(dev); 162 163 dev->fw_download_in_progress = true; 164 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 165 ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL); 166 if (r) 167 dev->fw_download_in_progress = false; 168 169 return r; 170 } 171 172 static int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data, 173 size_t data_len) 174 { 175 struct nci_dev *ndev = nfc_get_drvdata(dev); 176 177 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 178 ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL); 179 } 180 181 static int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data, 182 size_t data_len) 183 { 184 struct nci_dev *ndev = nfc_get_drvdata(dev); 185 186 if (dev->fw_download_in_progress) { 187 dev->fw_download_in_progress = false; 188 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 189 ST_NCI_HCI_DM_LOAD, data, data_len, NULL); 190 } 191 return -EPROTO; 192 } 193 194 static int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data, 195 size_t data_len) 196 { 197 struct nci_dev *ndev = nfc_get_drvdata(dev); 198 199 nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 200 ST_NCI_HCI_DM_RESET, data, data_len, NULL); 201 msleep(200); 202 203 return 0; 204 } 205 206 static int st_nci_hci_get_param(struct nfc_dev *dev, void *data, 207 size_t data_len) 208 { 209 int r; 210 struct sk_buff *msg, *skb; 211 struct nci_dev *ndev = nfc_get_drvdata(dev); 212 struct get_param_data *param = (struct get_param_data *)data; 213 214 if (data_len < sizeof(struct get_param_data)) 215 return -EPROTO; 216 217 r = nci_hci_get_param(ndev, param->gate, param->data, &skb); 218 if (r) 219 goto exit; 220 221 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 222 HCI_GET_PARAM, skb->len); 223 if (!msg) { 224 r = -ENOMEM; 225 goto free_skb; 226 } 227 228 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 229 kfree_skb(msg); 230 r = -ENOBUFS; 231 goto free_skb; 232 } 233 234 r = nfc_vendor_cmd_reply(msg); 235 236 free_skb: 237 kfree_skb(skb); 238 exit: 239 return r; 240 } 241 242 static int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data, 243 size_t data_len) 244 { 245 struct nci_dev *ndev = nfc_get_drvdata(dev); 246 247 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 248 ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL); 249 } 250 251 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data, 252 size_t data_len) 253 { 254 int r; 255 struct sk_buff *msg, *skb; 256 struct nci_dev *ndev = nfc_get_drvdata(dev); 257 258 if (data_len != 4) 259 return -EPROTO; 260 261 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 262 ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE, 263 data, data_len, &skb); 264 if (r) 265 goto exit; 266 267 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 268 HCI_DM_VDC_MEASUREMENT_VALUE, skb->len); 269 if (!msg) { 270 r = -ENOMEM; 271 goto free_skb; 272 } 273 274 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 275 kfree_skb(msg); 276 r = -ENOBUFS; 277 goto free_skb; 278 } 279 280 r = nfc_vendor_cmd_reply(msg); 281 282 free_skb: 283 kfree_skb(skb); 284 exit: 285 return r; 286 } 287 288 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data, 289 size_t data_len) 290 { 291 int r; 292 struct sk_buff *msg, *skb; 293 struct nci_dev *ndev = nfc_get_drvdata(dev); 294 295 if (data_len != 2) 296 return -EPROTO; 297 298 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 299 ST_NCI_HCI_DM_VDC_VALUE_COMPARISON, 300 data, data_len, &skb); 301 if (r) 302 goto exit; 303 304 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 305 HCI_DM_VDC_VALUE_COMPARISON, skb->len); 306 if (!msg) { 307 r = -ENOMEM; 308 goto free_skb; 309 } 310 311 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 312 kfree_skb(msg); 313 r = -ENOBUFS; 314 goto free_skb; 315 } 316 317 r = nfc_vendor_cmd_reply(msg); 318 319 free_skb: 320 kfree_skb(skb); 321 exit: 322 return r; 323 } 324 325 static int st_nci_loopback(struct nfc_dev *dev, void *data, 326 size_t data_len) 327 { 328 int r; 329 struct sk_buff *msg, *skb; 330 struct nci_dev *ndev = nfc_get_drvdata(dev); 331 332 if (data_len <= 0) 333 return -EPROTO; 334 335 r = nci_nfcc_loopback(ndev, data, data_len, &skb); 336 if (r < 0) 337 return r; 338 339 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 340 LOOPBACK, skb->len); 341 if (!msg) { 342 r = -ENOMEM; 343 goto free_skb; 344 } 345 346 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 347 kfree_skb(msg); 348 r = -ENOBUFS; 349 goto free_skb; 350 } 351 352 r = nfc_vendor_cmd_reply(msg); 353 free_skb: 354 kfree_skb(skb); 355 return r; 356 } 357 358 static int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data, 359 size_t data_len) 360 { 361 struct sk_buff *msg; 362 struct nci_dev *ndev = nfc_get_drvdata(dev); 363 364 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 365 MANUFACTURER_SPECIFIC, 366 sizeof(ndev->manufact_specific_info)); 367 if (!msg) 368 return -ENOMEM; 369 370 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info), 371 &ndev->manufact_specific_info)) { 372 kfree_skb(msg); 373 return -ENOBUFS; 374 } 375 376 return nfc_vendor_cmd_reply(msg); 377 } 378 379 static struct nfc_vendor_cmd st_nci_vendor_cmds[] = { 380 { 381 .vendor_id = ST_NCI_VENDOR_OUI, 382 .subcmd = FACTORY_MODE, 383 .doit = st_nci_factory_mode, 384 }, 385 { 386 .vendor_id = ST_NCI_VENDOR_OUI, 387 .subcmd = HCI_CLEAR_ALL_PIPES, 388 .doit = st_nci_hci_clear_all_pipes, 389 }, 390 { 391 .vendor_id = ST_NCI_VENDOR_OUI, 392 .subcmd = HCI_DM_PUT_DATA, 393 .doit = st_nci_hci_dm_put_data, 394 }, 395 { 396 .vendor_id = ST_NCI_VENDOR_OUI, 397 .subcmd = HCI_DM_UPDATE_AID, 398 .doit = st_nci_hci_dm_update_aid, 399 }, 400 { 401 .vendor_id = ST_NCI_VENDOR_OUI, 402 .subcmd = HCI_DM_GET_INFO, 403 .doit = st_nci_hci_dm_get_info, 404 }, 405 { 406 .vendor_id = ST_NCI_VENDOR_OUI, 407 .subcmd = HCI_DM_GET_DATA, 408 .doit = st_nci_hci_dm_get_data, 409 }, 410 { 411 .vendor_id = ST_NCI_VENDOR_OUI, 412 .subcmd = HCI_DM_DIRECT_LOAD, 413 .doit = st_nci_hci_dm_direct_load, 414 }, 415 { 416 .vendor_id = ST_NCI_VENDOR_OUI, 417 .subcmd = HCI_DM_RESET, 418 .doit = st_nci_hci_dm_reset, 419 }, 420 { 421 .vendor_id = ST_NCI_VENDOR_OUI, 422 .subcmd = HCI_GET_PARAM, 423 .doit = st_nci_hci_get_param, 424 }, 425 { 426 .vendor_id = ST_NCI_VENDOR_OUI, 427 .subcmd = HCI_DM_FIELD_GENERATOR, 428 .doit = st_nci_hci_dm_field_generator, 429 }, 430 { 431 .vendor_id = ST_NCI_VENDOR_OUI, 432 .subcmd = HCI_DM_FWUPD_START, 433 .doit = st_nci_hci_dm_fwupd_start, 434 }, 435 { 436 .vendor_id = ST_NCI_VENDOR_OUI, 437 .subcmd = HCI_DM_FWUPD_END, 438 .doit = st_nci_hci_dm_fwupd_end, 439 }, 440 { 441 .vendor_id = ST_NCI_VENDOR_OUI, 442 .subcmd = LOOPBACK, 443 .doit = st_nci_loopback, 444 }, 445 { 446 .vendor_id = ST_NCI_VENDOR_OUI, 447 .subcmd = HCI_DM_VDC_MEASUREMENT_VALUE, 448 .doit = st_nci_hci_dm_vdc_measurement_value, 449 }, 450 { 451 .vendor_id = ST_NCI_VENDOR_OUI, 452 .subcmd = HCI_DM_VDC_VALUE_COMPARISON, 453 .doit = st_nci_hci_dm_vdc_value_comparison, 454 }, 455 { 456 .vendor_id = ST_NCI_VENDOR_OUI, 457 .subcmd = MANUFACTURER_SPECIFIC, 458 .doit = st_nci_manufacturer_specific, 459 }, 460 }; 461 462 int st_nci_vendor_cmds_init(struct nci_dev *ndev) 463 { 464 return nfc_set_vendor_cmds(ndev->nfc_dev, st_nci_vendor_cmds, 465 sizeof(st_nci_vendor_cmds)); 466 } 467 EXPORT_SYMBOL(st_nci_vendor_cmds_init); 468