Linux NFC 子系统¶
近场通信 (NFC) 子系统用于标准化 NFC 设备驱动程序的开发,并创建一个统一的用户空间接口。
本文档涵盖了架构概述、设备驱动程序接口描述和用户空间接口描述。
架构概述¶
- NFC 子系统负责:
NFC 适配器管理;
轮询目标;
低级数据交换;
该子系统分为几个部分。“核心”负责提供设备驱动程序接口。另一方面,它还负责提供用于控制操作和低级数据交换的接口。
控制操作可通过通用 netlink 提供给用户空间。
低级数据交换接口由新的套接字系列 PF_NFC 提供。NFC_SOCKPROTO_RAW 执行与 NFC 目标的原始通信。
+--------------------------------------+
| USER SPACE |
+--------------------------------------+
^ ^
| low-level | control
| data exchange | operations
| |
| v
| +-----------+
| AF_NFC | netlink |
| socket +-----------+
| raw ^
| |
v v
+---------+ +-----------+
| rawsock | <--------> | core |
+---------+ +-----------+
^
|
v
+-----------+
| driver |
+-----------+
设备驱动程序接口¶
在 NFC 子系统上注册时,设备驱动程序必须将支持的 NFC 协议集和 ops 回调集告知核心。必须实现的 ops 回调如下:
start_poll - 设置设备以轮询目标
stop_poll - 停止正在进行的轮询操作
activate_target - 选择并初始化找到的目标之一
deactivate_target - 取消选择并取消初始化选定的目标
data_exchange - 发送数据并接收响应(收发操作)
用户空间接口¶
用户空间接口分为控制操作和低级数据交换操作。
控制操作
通用 netlink 用于实现控制操作的接口。这些操作由命令和事件组成,所有这些都列在下面:
NFC_CMD_GET_DEVICE - 获取特定设备信息或转储设备列表
NFC_CMD_START_POLL - 设置特定设备以轮询目标
NFC_CMD_STOP_POLL - 停止特定设备中的轮询操作
NFC_CMD_GET_TARGET - 转储特定设备找到的目标列表
NFC_EVENT_DEVICE_ADDED - 报告 NFC 设备添加
NFC_EVENT_DEVICE_REMOVED - 报告 NFC 设备移除
NFC_EVENT_TARGETS_FOUND - 当找到 1 个或多个目标时报告 START_POLL 结果
用户必须调用 START_POLL 来轮询 NFC 目标,并通过 NFC_ATTR_PROTOCOLS 属性传递所需的 NFC 协议。设备将保持轮询状态,直到找到任何目标。但是,用户可以通过调用 STOP_POLL 命令来停止轮询操作。在这种情况下,将检查 STOP_POLL 的请求者是否与 START_POLL 的请求者相同。
如果轮询操作找到一个或多个目标,则会发送 TARGETS_FOUND 事件(包括设备 ID)。用户必须调用 GET_TARGET 来获取此设备找到的所有目标的列表。每个回复消息都具有目标属性,其中包含相关信息,例如支持的 NFC 协议。
通过一个 netlink 套接字请求的所有轮询操作在其关闭时都会停止。
低级数据交换
用户空间必须使用 PF_NFC 套接字来执行与目标的任何数据通信。所有 NFC 套接字都使用 AF_NFC
struct sockaddr_nfc {
sa_family_t sa_family;
__u32 dev_idx;
__u32 target_idx;
__u32 nfc_protocol;
};
要与一个目标建立连接,用户必须创建一个 NFC_SOCKPROTO_RAW 套接字,并使用正确填充的 sockaddr_nfc 结构调用“connect”系统调用。所有信息都来自 NFC_EVENT_TARGETS_FOUND netlink 事件。由于一个目标可以支持多个 NFC 协议,因此用户必须告知要使用哪个协议。
在内部,“connect”将导致对驱动程序进行 activate_target 调用。当套接字关闭时,目标将被停用。
通过套接字交换的数据格式与 NFC 协议相关。例如,在与 MIFARE 标签通信时,交换的数据是 MIFARE 命令及其响应。
第一个接收到的包是对第一个发送的包的响应,依此类推。为了允许有效的“空”响应,每个接收到的数据都有一个 1 字节的 NULL 标头。