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