NFC驱动调试
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函数开始:
/*
* 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传输相应数据。
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匹配上:
static struct of_device_id msm_match_table[] = {
{.compatible = "qcom,nq-nci"},
{}
};
6.2 probe函数
probe函数如下:
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功能。
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
};
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功能写博客,挺好用的;
NFC驱动调试的更多相关文章
- Android驱动调试利器Busybox之初体验
工欲善其事必先利其器,之前做WinCE开发时,经常写一些小工具以提高开发调试的效率,如WinCE驱动调试助手.WinCE串口调试助手.WinCE6.0寄存器访问工具.WinCE远程桌面助手和S3C24 ...
- [windows驱动]windows8.1驱动调试前戏
人们都说在干正事之前,得先做足前戏才会爽,我一直很认同这个观点,下面我来总结下进行windows8.1的WDK调试所要做的准备工作. 软件安装: 1.VS2013. 2.WDK8.1 3.Window ...
- Linux驱动设计—— 驱动调试技术
参考博客与书籍: <Linux设备驱动开发详解> <Linux设备驱动程序> http://blog.chinaunix.net/uid-24219701-id-2884942 ...
- android 电容屏(二):驱动调试之基本概念篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
- 【转】android 电容屏(三):驱动调试之驱动程序分析篇
关键词:android 电容屏 tp 工作队列 中断 坐点计算 电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310( ...
- 【转】android 电容屏(二):驱动调试之基本概念篇
关键词:android 电容屏 tp 工作队列 中断 多点触摸协议平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310(samsung ...
- 【转】Android LCD(四):LCD驱动调试篇
关键词:android LCD TFTSN75LVDS83B TTL-LVDS LCD电压背光电压 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台 ...
- linux驱动调试--段错误之oops信息分析
linux驱动调试--段错误之oops信息分析 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id= ...
- Windows7驱动调试小Tips
v:* { } o:* { } w:* { } .shape { }p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-botto ...
随机推荐
- Spring Boot初探之log4j2配置
一.背景 下面讲在使用Spring Boot搭建微服务框架时如何配置log4j2,通过log4j2输出系统中日志信息. 二.添加log4j2的配置文件 在项目的src/main/rescources目 ...
- 网页提示错误(net::ERR_EMPTY_RESPONSE)
突然个别网页打不开,报上面的错,本来还以为是网页的问题,结果发现是自己的电脑的问题..因为从别的设备上可以打开相同网页. 1.运行→regedit→进入注册表, 在 HKEY_LOCAL_MACHIN ...
- MongoDB系列一(查询).
一.简述 MongoDB中使用find来进行查询.查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合.默认情况下,"_id"这个键总是被返回,即便是没有指定要返回这 ...
- PAT乙级-1036.跟奥巴马一起编程(15)
题解 题解: 注意"行数是列数的50%(四舍五入)" #include<iostream> using namespace std; int main() { int ...
- K-Means 聚类
机器学习中的算法主要分为两类,一类是监督学习,监督学习顾名思义就是在学习的过程中有人监督,即对于每一个训练样本,有对应的标记指明它的类型.如识别算法的训练集中猫的图片,在训练之前会人工打上标签,告诉电 ...
- ReactNative环境配置的坑
我用的是windows开发android,mac的可以绕道了. 1.android studio及Android SDK的安装 现在需要的Android版本及对应的tool 2.真机运行要配置对and ...
- Java I/O 总结
Java I/O的的架构使用了装饰器的模式,我们在使用流的时候需要新建很多的装饰器对象,对源数据进行层层包装.各个包装类名以及它们的应用场景比较多,初学的时候难以摸清规律,这里我把它们归一下类,方便大 ...
- Android_scaleType属性
这里我们重点理解ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType).android:scaleType ...
- 【JS】 Javascript与HTML DOM的互动 寻路
JS HTML DOM DOM的全程是Document Object Module,即文档对象模型.一般来说,当一个页面被加载时,浏览器会在内部创建一个当前文档的DOM.就像用python的Etree ...
- Mysql中一级缓存二级缓存区别
一级缓存: 也称本地缓存,sqlSession级别的缓存.一级缓存是一直开启的:与数据库同一次会话期间查询到的数据会放在本地缓存中. 如果需要获取相同的数据,直接从缓存中拿,不会再查数据库. 一级缓存 ...