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 return r; 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 return r; 121 } 122 123 static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data, 124 size_t data_len) 125 { 126 int r; 127 struct sk_buff *msg, *skb; 128 struct nci_dev *ndev = nfc_get_drvdata(dev); 129 130 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA, 131 data, data_len, &skb); 132 if (r) 133 return r; 134 135 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_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 return r; 153 } 154 155 static int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data, 156 size_t data_len) 157 { 158 int r; 159 struct nci_dev *ndev = nfc_get_drvdata(dev); 160 161 dev->fw_download_in_progress = true; 162 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 163 ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL); 164 if (r) 165 dev->fw_download_in_progress = false; 166 167 return r; 168 } 169 170 static int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data, 171 size_t data_len) 172 { 173 struct nci_dev *ndev = nfc_get_drvdata(dev); 174 175 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 176 ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL); 177 } 178 179 static int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data, 180 size_t data_len) 181 { 182 struct nci_dev *ndev = nfc_get_drvdata(dev); 183 184 if (dev->fw_download_in_progress) { 185 dev->fw_download_in_progress = false; 186 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 187 ST_NCI_HCI_DM_LOAD, data, data_len, NULL); 188 } 189 return -EPROTO; 190 } 191 192 static int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data, 193 size_t data_len) 194 { 195 struct nci_dev *ndev = nfc_get_drvdata(dev); 196 197 nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 198 ST_NCI_HCI_DM_RESET, data, data_len, NULL); 199 msleep(200); 200 201 return 0; 202 } 203 204 static int st_nci_hci_get_param(struct nfc_dev *dev, void *data, 205 size_t data_len) 206 { 207 int r; 208 struct sk_buff *msg, *skb; 209 struct nci_dev *ndev = nfc_get_drvdata(dev); 210 struct get_param_data *param = (struct get_param_data *)data; 211 212 if (data_len < sizeof(struct get_param_data)) 213 return -EPROTO; 214 215 r = nci_hci_get_param(ndev, param->gate, param->data, &skb); 216 if (r) 217 return r; 218 219 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 220 HCI_GET_PARAM, skb->len); 221 if (!msg) { 222 r = -ENOMEM; 223 goto free_skb; 224 } 225 226 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 227 kfree_skb(msg); 228 r = -ENOBUFS; 229 goto free_skb; 230 } 231 232 r = nfc_vendor_cmd_reply(msg); 233 234 free_skb: 235 kfree_skb(skb); 236 return r; 237 } 238 239 static int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data, 240 size_t data_len) 241 { 242 struct nci_dev *ndev = nfc_get_drvdata(dev); 243 244 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 245 ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL); 246 } 247 248 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data, 249 size_t data_len) 250 { 251 int r; 252 struct sk_buff *msg, *skb; 253 struct nci_dev *ndev = nfc_get_drvdata(dev); 254 255 if (data_len != 4) 256 return -EPROTO; 257 258 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 259 ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE, 260 data, data_len, &skb); 261 if (r) 262 return r; 263 264 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 265 HCI_DM_VDC_MEASUREMENT_VALUE, skb->len); 266 if (!msg) { 267 r = -ENOMEM; 268 goto free_skb; 269 } 270 271 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 272 kfree_skb(msg); 273 r = -ENOBUFS; 274 goto free_skb; 275 } 276 277 r = nfc_vendor_cmd_reply(msg); 278 279 free_skb: 280 kfree_skb(skb); 281 return r; 282 } 283 284 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data, 285 size_t data_len) 286 { 287 int r; 288 struct sk_buff *msg, *skb; 289 struct nci_dev *ndev = nfc_get_drvdata(dev); 290 291 if (data_len != 2) 292 return -EPROTO; 293 294 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 295 ST_NCI_HCI_DM_VDC_VALUE_COMPARISON, 296 data, data_len, &skb); 297 if (r) 298 return r; 299 300 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 301 HCI_DM_VDC_VALUE_COMPARISON, skb->len); 302 if (!msg) { 303 r = -ENOMEM; 304 goto free_skb; 305 } 306 307 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 308 kfree_skb(msg); 309 r = -ENOBUFS; 310 goto free_skb; 311 } 312 313 r = nfc_vendor_cmd_reply(msg); 314 315 free_skb: 316 kfree_skb(skb); 317 return r; 318 } 319 320 static int st_nci_loopback(struct nfc_dev *dev, void *data, 321 size_t data_len) 322 { 323 int r; 324 struct sk_buff *msg, *skb; 325 struct nci_dev *ndev = nfc_get_drvdata(dev); 326 327 if (data_len <= 0) 328 return -EPROTO; 329 330 r = nci_nfcc_loopback(ndev, data, data_len, &skb); 331 if (r < 0) 332 return r; 333 334 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 335 LOOPBACK, skb->len); 336 if (!msg) { 337 r = -ENOMEM; 338 goto free_skb; 339 } 340 341 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 342 kfree_skb(msg); 343 r = -ENOBUFS; 344 goto free_skb; 345 } 346 347 r = nfc_vendor_cmd_reply(msg); 348 free_skb: 349 kfree_skb(skb); 350 return r; 351 } 352 353 static int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data, 354 size_t data_len) 355 { 356 struct sk_buff *msg; 357 struct nci_dev *ndev = nfc_get_drvdata(dev); 358 359 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 360 MANUFACTURER_SPECIFIC, 361 sizeof(ndev->manufact_specific_info)); 362 if (!msg) 363 return -ENOMEM; 364 365 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info), 366 &ndev->manufact_specific_info)) { 367 kfree_skb(msg); 368 return -ENOBUFS; 369 } 370 371 return nfc_vendor_cmd_reply(msg); 372 } 373 374 static struct nfc_vendor_cmd st_nci_vendor_cmds[] = { 375 { 376 .vendor_id = ST_NCI_VENDOR_OUI, 377 .subcmd = FACTORY_MODE, 378 .doit = st_nci_factory_mode, 379 }, 380 { 381 .vendor_id = ST_NCI_VENDOR_OUI, 382 .subcmd = HCI_CLEAR_ALL_PIPES, 383 .doit = st_nci_hci_clear_all_pipes, 384 }, 385 { 386 .vendor_id = ST_NCI_VENDOR_OUI, 387 .subcmd = HCI_DM_PUT_DATA, 388 .doit = st_nci_hci_dm_put_data, 389 }, 390 { 391 .vendor_id = ST_NCI_VENDOR_OUI, 392 .subcmd = HCI_DM_UPDATE_AID, 393 .doit = st_nci_hci_dm_update_aid, 394 }, 395 { 396 .vendor_id = ST_NCI_VENDOR_OUI, 397 .subcmd = HCI_DM_GET_INFO, 398 .doit = st_nci_hci_dm_get_info, 399 }, 400 { 401 .vendor_id = ST_NCI_VENDOR_OUI, 402 .subcmd = HCI_DM_GET_DATA, 403 .doit = st_nci_hci_dm_get_data, 404 }, 405 { 406 .vendor_id = ST_NCI_VENDOR_OUI, 407 .subcmd = HCI_DM_DIRECT_LOAD, 408 .doit = st_nci_hci_dm_direct_load, 409 }, 410 { 411 .vendor_id = ST_NCI_VENDOR_OUI, 412 .subcmd = HCI_DM_RESET, 413 .doit = st_nci_hci_dm_reset, 414 }, 415 { 416 .vendor_id = ST_NCI_VENDOR_OUI, 417 .subcmd = HCI_GET_PARAM, 418 .doit = st_nci_hci_get_param, 419 }, 420 { 421 .vendor_id = ST_NCI_VENDOR_OUI, 422 .subcmd = HCI_DM_FIELD_GENERATOR, 423 .doit = st_nci_hci_dm_field_generator, 424 }, 425 { 426 .vendor_id = ST_NCI_VENDOR_OUI, 427 .subcmd = HCI_DM_FWUPD_START, 428 .doit = st_nci_hci_dm_fwupd_start, 429 }, 430 { 431 .vendor_id = ST_NCI_VENDOR_OUI, 432 .subcmd = HCI_DM_FWUPD_END, 433 .doit = st_nci_hci_dm_fwupd_end, 434 }, 435 { 436 .vendor_id = ST_NCI_VENDOR_OUI, 437 .subcmd = LOOPBACK, 438 .doit = st_nci_loopback, 439 }, 440 { 441 .vendor_id = ST_NCI_VENDOR_OUI, 442 .subcmd = HCI_DM_VDC_MEASUREMENT_VALUE, 443 .doit = st_nci_hci_dm_vdc_measurement_value, 444 }, 445 { 446 .vendor_id = ST_NCI_VENDOR_OUI, 447 .subcmd = HCI_DM_VDC_VALUE_COMPARISON, 448 .doit = st_nci_hci_dm_vdc_value_comparison, 449 }, 450 { 451 .vendor_id = ST_NCI_VENDOR_OUI, 452 .subcmd = MANUFACTURER_SPECIFIC, 453 .doit = st_nci_manufacturer_specific, 454 }, 455 }; 456 457 int st_nci_vendor_cmds_init(struct nci_dev *ndev) 458 { 459 return nfc_set_vendor_cmds(ndev->nfc_dev, st_nci_vendor_cmds, 460 sizeof(st_nci_vendor_cmds)); 461 } 462 EXPORT_SYMBOL(st_nci_vendor_cmds_init); 463