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 nci_dev *ndev, 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        skb = nfcwilink_skb_alloc(sizeof(struct nci_vs_nfcc_info_cmd),
 150                                        GFP_KERNEL);
 151        if (!skb) {
 152                nfc_err(&drv->pdev->dev,
 153                        "no memory for nci_vs_nfcc_info_cmd\n");
 154                return -ENOMEM;
 155        }
 156
 157        cmd = (struct nci_vs_nfcc_info_cmd *)
 158                        skb_put(skb, sizeof(struct nci_vs_nfcc_info_cmd));
 159        cmd->gid = NCI_VS_NFCC_INFO_CMD_GID;
 160        cmd->oid = NCI_VS_NFCC_INFO_CMD_OID;
 161        cmd->plen = 0;
 162
 163        drv->nfcc_info.plen = 0;
 164
 165        rc = nfcwilink_send(drv->ndev, skb);
 166        if (rc)
 167                return rc;
 168
 169        comp_ret = wait_for_completion_timeout(&drv->completed,
 170                                msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
 171        dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
 172                comp_ret);
 173        if (comp_ret == 0) {
 174                nfc_err(&drv->pdev->dev,
 175                        "timeout on wait_for_completion_timeout\n");
 176                return -ETIMEDOUT;
 177        }
 178
 179        dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d\n",
 180                drv->nfcc_info.plen, drv->nfcc_info.status);
 181
 182        if ((drv->nfcc_info.plen != 5) || (drv->nfcc_info.status != 0)) {
 183                nfc_err(&drv->pdev->dev, "invalid nci_vs_nfcc_info_rsp\n");
 184                return -EINVAL;
 185        }
 186
 187        snprintf(file_name, BTS_FILE_NAME_MAX_SIZE,
 188                        "TINfcInit_%d.%d.%d.%d.bts",
 189                        drv->nfcc_info.hw_id,
 190                        drv->nfcc_info.sw_ver_x,
 191                        drv->nfcc_info.sw_ver_z,
 192                        drv->nfcc_info.patch_id);
 193
 194        nfc_info(&drv->pdev->dev, "nfcwilink FW file name: %s\n", file_name);
 195
 196        return 0;
 197}
 198
 199static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
 200{
 201        struct nfcwilink_hdr *hdr = (struct nfcwilink_hdr *)data;
 202        struct sk_buff *skb;
 203        unsigned long comp_ret;
 204        int rc;
 205
 206        /* verify valid cmd for the NFC channel */
 207        if ((len <= sizeof(struct nfcwilink_hdr)) ||
 208                (len > BTS_FILE_CMD_MAX_LEN) ||
 209                (hdr->chnl != NFCWILINK_CHNL) ||
 210                (hdr->opcode != NFCWILINK_OPCODE)) {
 211                nfc_err(&drv->pdev->dev,
 212                        "ignoring invalid bts cmd, len %d, chnl %d, opcode %d\n",
 213                        len, hdr->chnl, hdr->opcode);
 214                return 0;
 215        }
 216
 217        /* remove the ST header */
 218        len -= sizeof(struct nfcwilink_hdr);
 219        data += sizeof(struct nfcwilink_hdr);
 220
 221        skb = nfcwilink_skb_alloc(len, GFP_KERNEL);
 222        if (!skb) {
 223                nfc_err(&drv->pdev->dev, "no memory for bts cmd\n");
 224                return -ENOMEM;
 225        }
 226
 227        memcpy(skb_put(skb, len), data, len);
 228
 229        rc = nfcwilink_send(drv->ndev, skb);
 230        if (rc)
 231                return rc;
 232
 233        comp_ret = wait_for_completion_timeout(&drv->completed,
 234                                msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
 235        dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
 236                comp_ret);
 237        if (comp_ret == 0) {
 238                nfc_err(&drv->pdev->dev,
 239                        "timeout on wait_for_completion_timeout\n");
 240                return -ETIMEDOUT;
 241        }
 242
 243        return 0;
 244}
 245
 246static int nfcwilink_download_fw(struct nfcwilink *drv)
 247{
 248        unsigned char file_name[BTS_FILE_NAME_MAX_SIZE];
 249        const struct firmware *fw;
 250        __u16 action_type, action_len;
 251        __u8 *ptr;
 252        int len, rc;
 253
 254        set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
 255
 256        rc = nfcwilink_get_bts_file_name(drv, file_name);
 257        if (rc)
 258                goto exit;
 259
 260        rc = request_firmware(&fw, file_name, &drv->pdev->dev);
 261        if (rc) {
 262                nfc_err(&drv->pdev->dev, "request_firmware failed %d\n", rc);
 263
 264                /* if the file is not found, don't exit with failure */
 265                if (rc == -ENOENT)
 266                        rc = 0;
 267
 268                goto exit;
 269        }
 270
 271        len = fw->size;
 272        ptr = (__u8 *)fw->data;
 273
 274        if ((len == 0) || (ptr == NULL)) {
 275                dev_dbg(&drv->pdev->dev,
 276                        "request_firmware returned size %d\n", len);
 277                goto release_fw;
 278        }
 279
 280        if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
 281                        BTS_FILE_HDR_MAGIC) {
 282                nfc_err(&drv->pdev->dev, "wrong bts magic number\n");
 283                rc = -EINVAL;
 284                goto release_fw;
 285        }
 286
 287        /* remove the BTS header */
 288        len -= sizeof(struct bts_file_hdr);
 289        ptr += sizeof(struct bts_file_hdr);
 290
 291        while (len > 0) {
 292                action_type =
 293                        __le16_to_cpu(((struct bts_file_action *)ptr)->type);
 294                action_len =
 295                        __le16_to_cpu(((struct bts_file_action *)ptr)->len);
 296
 297                dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d\n",
 298                        action_type, action_len);
 299
 300                switch (action_type) {
 301                case BTS_FILE_ACTION_TYPE_SEND_CMD:
 302                        rc = nfcwilink_send_bts_cmd(drv,
 303                                        ((struct bts_file_action *)ptr)->data,
 304                                        action_len);
 305                        if (rc)
 306                                goto release_fw;
 307                        break;
 308                }
 309
 310                /* advance to the next action */
 311                len -= (sizeof(struct bts_file_action) + action_len);
 312                ptr += (sizeof(struct bts_file_action) + action_len);
 313        }
 314
 315release_fw:
 316        release_firmware(fw);
 317
 318exit:
 319        clear_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
 320        return rc;
 321}
 322
 323/* Called by ST when registration is complete */
 324static void nfcwilink_register_complete(void *priv_data, char data)
 325{
 326        struct nfcwilink *drv = priv_data;
 327
 328        /* store ST registration status */
 329        drv->st_register_cb_status = data;
 330
 331        /* complete the wait in nfc_st_open() */
 332        complete(&drv->completed);
 333}
 334
 335/* Called by ST when receive data is available */
 336static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
 337{
 338        struct nfcwilink *drv = priv_data;
 339        int rc;
 340
 341        if (!skb)
 342                return -EFAULT;
 343
 344        if (!drv) {
 345                kfree_skb(skb);
 346                return -EFAULT;
 347        }
 348
 349        dev_dbg(&drv->pdev->dev, "receive entry, len %d\n", skb->len);
 350
 351        /* strip the ST header
 352        (apart for the chnl byte, which is not received in the hdr) */
 353        skb_pull(skb, (NFCWILINK_HDR_LEN-1));
 354
 355        if (test_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags)) {
 356                nfcwilink_fw_download_receive(drv, skb);
 357                return 0;
 358        }
 359
 360        /* Forward skb to NCI core layer */
 361        rc = nci_recv_frame(drv->ndev, skb);
 362        if (rc < 0) {
 363                nfc_err(&drv->pdev->dev, "nci_recv_frame failed %d\n", rc);
 364                return rc;
 365        }
 366
 367        return 0;
 368}
 369
 370/* protocol structure registered with ST */
 371static struct st_proto_s nfcwilink_proto = {
 372        .chnl_id = NFCWILINK_CHNL,
 373        .max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
 374        .hdr_len = (NFCWILINK_HDR_LEN-1),       /* not including chnl byte */
 375        .offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
 376        .len_size = NFCWILINK_LEN_SIZE,
 377        .reserve = 0,
 378        .recv = nfcwilink_receive,
 379        .reg_complete_cb = nfcwilink_register_complete,
 380        .write = NULL,
 381};
 382
 383static int nfcwilink_open(struct nci_dev *ndev)
 384{
 385        struct nfcwilink *drv = nci_get_drvdata(ndev);
 386        unsigned long comp_ret;
 387        int rc;
 388
 389        if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
 390                rc = -EBUSY;
 391                goto exit;
 392        }
 393
 394        nfcwilink_proto.priv_data = drv;
 395
 396        init_completion(&drv->completed);
 397        drv->st_register_cb_status = -EINPROGRESS;
 398
 399        rc = st_register(&nfcwilink_proto);
 400        if (rc < 0) {
 401                if (rc == -EINPROGRESS) {
 402                        comp_ret = wait_for_completion_timeout(
 403                        &drv->completed,
 404                        msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
 405
 406                        dev_dbg(&drv->pdev->dev,
 407                                "wait_for_completion_timeout returned %ld\n",
 408                                comp_ret);
 409
 410                        if (comp_ret == 0) {
 411                                /* timeout */
 412                                rc = -ETIMEDOUT;
 413                                goto clear_exit;
 414                        } else if (drv->st_register_cb_status != 0) {
 415                                rc = drv->st_register_cb_status;
 416                                nfc_err(&drv->pdev->dev,
 417                                        "st_register_cb failed %d\n", rc);
 418                                goto clear_exit;
 419                        }
 420                } else {
 421                        nfc_err(&drv->pdev->dev, "st_register failed %d\n", rc);
 422                        goto clear_exit;
 423                }
 424        }
 425
 426        /* st_register MUST fill the write callback */
 427        BUG_ON(nfcwilink_proto.write == NULL);
 428        drv->st_write = nfcwilink_proto.write;
 429
 430        if (nfcwilink_download_fw(drv)) {
 431                nfc_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d\n",
 432                        rc);
 433                /* open should succeed, even if the FW download failed */
 434        }
 435
 436        goto exit;
 437
 438clear_exit:
 439        clear_bit(NFCWILINK_RUNNING, &drv->flags);
 440
 441exit:
 442        return rc;
 443}
 444
 445static int nfcwilink_close(struct nci_dev *ndev)
 446{
 447        struct nfcwilink *drv = nci_get_drvdata(ndev);
 448        int rc;
 449
 450        if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
 451                return 0;
 452
 453        rc = st_unregister(&nfcwilink_proto);
 454        if (rc)
 455                nfc_err(&drv->pdev->dev, "st_unregister failed %d\n", rc);
 456
 457        drv->st_write = NULL;
 458
 459        return rc;
 460}
 461
 462static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
 463{
 464        struct nfcwilink *drv = nci_get_drvdata(ndev);
 465        struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
 466        long len;
 467
 468        dev_dbg(&drv->pdev->dev, "send entry, len %d\n", skb->len);
 469
 470        if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) {
 471                kfree_skb(skb);
 472                return -EINVAL;
 473        }
 474
 475        /* add the ST hdr to the start of the buffer */
 476        hdr.len = cpu_to_le16(skb->len);
 477        memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
 478
 479        /* Insert skb to shared transport layer's transmit queue.
 480         * Freeing skb memory is taken care in shared transport layer,
 481         * so don't free skb memory here.
 482         */
 483        len = drv->st_write(skb);
 484        if (len < 0) {
 485                kfree_skb(skb);
 486                nfc_err(&drv->pdev->dev, "st_write failed %ld\n", len);
 487                return -EFAULT;
 488        }
 489
 490        return 0;
 491}
 492
 493static struct nci_ops nfcwilink_ops = {
 494        .open = nfcwilink_open,
 495        .close = nfcwilink_close,
 496        .send = nfcwilink_send,
 497};
 498
 499static int nfcwilink_probe(struct platform_device *pdev)
 500{
 501        static struct nfcwilink *drv;
 502        int rc;
 503        __u32 protocols;
 504
 505        drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
 506        if (!drv) {
 507                rc = -ENOMEM;
 508                goto exit;
 509        }
 510
 511        drv->pdev = pdev;
 512
 513        protocols = NFC_PROTO_JEWEL_MASK
 514                | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
 515                | NFC_PROTO_ISO14443_MASK
 516                | NFC_PROTO_ISO14443_B_MASK
 517                | NFC_PROTO_NFC_DEP_MASK;
 518
 519        drv->ndev = nci_allocate_device(&nfcwilink_ops,
 520                                        protocols,
 521                                        NFCWILINK_HDR_LEN,
 522                                        0);
 523        if (!drv->ndev) {
 524                nfc_err(&pdev->dev, "nci_allocate_device failed\n");
 525                rc = -ENOMEM;
 526                goto exit;
 527        }
 528
 529        nci_set_parent_dev(drv->ndev, &pdev->dev);
 530        nci_set_drvdata(drv->ndev, drv);
 531
 532        rc = nci_register_device(drv->ndev);
 533        if (rc < 0) {
 534                nfc_err(&pdev->dev, "nci_register_device failed %d\n", rc);
 535                goto free_dev_exit;
 536        }
 537
 538        dev_set_drvdata(&pdev->dev, drv);
 539
 540        goto exit;
 541
 542free_dev_exit:
 543        nci_free_device(drv->ndev);
 544
 545exit:
 546        return rc;
 547}
 548
 549static int nfcwilink_remove(struct platform_device *pdev)
 550{
 551        struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
 552        struct nci_dev *ndev;
 553
 554        if (!drv)
 555                return -EFAULT;
 556
 557        ndev = drv->ndev;
 558
 559        nci_unregister_device(ndev);
 560        nci_free_device(ndev);
 561
 562        return 0;
 563}
 564
 565static struct platform_driver nfcwilink_driver = {
 566        .probe = nfcwilink_probe,
 567        .remove = nfcwilink_remove,
 568        .driver = {
 569                .name = "nfcwilink",
 570                .owner = THIS_MODULE,
 571        },
 572};
 573
 574module_platform_driver(nfcwilink_driver);
 575
 576/* ------ Module Info ------ */
 577
 578MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
 579MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
 580MODULE_LICENSE("GPL");
 581