162306a36Sopenharmony_ci======================== 262306a36Sopenharmony_ciHCI backend for NFC Core 362306a36Sopenharmony_ci======================== 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci- Author: Eric Lapuyade, Samuel Ortiz 662306a36Sopenharmony_ci- Contact: eric.lapuyade@intel.com, samuel.ortiz@intel.com 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciGeneral 962306a36Sopenharmony_ci------- 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciThe HCI layer implements much of the ETSI TS 102 622 V10.2.0 specification. It 1262306a36Sopenharmony_cienables easy writing of HCI-based NFC drivers. The HCI layer runs as an NFC Core 1362306a36Sopenharmony_cibackend, implementing an abstract nfc device and translating NFC Core API 1462306a36Sopenharmony_cito HCI commands and events. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciHCI 1762306a36Sopenharmony_ci--- 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciHCI registers as an nfc device with NFC Core. Requests coming from userspace are 2062306a36Sopenharmony_cirouted through netlink sockets to NFC Core and then to HCI. From this point, 2162306a36Sopenharmony_cithey are translated in a sequence of HCI commands sent to the HCI layer in the 2262306a36Sopenharmony_cihost controller (the chip). Commands can be executed synchronously (the sending 2362306a36Sopenharmony_cicontext blocks waiting for response) or asynchronously (the response is returned 2462306a36Sopenharmony_cifrom HCI Rx context). 2562306a36Sopenharmony_ciHCI events can also be received from the host controller. They will be handled 2662306a36Sopenharmony_ciand a translation will be forwarded to NFC Core as needed. There are hooks to 2762306a36Sopenharmony_cilet the HCI driver handle proprietary events or override standard behavior. 2862306a36Sopenharmony_ciHCI uses 2 execution contexts: 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci- one for executing commands : nfc_hci_msg_tx_work(). Only one command 3162306a36Sopenharmony_ci can be executing at any given moment. 3262306a36Sopenharmony_ci- one for dispatching received events and commands : nfc_hci_msg_rx_work(). 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciHCI Session initialization 3562306a36Sopenharmony_ci-------------------------- 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciThe Session initialization is an HCI standard which must unfortunately 3862306a36Sopenharmony_cisupport proprietary gates. This is the reason why the driver will pass a list 3962306a36Sopenharmony_ciof proprietary gates that must be part of the session. HCI will ensure all 4062306a36Sopenharmony_cithose gates have pipes connected when the hci device is set up. 4162306a36Sopenharmony_ciIn case the chip supports pre-opened gates and pseudo-static pipes, the driver 4262306a36Sopenharmony_cican pass that information to HCI core. 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciHCI Gates and Pipes 4562306a36Sopenharmony_ci------------------- 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciA gate defines the 'port' where some service can be found. In order to access 4862306a36Sopenharmony_cia service, one must create a pipe to that gate and open it. In this 4962306a36Sopenharmony_ciimplementation, pipes are totally hidden. The public API only knows gates. 5062306a36Sopenharmony_ciThis is consistent with the driver need to send commands to proprietary gates 5162306a36Sopenharmony_ciwithout knowing the pipe connected to it. 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciDriver interface 5462306a36Sopenharmony_ci---------------- 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciA driver is generally written in two parts : the physical link management and 5762306a36Sopenharmony_cithe HCI management. This makes it easier to maintain a driver for a chip that 5862306a36Sopenharmony_cican be connected using various phy (i2c, spi, ...) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciHCI Management 6162306a36Sopenharmony_ci-------------- 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciA driver would normally register itself with HCI and provide the following 6462306a36Sopenharmony_cientry points:: 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci struct nfc_hci_ops { 6762306a36Sopenharmony_ci int (*open)(struct nfc_hci_dev *hdev); 6862306a36Sopenharmony_ci void (*close)(struct nfc_hci_dev *hdev); 6962306a36Sopenharmony_ci int (*hci_ready) (struct nfc_hci_dev *hdev); 7062306a36Sopenharmony_ci int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb); 7162306a36Sopenharmony_ci int (*start_poll) (struct nfc_hci_dev *hdev, 7262306a36Sopenharmony_ci u32 im_protocols, u32 tm_protocols); 7362306a36Sopenharmony_ci int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target, 7462306a36Sopenharmony_ci u8 comm_mode, u8 *gb, size_t gb_len); 7562306a36Sopenharmony_ci int (*dep_link_down)(struct nfc_hci_dev *hdev); 7662306a36Sopenharmony_ci int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate, 7762306a36Sopenharmony_ci struct nfc_target *target); 7862306a36Sopenharmony_ci int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, 7962306a36Sopenharmony_ci struct nfc_target *target); 8062306a36Sopenharmony_ci int (*im_transceive) (struct nfc_hci_dev *hdev, 8162306a36Sopenharmony_ci struct nfc_target *target, struct sk_buff *skb, 8262306a36Sopenharmony_ci data_exchange_cb_t cb, void *cb_context); 8362306a36Sopenharmony_ci int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb); 8462306a36Sopenharmony_ci int (*check_presence)(struct nfc_hci_dev *hdev, 8562306a36Sopenharmony_ci struct nfc_target *target); 8662306a36Sopenharmony_ci int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, 8762306a36Sopenharmony_ci struct sk_buff *skb); 8862306a36Sopenharmony_ci }; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci- open() and close() shall turn the hardware on and off. 9162306a36Sopenharmony_ci- hci_ready() is an optional entry point that is called right after the hci 9262306a36Sopenharmony_ci session has been set up. The driver can use it to do additional initialization 9362306a36Sopenharmony_ci that must be performed using HCI commands. 9462306a36Sopenharmony_ci- xmit() shall simply write a frame to the physical link. 9562306a36Sopenharmony_ci- start_poll() is an optional entrypoint that shall set the hardware in polling 9662306a36Sopenharmony_ci mode. This must be implemented only if the hardware uses proprietary gates or a 9762306a36Sopenharmony_ci mechanism slightly different from the HCI standard. 9862306a36Sopenharmony_ci- dep_link_up() is called after a p2p target has been detected, to finish 9962306a36Sopenharmony_ci the p2p connection setup with hardware parameters that need to be passed back 10062306a36Sopenharmony_ci to nfc core. 10162306a36Sopenharmony_ci- dep_link_down() is called to bring the p2p link down. 10262306a36Sopenharmony_ci- target_from_gate() is an optional entrypoint to return the nfc protocols 10362306a36Sopenharmony_ci corresponding to a proprietary gate. 10462306a36Sopenharmony_ci- complete_target_discovered() is an optional entry point to let the driver 10562306a36Sopenharmony_ci perform additional proprietary processing necessary to auto activate the 10662306a36Sopenharmony_ci discovered target. 10762306a36Sopenharmony_ci- im_transceive() must be implemented by the driver if proprietary HCI commands 10862306a36Sopenharmony_ci are required to send data to the tag. Some tag types will require custom 10962306a36Sopenharmony_ci commands, others can be written to using the standard HCI commands. The driver 11062306a36Sopenharmony_ci can check the tag type and either do proprietary processing, or return 1 to ask 11162306a36Sopenharmony_ci for standard processing. The data exchange command itself must be sent 11262306a36Sopenharmony_ci asynchronously. 11362306a36Sopenharmony_ci- tm_send() is called to send data in the case of a p2p connection 11462306a36Sopenharmony_ci- check_presence() is an optional entry point that will be called regularly 11562306a36Sopenharmony_ci by the core to check that an activated tag is still in the field. If this is 11662306a36Sopenharmony_ci not implemented, the core will not be able to push tag_lost events to the user 11762306a36Sopenharmony_ci space 11862306a36Sopenharmony_ci- event_received() is called to handle an event coming from the chip. Driver 11962306a36Sopenharmony_ci can handle the event or return 1 to let HCI attempt standard processing. 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciOn the rx path, the driver is responsible to push incoming HCP frames to HCI 12262306a36Sopenharmony_ciusing nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling 12362306a36Sopenharmony_ciThis must be done from a context that can sleep. 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciPHY Management 12662306a36Sopenharmony_ci-------------- 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciThe physical link (i2c, ...) management is defined by the following structure:: 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci struct nfc_phy_ops { 13162306a36Sopenharmony_ci int (*write)(void *dev_id, struct sk_buff *skb); 13262306a36Sopenharmony_ci int (*enable)(void *dev_id); 13362306a36Sopenharmony_ci void (*disable)(void *dev_id); 13462306a36Sopenharmony_ci }; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cienable(): 13762306a36Sopenharmony_ci turn the phy on (power on), make it ready to transfer data 13862306a36Sopenharmony_cidisable(): 13962306a36Sopenharmony_ci turn the phy off 14062306a36Sopenharmony_ciwrite(): 14162306a36Sopenharmony_ci Send a data frame to the chip. Note that to enable higher 14262306a36Sopenharmony_ci layers such as an llc to store the frame for re-emission, this 14362306a36Sopenharmony_ci function must not alter the skb. It must also not return a positive 14462306a36Sopenharmony_ci result (return 0 for success, negative for failure). 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciData coming from the chip shall be sent directly to nfc_hci_recv_frame(). 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciLLC 14962306a36Sopenharmony_ci--- 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciCommunication between the CPU and the chip often requires some link layer 15262306a36Sopenharmony_ciprotocol. Those are isolated as modules managed by the HCI layer. There are 15362306a36Sopenharmony_cicurrently two modules : nop (raw transfer) and shdlc. 15462306a36Sopenharmony_ciA new llc must implement the following functions:: 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci struct nfc_llc_ops { 15762306a36Sopenharmony_ci void *(*init) (struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, 15862306a36Sopenharmony_ci rcv_to_hci_t rcv_to_hci, int tx_headroom, 15962306a36Sopenharmony_ci int tx_tailroom, int *rx_headroom, int *rx_tailroom, 16062306a36Sopenharmony_ci llc_failure_t llc_failure); 16162306a36Sopenharmony_ci void (*deinit) (struct nfc_llc *llc); 16262306a36Sopenharmony_ci int (*start) (struct nfc_llc *llc); 16362306a36Sopenharmony_ci int (*stop) (struct nfc_llc *llc); 16462306a36Sopenharmony_ci void (*rcv_from_drv) (struct nfc_llc *llc, struct sk_buff *skb); 16562306a36Sopenharmony_ci int (*xmit_from_hci) (struct nfc_llc *llc, struct sk_buff *skb); 16662306a36Sopenharmony_ci }; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciinit(): 16962306a36Sopenharmony_ci allocate and init your private storage 17062306a36Sopenharmony_cideinit(): 17162306a36Sopenharmony_ci cleanup 17262306a36Sopenharmony_cistart(): 17362306a36Sopenharmony_ci establish the logical connection 17462306a36Sopenharmony_cistop (): 17562306a36Sopenharmony_ci terminate the logical connection 17662306a36Sopenharmony_circv_from_drv(): 17762306a36Sopenharmony_ci handle data coming from the chip, going to HCI 17862306a36Sopenharmony_cixmit_from_hci(): 17962306a36Sopenharmony_ci handle data sent by HCI, going to the chip 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciThe llc must be registered with nfc before it can be used. Do that by 18262306a36Sopenharmony_cicalling:: 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci nfc_llc_register(const char *name, const struct nfc_llc_ops *ops); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ciAgain, note that the llc does not handle the physical link. It is thus very 18762306a36Sopenharmony_cieasy to mix any physical link with any llc for a given chip driver. 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciIncluded Drivers 19062306a36Sopenharmony_ci---------------- 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciAn HCI based driver for an NXP PN544, connected through I2C bus, and using 19362306a36Sopenharmony_cishdlc is included. 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ciExecution Contexts 19662306a36Sopenharmony_ci------------------ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciThe execution contexts are the following: 19962306a36Sopenharmony_ci- IRQ handler (IRQH): 20062306a36Sopenharmony_cifast, cannot sleep. sends incoming frames to HCI where they are passed to 20162306a36Sopenharmony_cithe current llc. In case of shdlc, the frame is queued in shdlc rx queue. 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci- SHDLC State Machine worker (SMW) 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci Only when llc_shdlc is used: handles shdlc rx & tx queues. 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci Dispatches HCI cmd responses. 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci- HCI Tx Cmd worker (MSGTXWQ) 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci Serializes execution of HCI commands. 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci Completes execution in case of response timeout. 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci- HCI Rx worker (MSGRXWQ) 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci Dispatches incoming HCI commands or events. 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci- Syscall context from a userspace call (SYSCALL) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci Any entrypoint in HCI called from NFC Core 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciWorkflow executing an HCI command (using shdlc) 22462306a36Sopenharmony_ci----------------------------------------------- 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciExecuting an HCI command can easily be performed synchronously using the 22762306a36Sopenharmony_cifollowing API:: 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci int nfc_hci_send_cmd (struct nfc_hci_dev *hdev, u8 gate, u8 cmd, 23062306a36Sopenharmony_ci const u8 *param, size_t param_len, struct sk_buff **skb) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciThe API must be invoked from a context that can sleep. Most of the time, this 23362306a36Sopenharmony_ciwill be the syscall context. skb will return the result that was received in 23462306a36Sopenharmony_cithe response. 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciInternally, execution is asynchronous. So all this API does is to enqueue the 23762306a36Sopenharmony_ciHCI command, setup a local wait queue on stack, and wait_event() for completion. 23862306a36Sopenharmony_ciThe wait is not interruptible because it is guaranteed that the command will 23962306a36Sopenharmony_cicomplete after some short timeout anyway. 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ciMSGTXWQ context will then be scheduled and invoke nfc_hci_msg_tx_work(). 24262306a36Sopenharmony_ciThis function will dequeue the next pending command and send its HCP fragments 24362306a36Sopenharmony_cito the lower layer which happens to be shdlc. It will then start a timer to be 24462306a36Sopenharmony_ciable to complete the command with a timeout error if no response arrive. 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciSMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function 24762306a36Sopenharmony_cihandles shdlc framing in and out. It uses the driver xmit to send frames and 24862306a36Sopenharmony_cireceives incoming frames in an skb queue filled from the driver IRQ handler. 24962306a36Sopenharmony_ciSHDLC I(nformation) frames payload are HCP fragments. They are aggregated to 25062306a36Sopenharmony_ciform complete HCI frames, which can be a response, command, or event. 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciHCI Responses are dispatched immediately from this context to unblock 25362306a36Sopenharmony_ciwaiting command execution. Response processing involves invoking the completion 25462306a36Sopenharmony_cicallback that was provided by nfc_hci_msg_tx_work() when it sent the command. 25562306a36Sopenharmony_ciThe completion callback will then wake the syscall context. 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciIt is also possible to execute the command asynchronously using this API:: 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, 26062306a36Sopenharmony_ci const u8 *param, size_t param_len, 26162306a36Sopenharmony_ci data_exchange_cb_t cb, void *cb_context) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ciThe workflow is the same, except that the API call returns immediately, and 26462306a36Sopenharmony_cithe callback will be called with the result from the SMW context. 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciWorkflow receiving an HCI event or command 26762306a36Sopenharmony_ci------------------------------------------ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciHCI commands or events are not dispatched from SMW context. Instead, they are 27062306a36Sopenharmony_ciqueued to HCI rx_queue and will be dispatched from HCI rx worker 27162306a36Sopenharmony_cicontext (MSGRXWQ). This is done this way to allow a cmd or event handler 27262306a36Sopenharmony_cito also execute other commands (for example, handling the 27362306a36Sopenharmony_ciNFC_HCI_EVT_TARGET_DISCOVERED event from PN544 requires to issue an 27462306a36Sopenharmony_ciANY_GET_PARAMETER to the reader A gate to get information on the target 27562306a36Sopenharmony_cithat was discovered). 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciTypically, such an event will be propagated to NFC Core from MSGRXWQ context. 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciError management 28062306a36Sopenharmony_ci---------------- 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciErrors that occur synchronously with the execution of an NFC Core request are 28362306a36Sopenharmony_cisimply returned as the execution result of the request. These are easy. 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciErrors that occur asynchronously (e.g. in a background protocol handling thread) 28662306a36Sopenharmony_cimust be reported such that upper layers don't stay ignorant that something 28762306a36Sopenharmony_ciwent wrong below and know that expected events will probably never happen. 28862306a36Sopenharmony_ciHandling of these errors is done as follows: 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci- driver (pn544) fails to deliver an incoming frame: it stores the error such 29162306a36Sopenharmony_ci that any subsequent call to the driver will result in this error. Then it 29262306a36Sopenharmony_ci calls the standard nfc_shdlc_recv_frame() with a NULL argument to report the 29362306a36Sopenharmony_ci problem above. shdlc stores a EREMOTEIO sticky status, which will trigger 29462306a36Sopenharmony_ci SMW to report above in turn. 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci- SMW is basically a background thread to handle incoming and outgoing shdlc 29762306a36Sopenharmony_ci frames. This thread will also check the shdlc sticky status and report to HCI 29862306a36Sopenharmony_ci when it discovers it is not able to run anymore because of an unrecoverable 29962306a36Sopenharmony_ci error that happened within shdlc or below. If the problem occurs during shdlc 30062306a36Sopenharmony_ci connection, the error is reported through the connect completion. 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an 30362306a36Sopenharmony_ci error from a lower layer, HCI will either complete the currently executing 30462306a36Sopenharmony_ci command with that error, or notify NFC Core directly if no command is 30562306a36Sopenharmony_ci executing. 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci- NFC Core: when NFC Core is notified of an error from below and polling is 30862306a36Sopenharmony_ci active, it will send a tag discovered event with an empty tag list to the user 30962306a36Sopenharmony_ci space to let it know that the poll operation will never be able to detect a 31062306a36Sopenharmony_ci tag. If polling is not active and the error was sticky, lower levels will 31162306a36Sopenharmony_ci return it at next invocation. 312