Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Proprietary commands extension for STMicroelectronics NFC 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 <net/nfc/hci.h>
0012 #include <net/nfc/llc.h>
0013 
0014 #include "st21nfca.h"
0015 
0016 #define ST21NFCA_HCI_DM_GETDATA         0x10
0017 #define ST21NFCA_HCI_DM_PUTDATA         0x11
0018 #define ST21NFCA_HCI_DM_LOAD            0x12
0019 #define ST21NFCA_HCI_DM_GETINFO         0x13
0020 #define ST21NFCA_HCI_DM_UPDATE_AID      0x20
0021 #define ST21NFCA_HCI_DM_RESET           0x3e
0022 
0023 #define ST21NFCA_HCI_DM_FIELD_GENERATOR     0x32
0024 
0025 #define ST21NFCA_FACTORY_MODE_ON        1
0026 #define ST21NFCA_FACTORY_MODE_OFF       0
0027 
0028 #define ST21NFCA_EVT_POST_DATA          0x02
0029 
0030 struct get_param_data {
0031     u8 gate;
0032     u8 data;
0033 } __packed;
0034 
0035 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
0036                    size_t data_len)
0037 {
0038     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0039 
0040     if (data_len != 1)
0041         return -EINVAL;
0042 
0043     pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
0044 
0045     switch (((u8 *)data)[0]) {
0046     case ST21NFCA_FACTORY_MODE_ON:
0047         test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
0048     break;
0049     case ST21NFCA_FACTORY_MODE_OFF:
0050         clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
0051     break;
0052     default:
0053         return -EINVAL;
0054     }
0055 
0056     return 0;
0057 }
0058 
0059 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
0060                       size_t data_len)
0061 {
0062     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0063 
0064     return nfc_hci_disconnect_all_gates(hdev);
0065 }
0066 
0067 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
0068                   size_t data_len)
0069 {
0070     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0071 
0072     return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
0073                 ST21NFCA_HCI_DM_PUTDATA, data,
0074                 data_len, NULL);
0075 }
0076 
0077 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
0078                     size_t data_len)
0079 {
0080     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0081 
0082     return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
0083             ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
0084 }
0085 
0086 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
0087                     size_t data_len)
0088 {
0089     int r;
0090     struct sk_buff *msg, *skb;
0091     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0092 
0093     r = nfc_hci_send_cmd(hdev,
0094                  ST21NFCA_DEVICE_MGNT_GATE,
0095                  ST21NFCA_HCI_DM_GETINFO,
0096                  data, data_len, &skb);
0097     if (r)
0098         goto exit;
0099 
0100     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
0101                          HCI_DM_GET_INFO, skb->len);
0102     if (!msg) {
0103         r = -ENOMEM;
0104         goto free_skb;
0105     }
0106 
0107     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0108         kfree_skb(msg);
0109         r = -ENOBUFS;
0110         goto free_skb;
0111     }
0112 
0113     r = nfc_vendor_cmd_reply(msg);
0114 
0115 free_skb:
0116     kfree_skb(skb);
0117 exit:
0118     return r;
0119 }
0120 
0121 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
0122                     size_t data_len)
0123 {
0124     int r;
0125     struct sk_buff *msg, *skb;
0126     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0127 
0128     r = nfc_hci_send_cmd(hdev,
0129                  ST21NFCA_DEVICE_MGNT_GATE,
0130                  ST21NFCA_HCI_DM_GETDATA,
0131                  data, data_len, &skb);
0132     if (r)
0133         goto exit;
0134 
0135     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_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 exit:
0153     return r;
0154 }
0155 
0156 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
0157                 size_t data_len)
0158 {
0159     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0160 
0161     return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
0162                 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
0163 }
0164 
0165 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
0166                  size_t data_len)
0167 {
0168     int r;
0169     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0170 
0171     r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
0172             ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
0173     if (r < 0)
0174         return r;
0175 
0176     r = nfc_llc_stop(hdev->llc);
0177     if (r < 0)
0178         return r;
0179 
0180     return nfc_llc_start(hdev->llc);
0181 }
0182 
0183 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
0184                   size_t data_len)
0185 {
0186     int r;
0187     struct sk_buff *msg, *skb;
0188     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0189     struct get_param_data *param = (struct get_param_data *)data;
0190 
0191     if (data_len < sizeof(struct get_param_data))
0192         return -EPROTO;
0193 
0194     r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
0195     if (r)
0196         goto exit;
0197 
0198     msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
0199                          HCI_GET_PARAM, skb->len);
0200     if (!msg) {
0201         r = -ENOMEM;
0202         goto free_skb;
0203     }
0204 
0205     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
0206         kfree_skb(msg);
0207         r = -ENOBUFS;
0208         goto free_skb;
0209     }
0210 
0211     r = nfc_vendor_cmd_reply(msg);
0212 
0213 free_skb:
0214     kfree_skb(skb);
0215 exit:
0216     return r;
0217 }
0218 
0219 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
0220                        size_t data_len)
0221 {
0222     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0223 
0224     return nfc_hci_send_cmd(hdev,
0225                 ST21NFCA_DEVICE_MGNT_GATE,
0226                 ST21NFCA_HCI_DM_FIELD_GENERATOR,
0227                 data, data_len, NULL);
0228 }
0229 
0230 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
0231                      struct sk_buff *skb)
0232 {
0233     struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
0234 
0235     switch (event) {
0236     case ST21NFCA_EVT_POST_DATA:
0237         info->vendor_info.rx_skb = skb;
0238     break;
0239     default:
0240         nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
0241     }
0242     complete(&info->vendor_info.req_completion);
0243     return 0;
0244 }
0245 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
0246 
0247 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
0248                  size_t data_len)
0249 {
0250     int r;
0251     struct sk_buff *msg;
0252     struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
0253     struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
0254 
0255     if (data_len <= 0)
0256         return -EPROTO;
0257 
0258     reinit_completion(&info->vendor_info.req_completion);
0259     info->vendor_info.rx_skb = NULL;
0260 
0261     r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
0262                    ST21NFCA_EVT_POST_DATA, data, data_len);
0263     if (r < 0) {
0264         r = -EPROTO;
0265         goto exit;
0266     }
0267 
0268     wait_for_completion_interruptible(&info->vendor_info.req_completion);
0269     if (!info->vendor_info.rx_skb ||
0270         info->vendor_info.rx_skb->len != data_len) {
0271         r = -EPROTO;
0272         goto exit;
0273     }
0274 
0275     msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
0276                     ST21NFCA_VENDOR_OUI,
0277                     HCI_LOOPBACK,
0278                     info->vendor_info.rx_skb->len);
0279     if (!msg) {
0280         r = -ENOMEM;
0281         goto free_skb;
0282     }
0283 
0284     if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
0285             info->vendor_info.rx_skb->data)) {
0286         kfree_skb(msg);
0287         r = -ENOBUFS;
0288         goto free_skb;
0289     }
0290 
0291     r = nfc_vendor_cmd_reply(msg);
0292 free_skb:
0293     kfree_skb(info->vendor_info.rx_skb);
0294 exit:
0295     return r;
0296 }
0297 
0298 static const struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
0299     {
0300         .vendor_id = ST21NFCA_VENDOR_OUI,
0301         .subcmd = FACTORY_MODE,
0302         .doit = st21nfca_factory_mode,
0303     },
0304     {
0305         .vendor_id = ST21NFCA_VENDOR_OUI,
0306         .subcmd = HCI_CLEAR_ALL_PIPES,
0307         .doit = st21nfca_hci_clear_all_pipes,
0308     },
0309     {
0310         .vendor_id = ST21NFCA_VENDOR_OUI,
0311         .subcmd = HCI_DM_PUT_DATA,
0312         .doit = st21nfca_hci_dm_put_data,
0313     },
0314     {
0315         .vendor_id = ST21NFCA_VENDOR_OUI,
0316         .subcmd = HCI_DM_UPDATE_AID,
0317         .doit = st21nfca_hci_dm_update_aid,
0318     },
0319     {
0320         .vendor_id = ST21NFCA_VENDOR_OUI,
0321         .subcmd = HCI_DM_GET_INFO,
0322         .doit = st21nfca_hci_dm_get_info,
0323     },
0324     {
0325         .vendor_id = ST21NFCA_VENDOR_OUI,
0326         .subcmd = HCI_DM_GET_DATA,
0327         .doit = st21nfca_hci_dm_get_data,
0328     },
0329     {
0330         .vendor_id = ST21NFCA_VENDOR_OUI,
0331         .subcmd = HCI_DM_LOAD,
0332         .doit = st21nfca_hci_dm_load,
0333     },
0334     {
0335         .vendor_id = ST21NFCA_VENDOR_OUI,
0336         .subcmd = HCI_DM_RESET,
0337         .doit = st21nfca_hci_dm_reset,
0338     },
0339     {
0340         .vendor_id = ST21NFCA_VENDOR_OUI,
0341         .subcmd = HCI_GET_PARAM,
0342         .doit = st21nfca_hci_get_param,
0343     },
0344     {
0345         .vendor_id = ST21NFCA_VENDOR_OUI,
0346         .subcmd = HCI_DM_FIELD_GENERATOR,
0347         .doit = st21nfca_hci_dm_field_generator,
0348     },
0349     {
0350         .vendor_id = ST21NFCA_VENDOR_OUI,
0351         .subcmd = HCI_LOOPBACK,
0352         .doit = st21nfca_hci_loopback,
0353     },
0354 };
0355 
0356 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
0357 {
0358     struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
0359 
0360     init_completion(&info->vendor_info.req_completion);
0361     return nfc_hci_set_vendor_cmds(hdev, st21nfca_vendor_cmds,
0362                        sizeof(st21nfca_vendor_cmds));
0363 }
0364 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);