前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NFC驱动调试

NFC驱动调试

作者头像
233333
发布2018-04-17 15:12:15
3.3K0
发布2018-04-17 15:12:15
举报

1.NFC基本概念:

NFC 又称为近场通信,是一种新兴技术,可以在彼此靠近的情况下进行数据交换,是由非接触式射频识别(RFID)及互连互通技术整合演变而来,通过单一芯片集成感应式读卡器; NFC有效通讯距离一般不超过10厘米,其传输速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三种。

2.NFC的工作模式:

  • 读卡器模式(Reader / Writer Mode)
  • 仿真卡模式(Card Emulation Mode)
  • 点对点模式(P2P Mode)

读卡器模式: 读卡器模式本质上就是通过NFC设备(比如支持NFC的Android手机)从带有NFC芯片的标签,贴纸,明信片,报纸,名片等媒介读取信息,或者将数据写到这些媒介中。贴有NFC贴纸的产品在市面上很常见。

仿真卡模式: 仿真卡模式就是将支持NFC的手机或者其他电子设备当成借记卡、信用卡、公交卡、门禁卡等IC卡使用。基本原理就是将相应IC卡中的信息(支付凭证)封装成数据包存储在支持NFC的手机中。在使用时,还需要一个NFC射频器(相当于刷传统IC卡使用的刷卡器)。将手机靠近NFC射频器,手机就会接收到NFC射频器发过来的信号,在通过一些列验证后,将IC卡的相应信息传入NFC射频器,最后这些IC卡数据会传入NFC射频器连接的电脑,并进行相应的处理。

点对点(P2P)模式: 该模式与蓝牙、红外线差不多,可以用于不同NFC设备之间进行数据交换,只是NFC的点对点模式有效距离更短(不能超过10厘米),而且传输建立速度要比红外线和蓝牙技术快很多。 点对点模式的典型应用是两部支持NFC的手机或平板电脑实现数据的点对点传输,例如,下载音乐、交换图片、同步设备地址薄。因此,通过NFC,多个设备如数字相机,PDA,计算机,手机之间,都可以快速链接并交换资料或者服务。

3.NFC与其他模块的比较

对比项

NFC

蓝牙

红外

网络类型

点对点

单点对多点

点对点

使用距离

≤0.1m

≤10m

≤1m

传输速度

106、212、424、868、721、115Kbps

2.1 Mbps

~1.0 Mbps

建立时间

< 0.1s

6s

0.5s

安全性

主动-主动/被动

主动-主动

主动-主动

成本

4.NFC的物理组成

读写器(Reader/Interrogator)、标签(Tag/Transponder)、天线(Antenna) 1.读写器将要发送的信息,编码并加载到高频载波信号上再经天线向外发送。 2.进入读写器工作区域的电子标签接收到信号,其卡内芯片的有关电路就会进行倍压整流、调制、解密,然后对命令请求、密码、权限进行判断。

5.NFC手机的几种实现方式

根据SE(安全模块的Security Element为用用户账号,身份认证等敏感信息提供安全载体,为加强手机支付的安全性)所在位置不同;

5.1 NFC-SD卡方案

5.2 NFC-SWP模式

5.3 NFC的全终端模式

6.NFC kernel分析

6.1 从module_init函数开始:

代码语言:javascript
复制
/*
 * module load/unload record keeping
 */
static int __init nqx_dev_init(void)
{
    return i2c_add_driver(&nqx);
}
module_init(nqx_dev_init);

static void __exit nqx_dev_exit(void)
{
    unregister_reboot_notifier(&nfcc_notifier);
    i2c_del_driver(&nqx);
}
module_exit(nqx_dev_exit);

通过i2c_add_driver(&nqx)和i2c_del_driver(&nqx)注册相应的i2c设备驱动,通过i2c传输相应数据。

代码语言:javascript
复制
static struct i2c_driver nqx = {
    .id_table = nqx_id,
    .probe = nqx_probe,
    .remove = nqx_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "nq-nci",
        .of_match_table = msm_match_table,
        .pm = &nfc_pm_ops,
    },
};

通过of_match_table匹配上:

代码语言:javascript
复制
static struct of_device_id msm_match_table[] = {
    {.compatible = "qcom,nq-nci"},
    {}
};

6.2 probe函数

probe函数如下:

代码语言:javascript
复制
static int nqx_probe(struct i2c_client *client,
            const struct i2c_device_id *id)
{
    int r = 0;
    int irqn = 0;
    struct nqx_platform_data *platform_data;
    struct nqx_dev *nqx_dev;

    dev_dbg(&client->dev, "%s: enter\n", __func__);
    if (client->dev.of_node) {
        platform_data = devm_kzalloc(&client->dev,
            sizeof(struct nqx_platform_data), GFP_KERNEL);
        if (!platform_data) {
            r = -ENOMEM;
            goto err_platform_data;
        }
        //解析设备树
        r = nfc_parse_dt(&client->dev, platform_data);
        if (r)
            goto err_free_data;
    } else
        platform_data = client->dev.platform_data;

    dev_dbg(&client->dev,
        "%s, inside nfc-nci flags = %x\n",
        __func__, client->flags);

    if (platform_data == NULL) {
        dev_err(&client->dev, "%s: failed\n", __func__);
        r = -ENODEV;
        goto err_platform_data;
    }
    //判断适配器能力,这里检测适配器具有I2C功能
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        dev_err(&client->dev, "%s: need I2C_FUNC_I2C\n", __func__);
        r = -ENODEV;
        goto err_free_data;
    }
    //分配内存空间
    nqx_dev = kzalloc(sizeof(*nqx_dev), GFP_KERNEL);
    if (nqx_dev == NULL) {
        r = -ENOMEM;
        goto err_free_data;
    }
    nqx_dev->client = client;
    nqx_dev->kbuflen = MAX_BUFFER_SIZE;
    nqx_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL);
    if (!nqx_dev->kbuf) {
        dev_err(&client->dev,
            "failed to allocate memory for nqx_dev->kbuf\n");
        r = -ENOMEM;
        goto err_free_dev;
    }

    if (gpio_is_valid(platform_data->en_gpio)) {
        r = gpio_request(platform_data->en_gpio, "nfc_reset_gpio");
        if (r) {
            dev_err(&client->dev,
            "%s: unable to request nfc reset gpio [%d]\n",
                __func__,
                platform_data->en_gpio);
            goto err_mem;
        }
        r = gpio_direction_output(platform_data->en_gpio, 0);
        if (r) {
            dev_err(&client->dev,
                "%s: unable to set direction for nfc reset gpio [%d]\n",
                    __func__,
                    platform_data->en_gpio);
            goto err_en_gpio;
        }
    } else {
        dev_err(&client->dev,
        "%s: nfc reset gpio not provided\n", __func__);
        goto err_mem;
    }

    if (gpio_is_valid(platform_data->irq_gpio)) {
        r = gpio_request(platform_data->irq_gpio, "nfc_irq_gpio");
        if (r) {
            dev_err(&client->dev, "%s: unable to request nfc irq gpio [%d]\n",
                __func__, platform_data->irq_gpio);
            goto err_en_gpio;
        }
        r = gpio_direction_input(platform_data->irq_gpio);
        if (r) {
            dev_err(&client->dev,
            "%s: unable to set direction for nfc irq gpio [%d]\n",
                __func__,
                platform_data->irq_gpio);
            goto err_irq_gpio;
        }
        irqn = gpio_to_irq(platform_data->irq_gpio);
        if (irqn < 0) {
            r = irqn;
            goto err_irq_gpio;
        }
        client->irq = irqn;
    } else {
        dev_err(&client->dev, "%s: irq gpio not provided\n", __func__);
        goto err_en_gpio;
    }
    if (gpio_is_valid(platform_data->firm_gpio)) {
        r = gpio_request(platform_data->firm_gpio,
            "nfc_firm_gpio");
        if (r) {
            dev_err(&client->dev,
                "%s: unable to request nfc firmware gpio [%d]\n",
                __func__, platform_data->firm_gpio);
            goto err_irq_gpio;
        }
        r = gpio_direction_output(platform_data->firm_gpio, 0);
        if (r) {
            dev_err(&client->dev,
            "%s: cannot set direction for nfc firmware gpio [%d]\n",
            __func__, platform_data->firm_gpio);
            goto err_firm_gpio;
        }
    } else {
        dev_err(&client->dev,
            "%s: firm gpio not provided\n", __func__);
        goto err_irq_gpio;
    }
    if (gpio_is_valid(platform_data->ese_gpio)) {
        //申请中断
        r = gpio_request(platform_data->ese_gpio,
                "nfc-ese_pwr");
        if (r) {
            nqx_dev->ese_gpio = -EINVAL;
            dev_err(&client->dev,
                "%s: unable to request nfc ese gpio [%d]\n",
                    __func__, platform_data->ese_gpio);
            /* ese gpio optional so we should continue */
        } else {
            nqx_dev->ese_gpio = platform_data->ese_gpio;
            r = gpio_direction_output(platform_data->ese_gpio, 0);
            if (r) {
                /* free ese gpio and set invalid
                   to avoid further use
                */
                gpio_free(platform_data->ese_gpio);
                nqx_dev->ese_gpio = -EINVAL;
                dev_err(&client->dev,
                "%s: cannot set direction for nfc ese gpio [%d]\n",
                __func__, platform_data->ese_gpio);
                /* ese gpio optional so we should continue */
            }
        }
    } else {
        nqx_dev->ese_gpio = -EINVAL;
        dev_err(&client->dev,
            "%s: ese gpio not provided\n", __func__);
        /* ese gpio optional so we should continue */
    }
    if (gpio_is_valid(platform_data->clkreq_gpio)) {
        r = gpio_request(platform_data->clkreq_gpio,
            "nfc_clkreq_gpio");
        if (r) {
            dev_err(&client->dev,
                "%s: unable to request nfc clkreq gpio [%d]\n",
                __func__, platform_data->clkreq_gpio);
            goto err_ese_gpio;
        }
        r = gpio_direction_input(platform_data->clkreq_gpio);
        if (r) {
            dev_err(&client->dev,
            "%s: cannot set direction for nfc clkreq gpio [%d]\n",
            __func__, platform_data->clkreq_gpio);
            goto err_clkreq_gpio;
        }
    } else {
        dev_err(&client->dev,
            "%s: clkreq gpio not provided\n", __func__);
        goto err_ese_gpio;
    }

    nqx_dev->en_gpio = platform_data->en_gpio;
    nqx_dev->irq_gpio = platform_data->irq_gpio;
    nqx_dev->firm_gpio  = platform_data->firm_gpio;
    nqx_dev->clkreq_gpio = platform_data->clkreq_gpio;
    nqx_dev->pdata = platform_data;

    /* init mutex and queues */
    init_waitqueue_head(&nqx_dev->read_wq);
    mutex_init(&nqx_dev->read_mutex);
    spin_lock_init(&nqx_dev->irq_enabled_lock);

    nqx_dev->nqx_device.minor = MISC_DYNAMIC_MINOR;
    nqx_dev->nqx_device.name = "nq-nci";
     //在此处与 nfc_dev_fops 操作列表进行连接
    nqx_dev->nqx_device.fops = &nfc_dev_fops;
    //注册混杂设备驱动
    r = misc_register(&nqx_dev->nqx_device);
    if (r) {
        dev_err(&client->dev, "%s: misc_register failed\n", __func__);
        goto err_misc_register;
    }

    /* NFC_INT IRQ */
    nqx_dev->irq_enabled = true;
    r = request_irq(client->irq, nqx_dev_irq_handler,
              IRQF_TRIGGER_HIGH, client->name, nqx_dev);
    if (r) {
        dev_err(&client->dev, "%s: request_irq failed\n", __func__);
        goto err_request_irq_failed;
    }
    nqx_disable_irq(nqx_dev);

    /*
     * To be efficient we need to test whether nfcc hardware is physically
     * present before attempting further hardware initialisation.
     *
     */
    r = nfcc_hw_check(client , platform_data->en_gpio);
    if (r) {
        /* make sure NFCC is not enabled */
        gpio_set_value(platform_data->en_gpio, 0);
        /* We don't think there is hardware switch NFC OFF */
        goto err_request_hw_check_failed;
    }

    /* Register reboot notifier here */
    r = register_reboot_notifier(&nfcc_notifier);
    if (r) {
        dev_err(&client->dev,
            "%s: cannot register reboot notifier(err = %d)\n",
            __func__, r);
        /* nfcc_hw_check function not doing memory
           allocation so using same goto target here
        */
        goto err_request_hw_check_failed;
    }

#ifdef NFC_KERNEL_BU
    r = nqx_clock_select(nqx_dev);
    if (r < 0) {
        dev_err(&client->dev,
            "%s: nqx_clock_select failed\n", __func__);
        goto err_clock_en_failed;
    }
    gpio_set_value(platform_data->en_gpio, 1);
#endif
    device_init_wakeup(&client->dev, true);
    device_set_wakeup_capable(&client->dev, true);
    i2c_set_clientdata(client, nqx_dev);
    nqx_dev->irq_wake_up = false;

    dev_err(&client->dev,
    "%s: probing NFCC NQxxx exited successfully\n",
         __func__);
    return 0;

#ifdef NFC_KERNEL_BU
err_clock_en_failed:
    unregister_reboot_notifier(&nfcc_notifier);
#endif
err_request_hw_check_failed:
    free_irq(client->irq, nqx_dev);
err_request_irq_failed:
    misc_deregister(&nqx_dev->nqx_device);
err_misc_register:
    mutex_destroy(&nqx_dev->read_mutex);
err_clkreq_gpio:
    gpio_free(platform_data->clkreq_gpio);
err_ese_gpio:
    /* optional gpio, not sure was configured in probe */
    if (nqx_dev->ese_gpio > 0)
        gpio_free(platform_data->ese_gpio);
err_firm_gpio:
    gpio_free(platform_data->firm_gpio);
err_irq_gpio:
    gpio_free(platform_data->irq_gpio);
err_en_gpio:
    gpio_free(platform_data->en_gpio);
err_mem:
    kfree(nqx_dev->kbuf);
err_free_dev:
    kfree(nqx_dev);
err_free_data:
    if (client->dev.of_node)
        devm_kfree(&client->dev, platform_data);
err_platform_data:
    dev_err(&client->dev,
    "%s: probing nqxx failed, check hardware\n",
         __func__);
    return r;
}

6.3 file_operations

fops 中包含了 ioctl 的操作方式,cmd 为 1 关闭 nfc , 2 为开启ese功能,3 为获取ese功能。

代码语言:javascript
复制
static const struct file_operations nfc_dev_fops = {
    .owner = THIS_MODULE,
    .llseek = no_llseek,
    .read  = nfc_read,
    .write = nfc_write,
    .open = nfc_open,
    .unlocked_ioctl = nfc_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = nfc_compat_ioctl
#endif
};
代码语言:javascript
复制
static long nfc_ioctl(struct file *pfile, unsigned int cmd,
            unsigned long arg)
{
    int r = 0;

    switch (cmd) {
    case NFC_SET_PWR:
        r = nfc_ioctl_power_states(pfile, arg);
        break;
    case ESE_SET_PWR:
        r = nqx_ese_pwr(pfile->private_data, arg);
        break;
    case ESE_GET_PWR:
        r = nqx_ese_pwr(pfile->private_data, 3);
        break;
    case SET_RX_BLOCK:
        break;
    case SET_EMULATOR_TEST_POINT:
        break;
    case NFCC_INITIAL_CORE_RESET_NTF:
        r = nfc_ioctl_core_reset_ntf(pfile);
        break;
    default:
        r = -ENOIOCTLCMD;
    }
    return r;
}

因为NQ210的eSE功能被阉割,所以,只需要调通I2C即可;上层只需调用相应的ioctl功能;高通的中NQ220有eSE功能就是在trustzone的QSEE环境下运行的;如果有调试到,再分析分析; 第一次使用markdown功能写博客,挺好用的;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-04-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.NFC基本概念:
  • 2.NFC的工作模式:
  • 3.NFC与其他模块的比较
  • 4.NFC的物理组成
  • 5.NFC手机的几种实现方式
    • 5.1 NFC-SD卡方案
      • 5.2 NFC-SWP模式
        • 5.3 NFC的全终端模式
        • 6.NFC kernel分析
          • 6.1 从module_init函数开始:
            • 6.2 probe函数
              • 6.3 file_operations
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档