Commit | Line | Data |
---|---|---|
bbed0dee EL |
1 | /* |
2 | * HCI based Driver for NXP PN544 NFC Chip | |
3 | * | |
4 | * Copyright (C) 2012 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 | ||
17936b43 JP |
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
22 | ||
bbed0dee EL |
23 | #include <linux/delay.h> |
24 | #include <linux/slab.h> | |
aa741030 | 25 | #include <linux/module.h> |
bbed0dee EL |
26 | |
27 | #include <linux/nfc.h> | |
28 | #include <net/nfc/hci.h> | |
412fda53 | 29 | #include <net/nfc/llc.h> |
bbed0dee | 30 | |
97f18414 | 31 | #include "pn544.h" |
bbed0dee EL |
32 | |
33 | /* Timing restrictions (ms) */ | |
34 | #define PN544_HCI_RESETVEN_TIME 30 | |
35 | ||
bbed0dee EL |
36 | enum pn544_state { |
37 | PN544_ST_COLD, | |
38 | PN544_ST_FW_READY, | |
39 | PN544_ST_READY, | |
40 | }; | |
41 | ||
42 | #define FULL_VERSION_LEN 11 | |
43 | ||
44 | /* Proprietary commands */ | |
45 | #define PN544_WRITE 0x3f | |
5faba2fd | 46 | #define PN544_TEST_SWP 0x21 |
bbed0dee EL |
47 | |
48 | /* Proprietary gates, events, commands and registers */ | |
49 | ||
50 | /* NFC_HCI_RF_READER_A_GATE additional registers and commands */ | |
51 | #define PN544_RF_READER_A_AUTO_ACTIVATION 0x10 | |
52 | #define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12 | |
53 | #define PN544_MIFARE_CMD 0x21 | |
54 | ||
55 | /* Commands that apply to all RF readers */ | |
56 | #define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30 | |
57 | #define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32 | |
58 | ||
59 | /* NFC_HCI_ID_MGMT_GATE additional registers */ | |
60 | #define PN544_ID_MGMT_FULL_VERSION_SW 0x10 | |
61 | ||
62 | #define PN544_RF_READER_ISO15693_GATE 0x12 | |
63 | ||
64 | #define PN544_RF_READER_F_GATE 0x14 | |
65 | #define PN544_FELICA_ID 0x04 | |
66 | #define PN544_FELICA_RAW 0x20 | |
67 | ||
68 | #define PN544_RF_READER_JEWEL_GATE 0x15 | |
69 | #define PN544_JEWEL_RAW_CMD 0x23 | |
70 | ||
71 | #define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30 | |
72 | #define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31 | |
73 | ||
74 | #define PN544_SYS_MGMT_GATE 0x90 | |
75 | #define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02 | |
76 | ||
77 | #define PN544_POLLING_LOOP_MGMT_GATE 0x94 | |
7e2afc9d AW |
78 | #define PN544_DEP_MODE 0x01 |
79 | #define PN544_DEP_ATR_REQ 0x02 | |
80 | #define PN544_DEP_ATR_RES 0x03 | |
81 | #define PN544_DEP_MERGE 0x0D | |
bbed0dee EL |
82 | #define PN544_PL_RDPHASES 0x06 |
83 | #define PN544_PL_EMULATION 0x07 | |
84 | #define PN544_PL_NFCT_DEACTIVATED 0x09 | |
85 | ||
86 | #define PN544_SWP_MGMT_GATE 0xA0 | |
39438261 | 87 | #define PN544_SWP_DEFAULT_MODE 0x01 |
bbed0dee EL |
88 | |
89 | #define PN544_NFC_WI_MGMT_GATE 0xA1 | |
5faba2fd | 90 | #define PN544_NFC_ESE_DEFAULT_MODE 0x01 |
bbed0dee | 91 | |
f7a5f6c5 AW |
92 | #define PN544_HCI_EVT_SND_DATA 0x01 |
93 | #define PN544_HCI_EVT_ACTIVATED 0x02 | |
94 | #define PN544_HCI_EVT_DEACTIVATED 0x03 | |
95 | #define PN544_HCI_EVT_RCV_DATA 0x04 | |
96 | #define PN544_HCI_EVT_CONTINUE_MI 0x05 | |
5faba2fd | 97 | #define PN544_HCI_EVT_SWITCH_MODE 0x03 |
f7a5f6c5 | 98 | |
da052850 | 99 | #define PN544_HCI_CMD_ATTREQUEST 0x12 |
928326f2 AW |
100 | #define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13 |
101 | ||
a10d595b EL |
102 | static struct nfc_hci_gate pn544_gates[] = { |
103 | {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE}, | |
104 | {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, | |
105 | {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
106 | {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
107 | {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, | |
108 | {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, | |
109 | {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
110 | {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
111 | {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
112 | {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE}, | |
113 | {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, | |
114 | {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE}, | |
115 | {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, | |
116 | {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE}, | |
117 | {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE} | |
bbed0dee EL |
118 | }; |
119 | ||
120 | /* Largest headroom needed for outgoing custom commands */ | |
121 | #define PN544_CMDS_HEADROOM 2 | |
122 | ||
123 | struct pn544_hci_info { | |
97f18414 EL |
124 | struct nfc_phy_ops *phy_ops; |
125 | void *phy_id; | |
126 | ||
412fda53 | 127 | struct nfc_hci_dev *hdev; |
bbed0dee EL |
128 | |
129 | enum pn544_state state; | |
130 | ||
131 | struct mutex info_lock; | |
132 | ||
f3e8fb55 EL |
133 | int async_cb_type; |
134 | data_exchange_cb_t async_cb; | |
135 | void *async_cb_context; | |
8bd7fc89 EL |
136 | |
137 | fw_download_t fw_download; | |
bbed0dee EL |
138 | }; |
139 | ||
412fda53 | 140 | static int pn544_hci_open(struct nfc_hci_dev *hdev) |
bbed0dee | 141 | { |
412fda53 | 142 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
bbed0dee EL |
143 | int r = 0; |
144 | ||
145 | mutex_lock(&info->info_lock); | |
146 | ||
147 | if (info->state != PN544_ST_COLD) { | |
148 | r = -EBUSY; | |
149 | goto out; | |
150 | } | |
151 | ||
97f18414 | 152 | r = info->phy_ops->enable(info->phy_id); |
bbed0dee | 153 | |
eae202aa EL |
154 | if (r == 0) |
155 | info->state = PN544_ST_READY; | |
156 | ||
bbed0dee EL |
157 | out: |
158 | mutex_unlock(&info->info_lock); | |
159 | return r; | |
160 | } | |
161 | ||
412fda53 | 162 | static void pn544_hci_close(struct nfc_hci_dev *hdev) |
bbed0dee | 163 | { |
412fda53 | 164 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
bbed0dee EL |
165 | |
166 | mutex_lock(&info->info_lock); | |
167 | ||
168 | if (info->state == PN544_ST_COLD) | |
169 | goto out; | |
170 | ||
97f18414 | 171 | info->phy_ops->disable(info->phy_id); |
bbed0dee | 172 | |
eae202aa EL |
173 | info->state = PN544_ST_COLD; |
174 | ||
bbed0dee EL |
175 | out: |
176 | mutex_unlock(&info->info_lock); | |
177 | } | |
178 | ||
412fda53 | 179 | static int pn544_hci_ready(struct nfc_hci_dev *hdev) |
bbed0dee | 180 | { |
bbed0dee EL |
181 | struct sk_buff *skb; |
182 | static struct hw_config { | |
183 | u8 adr[2]; | |
184 | u8 value; | |
185 | } hw_config[] = { | |
186 | {{0x9f, 0x9a}, 0x00}, | |
187 | ||
188 | {{0x98, 0x10}, 0xbc}, | |
189 | ||
190 | {{0x9e, 0x71}, 0x00}, | |
191 | ||
192 | {{0x98, 0x09}, 0x00}, | |
193 | ||
194 | {{0x9e, 0xb4}, 0x00}, | |
195 | ||
bbed0dee EL |
196 | {{0x9c, 0x01}, 0x08}, |
197 | ||
198 | {{0x9e, 0xaa}, 0x01}, | |
199 | ||
200 | {{0x9b, 0xd1}, 0x0d}, | |
201 | {{0x9b, 0xd2}, 0x24}, | |
202 | {{0x9b, 0xd3}, 0x0a}, | |
203 | {{0x9b, 0xd4}, 0x22}, | |
204 | {{0x9b, 0xd5}, 0x08}, | |
205 | {{0x9b, 0xd6}, 0x1e}, | |
206 | {{0x9b, 0xdd}, 0x1c}, | |
207 | ||
208 | {{0x9b, 0x84}, 0x13}, | |
209 | {{0x99, 0x81}, 0x7f}, | |
210 | {{0x99, 0x31}, 0x70}, | |
211 | ||
212 | {{0x98, 0x00}, 0x3f}, | |
213 | ||
214 | {{0x9f, 0x09}, 0x00}, | |
215 | ||
216 | {{0x9f, 0x0a}, 0x05}, | |
217 | ||
218 | {{0x9e, 0xd1}, 0xa1}, | |
219 | {{0x99, 0x23}, 0x00}, | |
220 | ||
221 | {{0x9e, 0x74}, 0x80}, | |
222 | ||
223 | {{0x9f, 0x28}, 0x10}, | |
224 | ||
225 | {{0x9f, 0x35}, 0x14}, | |
226 | ||
227 | {{0x9f, 0x36}, 0x60}, | |
228 | ||
229 | {{0x9c, 0x31}, 0x00}, | |
230 | ||
231 | {{0x9c, 0x32}, 0xc8}, | |
232 | ||
233 | {{0x9c, 0x19}, 0x40}, | |
234 | ||
235 | {{0x9c, 0x1a}, 0x40}, | |
236 | ||
237 | {{0x9c, 0x0c}, 0x00}, | |
238 | ||
239 | {{0x9c, 0x0d}, 0x00}, | |
240 | ||
241 | {{0x9c, 0x12}, 0x00}, | |
242 | ||
243 | {{0x9c, 0x13}, 0x00}, | |
244 | ||
245 | {{0x98, 0xa2}, 0x0e}, | |
246 | ||
247 | {{0x98, 0x93}, 0x40}, | |
248 | ||
249 | {{0x98, 0x7d}, 0x02}, | |
250 | {{0x98, 0x7e}, 0x00}, | |
251 | {{0x9f, 0xc8}, 0x01}, | |
252 | }; | |
253 | struct hw_config *p = hw_config; | |
254 | int count = ARRAY_SIZE(hw_config); | |
255 | struct sk_buff *res_skb; | |
256 | u8 param[4]; | |
257 | int r; | |
258 | ||
259 | param[0] = 0; | |
260 | while (count--) { | |
261 | param[1] = p->adr[0]; | |
262 | param[2] = p->adr[1]; | |
263 | param[3] = p->value; | |
264 | ||
265 | r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE, | |
266 | param, 4, &res_skb); | |
267 | if (r < 0) | |
268 | return r; | |
269 | ||
270 | if (res_skb->len != 1) { | |
271 | kfree_skb(res_skb); | |
272 | return -EPROTO; | |
273 | } | |
274 | ||
275 | if (res_skb->data[0] != p->value) { | |
276 | kfree_skb(res_skb); | |
277 | return -EIO; | |
278 | } | |
279 | ||
280 | kfree_skb(res_skb); | |
281 | ||
282 | p++; | |
283 | } | |
284 | ||
285 | param[0] = NFC_HCI_UICC_HOST_ID; | |
286 | r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, | |
287 | NFC_HCI_ADMIN_WHITELIST, param, 1); | |
288 | if (r < 0) | |
289 | return r; | |
290 | ||
291 | param[0] = 0x3d; | |
292 | r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE, | |
293 | PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1); | |
294 | if (r < 0) | |
295 | return r; | |
296 | ||
297 | param[0] = 0x0; | |
298 | r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE, | |
299 | PN544_RF_READER_A_AUTO_ACTIVATION, param, 1); | |
300 | if (r < 0) | |
301 | return r; | |
302 | ||
303 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | |
304 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
305 | if (r < 0) | |
306 | return r; | |
307 | ||
308 | param[0] = 0x1; | |
309 | r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, | |
310 | PN544_PL_NFCT_DEACTIVATED, param, 1); | |
311 | if (r < 0) | |
312 | return r; | |
313 | ||
314 | param[0] = 0x0; | |
315 | r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, | |
316 | PN544_PL_RDPHASES, param, 1); | |
317 | if (r < 0) | |
318 | return r; | |
319 | ||
320 | r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, | |
321 | PN544_ID_MGMT_FULL_VERSION_SW, &skb); | |
322 | if (r < 0) | |
323 | return r; | |
324 | ||
325 | if (skb->len != FULL_VERSION_LEN) { | |
326 | kfree_skb(skb); | |
327 | return -EINVAL; | |
328 | } | |
329 | ||
330 | print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ", | |
331 | DUMP_PREFIX_NONE, 16, 1, | |
332 | skb->data, FULL_VERSION_LEN, false); | |
333 | ||
334 | kfree_skb(skb); | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
412fda53 | 339 | static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
bbed0dee | 340 | { |
412fda53 | 341 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
ade67208 | 342 | |
97f18414 | 343 | return info->phy_ops->write(info->phy_id, skb); |
bbed0dee EL |
344 | } |
345 | ||
412fda53 | 346 | static int pn544_hci_start_poll(struct nfc_hci_dev *hdev, |
fe7c5800 | 347 | u32 im_protocols, u32 tm_protocols) |
bbed0dee | 348 | { |
bbed0dee EL |
349 | u8 phases = 0; |
350 | int r; | |
351 | u8 duration[2]; | |
352 | u8 activated; | |
7e2afc9d AW |
353 | u8 i_mode = 0x3f; /* Enable all supported modes */ |
354 | u8 t_mode = 0x0f; | |
355 | u8 t_merge = 0x01; /* Enable merge by default */ | |
bbed0dee | 356 | |
fe7c5800 SO |
357 | pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n", |
358 | __func__, im_protocols, tm_protocols); | |
bbed0dee EL |
359 | |
360 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | |
361 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
362 | if (r < 0) | |
363 | return r; | |
364 | ||
365 | duration[0] = 0x18; | |
366 | duration[1] = 0x6a; | |
367 | r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, | |
368 | PN544_PL_EMULATION, duration, 2); | |
369 | if (r < 0) | |
370 | return r; | |
371 | ||
372 | activated = 0; | |
373 | r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, | |
374 | PN544_PL_NFCT_DEACTIVATED, &activated, 1); | |
375 | if (r < 0) | |
376 | return r; | |
377 | ||
fe7c5800 | 378 | if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK | |
bbed0dee EL |
379 | NFC_PROTO_JEWEL_MASK)) |
380 | phases |= 1; /* Type A */ | |
fe7c5800 | 381 | if (im_protocols & NFC_PROTO_FELICA_MASK) { |
bbed0dee EL |
382 | phases |= (1 << 2); /* Type F 212 */ |
383 | phases |= (1 << 3); /* Type F 424 */ | |
384 | } | |
385 | ||
386 | phases |= (1 << 5); /* NFC active */ | |
387 | ||
388 | r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, | |
389 | PN544_PL_RDPHASES, &phases, 1); | |
390 | if (r < 0) | |
391 | return r; | |
392 | ||
7e2afc9d AW |
393 | if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) { |
394 | hdev->gb = nfc_get_local_general_bytes(hdev->ndev, | |
395 | &hdev->gb_len); | |
17936b43 | 396 | pr_debug("generate local bytes %p\n", hdev->gb); |
7e2afc9d AW |
397 | if (hdev->gb == NULL || hdev->gb_len == 0) { |
398 | im_protocols &= ~NFC_PROTO_NFC_DEP_MASK; | |
399 | tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK; | |
400 | } | |
401 | } | |
402 | ||
403 | if (im_protocols & NFC_PROTO_NFC_DEP_MASK) { | |
404 | r = nfc_hci_send_event(hdev, | |
405 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
406 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
407 | if (r < 0) | |
408 | return r; | |
409 | ||
410 | r = nfc_hci_set_param(hdev, | |
411 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
412 | PN544_DEP_MODE, &i_mode, 1); | |
413 | if (r < 0) | |
414 | return r; | |
415 | ||
416 | r = nfc_hci_set_param(hdev, | |
417 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
418 | PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len); | |
419 | if (r < 0) | |
420 | return r; | |
421 | ||
422 | r = nfc_hci_send_event(hdev, | |
423 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
424 | NFC_HCI_EVT_READER_REQUESTED, NULL, 0); | |
425 | if (r < 0) | |
426 | nfc_hci_send_event(hdev, | |
427 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
428 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
429 | } | |
430 | ||
431 | if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { | |
432 | r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, | |
433 | PN544_DEP_MODE, &t_mode, 1); | |
434 | if (r < 0) | |
435 | return r; | |
436 | ||
437 | r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, | |
438 | PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len); | |
439 | if (r < 0) | |
440 | return r; | |
441 | ||
442 | r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, | |
443 | PN544_DEP_MERGE, &t_merge, 1); | |
444 | if (r < 0) | |
445 | return r; | |
446 | } | |
447 | ||
bbed0dee EL |
448 | r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, |
449 | NFC_HCI_EVT_READER_REQUESTED, NULL, 0); | |
450 | if (r < 0) | |
451 | nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, | |
452 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
453 | ||
454 | return r; | |
455 | } | |
456 | ||
c40d1740 AW |
457 | static int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev, |
458 | struct nfc_target *target, u8 comm_mode, | |
459 | u8 *gb, size_t gb_len) | |
460 | { | |
461 | struct sk_buff *rgb_skb = NULL; | |
462 | int r; | |
463 | ||
464 | r = nfc_hci_get_param(hdev, target->hci_reader_gate, | |
465 | PN544_DEP_ATR_RES, &rgb_skb); | |
466 | if (r < 0) | |
467 | return r; | |
468 | ||
469 | if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) { | |
470 | r = -EPROTO; | |
471 | goto exit; | |
472 | } | |
473 | print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET, | |
474 | 16, 1, rgb_skb->data, rgb_skb->len, true); | |
475 | ||
476 | r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data, | |
477 | rgb_skb->len); | |
478 | ||
479 | if (r == 0) | |
480 | r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode, | |
481 | NFC_RF_INITIATOR); | |
482 | exit: | |
483 | kfree_skb(rgb_skb); | |
484 | return r; | |
485 | } | |
486 | ||
487 | static int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev) | |
488 | { | |
489 | ||
490 | return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
491 | NFC_HCI_EVT_END_OPERATION, NULL, 0); | |
492 | } | |
493 | ||
412fda53 | 494 | static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate, |
bbed0dee EL |
495 | struct nfc_target *target) |
496 | { | |
497 | switch (gate) { | |
498 | case PN544_RF_READER_F_GATE: | |
499 | target->supported_protocols = NFC_PROTO_FELICA_MASK; | |
500 | break; | |
501 | case PN544_RF_READER_JEWEL_GATE: | |
502 | target->supported_protocols = NFC_PROTO_JEWEL_MASK; | |
503 | target->sens_res = 0x0c00; | |
504 | break; | |
928326f2 AW |
505 | case PN544_RF_READER_NFCIP1_INITIATOR_GATE: |
506 | target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; | |
507 | break; | |
bbed0dee EL |
508 | default: |
509 | return -EPROTO; | |
510 | } | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
412fda53 | 515 | static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev, |
bbed0dee EL |
516 | u8 gate, |
517 | struct nfc_target *target) | |
518 | { | |
bbed0dee EL |
519 | struct sk_buff *uid_skb; |
520 | int r = 0; | |
521 | ||
928326f2 AW |
522 | if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) |
523 | return r; | |
524 | ||
525 | if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { | |
526 | r = nfc_hci_send_cmd(hdev, | |
527 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, | |
528 | PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL); | |
529 | if (r < 0) | |
530 | return r; | |
531 | ||
532 | target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE; | |
533 | } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { | |
bbed0dee EL |
534 | if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && |
535 | target->nfcid1_len != 10) | |
536 | return -EPROTO; | |
537 | ||
538 | r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, | |
539 | PN544_RF_READER_CMD_ACTIVATE_NEXT, | |
540 | target->nfcid1, target->nfcid1_len, NULL); | |
541 | } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { | |
542 | r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE, | |
543 | PN544_FELICA_ID, &uid_skb); | |
544 | if (r < 0) | |
545 | return r; | |
546 | ||
547 | if (uid_skb->len != 8) { | |
548 | kfree_skb(uid_skb); | |
549 | return -EPROTO; | |
550 | } | |
551 | ||
9c598440 AW |
552 | /* Type F NFC-DEP IDm has prefix 0x01FE */ |
553 | if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) { | |
554 | kfree_skb(uid_skb); | |
555 | r = nfc_hci_send_cmd(hdev, | |
928326f2 AW |
556 | PN544_RF_READER_NFCIP1_INITIATOR_GATE, |
557 | PN544_HCI_CMD_CONTINUE_ACTIVATION, | |
558 | NULL, 0, NULL); | |
9c598440 AW |
559 | if (r < 0) |
560 | return r; | |
561 | ||
562 | target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; | |
563 | target->hci_reader_gate = | |
564 | PN544_RF_READER_NFCIP1_INITIATOR_GATE; | |
565 | } else { | |
566 | r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, | |
567 | PN544_RF_READER_CMD_ACTIVATE_NEXT, | |
568 | uid_skb->data, uid_skb->len, NULL); | |
569 | kfree_skb(uid_skb); | |
570 | } | |
bbed0dee EL |
571 | } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) { |
572 | /* | |
573 | * TODO: maybe other ISO 14443 require some kind of continue | |
574 | * activation, but for now we've seen only this one below. | |
575 | */ | |
576 | if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */ | |
577 | r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, | |
578 | PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION, | |
579 | NULL, 0, NULL); | |
580 | } | |
581 | ||
582 | return r; | |
583 | } | |
584 | ||
f3e8fb55 EL |
585 | #define PN544_CB_TYPE_READER_F 1 |
586 | ||
587 | static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb, | |
588 | int err) | |
589 | { | |
590 | struct pn544_hci_info *info = context; | |
591 | ||
592 | switch (info->async_cb_type) { | |
593 | case PN544_CB_TYPE_READER_F: | |
594 | if (err == 0) | |
595 | skb_pull(skb, 1); | |
596 | info->async_cb(info->async_cb_context, skb, err); | |
597 | break; | |
598 | default: | |
599 | if (err == 0) | |
600 | kfree_skb(skb); | |
601 | break; | |
602 | } | |
603 | } | |
604 | ||
bbed0dee EL |
605 | #define MIFARE_CMD_AUTH_KEY_A 0x60 |
606 | #define MIFARE_CMD_AUTH_KEY_B 0x61 | |
607 | #define MIFARE_CMD_HEADER 2 | |
608 | #define MIFARE_UID_LEN 4 | |
609 | #define MIFARE_KEY_LEN 6 | |
610 | #define MIFARE_CMD_LEN 12 | |
611 | /* | |
612 | * Returns: | |
613 | * <= 0: driver handled the data exchange | |
614 | * 1: driver doesn't especially handle, please do standard processing | |
615 | */ | |
e8107623 | 616 | static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev, |
bbed0dee | 617 | struct nfc_target *target, |
f3e8fb55 EL |
618 | struct sk_buff *skb, data_exchange_cb_t cb, |
619 | void *cb_context) | |
bbed0dee | 620 | { |
412fda53 | 621 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
bbed0dee EL |
622 | |
623 | pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, | |
624 | target->hci_reader_gate); | |
625 | ||
626 | switch (target->hci_reader_gate) { | |
627 | case NFC_HCI_RF_READER_A_GATE: | |
628 | if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { | |
629 | /* | |
630 | * It seems that pn544 is inverting key and UID for | |
631 | * MIFARE authentication commands. | |
632 | */ | |
633 | if (skb->len == MIFARE_CMD_LEN && | |
634 | (skb->data[0] == MIFARE_CMD_AUTH_KEY_A || | |
635 | skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) { | |
636 | u8 uid[MIFARE_UID_LEN]; | |
637 | u8 *data = skb->data + MIFARE_CMD_HEADER; | |
638 | ||
639 | memcpy(uid, data + MIFARE_KEY_LEN, | |
640 | MIFARE_UID_LEN); | |
641 | memmove(data + MIFARE_UID_LEN, data, | |
642 | MIFARE_KEY_LEN); | |
643 | memcpy(data, uid, MIFARE_UID_LEN); | |
644 | } | |
645 | ||
f3e8fb55 EL |
646 | return nfc_hci_send_cmd_async(hdev, |
647 | target->hci_reader_gate, | |
648 | PN544_MIFARE_CMD, | |
649 | skb->data, skb->len, | |
650 | cb, cb_context); | |
bbed0dee EL |
651 | } else |
652 | return 1; | |
653 | case PN544_RF_READER_F_GATE: | |
654 | *skb_push(skb, 1) = 0; | |
655 | *skb_push(skb, 1) = 0; | |
656 | ||
f3e8fb55 EL |
657 | info->async_cb_type = PN544_CB_TYPE_READER_F; |
658 | info->async_cb = cb; | |
659 | info->async_cb_context = cb_context; | |
660 | ||
661 | return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, | |
662 | PN544_FELICA_RAW, skb->data, | |
663 | skb->len, | |
664 | pn544_hci_data_exchange_cb, info); | |
bbed0dee | 665 | case PN544_RF_READER_JEWEL_GATE: |
f3e8fb55 EL |
666 | return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate, |
667 | PN544_JEWEL_RAW_CMD, skb->data, | |
668 | skb->len, cb, cb_context); | |
e8107623 AW |
669 | case PN544_RF_READER_NFCIP1_INITIATOR_GATE: |
670 | *skb_push(skb, 1) = 0; | |
671 | ||
672 | return nfc_hci_send_event(hdev, target->hci_reader_gate, | |
673 | PN544_HCI_EVT_SND_DATA, skb->data, | |
674 | skb->len); | |
bbed0dee EL |
675 | default: |
676 | return 1; | |
677 | } | |
678 | } | |
679 | ||
e8107623 AW |
680 | static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb) |
681 | { | |
924d4a02 EL |
682 | int r; |
683 | ||
e8107623 AW |
684 | /* Set default false for multiple information chaining */ |
685 | *skb_push(skb, 1) = 0; | |
686 | ||
924d4a02 EL |
687 | r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE, |
688 | PN544_HCI_EVT_SND_DATA, skb->data, skb->len); | |
689 | ||
690 | kfree_skb(skb); | |
691 | ||
692 | return r; | |
e8107623 AW |
693 | } |
694 | ||
412fda53 | 695 | static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, |
bbed0dee EL |
696 | struct nfc_target *target) |
697 | { | |
17936b43 | 698 | pr_debug("supported protocol %d\b", target->supported_protocols); |
da052850 AW |
699 | if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK | |
700 | NFC_PROTO_ISO14443_B_MASK)) { | |
701 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, | |
702 | PN544_RF_READER_CMD_PRESENCE_CHECK, | |
703 | NULL, 0, NULL); | |
704 | } else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { | |
705 | if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && | |
706 | target->nfcid1_len != 10) | |
632c016a | 707 | return -EOPNOTSUPP; |
da052850 AW |
708 | |
709 | return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, | |
710 | PN544_RF_READER_CMD_ACTIVATE_NEXT, | |
711 | target->nfcid1, target->nfcid1_len, NULL); | |
a69bdc1e AW |
712 | } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK | |
713 | NFC_PROTO_FELICA_MASK)) { | |
714 | return -EOPNOTSUPP; | |
da052850 AW |
715 | } else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) { |
716 | return nfc_hci_send_cmd(hdev, target->hci_reader_gate, | |
717 | PN544_HCI_CMD_ATTREQUEST, | |
718 | NULL, 0, NULL); | |
719 | } | |
720 | ||
721 | return 0; | |
bbed0dee EL |
722 | } |
723 | ||
40d06d36 EL |
724 | /* |
725 | * Returns: | |
726 | * <= 0: driver handled the event, skb consumed | |
727 | * 1: driver does not handle the event, please do standard processing | |
728 | */ | |
27c31191 EL |
729 | static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event, |
730 | struct sk_buff *skb) | |
f7a5f6c5 AW |
731 | { |
732 | struct sk_buff *rgb_skb = NULL; | |
40d06d36 | 733 | int r; |
f7a5f6c5 | 734 | |
17936b43 | 735 | pr_debug("hci event %d\n", event); |
f7a5f6c5 AW |
736 | switch (event) { |
737 | case PN544_HCI_EVT_ACTIVATED: | |
40d06d36 | 738 | if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) { |
27c31191 | 739 | r = nfc_hci_target_discovered(hdev, gate); |
40d06d36 | 740 | } else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) { |
f7a5f6c5 | 741 | r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ, |
27c31191 | 742 | &rgb_skb); |
f7a5f6c5 AW |
743 | if (r < 0) |
744 | goto exit; | |
745 | ||
27c31191 EL |
746 | r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK, |
747 | NFC_COMM_PASSIVE, rgb_skb->data, | |
748 | rgb_skb->len); | |
f7a5f6c5 AW |
749 | |
750 | kfree_skb(rgb_skb); | |
40d06d36 EL |
751 | } else { |
752 | r = -EINVAL; | |
f7a5f6c5 | 753 | } |
f7a5f6c5 AW |
754 | break; |
755 | case PN544_HCI_EVT_DEACTIVATED: | |
27c31191 EL |
756 | r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION, |
757 | NULL, 0); | |
f7a5f6c5 | 758 | break; |
e8107623 AW |
759 | case PN544_HCI_EVT_RCV_DATA: |
760 | if (skb->len < 2) { | |
761 | r = -EPROTO; | |
762 | goto exit; | |
763 | } | |
764 | ||
765 | if (skb->data[0] != 0) { | |
17936b43 | 766 | pr_debug("data0 %d\n", skb->data[0]); |
e8107623 AW |
767 | r = -EPROTO; |
768 | goto exit; | |
769 | } | |
770 | ||
771 | skb_pull(skb, 2); | |
27c31191 | 772 | return nfc_tm_data_received(hdev->ndev, skb); |
f7a5f6c5 | 773 | default: |
40d06d36 | 774 | return 1; |
f7a5f6c5 AW |
775 | } |
776 | ||
777 | exit: | |
778 | kfree_skb(skb); | |
27c31191 EL |
779 | |
780 | return r; | |
f7a5f6c5 AW |
781 | } |
782 | ||
8bd7fc89 EL |
783 | static int pn544_hci_fw_download(struct nfc_hci_dev *hdev, |
784 | const char *firmware_name) | |
785 | { | |
786 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); | |
787 | ||
788 | if (info->fw_download == NULL) | |
789 | return -ENOTSUPP; | |
790 | ||
791 | return info->fw_download(info->phy_id, firmware_name); | |
792 | } | |
793 | ||
5faba2fd AW |
794 | static int pn544_hci_discover_se(struct nfc_hci_dev *hdev) |
795 | { | |
796 | u32 se_idx = 0; | |
797 | u8 ese_mode = 0x01; /* Default mode */ | |
798 | struct sk_buff *res_skb; | |
799 | int r; | |
800 | ||
801 | r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP, | |
802 | NULL, 0, &res_skb); | |
803 | ||
804 | if (r == 0) { | |
805 | if (res_skb->len == 2 && res_skb->data[0] == 0x00) | |
806 | nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC); | |
807 | ||
808 | kfree_skb(res_skb); | |
809 | } | |
810 | ||
811 | r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE, | |
812 | PN544_HCI_EVT_SWITCH_MODE, | |
813 | &ese_mode, 1); | |
814 | if (r == 0) | |
815 | nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED); | |
816 | ||
817 | return !se_idx; | |
818 | } | |
819 | ||
39438261 AW |
820 | #define PN544_SE_MODE_OFF 0x00 |
821 | #define PN544_SE_MODE_ON 0x01 | |
822 | static int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx) | |
823 | { | |
824 | struct nfc_se *se; | |
825 | u8 enable = PN544_SE_MODE_ON; | |
826 | static struct uicc_gatelist { | |
827 | u8 head; | |
828 | u8 adr[2]; | |
829 | u8 value; | |
830 | } uicc_gatelist[] = { | |
831 | {0x00, {0x9e, 0xd9}, 0x23}, | |
832 | {0x00, {0x9e, 0xda}, 0x21}, | |
833 | {0x00, {0x9e, 0xdb}, 0x22}, | |
834 | {0x00, {0x9e, 0xdc}, 0x24}, | |
835 | }; | |
836 | struct uicc_gatelist *p = uicc_gatelist; | |
837 | int count = ARRAY_SIZE(uicc_gatelist); | |
838 | struct sk_buff *res_skb; | |
839 | int r; | |
840 | ||
841 | se = nfc_find_se(hdev->ndev, se_idx); | |
842 | ||
843 | switch (se->type) { | |
844 | case NFC_SE_UICC: | |
845 | while (count--) { | |
846 | r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, | |
847 | PN544_WRITE, (u8 *)p, 4, &res_skb); | |
848 | if (r < 0) | |
849 | return r; | |
850 | ||
851 | if (res_skb->len != 1) { | |
852 | kfree_skb(res_skb); | |
853 | return -EPROTO; | |
854 | } | |
855 | ||
856 | if (res_skb->data[0] != p->value) { | |
857 | kfree_skb(res_skb); | |
858 | return -EIO; | |
859 | } | |
860 | ||
861 | kfree_skb(res_skb); | |
862 | ||
863 | p++; | |
864 | } | |
865 | ||
866 | return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE, | |
867 | PN544_SWP_DEFAULT_MODE, &enable, 1); | |
868 | case NFC_SE_EMBEDDED: | |
869 | return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE, | |
870 | PN544_NFC_ESE_DEFAULT_MODE, &enable, 1); | |
871 | ||
872 | default: | |
873 | return -EINVAL; | |
874 | } | |
875 | } | |
876 | ||
877 | static int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx) | |
878 | { | |
879 | struct nfc_se *se; | |
880 | u8 disable = PN544_SE_MODE_OFF; | |
881 | ||
882 | se = nfc_find_se(hdev->ndev, se_idx); | |
883 | ||
884 | switch (se->type) { | |
885 | case NFC_SE_UICC: | |
886 | return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE, | |
887 | PN544_SWP_DEFAULT_MODE, &disable, 1); | |
888 | case NFC_SE_EMBEDDED: | |
889 | return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE, | |
890 | PN544_NFC_ESE_DEFAULT_MODE, &disable, 1); | |
891 | default: | |
892 | return -EINVAL; | |
893 | } | |
894 | } | |
895 | ||
412fda53 | 896 | static struct nfc_hci_ops pn544_hci_ops = { |
bbed0dee EL |
897 | .open = pn544_hci_open, |
898 | .close = pn544_hci_close, | |
899 | .hci_ready = pn544_hci_ready, | |
900 | .xmit = pn544_hci_xmit, | |
901 | .start_poll = pn544_hci_start_poll, | |
c40d1740 AW |
902 | .dep_link_up = pn544_hci_dep_link_up, |
903 | .dep_link_down = pn544_hci_dep_link_down, | |
bbed0dee EL |
904 | .target_from_gate = pn544_hci_target_from_gate, |
905 | .complete_target_discovered = pn544_hci_complete_target_discovered, | |
e8107623 AW |
906 | .im_transceive = pn544_hci_im_transceive, |
907 | .tm_send = pn544_hci_tm_send, | |
bbed0dee | 908 | .check_presence = pn544_hci_check_presence, |
f7a5f6c5 | 909 | .event_received = pn544_hci_event_received, |
8bd7fc89 | 910 | .fw_download = pn544_hci_fw_download, |
5faba2fd | 911 | .discover_se = pn544_hci_discover_se, |
39438261 AW |
912 | .enable_se = pn544_hci_enable_se, |
913 | .disable_se = pn544_hci_disable_se, | |
bbed0dee EL |
914 | }; |
915 | ||
97f18414 EL |
916 | int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, |
917 | int phy_headroom, int phy_tailroom, int phy_payload, | |
8bd7fc89 | 918 | fw_download_t fw_download, struct nfc_hci_dev **hdev) |
bbed0dee EL |
919 | { |
920 | struct pn544_hci_info *info; | |
0b456c41 | 921 | u32 protocols; |
bbed0dee | 922 | struct nfc_hci_init_data init_data; |
97f18414 | 923 | int r; |
bbed0dee EL |
924 | |
925 | info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL); | |
926 | if (!info) { | |
bbed0dee EL |
927 | r = -ENOMEM; |
928 | goto err_info_alloc; | |
929 | } | |
930 | ||
97f18414 EL |
931 | info->phy_ops = phy_ops; |
932 | info->phy_id = phy_id; | |
8bd7fc89 | 933 | info->fw_download = fw_download; |
bbed0dee EL |
934 | info->state = PN544_ST_COLD; |
935 | mutex_init(&info->info_lock); | |
bbed0dee | 936 | |
a10d595b | 937 | init_data.gate_count = ARRAY_SIZE(pn544_gates); |
bbed0dee | 938 | |
a10d595b | 939 | memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates)); |
bbed0dee EL |
940 | |
941 | /* | |
942 | * TODO: Session id must include the driver name + some bus addr | |
943 | * persistent info to discriminate 2 identical chips | |
944 | */ | |
945 | strcpy(init_data.session_id, "ID544HCI"); | |
946 | ||
947 | protocols = NFC_PROTO_JEWEL_MASK | | |
948 | NFC_PROTO_MIFARE_MASK | | |
949 | NFC_PROTO_FELICA_MASK | | |
950 | NFC_PROTO_ISO14443_MASK | | |
01d719a2 | 951 | NFC_PROTO_ISO14443_B_MASK | |
bbed0dee EL |
952 | NFC_PROTO_NFC_DEP_MASK; |
953 | ||
bf71ab8b | 954 | info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0, |
0b456c41 | 955 | protocols, llc_name, |
97f18414 EL |
956 | phy_headroom + PN544_CMDS_HEADROOM, |
957 | phy_tailroom, phy_payload); | |
412fda53 | 958 | if (!info->hdev) { |
17936b43 | 959 | pr_err("Cannot allocate nfc hdev\n"); |
bbed0dee | 960 | r = -ENOMEM; |
412fda53 | 961 | goto err_alloc_hdev; |
bbed0dee EL |
962 | } |
963 | ||
412fda53 EL |
964 | nfc_hci_set_clientdata(info->hdev, info); |
965 | ||
966 | r = nfc_hci_register_device(info->hdev); | |
967 | if (r) | |
968 | goto err_regdev; | |
bbed0dee | 969 | |
97f18414 EL |
970 | *hdev = info->hdev; |
971 | ||
bbed0dee EL |
972 | return 0; |
973 | ||
412fda53 EL |
974 | err_regdev: |
975 | nfc_hci_free_device(info->hdev); | |
976 | ||
977 | err_alloc_hdev: | |
bbed0dee EL |
978 | kfree(info); |
979 | ||
980 | err_info_alloc: | |
981 | return r; | |
982 | } | |
aa741030 | 983 | EXPORT_SYMBOL(pn544_hci_probe); |
bbed0dee | 984 | |
97f18414 | 985 | void pn544_hci_remove(struct nfc_hci_dev *hdev) |
bbed0dee | 986 | { |
97f18414 | 987 | struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev); |
bbed0dee | 988 | |
97f18414 EL |
989 | nfc_hci_unregister_device(hdev); |
990 | nfc_hci_free_device(hdev); | |
bbed0dee | 991 | kfree(info); |
bbed0dee | 992 | } |
aa741030 SO |
993 | EXPORT_SYMBOL(pn544_hci_remove); |
994 | ||
995 | MODULE_LICENSE("GPL"); | |
996 | MODULE_DESCRIPTION(DRIVER_DESC); |