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