blob: dccfcccf6998c4ddd5a241b681f53df6511825a3 [file] [log] [blame]
Thierry Escande4b10884eb2013-09-19 17:55:25 +02001/*
2 * NFC Digital Protocol stack
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/module.h>
17
18#include "digital.h"
19
Thierry Escande59ee2362013-09-19 17:55:26 +020020#define DIGITAL_PROTO_NFCA_RF_TECH \
Thierry Escande7d0911c2013-09-19 17:55:29 +020021 (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | NFC_PROTO_NFC_DEP_MASK)
Thierry Escande59ee2362013-09-19 17:55:26 +020022
Thierry Escande7d0911c2013-09-19 17:55:29 +020023#define DIGITAL_PROTO_NFCF_RF_TECH \
24 (NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK)
Thierry Escande8c0695e42013-09-19 17:55:28 +020025
Thierry Escande59ee2362013-09-19 17:55:26 +020026struct digital_cmd {
27 struct list_head queue;
28
29 u8 type;
30 u8 pending;
31
32 u16 timeout;
33 struct sk_buff *req;
34 struct sk_buff *resp;
35
36 nfc_digital_cmd_complete_t cmd_cb;
37 void *cb_context;
38};
39
40struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
41 unsigned int len)
42{
43 struct sk_buff *skb;
44
45 skb = alloc_skb(len + ddev->tx_headroom + ddev->tx_tailroom,
46 GFP_KERNEL);
47 if (skb)
48 skb_reserve(skb, ddev->tx_headroom);
49
50 return skb;
51}
52
Thierry Escande2c66dae2013-09-19 17:55:27 +020053void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
54 u8 bitwise_inv, u8 msb_first)
55{
56 u16 crc;
57
58 crc = crc_func(init, skb->data, skb->len);
59
60 if (bitwise_inv)
61 crc = ~crc;
62
63 if (msb_first)
64 crc = __fswab16(crc);
65
66 *skb_put(skb, 1) = crc & 0xFF;
67 *skb_put(skb, 1) = (crc >> 8) & 0xFF;
68}
69
70int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
71 u16 crc_init, u8 bitwise_inv, u8 msb_first)
72{
73 int rc;
74 u16 crc;
75
76 if (skb->len <= 2)
77 return -EIO;
78
79 crc = crc_func(crc_init, skb->data, skb->len - 2);
80
81 if (bitwise_inv)
82 crc = ~crc;
83
84 if (msb_first)
85 crc = __swab16(crc);
86
87 rc = (skb->data[skb->len - 2] - (crc & 0xFF)) +
88 (skb->data[skb->len - 1] - ((crc >> 8) & 0xFF));
89
90 if (rc)
91 return -EIO;
92
93 skb_trim(skb, skb->len - 2);
94
95 return 0;
96}
97
Thierry Escande59ee2362013-09-19 17:55:26 +020098static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on)
99{
100 ddev->ops->switch_rf(ddev, on);
101}
102
103static inline void digital_abort_cmd(struct nfc_digital_dev *ddev)
104{
105 ddev->ops->abort_cmd(ddev);
106}
107
108static void digital_wq_cmd_complete(struct work_struct *work)
109{
110 struct digital_cmd *cmd;
111 struct nfc_digital_dev *ddev = container_of(work,
112 struct nfc_digital_dev,
113 cmd_complete_work);
114
115 mutex_lock(&ddev->cmd_lock);
116
117 cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
118 queue);
119 if (!cmd) {
120 mutex_unlock(&ddev->cmd_lock);
121 return;
122 }
123
124 list_del(&cmd->queue);
125
126 mutex_unlock(&ddev->cmd_lock);
127
128 if (!IS_ERR(cmd->resp))
129 print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1,
130 cmd->resp->data, cmd->resp->len, false);
131
132 cmd->cmd_cb(ddev, cmd->cb_context, cmd->resp);
133
134 kfree(cmd);
135
136 schedule_work(&ddev->cmd_work);
137}
138
139static void digital_send_cmd_complete(struct nfc_digital_dev *ddev,
140 void *arg, struct sk_buff *resp)
141{
142 struct digital_cmd *cmd = arg;
143
144 cmd->resp = resp;
145
146 schedule_work(&ddev->cmd_complete_work);
147}
148
149static void digital_wq_cmd(struct work_struct *work)
150{
151 int rc;
152 struct digital_cmd *cmd;
153 struct nfc_digital_dev *ddev = container_of(work,
154 struct nfc_digital_dev,
155 cmd_work);
156
157 mutex_lock(&ddev->cmd_lock);
158
159 cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
160 queue);
161 if (!cmd || cmd->pending) {
162 mutex_unlock(&ddev->cmd_lock);
163 return;
164 }
165
166 mutex_unlock(&ddev->cmd_lock);
167
168 if (cmd->req)
169 print_hex_dump_debug("DIGITAL TX: ", DUMP_PREFIX_NONE, 16, 1,
170 cmd->req->data, cmd->req->len, false);
171
172 switch (cmd->type) {
173 case DIGITAL_CMD_IN_SEND:
174 rc = ddev->ops->in_send_cmd(ddev, cmd->req, cmd->timeout,
175 digital_send_cmd_complete, cmd);
176 break;
177 default:
178 PR_ERR("Unknown cmd type %d", cmd->type);
179 return;
180 }
181
182 if (!rc)
183 return;
184
185 PR_ERR("in_send_command returned err %d", rc);
186
187 mutex_lock(&ddev->cmd_lock);
188 list_del(&cmd->queue);
189 mutex_unlock(&ddev->cmd_lock);
190
191 kfree_skb(cmd->req);
192 kfree(cmd);
193
194 schedule_work(&ddev->cmd_work);
195}
196
197int digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type,
198 struct sk_buff *skb, u16 timeout,
199 nfc_digital_cmd_complete_t cmd_cb, void *cb_context)
200{
201 struct digital_cmd *cmd;
202
203 cmd = kzalloc(sizeof(struct digital_cmd), GFP_KERNEL);
204 if (!cmd)
205 return -ENOMEM;
206
207 cmd->type = cmd_type;
208 cmd->timeout = timeout;
209 cmd->req = skb;
210 cmd->cmd_cb = cmd_cb;
211 cmd->cb_context = cb_context;
212 INIT_LIST_HEAD(&cmd->queue);
213
214 mutex_lock(&ddev->cmd_lock);
215 list_add_tail(&cmd->queue, &ddev->cmd_queue);
216 mutex_unlock(&ddev->cmd_lock);
217
218 schedule_work(&ddev->cmd_work);
219
220 return 0;
221}
222
223int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
224{
225 int rc;
226
227 rc = ddev->ops->in_configure_hw(ddev, type, param);
228 if (rc)
229 PR_ERR("in_configure_hw failed: %d", rc);
230
231 return rc;
232}
233
Thierry Escande2c66dae2013-09-19 17:55:27 +0200234int digital_target_found(struct nfc_digital_dev *ddev,
235 struct nfc_target *target, u8 protocol)
236{
237 int rc;
238 u8 framing;
239 u8 rf_tech;
240 int (*check_crc)(struct sk_buff *skb);
241 void (*add_crc)(struct sk_buff *skb);
242
243 rf_tech = ddev->poll_techs[ddev->poll_tech_index].rf_tech;
244
245 switch (protocol) {
246 case NFC_PROTO_JEWEL:
247 framing = NFC_DIGITAL_FRAMING_NFCA_T1T;
248 check_crc = digital_skb_check_crc_b;
249 add_crc = digital_skb_add_crc_b;
250 break;
251
252 case NFC_PROTO_MIFARE:
253 framing = NFC_DIGITAL_FRAMING_NFCA_T2T;
254 check_crc = digital_skb_check_crc_a;
255 add_crc = digital_skb_add_crc_a;
256 break;
257
Thierry Escande8c0695e42013-09-19 17:55:28 +0200258 case NFC_PROTO_FELICA:
259 framing = NFC_DIGITAL_FRAMING_NFCF_T3T;
260 check_crc = digital_skb_check_crc_f;
261 add_crc = digital_skb_add_crc_f;
262 break;
263
Thierry Escande7d0911c2013-09-19 17:55:29 +0200264 case NFC_PROTO_NFC_DEP:
265 if (rf_tech == NFC_DIGITAL_RF_TECH_106A) {
266 framing = NFC_DIGITAL_FRAMING_NFCA_NFC_DEP;
267 check_crc = digital_skb_check_crc_a;
268 add_crc = digital_skb_add_crc_a;
269 } else {
270 framing = NFC_DIGITAL_FRAMING_NFCF_NFC_DEP;
271 check_crc = digital_skb_check_crc_f;
272 add_crc = digital_skb_add_crc_f;
273 }
274 break;
275
Thierry Escande2c66dae2013-09-19 17:55:27 +0200276 default:
277 PR_ERR("Invalid protocol %d", protocol);
278 return -EINVAL;
279 }
280
281 PR_DBG("rf_tech=%d, protocol=%d", rf_tech, protocol);
282
283 ddev->curr_rf_tech = rf_tech;
284 ddev->curr_protocol = protocol;
285
286 if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
287 ddev->skb_add_crc = digital_skb_add_crc_none;
288 ddev->skb_check_crc = digital_skb_check_crc_none;
289 } else {
290 ddev->skb_add_crc = add_crc;
291 ddev->skb_check_crc = check_crc;
292 }
293
294 rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, framing);
295 if (rc)
296 return rc;
297
298 target->supported_protocols = (1 << protocol);
299 rc = nfc_targets_found(ddev->nfc_dev, target, 1);
300 if (rc)
301 return rc;
302
303 ddev->poll_tech_count = 0;
304
305 return 0;
306}
307
Thierry Escande59ee2362013-09-19 17:55:26 +0200308void digital_poll_next_tech(struct nfc_digital_dev *ddev)
309{
310 digital_switch_rf(ddev, 0);
311
312 mutex_lock(&ddev->poll_lock);
313
314 if (!ddev->poll_tech_count) {
315 mutex_unlock(&ddev->poll_lock);
316 return;
317 }
318
319 ddev->poll_tech_index = (ddev->poll_tech_index + 1) %
320 ddev->poll_tech_count;
321
322 mutex_unlock(&ddev->poll_lock);
323
324 schedule_work(&ddev->poll_work);
325}
326
327static void digital_wq_poll(struct work_struct *work)
328{
329 int rc;
330 struct digital_poll_tech *poll_tech;
331 struct nfc_digital_dev *ddev = container_of(work,
332 struct nfc_digital_dev,
333 poll_work);
334 mutex_lock(&ddev->poll_lock);
335
336 if (!ddev->poll_tech_count) {
337 mutex_unlock(&ddev->poll_lock);
338 return;
339 }
340
341 poll_tech = &ddev->poll_techs[ddev->poll_tech_index];
342
343 mutex_unlock(&ddev->poll_lock);
344
345 rc = poll_tech->poll_func(ddev, poll_tech->rf_tech);
346 if (rc)
347 digital_poll_next_tech(ddev);
348}
349
350static void digital_add_poll_tech(struct nfc_digital_dev *ddev, u8 rf_tech,
351 digital_poll_t poll_func)
352{
353 struct digital_poll_tech *poll_tech;
354
355 if (ddev->poll_tech_count >= NFC_DIGITAL_POLL_MODE_COUNT_MAX)
356 return;
357
358 poll_tech = &ddev->poll_techs[ddev->poll_tech_count++];
359
360 poll_tech->rf_tech = rf_tech;
361 poll_tech->poll_func = poll_func;
362}
363
364/**
365 * start_poll operation
366 *
367 * For every supported protocol, the corresponding polling function is added
368 * to the table of polling technologies (ddev->poll_techs[]) using
369 * digital_add_poll_tech().
370 * When a polling function fails (by timeout or protocol error) the next one is
371 * schedule by digital_poll_next_tech() on the poll workqueue (ddev->poll_work).
372 */
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200373static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
374 __u32 tm_protocols)
375{
Thierry Escande59ee2362013-09-19 17:55:26 +0200376 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
377 u32 matching_im_protocols, matching_tm_protocols;
378
379 PR_DBG("protocols: im 0x%x, tm 0x%x, supported 0x%x", im_protocols,
380 tm_protocols, ddev->protocols);
381
382 matching_im_protocols = ddev->protocols & im_protocols;
383 matching_tm_protocols = ddev->protocols & tm_protocols;
384
385 if (!matching_im_protocols && !matching_tm_protocols) {
386 PR_ERR("No known protocol");
387 return -EINVAL;
388 }
389
390 if (ddev->poll_tech_count) {
391 PR_ERR("Already polling");
392 return -EBUSY;
393 }
394
395 if (ddev->curr_protocol) {
396 PR_ERR("A target is already active");
397 return -EBUSY;
398 }
399
400 ddev->poll_tech_count = 0;
401 ddev->poll_tech_index = 0;
402
403 if (matching_im_protocols & DIGITAL_PROTO_NFCA_RF_TECH)
404 digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
405 digital_in_send_sens_req);
406
Thierry Escande8c0695e42013-09-19 17:55:28 +0200407 if (im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) {
408 digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
409 digital_in_send_sensf_req);
410
411 digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
412 digital_in_send_sensf_req);
413 }
414
Thierry Escande59ee2362013-09-19 17:55:26 +0200415 if (!ddev->poll_tech_count) {
416 PR_ERR("Unsupported protocols: im=0x%x, tm=0x%x",
417 matching_im_protocols, matching_tm_protocols);
418 return -EINVAL;
419 }
420
421 schedule_work(&ddev->poll_work);
422
423 return 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200424}
425
426static void digital_stop_poll(struct nfc_dev *nfc_dev)
427{
Thierry Escande59ee2362013-09-19 17:55:26 +0200428 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
429
430 mutex_lock(&ddev->poll_lock);
431
432 if (!ddev->poll_tech_count) {
433 PR_ERR("Polling operation was not running");
434 mutex_unlock(&ddev->poll_lock);
435 return;
436 }
437
438 ddev->poll_tech_count = 0;
439
440 mutex_unlock(&ddev->poll_lock);
441
442 cancel_work_sync(&ddev->poll_work);
443
444 digital_abort_cmd(ddev);
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200445}
446
447static int digital_dev_up(struct nfc_dev *nfc_dev)
448{
Thierry Escande59ee2362013-09-19 17:55:26 +0200449 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
450
451 digital_switch_rf(ddev, 1);
452
453 return 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200454}
455
456static int digital_dev_down(struct nfc_dev *nfc_dev)
457{
Thierry Escande59ee2362013-09-19 17:55:26 +0200458 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
459
460 digital_switch_rf(ddev, 0);
461
462 return 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200463}
464
465static int digital_dep_link_up(struct nfc_dev *nfc_dev,
466 struct nfc_target *target,
467 __u8 comm_mode, __u8 *gb, size_t gb_len)
468{
Thierry Escande7d0911c2013-09-19 17:55:29 +0200469 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
470
471 return digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200472}
473
474static int digital_dep_link_down(struct nfc_dev *nfc_dev)
475{
Thierry Escande7d0911c2013-09-19 17:55:29 +0200476 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
477
478 ddev->curr_protocol = 0;
479
480 return 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200481}
482
483static int digital_activate_target(struct nfc_dev *nfc_dev,
484 struct nfc_target *target, __u32 protocol)
485{
Thierry Escande59ee2362013-09-19 17:55:26 +0200486 return 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200487}
488
489static void digital_deactivate_target(struct nfc_dev *nfc_dev,
490 struct nfc_target *target)
491{
Thierry Escande59ee2362013-09-19 17:55:26 +0200492 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
493
494 ddev->curr_protocol = 0;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200495}
496
497static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb)
498{
499 return -EOPNOTSUPP;
500}
501
Thierry Escande2c66dae2013-09-19 17:55:27 +0200502static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
503 struct sk_buff *resp)
504{
505 struct digital_data_exch *data_exch = arg;
506 int rc;
507
508 if (IS_ERR(resp)) {
509 rc = PTR_ERR(resp);
510 goto done;
511 }
512
513 if (ddev->curr_protocol == NFC_PROTO_MIFARE)
514 rc = digital_in_recv_mifare_res(resp);
515 else
516 rc = ddev->skb_check_crc(resp);
517
518 if (rc) {
519 kfree_skb(resp);
520 resp = NULL;
521 }
522
523done:
524 data_exch->cb(data_exch->cb_context, resp, rc);
525
526 kfree(data_exch);
527}
528
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200529static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
530 struct sk_buff *skb, data_exchange_cb_t cb,
531 void *cb_context)
532{
Thierry Escande2c66dae2013-09-19 17:55:27 +0200533 struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
534 struct digital_data_exch *data_exch;
535
536 data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL);
537 if (!data_exch) {
538 PR_ERR("Failed to allocate data_exch struct");
539 return -ENOMEM;
540 }
541
542 data_exch->cb = cb;
543 data_exch->cb_context = cb_context;
544
Thierry Escande7d0911c2013-09-19 17:55:29 +0200545 if (ddev->curr_protocol == NFC_PROTO_NFC_DEP)
546 return digital_in_send_dep_req(ddev, target, skb, data_exch);
547
Thierry Escande2c66dae2013-09-19 17:55:27 +0200548 ddev->skb_add_crc(skb);
549
550 return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete,
551 data_exch);
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200552}
553
554static struct nfc_ops digital_nfc_ops = {
555 .dev_up = digital_dev_up,
556 .dev_down = digital_dev_down,
557 .start_poll = digital_start_poll,
558 .stop_poll = digital_stop_poll,
559 .dep_link_up = digital_dep_link_up,
560 .dep_link_down = digital_dep_link_down,
561 .activate_target = digital_activate_target,
562 .deactivate_target = digital_deactivate_target,
563 .tm_send = digital_tg_send,
564 .im_transceive = digital_in_send,
565};
566
567struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
568 __u32 supported_protocols,
569 __u32 driver_capabilities,
570 int tx_headroom, int tx_tailroom)
571{
572 struct nfc_digital_dev *ddev;
573
574 if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen ||
575 !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd ||
576 !ops->switch_rf)
577 return NULL;
578
579 ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL);
580 if (!ddev) {
581 PR_ERR("kzalloc failed");
582 return NULL;
583 }
584
585 ddev->driver_capabilities = driver_capabilities;
586 ddev->ops = ops;
587
Thierry Escande59ee2362013-09-19 17:55:26 +0200588 mutex_init(&ddev->cmd_lock);
589 INIT_LIST_HEAD(&ddev->cmd_queue);
590
591 INIT_WORK(&ddev->cmd_work, digital_wq_cmd);
592 INIT_WORK(&ddev->cmd_complete_work, digital_wq_cmd_complete);
593
594 mutex_init(&ddev->poll_lock);
595 INIT_WORK(&ddev->poll_work, digital_wq_poll);
596
597 if (supported_protocols & NFC_PROTO_JEWEL_MASK)
598 ddev->protocols |= NFC_PROTO_JEWEL_MASK;
599 if (supported_protocols & NFC_PROTO_MIFARE_MASK)
600 ddev->protocols |= NFC_PROTO_MIFARE_MASK;
Thierry Escande8c0695e42013-09-19 17:55:28 +0200601 if (supported_protocols & NFC_PROTO_FELICA_MASK)
602 ddev->protocols |= NFC_PROTO_FELICA_MASK;
Thierry Escande7d0911c2013-09-19 17:55:29 +0200603 if (supported_protocols & NFC_PROTO_NFC_DEP_MASK)
604 ddev->protocols |= NFC_PROTO_NFC_DEP_MASK;
Thierry Escande59ee2362013-09-19 17:55:26 +0200605
606 ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
607 ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200608
609 ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols,
610 ddev->tx_headroom,
611 ddev->tx_tailroom);
612 if (!ddev->nfc_dev) {
613 PR_ERR("nfc_allocate_device failed");
614 goto free_dev;
615 }
616
617 nfc_set_drvdata(ddev->nfc_dev, ddev);
618
619 return ddev;
620
621free_dev:
622 kfree(ddev);
623
624 return NULL;
625}
626EXPORT_SYMBOL(nfc_digital_allocate_device);
627
628void nfc_digital_free_device(struct nfc_digital_dev *ddev)
629{
630 nfc_free_device(ddev->nfc_dev);
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200631 kfree(ddev);
632}
633EXPORT_SYMBOL(nfc_digital_free_device);
634
635int nfc_digital_register_device(struct nfc_digital_dev *ddev)
636{
637 return nfc_register_device(ddev->nfc_dev);
638}
639EXPORT_SYMBOL(nfc_digital_register_device);
640
641void nfc_digital_unregister_device(struct nfc_digital_dev *ddev)
642{
Thierry Escande59ee2362013-09-19 17:55:26 +0200643 struct digital_cmd *cmd, *n;
644
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200645 nfc_unregister_device(ddev->nfc_dev);
Thierry Escande59ee2362013-09-19 17:55:26 +0200646
647 mutex_lock(&ddev->poll_lock);
648 ddev->poll_tech_count = 0;
649 mutex_unlock(&ddev->poll_lock);
650
651 cancel_work_sync(&ddev->poll_work);
652 cancel_work_sync(&ddev->cmd_work);
653 cancel_work_sync(&ddev->cmd_complete_work);
654
655 list_for_each_entry_safe(cmd, n, &ddev->cmd_queue, queue) {
656 list_del(&cmd->queue);
657 kfree(cmd);
658 }
Thierry Escande4b10884eb2013-09-19 17:55:25 +0200659}
660EXPORT_SYMBOL(nfc_digital_unregister_device);
661
662MODULE_LICENSE("GPL");