1cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/*
2cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * HCI based Driver for Inside Secure microread NFC Chip
3cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade *
4cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * Copyright (C) 2013  Intel Corporation. All rights reserved.
5cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade *
6cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * This program is free software; you can redistribute it and/or modify it
7cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * under the terms and conditions of the GNU General Public License,
8cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * version 2, as published by the Free Software Foundation.
9cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade *
10cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * This program is distributed in the hope that it will be useful,
11cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * but WITHOUT ANY WARRANTY; without even the implied warranty of
12cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * GNU General Public License for more details.
14cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade *
15cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * You should have received a copy of the GNU General Public License
1698b32decc83ed3137e3ddbc918b102f8fc406b6dJeff Kirsher * along with this program; if not, see <http://www.gnu.org/licenses/>.
17cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade */
18cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
1917936b43f0fdede23582d83a45622751409c99b9Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2017936b43f0fdede23582d83a45622751409c99b9Joe Perches
21cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <linux/module.h>
22cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <linux/delay.h>
23cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <linux/slab.h>
24cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <linux/crc-ccitt.h>
25cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
26cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <linux/nfc.h>
27cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <net/nfc/nfc.h>
28cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <net/nfc/hci.h>
29cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include <net/nfc/llc.h>
30cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
31cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#include "microread.h"
32cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
33cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Proprietary gates, events, commands and registers */
34cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Admin */
35cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_ADM NFC_HCI_ADMIN_GATE
36cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MGT 0x01
37cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_OS 0x02
38cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_TESTRF 0x03
39cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_LOOPBACK NFC_HCI_LOOPBACK_GATE
40cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_IDT NFC_HCI_ID_MGMT_GATE
41cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_LMS NFC_HCI_LINK_MGMT_GATE
42cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
43cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Reader */
44cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_GEN 0x10
45cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_B NFC_HCI_RF_READER_B_GATE
46cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_NFC_T1 0x12
47cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_A NFC_HCI_RF_READER_A_GATE
48cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_NFC_T3 0x14
49cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_15_3 0x15
50cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_15_2 0x16
51cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_B_3 0x17
52cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_BPRIME 0x18
53cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MREAD_ISO_A_3 0x19
54cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
55cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Card */
56cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_GEN 0x20
57cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_B 0x21
58cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_BPRIME 0x22
59cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_A 0x23
60cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_NFC_T3 0x24
61cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_15_3 0x25
62cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_15_2 0x26
63cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_B_2 0x27
64cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_MCARD_ISO_CUSTOM 0x28
65cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_SECURE_ELEMENT 0x2F
66cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
67cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* P2P */
68cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_P2P_GEN 0x30
69cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_P2P_TARGET 0x31
70cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PAR_P2P_TARGET_MODE 0x01
71cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PAR_P2P_TARGET_GT 0x04
72cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_GATE_ID_P2P_INITIATOR 0x32
73cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PAR_P2P_INITIATOR_GI 0x01
74cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PAR_P2P_INITIATOR_GT 0x03
75cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
76cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Those pipes are created/opened by default in the chip */
77cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_LMS 0x00
78cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_ADMIN 0x01
79cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_MGT 0x02
80cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_OS 0x03
81cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_LOOPBACK 0x04
82cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_IDT 0x05
83cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B 0x08
84cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_BPRIME 0x09
85cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_A 0x0A
86cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_3 0x0B
87cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_15_2 0x0C
88cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_NFC_T3 0x0D
89cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_ISO_B_2 0x0E
90cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MCARD_CUSTOM 0x0F
91cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B 0x10
92cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1 0x11
93cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A 0x12
94cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_3 0x13
95cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_15_2 0x14
96cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3 0x15
97cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_B_3 0x16
98cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_BPRIME 0x17
99cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3 0x18
100cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_MREAD_GEN 0x1B
101cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_STACKED_ELEMENT 0x1C
102cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_INSTANCES 0x1D
103cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_TESTRF 0x1E
104cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_P2P_TARGET 0x1F
105cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_PIPE_ID_HDS_P2P_INITIATOR 0x20
106cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
107cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Events */
108cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_DISCOVERY_OCCURED NFC_HCI_EVT_TARGET_DISCOVERED
109cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_CARD_FOUND 0x3D
110cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A_ATQA 0
111cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A_SAK 2
112cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A_LEN 3
113cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A_UID 4
114cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A3_ATQA 0
115cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A3_SAK 2
116cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A3_LEN 3
117cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_A3_UID 4
118cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_B_UID 0
119cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_T1_ATQA 0
120cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_T1_UID 4
121cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EMCF_T3_UID 0
122cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_DISCOVERY_START NFC_HCI_EVT_READER_REQUESTED
123cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_DISCOVERY_START_SOME 0x3E
124cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_DISCOVERY_STOP NFC_HCI_EVT_END_OPERATION
125cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MREAD_SIM_REQUESTS 0x3F
126cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MCARD_EXCHANGE NFC_HCI_EVT_TARGET_DISCOVERED
127cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF 0x20
128cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF 0x21
129cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MCARD_FIELD_ON 0x11
130cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_P2P_TARGET_ACTIVATED 0x13
131cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_P2P_TARGET_DEACTIVATED 0x12
132cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_EVT_MCARD_FIELD_OFF 0x14
133cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
134cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Commands */
135cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_CMD_MREAD_EXCHANGE 0x10
136cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_CMD_MREAD_SUBSCRIBE 0x3F
137cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
138cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Hosts IDs */
139cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_ELT_ID_HDS NFC_HCI_TERMINAL_HOST_ID
140cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_ELT_ID_SIM NFC_HCI_UICC_HOST_ID
141cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_ELT_ID_SE1 0x03
142cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_ELT_ID_SE2 0x04
143cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_ELT_ID_SE3 0x05
144cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
145cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic struct nfc_hci_gate microread_gates[] = {
146cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_ADM, MICROREAD_PIPE_ID_ADMIN},
147cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_LOOPBACK, MICROREAD_PIPE_ID_HDS_LOOPBACK},
148cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_IDT, MICROREAD_PIPE_ID_HDS_IDT},
149cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_LMS, MICROREAD_PIPE_ID_LMS},
150cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MREAD_ISO_B, MICROREAD_PIPE_ID_HDS_MREAD_ISO_B},
151cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MREAD_ISO_A, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A},
152cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MREAD_ISO_A_3, MICROREAD_PIPE_ID_HDS_MREAD_ISO_A_3},
153cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MGT, MICROREAD_PIPE_ID_MGT},
154cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_OS, MICROREAD_PIPE_ID_OS},
155cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MREAD_NFC_T1, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T1},
156cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_MREAD_NFC_T3, MICROREAD_PIPE_ID_HDS_MREAD_NFC_T3},
157cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_P2P_TARGET, MICROREAD_PIPE_ID_HDS_P2P_TARGET},
158cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	{MICROREAD_GATE_ID_P2P_INITIATOR, MICROREAD_PIPE_ID_HDS_P2P_INITIATOR}
159cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade};
160cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
161cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/* Largest headroom needed for outgoing custom commands */
162cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_CMDS_HEADROOM	2
163cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_CMD_TAILROOM	2
164cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
165cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestruct microread_info {
166cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct nfc_phy_ops *phy_ops;
167cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	void *phy_id;
168cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
169cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct nfc_hci_dev *hdev;
170cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
171cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int async_cb_type;
172cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	data_exchange_cb_t async_cb;
173cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	void *async_cb_context;
174cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade};
175cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
176cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_open(struct nfc_hci_dev *hdev)
177cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
178cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = nfc_hci_get_clientdata(hdev);
179cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
180cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return info->phy_ops->enable(info->phy_id);
181cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
182cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
183cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic void microread_close(struct nfc_hci_dev *hdev)
184cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
185cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = nfc_hci_get_clientdata(hdev);
186cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
187cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->phy_ops->disable(info->phy_id);
188cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
189cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
190cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_hci_ready(struct nfc_hci_dev *hdev)
191cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
192cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
193cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u8 param[4];
194cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
195cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[0] = 0x03;
196cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
197cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 1, NULL);
198cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
199cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
200cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
201cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_A_3,
202cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
203cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
204cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
205cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
206cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[0] = 0x00;
207cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[1] = 0x03;
208cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[2] = 0x00;
209cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_ISO_B,
210cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 3, NULL);
211cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
212cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
213cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
214cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T1,
215cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			     MICROREAD_CMD_MREAD_SUBSCRIBE, NULL, 0, NULL);
216cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
217cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
218cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
219cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[0] = 0xFF;
220cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[1] = 0xFF;
221cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[2] = 0x00;
222cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[3] = 0x00;
223cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_cmd(hdev, MICROREAD_GATE_ID_MREAD_NFC_T3,
224cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			     MICROREAD_CMD_MREAD_SUBSCRIBE, param, 4, NULL);
225cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
226cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return r;
227cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
228cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
229cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
230cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
231cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = nfc_hci_get_clientdata(hdev);
232cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
233cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return info->phy_ops->write(info->phy_id, skb);
234cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
235cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
236cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_start_poll(struct nfc_hci_dev *hdev,
237cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				u32 im_protocols, u32 tm_protocols)
238cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
239cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
240cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
241cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u8 param[2];
242cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u8 mode;
243cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
244cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[0] = 0x00;
245cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	param[1] = 0x00;
246cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
247cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_ISO14443_MASK)
248cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[0] |= (1 << 2);
249cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
250cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_ISO14443_B_MASK)
251cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[0] |= 1;
252cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
253cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_MIFARE_MASK)
254cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[1] |= 1;
255cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
256cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_JEWEL_MASK)
257cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[0] |= (1 << 1);
258cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
259cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_FELICA_MASK)
260cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[0] |= (1 << 5);
261cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
262cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
263cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		param[1] |= (1 << 1);
264cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
265cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
266cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
267cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade						       &hdev->gb_len);
268cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (hdev->gb == NULL || hdev->gb_len == 0) {
269cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
270cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
271cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
272cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
273cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
274cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
275cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
276cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
277cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
278cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
279cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	mode = 0xff;
280cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
281cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
282cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
283cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
284cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
285cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
286cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
287cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      MICROREAD_PAR_P2P_INITIATOR_GI,
288cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      hdev->gb, hdev->gb_len);
289cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (r)
290cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return r;
291cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
292cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
293cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
294cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
295cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      MICROREAD_PAR_P2P_TARGET_GT,
296cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      hdev->gb, hdev->gb_len);
297cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (r)
298cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return r;
299cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
300cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		mode = 0x02;
301cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
302cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
303cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (r)
304cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return r;
305cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
306cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
307cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_MREAD_ISO_A,
308cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				  MICROREAD_EVT_MREAD_DISCOVERY_START_SOME,
309cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				  param, 2);
310cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
311cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
312cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_dep_link_up(struct nfc_hci_dev *hdev,
313cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				struct nfc_target *target, u8 comm_mode,
314cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				u8 *gb, size_t gb_len)
315cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
316cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct sk_buff *rgb_skb = NULL;
317cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
318cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
319cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
320cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			      MICROREAD_PAR_P2P_INITIATOR_GT, &rgb_skb);
321cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r < 0)
322cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return r;
323cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
324cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
325cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = -EPROTO;
326cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto exit;
327cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
328cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
329cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
330cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					 rgb_skb->len);
331cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r == 0)
332cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
333cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				       NFC_RF_INITIATOR);
334cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeexit:
335cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree_skb(rgb_skb);
336cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
337cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return r;
338cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
339cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
340cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_dep_link_down(struct nfc_hci_dev *hdev)
341cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
342cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_INITIATOR,
343cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				  MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL, 0);
344cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
345cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
346cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
347cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      struct nfc_target *target)
348cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
349cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	switch (gate) {
350cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_P2P_INITIATOR:
351cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
352cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
353cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	default:
354cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return -EPROTO;
355cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
356cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
357cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return 0;
358cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
359cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
360cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_complete_target_discovered(struct nfc_hci_dev *hdev,
361cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade						u8 gate,
362cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade						struct nfc_target *target)
363cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
364cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return 0;
365cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
366cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
367cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade#define MICROREAD_CB_TYPE_READER_ALL 1
368cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
369cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic void microread_im_transceive_cb(void *context, struct sk_buff *skb,
370cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				       int err)
371cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
372cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = context;
373cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
374cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	switch (info->async_cb_type) {
375cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_CB_TYPE_READER_ALL:
376cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (err == 0) {
377cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			if (skb->len == 0) {
378cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				err = -EPROTO;
379cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				kfree_skb(skb);
380cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				info->async_cb(info->async_cb_context, NULL,
381cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					       -EPROTO);
382cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				return;
383cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			}
384cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
385cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			if (skb->data[skb->len - 1] != 0) {
386cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				err = nfc_hci_result_to_errno(
387cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade						       skb->data[skb->len - 1]);
388cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				kfree_skb(skb);
389cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				info->async_cb(info->async_cb_context, NULL,
390cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					       err);
391cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				return;
392cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			}
393cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
394cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			skb_trim(skb, skb->len - 1);	/* RF Error ind. */
395cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
396cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		info->async_cb(info->async_cb_context, skb, err);
397cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
398cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	default:
399cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (err == 0)
400cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			kfree_skb(skb);
401cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
402cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
403cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
404cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
405cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade/*
406cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * Returns:
407cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade * <= 0: driver handled the data exchange
408cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade *    1: driver doesn't especially handle, please do standard processing
409cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade */
410cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_im_transceive(struct nfc_hci_dev *hdev,
411cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				   struct nfc_target *target,
412cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				   struct sk_buff *skb, data_exchange_cb_t cb,
413cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				   void *cb_context)
414cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
415cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = nfc_hci_get_clientdata(hdev);
416cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u8 control_bits;
417cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u16 crc;
418cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
419cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	pr_info("data exchange to gate 0x%x\n", target->hci_reader_gate);
420cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
421cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (target->hci_reader_gate == MICROREAD_GATE_ID_P2P_INITIATOR) {
422cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		*skb_push(skb, 1) = 0;
423cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
424cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return nfc_hci_send_event(hdev, target->hci_reader_gate,
425cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				     MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_TO_RF,
426cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				     skb->data, skb->len);
427cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
428cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
429cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	switch (target->hci_reader_gate) {
430cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_A:
431cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		control_bits = 0xCB;
432cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
433cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
434cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		control_bits = 0xCB;
435cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
436cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_B:
437cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		control_bits = 0xCB;
438cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
439cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_NFC_T1:
440cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		control_bits = 0x1B;
441cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
442cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		crc = crc_ccitt(0xffff, skb->data, skb->len);
443cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		crc = ~crc;
444cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		*skb_put(skb, 1) = crc & 0xff;
445cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		*skb_put(skb, 1) = crc >> 8;
446cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
447cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_NFC_T3:
448cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		control_bits = 0xDB;
449cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
450cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	default:
451cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		pr_info("Abort im_transceive to invalid gate 0x%x\n",
452cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			target->hci_reader_gate);
453cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return 1;
454cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
455cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
456cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	*skb_push(skb, 1) = control_bits;
457cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
458cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->async_cb_type = MICROREAD_CB_TYPE_READER_ALL;
459cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->async_cb = cb;
460cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->async_cb_context = cb_context;
461cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
462cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
463cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      MICROREAD_CMD_MREAD_EXCHANGE,
464cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      skb->data, skb->len,
465cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      microread_im_transceive_cb, info);
466cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
467cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
468cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
469cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
470cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
471cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
472cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_send_event(hdev, MICROREAD_GATE_ID_P2P_TARGET,
473cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			       MICROREAD_EVT_MCARD_EXCHANGE,
474cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			       skb->data, skb->len);
475cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
476cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree_skb(skb);
477cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
478cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return r;
479cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
480cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
481cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
482cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					struct sk_buff *skb)
483cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
484cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct nfc_target *targets;
485cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r = 0;
486cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
487cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	pr_info("target discovered to gate 0x%x\n", gate);
488cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
489cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	targets = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
490cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (targets == NULL) {
491cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = -ENOMEM;
492cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto exit;
493cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
494cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
495cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	targets->hci_reader_gate = gate;
496cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
497cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	switch (gate) {
498cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_A:
499cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->supported_protocols =
500cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
501cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->sens_res =
502cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
503cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
504cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
505d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
506d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter			r = -EINVAL;
507d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter			goto exit_free;
508d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		}
509d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A_UID],
510d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		       targets->nfcid1_len);
511cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
512cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_A_3:
513cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->supported_protocols =
514cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		      nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
515cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->sens_res =
516cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			 be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
517cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
518cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
519d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
520d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter			r = -EINVAL;
521d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter			goto exit_free;
522d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		}
523d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_A3_UID],
524d07f1e8600ccb885c8f4143402b8912f7d827bcbDan Carpenter		       targets->nfcid1_len);
525cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
526cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_ISO_B:
527cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
528cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
529cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->nfcid1_len = 4;
530cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
531cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_NFC_T1:
532cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
533cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->sens_res =
534cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
535cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T1_UID], 4);
536cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->nfcid1_len = 4;
537cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
538cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_GATE_ID_MREAD_NFC_T3:
539cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->supported_protocols = NFC_PROTO_FELICA_MASK;
540cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
541cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		targets->nfcid1_len = 8;
542cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
543cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	default:
544cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		pr_info("discard target discovered to gate 0x%x\n", gate);
545cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto exit_free;
546cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
547cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
548cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_targets_found(hdev->ndev, targets, 1);
549cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
550cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeexit_free:
551cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree(targets);
552cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
553cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeexit:
554cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree_skb(skb);
555cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
556cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
55717936b43f0fdede23582d83a45622751409c99b9Joe Perches		pr_err("Failed to handle discovered target err=%d\n", r);
558cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
559cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
560cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
561cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				     u8 event, struct sk_buff *skb)
562cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
563cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
564cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	u8 mode;
565cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
566cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
567cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
568cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	switch (event) {
569cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_MREAD_CARD_FOUND:
570cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		microread_target_discovered(hdev, gate, skb);
571cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return 0;
572cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
573cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_P2P_INITIATOR_EXCHANGE_FROM_RF:
574cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (skb->len < 1) {
575cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			kfree_skb(skb);
576cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return -EPROTO;
577cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
578cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
579cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (skb->data[skb->len - 1]) {
580cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			kfree_skb(skb);
581cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return -EIO;
582cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
583cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
584cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		skb_trim(skb, skb->len - 1);
585cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
586cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_tm_data_received(hdev->ndev, skb);
587cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
588cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
589cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_MCARD_FIELD_ON:
590cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_MCARD_FIELD_OFF:
591cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		kfree_skb(skb);
592cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return 0;
593cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
594cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_P2P_TARGET_ACTIVATED:
595cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
596cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				     NFC_COMM_PASSIVE, skb->data,
597cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				     skb->len);
598cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
599cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		kfree_skb(skb);
600cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
601cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
602cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_MCARD_EXCHANGE:
603cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (skb->len < 1) {
604cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			kfree_skb(skb);
605cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return -EPROTO;
606cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
607cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
608cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (skb->data[skb->len-1]) {
609cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			kfree_skb(skb);
610cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			return -EIO;
611cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		}
612cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
613cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		skb_trim(skb, skb->len - 1);
614cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
615cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_tm_data_received(hdev->ndev, skb);
616cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
617cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
618cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	case MICROREAD_EVT_P2P_TARGET_DEACTIVATED:
619cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		kfree_skb(skb);
620cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
621cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		mode = 0xff;
622cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_hci_set_param(hdev, MICROREAD_GATE_ID_P2P_TARGET,
623cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				      MICROREAD_PAR_P2P_TARGET_MODE, &mode, 1);
624cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		if (r)
625cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade			break;
626cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
627cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = nfc_hci_send_event(hdev, gate,
628cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				       MICROREAD_EVT_MREAD_DISCOVERY_STOP, NULL,
629cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade				       0);
630cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		break;
631cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
632cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	default:
633cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		return 1;
634cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
635cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
636cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return r;
637cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
638cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
639cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadestatic struct nfc_hci_ops microread_hci_ops = {
640cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.open = microread_open,
641cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.close = microread_close,
642cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.hci_ready = microread_hci_ready,
643cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.xmit = microread_xmit,
644cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.start_poll = microread_start_poll,
645cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.dep_link_up = microread_dep_link_up,
646cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.dep_link_down = microread_dep_link_down,
647cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.target_from_gate = microread_target_from_gate,
648cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.complete_target_discovered = microread_complete_target_discovered,
649cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.im_transceive = microread_im_transceive,
650cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.tm_send = microread_tm_send,
651cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.check_presence = NULL,
652cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	.event_received = microread_event_received,
653cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade};
654cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
655cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeint microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
656cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    int phy_headroom, int phy_tailroom, int phy_payload,
657cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    struct nfc_hci_dev **hdev)
658cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
659cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info;
660cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	unsigned long quirks = 0;
6610b456c418a5595b9d67f300c9ac6a2441e774603Samuel Ortiz	u32 protocols;
662cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct nfc_hci_init_data init_data;
663cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	int r;
664cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
665cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info = kzalloc(sizeof(struct microread_info), GFP_KERNEL);
666cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (!info) {
667cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = -ENOMEM;
668cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto err_info_alloc;
669cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
670cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
671cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->phy_ops = phy_ops;
672cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->phy_id = phy_id;
673cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
674cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	init_data.gate_count = ARRAY_SIZE(microread_gates);
675cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	memcpy(init_data.gates, microread_gates, sizeof(microread_gates));
676cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
677cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	strcpy(init_data.session_id, "MICROREA");
678cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
679cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
680cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
681cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	protocols = NFC_PROTO_JEWEL_MASK |
682cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    NFC_PROTO_MIFARE_MASK |
683cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    NFC_PROTO_FELICA_MASK |
684cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    NFC_PROTO_ISO14443_MASK |
685cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    NFC_PROTO_ISO14443_B_MASK |
686cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		    NFC_PROTO_NFC_DEP_MASK;
687cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
688cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	info->hdev = nfc_hci_allocate_device(&microread_hci_ops, &init_data,
6890b456c418a5595b9d67f300c9ac6a2441e774603Samuel Ortiz					     quirks, protocols, llc_name,
690cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					     phy_headroom +
691cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					     MICROREAD_CMDS_HEADROOM,
692cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					     phy_tailroom +
693cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					     MICROREAD_CMD_TAILROOM,
694cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade					     phy_payload);
695cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (!info->hdev) {
69617936b43f0fdede23582d83a45622751409c99b9Joe Perches		pr_err("Cannot allocate nfc hdev\n");
697cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		r = -ENOMEM;
698cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto err_alloc_hdev;
699cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	}
700cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
701cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	nfc_hci_set_clientdata(info->hdev, info);
702cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
703cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	r = nfc_hci_register_device(info->hdev);
704cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	if (r)
705cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade		goto err_regdev;
706cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
707cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	*hdev = info->hdev;
708cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
709cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return 0;
710cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
711cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeerr_regdev:
712cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	nfc_hci_free_device(info->hdev);
713cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
714cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeerr_alloc_hdev:
715cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree(info);
716cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
717cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadeerr_info_alloc:
718cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	return r;
719cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
720cfad1ba87150e198be9ea32367a24e500e59de2cEric LapuyadeEXPORT_SYMBOL(microread_probe);
721cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
722cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyadevoid microread_remove(struct nfc_hci_dev *hdev)
723cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade{
724cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	struct microread_info *info = nfc_hci_get_clientdata(hdev);
725cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
726cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	nfc_hci_unregister_device(hdev);
727cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	nfc_hci_free_device(hdev);
728cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade	kfree(info);
729cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade}
730cfad1ba87150e198be9ea32367a24e500e59de2cEric LapuyadeEXPORT_SYMBOL(microread_remove);
731cfad1ba87150e198be9ea32367a24e500e59de2cEric Lapuyade
732cfad1ba87150e198be9ea32367a24e500e59de2cEric LapuyadeMODULE_LICENSE("GPL");
733cfad1ba87150e198be9ea32367a24e500e59de2cEric LapuyadeMODULE_DESCRIPTION(DRIVER_DESC);
734