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