Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Proprietary commands extension for STMicroelectronics NFC NCI Chip
0004  *
0005  * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
0006  */
0007 
0008 #include <net/genetlink.h>
0009 #include <linux/module.h>
0010 #include <linux/nfc.h>
0011 #include <linux/delay.h>
0012 #include <net/nfc/nci_core.h>
0013 
0014 #include "st-nci.h"
0015 
0016 #define ST_NCI_HCI_DM_GETDATA           0x10
0017 #define ST_NCI_HCI_DM_PUTDATA           0x11
0018 #define ST_NCI_HCI_DM_LOAD          0x12
0019 #define ST_NCI_HCI_DM_GETINFO           0x13
0020 #define ST_NCI_HCI_DM_FWUPD_START       0x14
0021 #define ST_NCI_HCI_DM_FWUPD_STOP        0x15
0022 #define ST_NCI_HCI_DM_UPDATE_AID        0x20
0023 #define ST_NCI_HCI_DM_RESET         0x3e
0024 
0025 #define ST_NCI_HCI_DM_FIELD_GENERATOR       0x32
0026 #define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE 0x33
0027 #define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON  0x34
0028 
0029 #define ST_NCI_FACTORY_MODE_ON          1
0030 #define ST_NCI_FACTORY_MODE_OFF         0
0031 
0032 #define ST_NCI_EVT_POST_DATA            0x02
0033 
0034 struct get_param_data {
0035     u8 gate;
0036     u8 data;
0037 } __packed;
0038 
0039 static int st_nci_factory_mode(struct nfc_dev *dev, void *data,
0040                    size_t data_len)
0041 {
0042     struct nci_dev *ndev = nfc_get_drvdata(dev);
0043     struct st_nci_info *info = nci_get_drvdata(ndev);
0044 
0045     if (data_len != 1)
0046         return -EINVAL;
0047 
0048     pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
0049 
0050     switch (((u8 *)data)[0]) {
0051     case ST_NCI_FACTORY_MODE_ON:
0052         test_and_set_bit(ST_NCI_FACTORY_MODE, &info->flags);
0053     break;
0054     case ST_NCI_FACTORY_MODE_OFF:
0055         clear_bit(ST_NCI_FACTORY_MODE, &info->flags);
0056     break;
0057     default:
0058         return -EINVAL;
0059     }
0060 
0061     return 0;
0062 }
0063 
0064 static int st_nci_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
0065                       size_t data_len)
0066 {
0067     struct nci_dev *ndev = nfc_get_drvdata(dev);
0068 
0069     return nci_hci_clear_all_pipes(ndev);
0070 }
0071 
0072 static int st_nci_hci_dm_put_data(struct nfc_dev *dev, void *data,
0073                   size_t data_len)
0074 {
0075     struct nci_dev *ndev = nfc_get_drvdata(dev);
0076 
0077     return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0078                 ST_NCI_HCI_DM_PUTDATA, data,
0079                 data_len, NULL);
0080 }
0081 
0082 static int st_nci_hci_dm_update_aid(struct nfc_dev *dev, void *data,
0083                     size_t data_len)
0084 {
0085     struct nci_dev *ndev = nfc_get_drvdata(dev);
0086 
0087     return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0088             ST_NCI_HCI_DM_UPDATE_AID, data, data_len, NULL);
0089 }
0090 
0091 static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data,
0092                   size_t data_len)
0093 {
0094     int r;
0095     struct sk_buff *msg, *skb;
0096     struct nci_dev *ndev = nfc_get_drvdata(dev);
0097 
0098     r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO,
0099                  data, data_len, &skb);
0100     if (r)
0101         return r;
0102 
0103     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0104                          HCI_DM_GET_INFO, skb->len);
0105     if (!msg) {
0106         r = -ENOMEM;
0107         goto free_skb;
0108     }
0109 
0110     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0111         kfree_skb(msg);
0112         r = -ENOBUFS;
0113         goto free_skb;
0114     }
0115 
0116     r = nfc_vendor_cmd_reply(msg);
0117 
0118 free_skb:
0119     kfree_skb(skb);
0120     return r;
0121 }
0122 
0123 static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data,
0124                   size_t data_len)
0125 {
0126     int r;
0127     struct sk_buff *msg, *skb;
0128     struct nci_dev *ndev = nfc_get_drvdata(dev);
0129 
0130     r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA,
0131                  data, data_len, &skb);
0132     if (r)
0133         return r;
0134 
0135     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0136                          HCI_DM_GET_DATA, skb->len);
0137     if (!msg) {
0138         r = -ENOMEM;
0139         goto free_skb;
0140     }
0141 
0142     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0143         kfree_skb(msg);
0144         r = -ENOBUFS;
0145         goto free_skb;
0146     }
0147 
0148     r = nfc_vendor_cmd_reply(msg);
0149 
0150 free_skb:
0151     kfree_skb(skb);
0152     return r;
0153 }
0154 
0155 static int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data,
0156                      size_t data_len)
0157 {
0158     int r;
0159     struct nci_dev *ndev = nfc_get_drvdata(dev);
0160 
0161     dev->fw_download_in_progress = true;
0162     r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0163             ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL);
0164     if (r)
0165         dev->fw_download_in_progress = false;
0166 
0167     return r;
0168 }
0169 
0170 static int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data,
0171                    size_t data_len)
0172 {
0173     struct nci_dev *ndev = nfc_get_drvdata(dev);
0174 
0175     return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0176             ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL);
0177 }
0178 
0179 static int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data,
0180                      size_t data_len)
0181 {
0182     struct nci_dev *ndev = nfc_get_drvdata(dev);
0183 
0184     if (dev->fw_download_in_progress) {
0185         dev->fw_download_in_progress = false;
0186         return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0187                 ST_NCI_HCI_DM_LOAD, data, data_len, NULL);
0188     }
0189     return -EPROTO;
0190 }
0191 
0192 static int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data,
0193                    size_t data_len)
0194 {
0195     struct nci_dev *ndev = nfc_get_drvdata(dev);
0196 
0197     nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0198             ST_NCI_HCI_DM_RESET, data, data_len, NULL);
0199     msleep(200);
0200 
0201     return 0;
0202 }
0203 
0204 static int st_nci_hci_get_param(struct nfc_dev *dev, void *data,
0205                 size_t data_len)
0206 {
0207     int r;
0208     struct sk_buff *msg, *skb;
0209     struct nci_dev *ndev = nfc_get_drvdata(dev);
0210     struct get_param_data *param = (struct get_param_data *)data;
0211 
0212     if (data_len < sizeof(struct get_param_data))
0213         return -EPROTO;
0214 
0215     r = nci_hci_get_param(ndev, param->gate, param->data, &skb);
0216     if (r)
0217         return r;
0218 
0219     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0220                          HCI_GET_PARAM, skb->len);
0221     if (!msg) {
0222         r = -ENOMEM;
0223         goto free_skb;
0224     }
0225 
0226     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0227         kfree_skb(msg);
0228         r = -ENOBUFS;
0229         goto free_skb;
0230     }
0231 
0232     r = nfc_vendor_cmd_reply(msg);
0233 
0234 free_skb:
0235     kfree_skb(skb);
0236     return r;
0237 }
0238 
0239 static int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data,
0240                      size_t data_len)
0241 {
0242     struct nci_dev *ndev = nfc_get_drvdata(dev);
0243 
0244     return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0245                 ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL);
0246 }
0247 
0248 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data,
0249                            size_t data_len)
0250 {
0251     int r;
0252     struct sk_buff *msg, *skb;
0253     struct nci_dev *ndev = nfc_get_drvdata(dev);
0254 
0255     if (data_len != 4)
0256         return -EPROTO;
0257 
0258     r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0259                  ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE,
0260                  data, data_len, &skb);
0261     if (r)
0262         return r;
0263 
0264     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0265                 HCI_DM_VDC_MEASUREMENT_VALUE, skb->len);
0266     if (!msg) {
0267         r = -ENOMEM;
0268         goto free_skb;
0269     }
0270 
0271     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0272         kfree_skb(msg);
0273         r = -ENOBUFS;
0274         goto free_skb;
0275     }
0276 
0277     r = nfc_vendor_cmd_reply(msg);
0278 
0279 free_skb:
0280     kfree_skb(skb);
0281     return r;
0282 }
0283 
0284 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
0285                           size_t data_len)
0286 {
0287     int r;
0288     struct sk_buff *msg, *skb;
0289     struct nci_dev *ndev = nfc_get_drvdata(dev);
0290 
0291     if (data_len != 2)
0292         return -EPROTO;
0293 
0294     r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
0295                  ST_NCI_HCI_DM_VDC_VALUE_COMPARISON,
0296                  data, data_len, &skb);
0297     if (r)
0298         return r;
0299 
0300     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0301                     HCI_DM_VDC_VALUE_COMPARISON, skb->len);
0302     if (!msg) {
0303         r = -ENOMEM;
0304         goto free_skb;
0305     }
0306 
0307     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0308         kfree_skb(msg);
0309         r = -ENOBUFS;
0310         goto free_skb;
0311     }
0312 
0313     r = nfc_vendor_cmd_reply(msg);
0314 
0315 free_skb:
0316     kfree_skb(skb);
0317     return r;
0318 }
0319 
0320 static int st_nci_loopback(struct nfc_dev *dev, void *data,
0321                size_t data_len)
0322 {
0323     int r;
0324     struct sk_buff *msg, *skb;
0325     struct nci_dev *ndev = nfc_get_drvdata(dev);
0326 
0327     if (data_len <= 0)
0328         return -EPROTO;
0329 
0330     r = nci_nfcc_loopback(ndev, data, data_len, &skb);
0331     if (r < 0)
0332         return r;
0333 
0334     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0335                          LOOPBACK, skb->len);
0336     if (!msg) {
0337         r = -ENOMEM;
0338         goto free_skb;
0339     }
0340 
0341     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0342         kfree_skb(msg);
0343         r = -ENOBUFS;
0344         goto free_skb;
0345     }
0346 
0347     r = nfc_vendor_cmd_reply(msg);
0348 free_skb:
0349     kfree_skb(skb);
0350     return r;
0351 }
0352 
0353 static int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data,
0354                     size_t data_len)
0355 {
0356     struct sk_buff *msg;
0357     struct nci_dev *ndev = nfc_get_drvdata(dev);
0358 
0359     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
0360                     MANUFACTURER_SPECIFIC,
0361                     sizeof(ndev->manufact_specific_info));
0362     if (!msg)
0363         return -ENOMEM;
0364 
0365     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info),
0366             &ndev->manufact_specific_info)) {
0367         kfree_skb(msg);
0368         return -ENOBUFS;
0369     }
0370 
0371     return nfc_vendor_cmd_reply(msg);
0372 }
0373 
0374 static const struct nfc_vendor_cmd st_nci_vendor_cmds[] = {
0375     {
0376         .vendor_id = ST_NCI_VENDOR_OUI,
0377         .subcmd = FACTORY_MODE,
0378         .doit = st_nci_factory_mode,
0379     },
0380     {
0381         .vendor_id = ST_NCI_VENDOR_OUI,
0382         .subcmd = HCI_CLEAR_ALL_PIPES,
0383         .doit = st_nci_hci_clear_all_pipes,
0384     },
0385     {
0386         .vendor_id = ST_NCI_VENDOR_OUI,
0387         .subcmd = HCI_DM_PUT_DATA,
0388         .doit = st_nci_hci_dm_put_data,
0389     },
0390     {
0391         .vendor_id = ST_NCI_VENDOR_OUI,
0392         .subcmd = HCI_DM_UPDATE_AID,
0393         .doit = st_nci_hci_dm_update_aid,
0394     },
0395     {
0396         .vendor_id = ST_NCI_VENDOR_OUI,
0397         .subcmd = HCI_DM_GET_INFO,
0398         .doit = st_nci_hci_dm_get_info,
0399     },
0400     {
0401         .vendor_id = ST_NCI_VENDOR_OUI,
0402         .subcmd = HCI_DM_GET_DATA,
0403         .doit = st_nci_hci_dm_get_data,
0404     },
0405     {
0406         .vendor_id = ST_NCI_VENDOR_OUI,
0407         .subcmd = HCI_DM_DIRECT_LOAD,
0408         .doit = st_nci_hci_dm_direct_load,
0409     },
0410     {
0411         .vendor_id = ST_NCI_VENDOR_OUI,
0412         .subcmd = HCI_DM_RESET,
0413         .doit = st_nci_hci_dm_reset,
0414     },
0415     {
0416         .vendor_id = ST_NCI_VENDOR_OUI,
0417         .subcmd = HCI_GET_PARAM,
0418         .doit = st_nci_hci_get_param,
0419     },
0420     {
0421         .vendor_id = ST_NCI_VENDOR_OUI,
0422         .subcmd = HCI_DM_FIELD_GENERATOR,
0423         .doit = st_nci_hci_dm_field_generator,
0424     },
0425     {
0426         .vendor_id = ST_NCI_VENDOR_OUI,
0427         .subcmd = HCI_DM_FWUPD_START,
0428         .doit = st_nci_hci_dm_fwupd_start,
0429     },
0430     {
0431         .vendor_id = ST_NCI_VENDOR_OUI,
0432         .subcmd = HCI_DM_FWUPD_END,
0433         .doit = st_nci_hci_dm_fwupd_end,
0434     },
0435     {
0436         .vendor_id = ST_NCI_VENDOR_OUI,
0437         .subcmd = LOOPBACK,
0438         .doit = st_nci_loopback,
0439     },
0440     {
0441         .vendor_id = ST_NCI_VENDOR_OUI,
0442         .subcmd = HCI_DM_VDC_MEASUREMENT_VALUE,
0443         .doit = st_nci_hci_dm_vdc_measurement_value,
0444     },
0445     {
0446         .vendor_id = ST_NCI_VENDOR_OUI,
0447         .subcmd = HCI_DM_VDC_VALUE_COMPARISON,
0448         .doit = st_nci_hci_dm_vdc_value_comparison,
0449     },
0450     {
0451         .vendor_id = ST_NCI_VENDOR_OUI,
0452         .subcmd = MANUFACTURER_SPECIFIC,
0453         .doit = st_nci_manufacturer_specific,
0454     },
0455 };
0456 
0457 int st_nci_vendor_cmds_init(struct nci_dev *ndev)
0458 {
0459     return nci_set_vendor_cmds(ndev, st_nci_vendor_cmds,
0460                    sizeof(st_nci_vendor_cmds));
0461 }
0462 EXPORT_SYMBOL(st_nci_vendor_cmds_init);