root/drivers/nfc/st-nci/vendor_cmds.c

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

DEFINITIONS

This source file includes following definitions.
  1. st_nci_factory_mode
  2. st_nci_hci_clear_all_pipes
  3. st_nci_hci_dm_put_data
  4. st_nci_hci_dm_update_aid
  5. st_nci_hci_dm_get_info
  6. st_nci_hci_dm_get_data
  7. st_nci_hci_dm_fwupd_start
  8. st_nci_hci_dm_fwupd_end
  9. st_nci_hci_dm_direct_load
  10. st_nci_hci_dm_reset
  11. st_nci_hci_get_param
  12. st_nci_hci_dm_field_generator
  13. st_nci_hci_dm_vdc_measurement_value
  14. st_nci_hci_dm_vdc_value_comparison
  15. st_nci_loopback
  16. st_nci_manufacturer_specific
  17. st_nci_vendor_cmds_init

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

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