[转载]NFC驱动调试

https://www.cnblogs.com/linhaostudy/p/8716333.html

 

正文

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、115Kbps2.1 Mbps~1.0 Mbps
建立时间< 0.1s6s0.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(&amp;client-&gt;dev, <span class="hljs-string">"%s: enter\n"</span>, __func__);
<span class="hljs-keyword">if</span> (client-&gt;dev.of_node) {
	platform_data = devm_kzalloc(&amp;client-&gt;dev,
		<span class="hljs-keyword">sizeof</span>(struct nqx_platform_data), GFP_KERNEL);
	<span class="hljs-keyword">if</span> (!platform_data) {
		r = -ENOMEM;
		<span class="hljs-keyword">goto</span> err_platform_data;
	}
	<span class="hljs-comment">//解析设备树</span>
	r = nfc_parse_dt(&amp;client-&gt;dev, platform_data);
	<span class="hljs-keyword">if</span> (r)
		<span class="hljs-keyword">goto</span> err_free_data;
} <span class="hljs-keyword">else</span>
	platform_data = client-&gt;dev.platform_data;

dev_dbg(&amp;client-&gt;dev,
	<span class="hljs-string">"%s, inside nfc-nci flags = %x\n"</span>,
	__func__, client-&gt;flags);

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

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

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

nqx_dev-&gt;en_gpio = platform_data-&gt;en_gpio;
nqx_dev-&gt;irq_gpio = platform_data-&gt;irq_gpio;
nqx_dev-&gt;firm_gpio  = platform_data-&gt;firm_gpio;
nqx_dev-&gt;clkreq_gpio = platform_data-&gt;clkreq_gpio;
nqx_dev-&gt;pdata = platform_data;

<span class="hljs-comment">/* init mutex and queues */</span>
init_waitqueue_head(&amp;nqx_dev-&gt;read_wq);
mutex_init(&amp;nqx_dev-&gt;read_mutex);
spin_lock_init(&amp;nqx_dev-&gt;irq_enabled_lock);

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

<span class="hljs-comment">/* NFC_INT IRQ */</span>
nqx_dev-&gt;irq_enabled = <span class="hljs-literal">true</span>;
r = request_irq(client-&gt;irq, nqx_dev_irq_handler,
		  IRQF_TRIGGER_HIGH, client-&gt;name, nqx_dev);
<span class="hljs-keyword">if</span> (r) {
	dev_err(&amp;client-&gt;dev, <span class="hljs-string">"%s: request_irq failed\n"</span>, __func__);
	<span class="hljs-keyword">goto</span> err_request_irq_failed;
}
nqx_disable_irq(nqx_dev);

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

<span class="hljs-comment">/* Register reboot notifier here */</span>
r = register_reboot_notifier(&amp;nfcc_notifier);
<span class="hljs-keyword">if</span> (r) {
	dev_err(&amp;client-&gt;dev,
		<span class="hljs-string">"%s: cannot register reboot notifier(err = %d)\n"</span>,
		__func__, r);
	<span class="hljs-comment">/* nfcc_hw_check function not doing memory
	   allocation so using same goto target here
	*/</span>
	<span class="hljs-keyword">goto</span> 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(&amp;client-&gt;dev,
<span class="hljs-string">"%s: probing NFCC NQxxx exited successfully\n"</span>,
	 __func__);
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;

#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;
<span class="hljs-keyword">switch</span> (cmd) {
<span class="hljs-keyword">case</span> NFC_SET_PWR:
	r = nfc_ioctl_power_states(pfile, arg);
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> ESE_SET_PWR:
	r = nqx_ese_pwr(pfile-&gt;private_data, arg);
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> ESE_GET_PWR:
	r = nqx_ese_pwr(pfile-&gt;private_data, <span class="hljs-number">3</span>);
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> SET_RX_BLOCK:
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> SET_EMULATOR_TEST_POINT:
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">case</span> NFCC_INITIAL_CORE_RESET_NTF:
	r = nfc_ioctl_core_reset_ntf(pfile);
	<span class="hljs-keyword">break</span>;
<span class="hljs-keyword">default</span>:
	r = -ENOIOCTLCMD;
}
<span class="hljs-keyword">return</span> r;

}

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



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值