162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Proprietary commands extension for STMicroelectronics NFC NCI Chip 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <net/genetlink.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/nfc.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <net/nfc/nci_core.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "st-nci.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define ST_NCI_HCI_DM_GETDATA 0x10 1762306a36Sopenharmony_ci#define ST_NCI_HCI_DM_PUTDATA 0x11 1862306a36Sopenharmony_ci#define ST_NCI_HCI_DM_LOAD 0x12 1962306a36Sopenharmony_ci#define ST_NCI_HCI_DM_GETINFO 0x13 2062306a36Sopenharmony_ci#define ST_NCI_HCI_DM_FWUPD_START 0x14 2162306a36Sopenharmony_ci#define ST_NCI_HCI_DM_FWUPD_STOP 0x15 2262306a36Sopenharmony_ci#define ST_NCI_HCI_DM_UPDATE_AID 0x20 2362306a36Sopenharmony_ci#define ST_NCI_HCI_DM_RESET 0x3e 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define ST_NCI_HCI_DM_FIELD_GENERATOR 0x32 2662306a36Sopenharmony_ci#define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE 0x33 2762306a36Sopenharmony_ci#define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON 0x34 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define ST_NCI_FACTORY_MODE_ON 1 3062306a36Sopenharmony_ci#define ST_NCI_FACTORY_MODE_OFF 0 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define ST_NCI_EVT_POST_DATA 0x02 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct get_param_data { 3562306a36Sopenharmony_ci u8 gate; 3662306a36Sopenharmony_ci u8 data; 3762306a36Sopenharmony_ci} __packed; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic int st_nci_factory_mode(struct nfc_dev *dev, void *data, 4062306a36Sopenharmony_ci size_t data_len) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 4362306a36Sopenharmony_ci struct st_nci_info *info = nci_get_drvdata(ndev); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (data_len != 1) 4662306a36Sopenharmony_ci return -EINVAL; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci pr_debug("factory mode: %x\n", ((u8 *)data)[0]); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci switch (((u8 *)data)[0]) { 5162306a36Sopenharmony_ci case ST_NCI_FACTORY_MODE_ON: 5262306a36Sopenharmony_ci test_and_set_bit(ST_NCI_FACTORY_MODE, &info->flags); 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci case ST_NCI_FACTORY_MODE_OFF: 5562306a36Sopenharmony_ci clear_bit(ST_NCI_FACTORY_MODE, &info->flags); 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci default: 5862306a36Sopenharmony_ci return -EINVAL; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int st_nci_hci_clear_all_pipes(struct nfc_dev *dev, void *data, 6562306a36Sopenharmony_ci size_t data_len) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return nci_hci_clear_all_pipes(ndev); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int st_nci_hci_dm_put_data(struct nfc_dev *dev, void *data, 7362306a36Sopenharmony_ci size_t data_len) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 7862306a36Sopenharmony_ci ST_NCI_HCI_DM_PUTDATA, data, 7962306a36Sopenharmony_ci data_len, NULL); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int st_nci_hci_dm_update_aid(struct nfc_dev *dev, void *data, 8362306a36Sopenharmony_ci size_t data_len) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 8862306a36Sopenharmony_ci ST_NCI_HCI_DM_UPDATE_AID, data, data_len, NULL); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data, 9262306a36Sopenharmony_ci size_t data_len) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci int r; 9562306a36Sopenharmony_ci struct sk_buff *msg, *skb; 9662306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO, 9962306a36Sopenharmony_ci data, data_len, &skb); 10062306a36Sopenharmony_ci if (r) 10162306a36Sopenharmony_ci return r; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 10462306a36Sopenharmony_ci HCI_DM_GET_INFO, skb->len); 10562306a36Sopenharmony_ci if (!msg) { 10662306a36Sopenharmony_ci r = -ENOMEM; 10762306a36Sopenharmony_ci goto free_skb; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 11162306a36Sopenharmony_ci kfree_skb(msg); 11262306a36Sopenharmony_ci r = -ENOBUFS; 11362306a36Sopenharmony_ci goto free_skb; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cifree_skb: 11962306a36Sopenharmony_ci kfree_skb(skb); 12062306a36Sopenharmony_ci return r; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data, 12462306a36Sopenharmony_ci size_t data_len) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci int r; 12762306a36Sopenharmony_ci struct sk_buff *msg, *skb; 12862306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA, 13162306a36Sopenharmony_ci data, data_len, &skb); 13262306a36Sopenharmony_ci if (r) 13362306a36Sopenharmony_ci return r; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 13662306a36Sopenharmony_ci HCI_DM_GET_DATA, skb->len); 13762306a36Sopenharmony_ci if (!msg) { 13862306a36Sopenharmony_ci r = -ENOMEM; 13962306a36Sopenharmony_ci goto free_skb; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 14362306a36Sopenharmony_ci kfree_skb(msg); 14462306a36Sopenharmony_ci r = -ENOBUFS; 14562306a36Sopenharmony_ci goto free_skb; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cifree_skb: 15162306a36Sopenharmony_ci kfree_skb(skb); 15262306a36Sopenharmony_ci return r; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data, 15662306a36Sopenharmony_ci size_t data_len) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int r; 15962306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci dev->fw_download_in_progress = true; 16262306a36Sopenharmony_ci r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 16362306a36Sopenharmony_ci ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL); 16462306a36Sopenharmony_ci if (r) 16562306a36Sopenharmony_ci dev->fw_download_in_progress = false; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return r; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data, 17162306a36Sopenharmony_ci size_t data_len) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 17662306a36Sopenharmony_ci ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data, 18062306a36Sopenharmony_ci size_t data_len) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (dev->fw_download_in_progress) { 18562306a36Sopenharmony_ci dev->fw_download_in_progress = false; 18662306a36Sopenharmony_ci return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 18762306a36Sopenharmony_ci ST_NCI_HCI_DM_LOAD, data, data_len, NULL); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci return -EPROTO; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data, 19362306a36Sopenharmony_ci size_t data_len) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 19862306a36Sopenharmony_ci ST_NCI_HCI_DM_RESET, data, data_len, NULL); 19962306a36Sopenharmony_ci msleep(200); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int st_nci_hci_get_param(struct nfc_dev *dev, void *data, 20562306a36Sopenharmony_ci size_t data_len) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci int r; 20862306a36Sopenharmony_ci struct sk_buff *msg, *skb; 20962306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 21062306a36Sopenharmony_ci struct get_param_data *param = (struct get_param_data *)data; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (data_len < sizeof(struct get_param_data)) 21362306a36Sopenharmony_ci return -EPROTO; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci r = nci_hci_get_param(ndev, param->gate, param->data, &skb); 21662306a36Sopenharmony_ci if (r) 21762306a36Sopenharmony_ci return r; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 22062306a36Sopenharmony_ci HCI_GET_PARAM, skb->len); 22162306a36Sopenharmony_ci if (!msg) { 22262306a36Sopenharmony_ci r = -ENOMEM; 22362306a36Sopenharmony_ci goto free_skb; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 22762306a36Sopenharmony_ci kfree_skb(msg); 22862306a36Sopenharmony_ci r = -ENOBUFS; 22962306a36Sopenharmony_ci goto free_skb; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cifree_skb: 23562306a36Sopenharmony_ci kfree_skb(skb); 23662306a36Sopenharmony_ci return r; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data, 24062306a36Sopenharmony_ci size_t data_len) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 24562306a36Sopenharmony_ci ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data, 24962306a36Sopenharmony_ci size_t data_len) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci int r; 25262306a36Sopenharmony_ci struct sk_buff *msg, *skb; 25362306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (data_len != 4) 25662306a36Sopenharmony_ci return -EPROTO; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 25962306a36Sopenharmony_ci ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE, 26062306a36Sopenharmony_ci data, data_len, &skb); 26162306a36Sopenharmony_ci if (r) 26262306a36Sopenharmony_ci return r; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 26562306a36Sopenharmony_ci HCI_DM_VDC_MEASUREMENT_VALUE, skb->len); 26662306a36Sopenharmony_ci if (!msg) { 26762306a36Sopenharmony_ci r = -ENOMEM; 26862306a36Sopenharmony_ci goto free_skb; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 27262306a36Sopenharmony_ci kfree_skb(msg); 27362306a36Sopenharmony_ci r = -ENOBUFS; 27462306a36Sopenharmony_ci goto free_skb; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cifree_skb: 28062306a36Sopenharmony_ci kfree_skb(skb); 28162306a36Sopenharmony_ci return r; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data, 28562306a36Sopenharmony_ci size_t data_len) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int r; 28862306a36Sopenharmony_ci struct sk_buff *msg, *skb; 28962306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (data_len != 2) 29262306a36Sopenharmony_ci return -EPROTO; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 29562306a36Sopenharmony_ci ST_NCI_HCI_DM_VDC_VALUE_COMPARISON, 29662306a36Sopenharmony_ci data, data_len, &skb); 29762306a36Sopenharmony_ci if (r) 29862306a36Sopenharmony_ci return r; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 30162306a36Sopenharmony_ci HCI_DM_VDC_VALUE_COMPARISON, skb->len); 30262306a36Sopenharmony_ci if (!msg) { 30362306a36Sopenharmony_ci r = -ENOMEM; 30462306a36Sopenharmony_ci goto free_skb; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 30862306a36Sopenharmony_ci kfree_skb(msg); 30962306a36Sopenharmony_ci r = -ENOBUFS; 31062306a36Sopenharmony_ci goto free_skb; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cifree_skb: 31662306a36Sopenharmony_ci kfree_skb(skb); 31762306a36Sopenharmony_ci return r; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int st_nci_loopback(struct nfc_dev *dev, void *data, 32162306a36Sopenharmony_ci size_t data_len) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int r; 32462306a36Sopenharmony_ci struct sk_buff *msg, *skb; 32562306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (data_len <= 0) 32862306a36Sopenharmony_ci return -EPROTO; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci r = nci_nfcc_loopback(ndev, data, data_len, &skb); 33162306a36Sopenharmony_ci if (r < 0) 33262306a36Sopenharmony_ci return r; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 33562306a36Sopenharmony_ci LOOPBACK, skb->len); 33662306a36Sopenharmony_ci if (!msg) { 33762306a36Sopenharmony_ci r = -ENOMEM; 33862306a36Sopenharmony_ci goto free_skb; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) { 34262306a36Sopenharmony_ci kfree_skb(msg); 34362306a36Sopenharmony_ci r = -ENOBUFS; 34462306a36Sopenharmony_ci goto free_skb; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci r = nfc_vendor_cmd_reply(msg); 34862306a36Sopenharmony_cifree_skb: 34962306a36Sopenharmony_ci kfree_skb(skb); 35062306a36Sopenharmony_ci return r; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data, 35462306a36Sopenharmony_ci size_t data_len) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct sk_buff *msg; 35762306a36Sopenharmony_ci struct nci_dev *ndev = nfc_get_drvdata(dev); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI, 36062306a36Sopenharmony_ci MANUFACTURER_SPECIFIC, 36162306a36Sopenharmony_ci sizeof(ndev->manufact_specific_info)); 36262306a36Sopenharmony_ci if (!msg) 36362306a36Sopenharmony_ci return -ENOMEM; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info), 36662306a36Sopenharmony_ci &ndev->manufact_specific_info)) { 36762306a36Sopenharmony_ci kfree_skb(msg); 36862306a36Sopenharmony_ci return -ENOBUFS; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return nfc_vendor_cmd_reply(msg); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic const struct nfc_vendor_cmd st_nci_vendor_cmds[] = { 37562306a36Sopenharmony_ci { 37662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 37762306a36Sopenharmony_ci .subcmd = FACTORY_MODE, 37862306a36Sopenharmony_ci .doit = st_nci_factory_mode, 37962306a36Sopenharmony_ci }, 38062306a36Sopenharmony_ci { 38162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 38262306a36Sopenharmony_ci .subcmd = HCI_CLEAR_ALL_PIPES, 38362306a36Sopenharmony_ci .doit = st_nci_hci_clear_all_pipes, 38462306a36Sopenharmony_ci }, 38562306a36Sopenharmony_ci { 38662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 38762306a36Sopenharmony_ci .subcmd = HCI_DM_PUT_DATA, 38862306a36Sopenharmony_ci .doit = st_nci_hci_dm_put_data, 38962306a36Sopenharmony_ci }, 39062306a36Sopenharmony_ci { 39162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 39262306a36Sopenharmony_ci .subcmd = HCI_DM_UPDATE_AID, 39362306a36Sopenharmony_ci .doit = st_nci_hci_dm_update_aid, 39462306a36Sopenharmony_ci }, 39562306a36Sopenharmony_ci { 39662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 39762306a36Sopenharmony_ci .subcmd = HCI_DM_GET_INFO, 39862306a36Sopenharmony_ci .doit = st_nci_hci_dm_get_info, 39962306a36Sopenharmony_ci }, 40062306a36Sopenharmony_ci { 40162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 40262306a36Sopenharmony_ci .subcmd = HCI_DM_GET_DATA, 40362306a36Sopenharmony_ci .doit = st_nci_hci_dm_get_data, 40462306a36Sopenharmony_ci }, 40562306a36Sopenharmony_ci { 40662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 40762306a36Sopenharmony_ci .subcmd = HCI_DM_DIRECT_LOAD, 40862306a36Sopenharmony_ci .doit = st_nci_hci_dm_direct_load, 40962306a36Sopenharmony_ci }, 41062306a36Sopenharmony_ci { 41162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 41262306a36Sopenharmony_ci .subcmd = HCI_DM_RESET, 41362306a36Sopenharmony_ci .doit = st_nci_hci_dm_reset, 41462306a36Sopenharmony_ci }, 41562306a36Sopenharmony_ci { 41662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 41762306a36Sopenharmony_ci .subcmd = HCI_GET_PARAM, 41862306a36Sopenharmony_ci .doit = st_nci_hci_get_param, 41962306a36Sopenharmony_ci }, 42062306a36Sopenharmony_ci { 42162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 42262306a36Sopenharmony_ci .subcmd = HCI_DM_FIELD_GENERATOR, 42362306a36Sopenharmony_ci .doit = st_nci_hci_dm_field_generator, 42462306a36Sopenharmony_ci }, 42562306a36Sopenharmony_ci { 42662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 42762306a36Sopenharmony_ci .subcmd = HCI_DM_FWUPD_START, 42862306a36Sopenharmony_ci .doit = st_nci_hci_dm_fwupd_start, 42962306a36Sopenharmony_ci }, 43062306a36Sopenharmony_ci { 43162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 43262306a36Sopenharmony_ci .subcmd = HCI_DM_FWUPD_END, 43362306a36Sopenharmony_ci .doit = st_nci_hci_dm_fwupd_end, 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci { 43662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 43762306a36Sopenharmony_ci .subcmd = LOOPBACK, 43862306a36Sopenharmony_ci .doit = st_nci_loopback, 43962306a36Sopenharmony_ci }, 44062306a36Sopenharmony_ci { 44162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 44262306a36Sopenharmony_ci .subcmd = HCI_DM_VDC_MEASUREMENT_VALUE, 44362306a36Sopenharmony_ci .doit = st_nci_hci_dm_vdc_measurement_value, 44462306a36Sopenharmony_ci }, 44562306a36Sopenharmony_ci { 44662306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 44762306a36Sopenharmony_ci .subcmd = HCI_DM_VDC_VALUE_COMPARISON, 44862306a36Sopenharmony_ci .doit = st_nci_hci_dm_vdc_value_comparison, 44962306a36Sopenharmony_ci }, 45062306a36Sopenharmony_ci { 45162306a36Sopenharmony_ci .vendor_id = ST_NCI_VENDOR_OUI, 45262306a36Sopenharmony_ci .subcmd = MANUFACTURER_SPECIFIC, 45362306a36Sopenharmony_ci .doit = st_nci_manufacturer_specific, 45462306a36Sopenharmony_ci }, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciint st_nci_vendor_cmds_init(struct nci_dev *ndev) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci return nci_set_vendor_cmds(ndev, st_nci_vendor_cmds, 46062306a36Sopenharmony_ci sizeof(st_nci_vendor_cmds)); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ciEXPORT_SYMBOL(st_nci_vendor_cmds_init); 463