root/drivers/nfc/st21nfca/vendor_cmds.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. st21nfca_factory_mode
  2. st21nfca_hci_clear_all_pipes
  3. st21nfca_hci_dm_put_data
  4. st21nfca_hci_dm_update_aid
  5. st21nfca_hci_dm_get_info
  6. st21nfca_hci_dm_get_data
  7. st21nfca_hci_dm_load
  8. st21nfca_hci_dm_reset
  9. st21nfca_hci_get_param
  10. st21nfca_hci_dm_field_generator
  11. st21nfca_hci_loopback_event_received
  12. st21nfca_hci_loopback
  13. st21nfca_vendor_cmds_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Proprietary commands extension for STMicroelectronics NFC 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 <net/nfc/hci.h>
  12 #include <net/nfc/llc.h>
  13 
  14 #include "st21nfca.h"
  15 
  16 #define ST21NFCA_HCI_DM_GETDATA                 0x10
  17 #define ST21NFCA_HCI_DM_PUTDATA                 0x11
  18 #define ST21NFCA_HCI_DM_LOAD                    0x12
  19 #define ST21NFCA_HCI_DM_GETINFO                 0x13
  20 #define ST21NFCA_HCI_DM_UPDATE_AID              0x20
  21 #define ST21NFCA_HCI_DM_RESET                   0x3e
  22 
  23 #define ST21NFCA_HCI_DM_FIELD_GENERATOR         0x32
  24 
  25 #define ST21NFCA_FACTORY_MODE_ON                1
  26 #define ST21NFCA_FACTORY_MODE_OFF               0
  27 
  28 #define ST21NFCA_EVT_POST_DATA                  0x02
  29 
  30 struct get_param_data {
  31         u8 gate;
  32         u8 data;
  33 } __packed;
  34 
  35 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
  36                                size_t data_len)
  37 {
  38         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  39 
  40         if (data_len != 1)
  41                 return -EINVAL;
  42 
  43         pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
  44 
  45         switch (((u8 *)data)[0]) {
  46         case ST21NFCA_FACTORY_MODE_ON:
  47                 test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
  48         break;
  49         case ST21NFCA_FACTORY_MODE_OFF:
  50                 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
  51         break;
  52         default:
  53                 return -EINVAL;
  54         }
  55 
  56         return 0;
  57 }
  58 
  59 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
  60                                       size_t data_len)
  61 {
  62         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  63 
  64         return nfc_hci_disconnect_all_gates(hdev);
  65 }
  66 
  67 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
  68                                   size_t data_len)
  69 {
  70         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  71 
  72         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  73                                 ST21NFCA_HCI_DM_PUTDATA, data,
  74                                 data_len, NULL);
  75 }
  76 
  77 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
  78                                     size_t data_len)
  79 {
  80         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  81 
  82         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  83                         ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
  84 }
  85 
  86 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
  87                                     size_t data_len)
  88 {
  89         int r;
  90         struct sk_buff *msg, *skb;
  91         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  92 
  93         r = nfc_hci_send_cmd(hdev,
  94                              ST21NFCA_DEVICE_MGNT_GATE,
  95                              ST21NFCA_HCI_DM_GETINFO,
  96                              data, data_len, &skb);
  97         if (r)
  98                 goto exit;
  99 
 100         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
 101                                              HCI_DM_GET_INFO, skb->len);
 102         if (!msg) {
 103                 r = -ENOMEM;
 104                 goto free_skb;
 105         }
 106 
 107         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
 108                 kfree_skb(msg);
 109                 r = -ENOBUFS;
 110                 goto free_skb;
 111         }
 112 
 113         r = nfc_vendor_cmd_reply(msg);
 114 
 115 free_skb:
 116         kfree_skb(skb);
 117 exit:
 118         return r;
 119 }
 120 
 121 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
 122                                     size_t data_len)
 123 {
 124         int r;
 125         struct sk_buff *msg, *skb;
 126         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 127 
 128         r = nfc_hci_send_cmd(hdev,
 129                              ST21NFCA_DEVICE_MGNT_GATE,
 130                              ST21NFCA_HCI_DM_GETDATA,
 131                              data, data_len, &skb);
 132         if (r)
 133                 goto exit;
 134 
 135         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_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 exit:
 153         return r;
 154 }
 155 
 156 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
 157                                 size_t data_len)
 158 {
 159         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 160 
 161         return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
 162                                 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
 163 }
 164 
 165 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
 166                                  size_t data_len)
 167 {
 168         int r;
 169         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 170 
 171         r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
 172                         ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
 173         if (r < 0)
 174                 return r;
 175 
 176         r = nfc_llc_stop(hdev->llc);
 177         if (r < 0)
 178                 return r;
 179 
 180         return nfc_llc_start(hdev->llc);
 181 }
 182 
 183 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
 184                                   size_t data_len)
 185 {
 186         int r;
 187         struct sk_buff *msg, *skb;
 188         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 189         struct get_param_data *param = (struct get_param_data *)data;
 190 
 191         if (data_len < sizeof(struct get_param_data))
 192                 return -EPROTO;
 193 
 194         r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
 195         if (r)
 196                 goto exit;
 197 
 198         msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
 199                                              HCI_GET_PARAM, skb->len);
 200         if (!msg) {
 201                 r = -ENOMEM;
 202                 goto free_skb;
 203         }
 204 
 205         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
 206                 kfree_skb(msg);
 207                 r = -ENOBUFS;
 208                 goto free_skb;
 209         }
 210 
 211         r = nfc_vendor_cmd_reply(msg);
 212 
 213 free_skb:
 214         kfree_skb(skb);
 215 exit:
 216         return r;
 217 }
 218 
 219 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
 220                                            size_t data_len)
 221 {
 222         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 223 
 224         return nfc_hci_send_cmd(hdev,
 225                                 ST21NFCA_DEVICE_MGNT_GATE,
 226                                 ST21NFCA_HCI_DM_FIELD_GENERATOR,
 227                                 data, data_len, NULL);
 228 }
 229 
 230 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
 231                                          struct sk_buff *skb)
 232 {
 233         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
 234 
 235         switch (event) {
 236         case ST21NFCA_EVT_POST_DATA:
 237                 info->vendor_info.rx_skb = skb;
 238         break;
 239         default:
 240                 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
 241         }
 242         complete(&info->vendor_info.req_completion);
 243         return 0;
 244 }
 245 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
 246 
 247 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
 248                                  size_t data_len)
 249 {
 250         int r;
 251         struct sk_buff *msg;
 252         struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
 253         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
 254 
 255         if (data_len <= 0)
 256                 return -EPROTO;
 257 
 258         reinit_completion(&info->vendor_info.req_completion);
 259         info->vendor_info.rx_skb = NULL;
 260 
 261         r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
 262                                ST21NFCA_EVT_POST_DATA, data, data_len);
 263         if (r < 0) {
 264                 r = -EPROTO;
 265                 goto exit;
 266         }
 267 
 268         wait_for_completion_interruptible(&info->vendor_info.req_completion);
 269         if (!info->vendor_info.rx_skb ||
 270             info->vendor_info.rx_skb->len != data_len) {
 271                 r = -EPROTO;
 272                 goto exit;
 273         }
 274 
 275         msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
 276                                         ST21NFCA_VENDOR_OUI,
 277                                         HCI_LOOPBACK,
 278                                         info->vendor_info.rx_skb->len);
 279         if (!msg) {
 280                 r = -ENOMEM;
 281                 goto free_skb;
 282         }
 283 
 284         if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
 285                     info->vendor_info.rx_skb->data)) {
 286                 kfree_skb(msg);
 287                 r = -ENOBUFS;
 288                 goto free_skb;
 289         }
 290 
 291         r = nfc_vendor_cmd_reply(msg);
 292 free_skb:
 293         kfree_skb(info->vendor_info.rx_skb);
 294 exit:
 295         return r;
 296 }
 297 
 298 static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
 299         {
 300                 .vendor_id = ST21NFCA_VENDOR_OUI,
 301                 .subcmd = FACTORY_MODE,
 302                 .doit = st21nfca_factory_mode,
 303         },
 304         {
 305                 .vendor_id = ST21NFCA_VENDOR_OUI,
 306                 .subcmd = HCI_CLEAR_ALL_PIPES,
 307                 .doit = st21nfca_hci_clear_all_pipes,
 308         },
 309         {
 310                 .vendor_id = ST21NFCA_VENDOR_OUI,
 311                 .subcmd = HCI_DM_PUT_DATA,
 312                 .doit = st21nfca_hci_dm_put_data,
 313         },
 314         {
 315                 .vendor_id = ST21NFCA_VENDOR_OUI,
 316                 .subcmd = HCI_DM_UPDATE_AID,
 317                 .doit = st21nfca_hci_dm_update_aid,
 318         },
 319         {
 320                 .vendor_id = ST21NFCA_VENDOR_OUI,
 321                 .subcmd = HCI_DM_GET_INFO,
 322                 .doit = st21nfca_hci_dm_get_info,
 323         },
 324         {
 325                 .vendor_id = ST21NFCA_VENDOR_OUI,
 326                 .subcmd = HCI_DM_GET_DATA,
 327                 .doit = st21nfca_hci_dm_get_data,
 328         },
 329         {
 330                 .vendor_id = ST21NFCA_VENDOR_OUI,
 331                 .subcmd = HCI_DM_LOAD,
 332                 .doit = st21nfca_hci_dm_load,
 333         },
 334         {
 335                 .vendor_id = ST21NFCA_VENDOR_OUI,
 336                 .subcmd = HCI_DM_RESET,
 337                 .doit = st21nfca_hci_dm_reset,
 338         },
 339         {
 340                 .vendor_id = ST21NFCA_VENDOR_OUI,
 341                 .subcmd = HCI_GET_PARAM,
 342                 .doit = st21nfca_hci_get_param,
 343         },
 344         {
 345                 .vendor_id = ST21NFCA_VENDOR_OUI,
 346                 .subcmd = HCI_DM_FIELD_GENERATOR,
 347                 .doit = st21nfca_hci_dm_field_generator,
 348         },
 349         {
 350                 .vendor_id = ST21NFCA_VENDOR_OUI,
 351                 .subcmd = HCI_LOOPBACK,
 352                 .doit = st21nfca_hci_loopback,
 353         },
 354 };
 355 
 356 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
 357 {
 358         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
 359 
 360         init_completion(&info->vendor_info.req_completion);
 361         return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
 362                                    sizeof(st21nfca_vendor_cmds));
 363 }
 364 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);

/* [<][>][^][v][top][bottom][index][help] */