linux/drivers/nfc/nfcwilink.c
<<
>>
Prefs
   1/*
   2 *  Texas Instrument's NFC Driver For Shared Transport.
   3 *
   4 *  NFC Driver acts as interface between NCI core and
   5 *  TI Shared Transport Layer.
   6 *
   7 *  Copyright (C) 2011 Texas Instruments, Inc.
   8 *
   9 *  Written by Ilan Elias <ilane@ti.com>
  10 *
  11 *  Acknowledgements:
  12 *  This file is based on btwilink.c, which was written
  13 *  by Raja Mani and Pavan Savoy.
  14 *
  15 *  This program is free software; you can redistribute it and/or modify
  16 *  it under the terms of the GNU General Public License version 2 as
  17 *  published by the Free Software Foundation.
  18 *
  19 *  This program is distributed in the hope that it will be useful,
  20 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 *  GNU General Public License for more details.
  23 *
  24 *  You should have received a copy of the GNU General Public License
  25 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  26 *
  27 */
  28#include <linux/platform_device.h>
  29#include <linux/module.h>
  30#include <linux/types.h>
  31#include <linux/firmware.h>
  32#include <linux/nfc.h>
  33#include <net/nfc/nci.h>
  34#include <net/nfc/nci_core.h>
  35#include <linux/ti_wilink_st.h>
  36
  37#define NFCWILINK_CHNL                  12
  38#define NFCWILINK_OPCODE                7
  39#define NFCWILINK_MAX_FRAME_SIZE        300
  40#define NFCWILINK_HDR_LEN               4
  41#define NFCWILINK_OFFSET_LEN_IN_HDR     1
  42#define NFCWILINK_LEN_SIZE              2
  43#define NFCWILINK_REGISTER_TIMEOUT      8000    /* 8 sec */
  44#define NFCWILINK_CMD_TIMEOUT           5000    /* 5 sec */
  45
  46#define BTS_FILE_NAME_MAX_SIZE          40
  47#define BTS_FILE_HDR_MAGIC              0x42535442
  48#define BTS_FILE_CMD_MAX_LEN            0xff
  49#define BTS_FILE_ACTION_TYPE_SEND_CMD   1
  50
  51#define NCI_VS_NFCC_INFO_CMD_GID        0x2f
  52#define NCI_VS_NFCC_INFO_CMD_OID        0x12
  53#define NCI_VS_NFCC_INFO_RSP_GID        0x4f
  54#define NCI_VS_NFCC_INFO_RSP_OID        0x12
  55
  56struct nfcwilink_hdr {
  57        __u8 chnl;
  58        __u8 opcode;
  59        __le16 len;
  60} __packed;
  61
  62struct nci_vs_nfcc_info_cmd {
  63        __u8 gid;
  64        __u8 oid;
  65        __u8 plen;
  66} __packed;
  67
  68struct nci_vs_nfcc_info_rsp {
  69        __u8 gid;
  70        __u8 oid;
  71        __u8 plen;
  72        __u8 status;
  73        __u8 hw_id;
  74        __u8 sw_ver_x;
  75        __u8 sw_ver_z;
  76        __u8 patch_id;
  77} __packed;
  78
  79struct bts_file_hdr {
  80        __le32 magic;
  81        __le32 ver;
  82        __u8 rfu[24];
  83        __u8 actions[0];
  84} __packed;
  85
  86struct bts_file_action {
  87        __le16 type;
  88        __le16 len;
  89        __u8 data[0];
  90} __packed;
  91
  92struct nfcwilink {
  93        struct platform_device          *pdev;
  94        struct nci_dev                  *ndev;
  95        unsigned long                   flags;
  96
  97        int                             st_register_cb_status;
  98        long                            (*st_write) (struct sk_buff *);
  99
 100        struct completion               completed;
 101
 102        struct nci_vs_nfcc_info_rsp     nfcc_info;
 103};
 104
 105/* NFCWILINK driver flags */
 106enum {
 107        NFCWILINK_RUNNING,
 108        NFCWILINK_FW_DOWNLOAD,
 109};
 110
 111static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb);
 112
 113static inline struct sk_buff *nfcwilink_skb_alloc(unsigned int len, gfp_t how)
 114{
 115        struct sk_buff *skb;
 116
 117        skb = alloc_skb(len + NFCWILINK_HDR_LEN, how);
 118        if (skb)
 119                skb_reserve(skb, NFCWILINK_HDR_LEN);
 120
 121        return skb;
 122}
 123
 124static void nfcwilink_fw_download_receive(struct nfcwilink *drv,
 125                                                struct sk_buff *skb)
 126{
 127        struct nci_vs_nfcc_info_rsp *rsp = (void *)skb->data;
 128
 129        /* Detect NCI_VS_NFCC_INFO_RSP and store the result */
 130        if ((skb->len > 3) && (rsp->gid == NCI_VS_NFCC_INFO_RSP_GID) &&
 131                (rsp->oid == NCI_VS_NFCC_INFO_RSP_OID)) {
 132                memcpy(&drv->nfcc_info, rsp,
 133                        sizeof(struct nci_vs_nfcc_info_rsp));
 134        }
 135
 136        kfree_skb(skb);
 137
 138        complete(&drv->completed);
 139}
 140
 141static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
 142{
 143        struct nci_vs_nfcc_info_cmd *cmd;
 144        struct sk_buff *skb;
 145        unsigned long comp_ret;
 146        int rc;
 147
 148        skb = nfcwilink_skb_alloc(sizeof(struct nci_vs_nfcc_info_cmd),
 149                                        GFP_KERNEL);
 150        if (!skb) {
 151                nfc_err(&drv->pdev->dev,
 152                        "no memory for nci_vs_nfcc_info_cmd\n");
 153                return -ENOMEM;
 154        }
 155
 156        cmd = (struct nci_vs_nfcc_info_cmd *)
 157                        skb_put(skb, sizeof(struct nci_vs_nfcc_info_cmd));
 158        cmd->gid = NCI_VS_NFCC_INFO_CMD_GID;
 159        cmd->oid = NCI_VS_NFCC_INFO_CMD_OID;
 160        cmd->plen = 0;
 161
 162        drv->nfcc_info.plen = 0;
 163
 164        rc = nfcwilink_send(drv->ndev, skb);
 165        if (rc)
 166                return rc;
 167
 168        comp_ret = wait_for_completion_timeout(&drv->completed,
 169                                msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
 170        dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
 171                comp_ret);
 172        if (comp_ret == 0) {
 173                nfc_err(&drv->pdev->dev,
 174                        "timeout on wait_for_completion_timeout\n");
 175                return -ETIMEDOUT;
 176        }
 177
 178        dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d\n",
 179                drv->nfcc_info.plen, drv->nfcc_info.status);
 180
 181        if ((drv->nfcc_info.plen != 5) || (drv->nfcc_info.status != 0)) {
 182                nfc_err(&drv->pdev->dev, "invalid nci_vs_nfcc_info_rsp\n");
 183                return -EINVAL;
 184        }
 185
 186        snprintf(file_name, BTS_FILE_NAME_MAX_SIZE,
 187                        "TINfcInit_%d.%d.%d.%d.bts",
 188                        drv->nfcc_info.hw_id,
 189                        drv->nfcc_info.sw_ver_x,
 190                        drv->nfcc_info.sw_ver_z,
 191                        drv->nfcc_info.patch_id);
 192
 193        nfc_info(&drv->pdev->dev, "nfcwilink FW file name: %s\n", file_name);
 194
 195        return 0;
 196}
 197
 198static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
 199{
 200        struct nfcwilink_hdr *hdr = (struct nfcwilink_hdr *)data;
 201        struct sk_buff *skb;
 202        unsigned long comp_ret;
 203        int rc;
 204
 205        /* verify valid cmd for the NFC channel */
 206        if ((len <= sizeof(struct nfcwilink_hdr)) ||
 207                (len > BTS_FILE_CMD_MAX_LEN) ||
 208                (hdr->chnl != NFCWILINK_CHNL) ||
 209                (hdr->opcode != NFCWILINK_OPCODE)) {
 210                nfc_err(&drv->pdev->dev,
 211                        "ignoring invalid bts cmd, len %d, chnl %d, opcode %d\n",
 212                        len, hdr->chnl, hdr->opcode);
 213                return 0;
 214        }
 215
 216        /* remove the ST header */
 217        len -= sizeof(struct nfcwilink_hdr);
 218        data += sizeof(struct nfcwilink_hdr);
 219
 220        skb = nfcwilink_skb_alloc(len, GFP_KERNEL);
 221        if (!skb) {
 222                nfc_err(&drv->pdev->dev, "no memory for bts cmd\n");
 223                return -ENOMEM;
 224        }
 225
 226        memcpy(skb_put(skb, len), data, len);
 227
 228        rc = nfcwilink_send(drv->ndev, skb);
 229        if (rc)
 230                return rc;
 231
 232        comp_ret = wait_for_completion_timeout(&drv->completed,
 233                                msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
 234        dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
 235                comp_ret);
 236        if (comp_ret == 0) {
 237                nfc_err(&drv->pdev->dev,
 238                        "timeout on wait_for_completion_timeout\n");
 239                return -ETIMEDOUT;
 240        }
 241
 242        return 0;
 243}
 244
 245static int nfcwilink_download_fw(struct nfcwilink *drv)
 246{
 247        unsigned char file_name[BTS_FILE_NAME_MAX_SIZE];
 248        const struct firmware *fw;
 249        __u16 action_type, action_len;
 250        __u8 *ptr;
 251        int len, rc;
 252
 253        set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
 254
 255        rc = nfcwilink_get_bts_file_name(drv, file_name);
 256        if (rc)
 257                goto exit;
 258
 259        rc = request_firmware(&fw, file_name, &drv->pdev->dev);
 260        if (rc) {
 261                nfc_err(&drv->pdev->dev, "request_firmware failed %d\n", rc);
 262
 263                /* if the file is not found, don't exit with failure */
 264                if (rc == -ENOENT)
 265                        rc = 0;
 266
 267                goto exit;
 268        }
 269
 270        len = fw->size;
 271        ptr = (__u8 *)fw->data;
 272
 273        if ((len == 0) || (ptr == NULL)) {
 274                dev_dbg(&drv->pdev->dev,
 275                        "request_firmware returned size %d\n", len);
 276                goto release_fw;
 277        }
 278
 279        if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
 280                        BTS_FILE_HDR_MAGIC) {
 281                nfc_err(&drv->pdev->dev, "wrong bts magic number\n");
 282                rc = -EINVAL;
 283                goto release_fw;
 284        }
 285
 286        /* remove the BTS header */
 287        len -= sizeof(struct bts_file_hdr);
 288        ptr += sizeof(struct bts_file_hdr);
 289
 290        while (len > 0) {
 291                action_type =
 292                        __le16_to_cpu(((struct bts_file_action *)ptr)->type);
 293                action_len =
 294                        __le16_to_cpu(((struct bts_file_action *)ptr)->len);
 295
 296                dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d\n",
 297                        action_type, action_len);
 298
 299                switch (action_type) {
 300                case BTS_FILE_ACTION_TYPE_SEND_CMD:
 301                        rc = nfcwilink_send_bts_cmd(drv,
 302                                        ((struct bts_file_action *)ptr)->data,
 303                                        action_len);
 304                        if (rc)
 305                                goto release_fw;
 306                        break;
 307                }
 308
 309                /* advance to the next action */
 310                len -= (sizeof(struct bts_file_action) + action_len);
 311                ptr += (sizeof(struct bts_file_action) + action_len);
 312        }
 313
 314release_fw:
 315        release_firmware(fw);
 316
 317exit:
 318        clear_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
 319        return rc;
 320}
 321
 322/* Called by ST when registration is complete */
 323static void nfcwilink_register_complete(void *priv_data, int data)
 324{
 325        struct nfcwilink *drv = priv_data;
 326
 327        /* store ST registration status */
 328        drv->st_register_cb_status = data;
 329
 330        /* complete the wait in nfc_st_open() */
 331        complete(&drv->completed);
 332}
 333
 334/* Called by ST when receive data is available */
 335static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
 336{
 337        struct nfcwilink *drv = priv_data;
 338        int rc;
 339
 340        if (!skb)
 341                return -EFAULT;
 342
 343        if (!drv) {
 344                kfree_skb(skb);
 345                return -EFAULT;
 346        }
 347
 348        dev_dbg(&drv->pdev->dev, "receive entry, len %d\n", skb->len);
 349
 350        /* strip the ST header
 351        (apart for the chnl byte, which is not received in the hdr) */
 352        skb_pull(skb, (NFCWILINK_HDR_LEN-1));
 353
 354        if (test_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags)) {
 355                nfcwilink_fw_download_receive(drv, skb);
 356                return 0;
 357        }
 358
 359        /* Forward skb to NCI core layer */
 360        rc = nci_recv_frame(drv->ndev, skb);
 361        if (rc < 0) {
 362                nfc_err(&drv->pdev->dev, "nci_recv_frame failed %d\n", rc);
 363                return rc;
 364        }
 365
 366        return 0;
 367}
 368
 369/* protocol structure registered with ST */
 370static struct st_proto_s nfcwilink_proto = {
 371        .chnl_id = NFCWILINK_CHNL,
 372        .max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
 373        .hdr_len = (NFCWILINK_HDR_LEN-1),       /* not including chnl byte */
 374        .offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
 375        .len_size = NFCWILINK_LEN_SIZE,
 376        .reserve = 0,
 377        .recv = nfcwilink_receive,
 378        .reg_complete_cb = nfcwilink_register_complete,
 379        .write = NULL,
 380};
 381
 382static int nfcwilink_open(struct nci_dev *ndev)
 383{
 384        struct nfcwilink *drv = nci_get_drvdata(ndev);
 385        unsigned long comp_ret;
 386        int rc;
 387
 388        if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
 389                rc = -EBUSY;
 390                goto exit;
 391        }
 392
 393        nfcwilink_proto.priv_data = drv;
 394
 395        init_completion(&drv->completed);
 396        drv->st_register_cb_status = -EINPROGRESS;
 397
 398        rc = st_register(&nfcwilink_proto);
 399        if (rc < 0) {
 400                if (rc == -EINPROGRESS) {
 401                        comp_ret = wait_for_completion_timeout(
 402                        &drv->completed,
 403                        msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
 404
 405                        dev_dbg(&drv->pdev->dev,
 406                                "wait_for_completion_timeout returned %ld\n",
 407                                comp_ret);
 408
 409                        if (comp_ret == 0) {
 410                                /* timeout */
 411                                rc = -ETIMEDOUT;
 412                                goto clear_exit;
 413                        } else if (drv->st_register_cb_status != 0) {
 414                                rc = drv->st_register_cb_status;
 415                                nfc_err(&drv->pdev->dev,
 416                                        "st_register_cb failed %d\n", rc);
 417                                goto clear_exit;
 418                        }
 419                } else {
 420                        nfc_err(&drv->pdev->dev, "st_register failed %d\n", rc);
 421                        goto clear_exit;
 422                }
 423        }
 424
 425        /* st_register MUST fill the write callback */
 426        BUG_ON(nfcwilink_proto.write == NULL);
 427        drv->st_write = nfcwilink_proto.write;
 428
 429        if (nfcwilink_download_fw(drv)) {
 430                nfc_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d\n",
 431                        rc);
 432                /* open should succeed, even if the FW download failed */
 433        }
 434
 435        goto exit;
 436
 437clear_exit:
 438        clear_bit(NFCWILINK_RUNNING, &drv->flags);
 439
 440exit:
 441        return rc;
 442}
 443
 444static int nfcwilink_close(struct nci_dev *ndev)
 445{
 446        struct nfcwilink *drv = nci_get_drvdata(ndev);
 447        int rc;
 448
 449        if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
 450                return 0;
 451
 452        rc = st_unregister(&nfcwilink_proto);
 453        if (rc)
 454                nfc_err(&drv->pdev->dev, "st_unregister failed %d\n", rc);
 455
 456        drv->st_write = NULL;
 457
 458        return rc;
 459}
 460
 461static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
 462{
 463        struct nfcwilink *drv = nci_get_drvdata(ndev);
 464        struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
 465        long len;
 466
 467        dev_dbg(&drv->pdev->dev, "send entry, len %d\n", skb->len);
 468
 469        if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) {
 470                kfree_skb(skb);
 471                return -EINVAL;
 472        }
 473
 474        /* add the ST hdr to the start of the buffer */
 475        hdr.len = cpu_to_le16(skb->len);
 476        memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
 477
 478        /* Insert skb to shared transport layer's transmit queue.
 479         * Freeing skb memory is taken care in shared transport layer,
 480         * so don't free skb memory here.
 481         */
 482        len = drv->st_write(skb);
 483        if (len < 0) {
 484                kfree_skb(skb);
 485                nfc_err(&drv->pdev->dev, "st_write failed %ld\n", len);
 486                return -EFAULT;
 487        }
 488
 489        return 0;
 490}
 491
 492static struct nci_ops nfcwilink_ops = {
 493        .open = nfcwilink_open,
 494        .close = nfcwilink_close,
 495        .send = nfcwilink_send,
 496};
 497
 498static int nfcwilink_probe(struct platform_device *pdev)
 499{
 500        struct nfcwilink *drv;
 501        int rc;
 502        __u32 protocols;
 503
 504        drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
 505        if (!drv) {
 506                rc = -ENOMEM;
 507                goto exit;
 508        }
 509
 510        drv->pdev = pdev;
 511
 512        protocols = NFC_PROTO_JEWEL_MASK
 513                | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
 514                | NFC_PROTO_ISO14443_MASK
 515                | NFC_PROTO_ISO14443_B_MASK
 516                | NFC_PROTO_NFC_DEP_MASK;
 517
 518        drv->ndev = nci_allocate_device(&nfcwilink_ops,
 519                                        protocols,
 520                                        NFCWILINK_HDR_LEN,
 521                                        0);
 522        if (!drv->ndev) {
 523                nfc_err(&pdev->dev, "nci_allocate_device failed\n");
 524                rc = -ENOMEM;
 525                goto exit;
 526        }
 527
 528        nci_set_parent_dev(drv->ndev, &pdev->dev);
 529        nci_set_drvdata(drv->ndev, drv);
 530
 531        rc = nci_register_device(drv->ndev);
 532        if (rc < 0) {
 533                nfc_err(&pdev->dev, "nci_register_device failed %d\n", rc);
 534                goto free_dev_exit;
 535        }
 536
 537        dev_set_drvdata(&pdev->dev, drv);
 538
 539        goto exit;
 540
 541free_dev_exit:
 542        nci_free_device(drv->ndev);
 543
 544exit:
 545        return rc;
 546}
 547
 548static int nfcwilink_remove(struct platform_device *pdev)
 549{
 550        struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
 551        struct nci_dev *ndev;
 552
 553        if (!drv)
 554                return -EFAULT;
 555
 556        ndev = drv->ndev;
 557
 558        nci_unregister_device(ndev);
 559        nci_free_device(ndev);
 560
 561        return 0;
 562}
 563
 564static struct platform_driver nfcwilink_driver = {
 565        .probe = nfcwilink_probe,
 566        .remove = nfcwilink_remove,
 567        .driver = {
 568                .name = "nfcwilink",
 569        },
 570};
 571
 572module_platform_driver(nfcwilink_driver);
 573
 574/* ------ Module Info ------ */
 575
 576MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
 577MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
 578MODULE_LICENSE("GPL");
 579