blob: eb3cecf1764ecb12bef5b17f92f5991d59158cc1 [file] [log] [blame]
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -03001/*
2 * Copyright (C) 2011 Instituto Nokia de Tecnologia
3 *
4 * Authors:
5 * Lauro Ramos Venancio <lauro.venancio@openbossa.org>
6 * Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the
20 * Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
Samuel Ortiz52858b52011-12-14 16:43:05 +010024#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
Joe Perchesed1e0ad2011-11-29 11:37:32 -080025
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -030026#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/slab.h>
Samuel Ortizbe055b22013-04-11 11:52:20 +020030#include <linux/rfkill.h>
Samuel Ortiz7c7cd3b2011-12-14 16:43:06 +010031#include <linux/nfc.h>
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -030032
Samuel Ortiz5df16ca2012-06-12 16:54:16 +020033#include <net/genetlink.h>
34
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -030035#include "nfc.h"
36
37#define VERSION "0.1"
38
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +020039#define NFC_CHECK_PRES_FREQ_MS 2000
40
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -030041int nfc_devlist_generation;
42DEFINE_MUTEX(nfc_devlist_mutex);
43
Samuel Ortiz7eda8b8e92012-10-22 15:57:58 +020044/* NFC device ID bitmap */
45static DEFINE_IDA(nfc_index_ida);
46
Eric Lapuyade9674da82013-04-29 17:13:27 +020047int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
48{
49 int rc = 0;
50
51 pr_debug("%s do firmware %s\n", dev_name(&dev->dev), firmware_name);
52
53 device_lock(&dev->dev);
54
55 if (!device_is_registered(&dev->dev)) {
56 rc = -ENODEV;
57 goto error;
58 }
59
60 if (dev->dev_up) {
61 rc = -EBUSY;
62 goto error;
63 }
64
65 if (!dev->ops->fw_upload) {
66 rc = -EOPNOTSUPP;
67 goto error;
68 }
69
70 dev->fw_upload_in_progress = true;
71 rc = dev->ops->fw_upload(dev, firmware_name);
72 if (rc)
73 dev->fw_upload_in_progress = false;
74
75error:
76 device_unlock(&dev->dev);
77 return rc;
78}
79
80int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
81{
82 dev->fw_upload_in_progress = false;
83
84 return nfc_genl_fw_upload_done(dev, firmware_name);
85}
86EXPORT_SYMBOL(nfc_fw_upload_done);
87
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -030088/**
Ilan Elias8b3fe7b2011-09-18 11:19:33 +030089 * nfc_dev_up - turn on the NFC device
90 *
91 * @dev: The nfc device to be turned on
92 *
93 * The device remains up until the nfc_dev_down function is called.
94 */
95int nfc_dev_up(struct nfc_dev *dev)
96{
97 int rc = 0;
98
Joe Perches20c239c2011-11-29 11:37:33 -080099 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300100
101 device_lock(&dev->dev);
102
Samuel Ortizbe055b22013-04-11 11:52:20 +0200103 if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
104 rc = -ERFKILL;
105 goto error;
106 }
107
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300108 if (!device_is_registered(&dev->dev)) {
109 rc = -ENODEV;
110 goto error;
111 }
112
Eric Lapuyade9674da82013-04-29 17:13:27 +0200113 if (dev->fw_upload_in_progress) {
114 rc = -EBUSY;
115 goto error;
116 }
117
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300118 if (dev->dev_up) {
119 rc = -EALREADY;
120 goto error;
121 }
122
123 if (dev->ops->dev_up)
124 rc = dev->ops->dev_up(dev);
125
126 if (!rc)
127 dev->dev_up = true;
128
129error:
130 device_unlock(&dev->dev);
131 return rc;
132}
133
134/**
135 * nfc_dev_down - turn off the NFC device
136 *
137 * @dev: The nfc device to be turned off
138 */
139int nfc_dev_down(struct nfc_dev *dev)
140{
141 int rc = 0;
142
Joe Perches20c239c2011-11-29 11:37:33 -0800143 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300144
145 device_lock(&dev->dev);
146
147 if (!device_is_registered(&dev->dev)) {
148 rc = -ENODEV;
149 goto error;
150 }
151
152 if (!dev->dev_up) {
153 rc = -EALREADY;
154 goto error;
155 }
156
Eric Lapuyade90099432012-05-07 12:31:13 +0200157 if (dev->polling || dev->active_target) {
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300158 rc = -EBUSY;
159 goto error;
160 }
161
162 if (dev->ops->dev_down)
163 dev->ops->dev_down(dev);
164
165 dev->dev_up = false;
166
167error:
168 device_unlock(&dev->dev);
169 return rc;
170}
171
Samuel Ortizbe055b22013-04-11 11:52:20 +0200172static int nfc_rfkill_set_block(void *data, bool blocked)
173{
174 struct nfc_dev *dev = data;
175
176 pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
177
178 if (!blocked)
179 return 0;
180
181 nfc_dev_down(dev);
182
183 return 0;
184}
185
186static const struct rfkill_ops nfc_rfkill_ops = {
187 .set_block = nfc_rfkill_set_block,
188};
189
Ilan Elias8b3fe7b2011-09-18 11:19:33 +0300190/**
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300191 * nfc_start_poll - start polling for nfc targets
192 *
193 * @dev: The nfc device that must start polling
194 * @protocols: bitset of nfc protocols that must be used for polling
195 *
196 * The device remains polling for targets until a target is found or
197 * the nfc_stop_poll function is called.
198 */
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200199int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300200{
201 int rc;
202
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200203 pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n",
204 dev_name(&dev->dev), im_protocols, tm_protocols);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300205
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200206 if (!im_protocols && !tm_protocols)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300207 return -EINVAL;
208
209 device_lock(&dev->dev);
210
211 if (!device_is_registered(&dev->dev)) {
212 rc = -ENODEV;
213 goto error;
214 }
215
Samuel Ortiz7757dc82013-04-10 12:25:30 +0200216 if (!dev->dev_up) {
217 rc = -ENODEV;
218 goto error;
219 }
220
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300221 if (dev->polling) {
222 rc = -EBUSY;
223 goto error;
224 }
225
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200226 rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
Samuel Ortizf212ad52012-05-31 00:02:26 +0200227 if (!rc) {
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300228 dev->polling = true;
Samuel Ortizf212ad52012-05-31 00:02:26 +0200229 dev->rf_mode = NFC_RF_NONE;
230 }
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300231
232error:
233 device_unlock(&dev->dev);
234 return rc;
235}
236
237/**
238 * nfc_stop_poll - stop polling for nfc targets
239 *
240 * @dev: The nfc device that must stop polling
241 */
242int nfc_stop_poll(struct nfc_dev *dev)
243{
244 int rc = 0;
245
Joe Perches20c239c2011-11-29 11:37:33 -0800246 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300247
248 device_lock(&dev->dev);
249
250 if (!device_is_registered(&dev->dev)) {
251 rc = -ENODEV;
252 goto error;
253 }
254
255 if (!dev->polling) {
256 rc = -EINVAL;
257 goto error;
258 }
259
260 dev->ops->stop_poll(dev);
261 dev->polling = false;
Thierry Escande5bcf0992012-10-05 11:05:45 +0200262 dev->rf_mode = NFC_RF_NONE;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300263
264error:
265 device_unlock(&dev->dev);
266 return rc;
267}
268
Eric Lapuyade90099432012-05-07 12:31:13 +0200269static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
270{
271 int i;
272
273 if (dev->n_targets == 0)
274 return NULL;
275
Szymon Janc0f450772012-10-17 15:23:39 +0200276 for (i = 0; i < dev->n_targets; i++) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200277 if (dev->targets[i].idx == target_idx)
278 return &dev->targets[i];
279 }
280
281 return NULL;
282}
283
Samuel Ortiz47807d32012-03-05 01:03:50 +0100284int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100285{
286 int rc = 0;
Samuel Ortiz47807d32012-03-05 01:03:50 +0100287 u8 *gb;
288 size_t gb_len;
Eric Lapuyade90099432012-05-07 12:31:13 +0200289 struct nfc_target *target;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100290
Samuel Ortiz47807d32012-03-05 01:03:50 +0100291 pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100292
293 if (!dev->ops->dep_link_up)
294 return -EOPNOTSUPP;
295
296 device_lock(&dev->dev);
297
298 if (!device_is_registered(&dev->dev)) {
299 rc = -ENODEV;
300 goto error;
301 }
302
303 if (dev->dep_link_up == true) {
304 rc = -EALREADY;
305 goto error;
306 }
307
Samuel Ortiz47807d32012-03-05 01:03:50 +0100308 gb = nfc_llcp_general_bytes(dev, &gb_len);
309 if (gb_len > NFC_MAX_GT_LEN) {
310 rc = -EINVAL;
311 goto error;
312 }
313
Eric Lapuyade90099432012-05-07 12:31:13 +0200314 target = nfc_find_target(dev, target_index);
315 if (target == NULL) {
316 rc = -ENOTCONN;
317 goto error;
318 }
319
320 rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
Samuel Ortizf212ad52012-05-31 00:02:26 +0200321 if (!rc) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200322 dev->active_target = target;
Samuel Ortizf212ad52012-05-31 00:02:26 +0200323 dev->rf_mode = NFC_RF_INITIATOR;
324 }
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100325
326error:
327 device_unlock(&dev->dev);
328 return rc;
329}
330
331int nfc_dep_link_down(struct nfc_dev *dev)
332{
333 int rc = 0;
334
335 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
336
337 if (!dev->ops->dep_link_down)
338 return -EOPNOTSUPP;
339
340 device_lock(&dev->dev);
341
342 if (!device_is_registered(&dev->dev)) {
343 rc = -ENODEV;
344 goto error;
345 }
346
347 if (dev->dep_link_up == false) {
348 rc = -EALREADY;
349 goto error;
350 }
351
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100352 rc = dev->ops->dep_link_down(dev);
353 if (!rc) {
354 dev->dep_link_up = false;
Eric Lapuyade90099432012-05-07 12:31:13 +0200355 dev->active_target = NULL;
Thierry Escande5bcf0992012-10-05 11:05:45 +0200356 dev->rf_mode = NFC_RF_NONE;
Samuel Ortizd6469602011-12-14 16:43:12 +0100357 nfc_llcp_mac_is_down(dev);
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100358 nfc_genl_dep_link_down_event(dev);
359 }
360
361error:
362 device_unlock(&dev->dev);
Thierry Escande5bcf0992012-10-05 11:05:45 +0200363
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100364 return rc;
365}
366
367int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100368 u8 comm_mode, u8 rf_mode)
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100369{
370 dev->dep_link_up = true;
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100371
Samuel Ortizd6469602011-12-14 16:43:12 +0100372 nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
373
Samuel Ortiz1ed28f62011-12-14 16:43:09 +0100374 return nfc_genl_dep_link_up_event(dev, target_idx, comm_mode, rf_mode);
375}
376EXPORT_SYMBOL(nfc_dep_link_is_up);
377
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300378/**
379 * nfc_activate_target - prepare the target for data exchange
380 *
381 * @dev: The nfc device that found the target
382 * @target_idx: index of the target that must be activated
383 * @protocol: nfc protocol that will be used for data exchange
384 */
385int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
386{
387 int rc;
Eric Lapuyade90099432012-05-07 12:31:13 +0200388 struct nfc_target *target;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300389
Joe Perches20c239c2011-11-29 11:37:33 -0800390 pr_debug("dev_name=%s target_idx=%u protocol=%u\n",
391 dev_name(&dev->dev), target_idx, protocol);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300392
393 device_lock(&dev->dev);
394
395 if (!device_is_registered(&dev->dev)) {
396 rc = -ENODEV;
397 goto error;
398 }
399
Eric Lapuyade90099432012-05-07 12:31:13 +0200400 if (dev->active_target) {
401 rc = -EBUSY;
402 goto error;
403 }
404
405 target = nfc_find_target(dev, target_idx);
406 if (target == NULL) {
407 rc = -ENOTCONN;
408 goto error;
409 }
410
411 rc = dev->ops->activate_target(dev, target, protocol);
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200412 if (!rc) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200413 dev->active_target = target;
Samuel Ortizf212ad52012-05-31 00:02:26 +0200414 dev->rf_mode = NFC_RF_INITIATOR;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300415
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100416 if (dev->ops->check_presence && !dev->shutting_down)
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200417 mod_timer(&dev->check_pres_timer, jiffies +
418 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
419 }
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300420
421error:
422 device_unlock(&dev->dev);
423 return rc;
424}
425
426/**
427 * nfc_deactivate_target - deactivate a nfc target
428 *
429 * @dev: The nfc device that found the target
430 * @target_idx: index of the target that must be deactivated
431 */
432int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
433{
434 int rc = 0;
435
Joe Perches20c239c2011-11-29 11:37:33 -0800436 pr_debug("dev_name=%s target_idx=%u\n",
437 dev_name(&dev->dev), target_idx);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300438
439 device_lock(&dev->dev);
440
441 if (!device_is_registered(&dev->dev)) {
442 rc = -ENODEV;
443 goto error;
444 }
445
Eric Lapuyade90099432012-05-07 12:31:13 +0200446 if (dev->active_target == NULL) {
447 rc = -ENOTCONN;
448 goto error;
449 }
450
451 if (dev->active_target->idx != target_idx) {
452 rc = -ENOTCONN;
453 goto error;
454 }
455
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200456 if (dev->ops->check_presence)
457 del_timer_sync(&dev->check_pres_timer);
458
Eric Lapuyade90099432012-05-07 12:31:13 +0200459 dev->ops->deactivate_target(dev, dev->active_target);
460 dev->active_target = NULL;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300461
462error:
463 device_unlock(&dev->dev);
464 return rc;
465}
466
467/**
468 * nfc_data_exchange - transceive data
469 *
470 * @dev: The nfc device that found the target
471 * @target_idx: index of the target
472 * @skb: data to be sent
473 * @cb: callback called when the response is received
474 * @cb_context: parameter for the callback function
475 *
476 * The user must wait for the callback before calling this function again.
477 */
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100478int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
479 data_exchange_cb_t cb, void *cb_context)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300480{
481 int rc;
482
Joe Perches20c239c2011-11-29 11:37:33 -0800483 pr_debug("dev_name=%s target_idx=%u skb->len=%u\n",
484 dev_name(&dev->dev), target_idx, skb->len);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300485
486 device_lock(&dev->dev);
487
488 if (!device_is_registered(&dev->dev)) {
489 rc = -ENODEV;
490 kfree_skb(skb);
491 goto error;
492 }
493
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200494 if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
495 if (dev->active_target->idx != target_idx) {
496 rc = -EADDRNOTAVAIL;
497 kfree_skb(skb);
498 goto error;
499 }
500
501 if (dev->ops->check_presence)
502 del_timer_sync(&dev->check_pres_timer);
503
504 rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
505 cb_context);
506
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100507 if (!rc && dev->ops->check_presence && !dev->shutting_down)
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200508 mod_timer(&dev->check_pres_timer, jiffies +
509 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
510 } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
511 rc = dev->ops->tm_send(dev, skb);
512 } else {
Eric Lapuyade144612c2012-04-10 19:43:11 +0200513 rc = -ENOTCONN;
514 kfree_skb(skb);
515 goto error;
516 }
517
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200518
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300519error:
520 device_unlock(&dev->dev);
521 return rc;
522}
523
Samuel Ortiz541d9202011-12-14 16:43:10 +0100524int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
525{
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100526 pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len);
Samuel Ortiz541d9202011-12-14 16:43:10 +0100527
528 if (gb_len > NFC_MAX_GT_LEN)
529 return -EINVAL;
530
Samuel Ortizd6469602011-12-14 16:43:12 +0100531 return nfc_llcp_set_remote_gb(dev, gb, gb_len);
Samuel Ortiz541d9202011-12-14 16:43:10 +0100532}
533EXPORT_SYMBOL(nfc_set_remote_general_bytes);
534
Samuel Ortizab73b752012-04-10 12:51:52 +0200535u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
536{
537 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
538
539 return nfc_llcp_general_bytes(dev, gb_len);
540}
541EXPORT_SYMBOL(nfc_get_local_general_bytes);
542
Samuel Ortiz73167ce2012-05-31 00:05:50 +0200543int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
544{
545 /* Only LLCP target mode for now */
546 if (dev->dep_link_up == false) {
547 kfree_skb(skb);
548 return -ENOLINK;
549 }
550
551 return nfc_llcp_data_received(dev, skb);
552}
553EXPORT_SYMBOL(nfc_tm_data_received);
554
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200555int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
556 u8 *gb, size_t gb_len)
557{
558 int rc;
559
560 device_lock(&dev->dev);
561
562 dev->polling = false;
563
564 if (gb != NULL) {
565 rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
566 if (rc < 0)
567 goto out;
568 }
569
Samuel Ortizf212ad52012-05-31 00:02:26 +0200570 dev->rf_mode = NFC_RF_TARGET;
571
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200572 if (protocol == NFC_PROTO_NFC_DEP_MASK)
573 nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
574
575 rc = nfc_genl_tm_activated(dev, protocol);
576
577out:
578 device_unlock(&dev->dev);
579
580 return rc;
581}
582EXPORT_SYMBOL(nfc_tm_activated);
583
584int nfc_tm_deactivated(struct nfc_dev *dev)
585{
586 dev->dep_link_up = false;
Thierry Escande5bcf0992012-10-05 11:05:45 +0200587 dev->rf_mode = NFC_RF_NONE;
Samuel Ortizfc40a8c2012-06-01 13:21:13 +0200588
589 return nfc_genl_tm_deactivated(dev);
590}
591EXPORT_SYMBOL(nfc_tm_deactivated);
592
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300593/**
Samuel Ortiz7c7cd3b2011-12-14 16:43:06 +0100594 * nfc_alloc_send_skb - allocate a skb for data exchange responses
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300595 *
596 * @size: size to allocate
597 * @gfp: gfp flags
598 */
Samuel Ortiz7c7cd3b2011-12-14 16:43:06 +0100599struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100600 unsigned int flags, unsigned int size,
601 unsigned int *err)
Samuel Ortiz7c7cd3b2011-12-14 16:43:06 +0100602{
603 struct sk_buff *skb;
604 unsigned int total_size;
605
606 total_size = size +
607 dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
608
609 skb = sock_alloc_send_skb(sk, total_size, flags & MSG_DONTWAIT, err);
610 if (skb)
611 skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
612
613 return skb;
614}
615
616/**
617 * nfc_alloc_recv_skb - allocate a skb for data exchange responses
618 *
619 * @size: size to allocate
620 * @gfp: gfp flags
621 */
622struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300623{
624 struct sk_buff *skb;
625 unsigned int total_size;
626
627 total_size = size + 1;
628 skb = alloc_skb(total_size, gfp);
629
630 if (skb)
631 skb_reserve(skb, 1);
632
633 return skb;
634}
Samuel Ortiz7c7cd3b2011-12-14 16:43:06 +0100635EXPORT_SYMBOL(nfc_alloc_recv_skb);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300636
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300637/**
638 * nfc_targets_found - inform that targets were found
639 *
640 * @dev: The nfc device that found the targets
641 * @targets: array of nfc targets found
642 * @ntargets: targets array size
643 *
644 * The device driver must call this function when one or many nfc targets
645 * are found. After calling this function, the device driver must stop
646 * polling for targets.
Eric Lapuyaded94f9c52012-05-03 16:33:32 +0200647 * NOTE: This function can be called with targets=NULL and n_targets=0 to
648 * notify a driver error, meaning that the polling operation cannot complete.
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200649 * IMPORTANT: this function must not be called from an atomic context.
650 * In addition, it must also not be called from a context that would prevent
651 * the NFC Core to call other nfc ops entry point concurrently.
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300652 */
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100653int nfc_targets_found(struct nfc_dev *dev,
654 struct nfc_target *targets, int n_targets)
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300655{
Samuel Ortizc4fbb652012-04-10 19:43:09 +0200656 int i;
657
Joe Perches20c239c2011-11-29 11:37:33 -0800658 pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300659
Samuel Ortizc4fbb652012-04-10 19:43:09 +0200660 for (i = 0; i < n_targets; i++)
Eric Lapuyade01ae0ee2012-04-10 19:43:10 +0200661 targets[i].idx = dev->target_next_idx++;
Samuel Ortizc4fbb652012-04-10 19:43:09 +0200662
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200663 device_lock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300664
Eric Lapuyade8668fdd2012-05-03 16:21:58 +0200665 if (dev->polling == false) {
666 device_unlock(&dev->dev);
667 return 0;
668 }
669
670 dev->polling = false;
671
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300672 dev->targets_generation++;
673
674 kfree(dev->targets);
Eric Lapuyaded94f9c52012-05-03 16:33:32 +0200675 dev->targets = NULL;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300676
Eric Lapuyaded94f9c52012-05-03 16:33:32 +0200677 if (targets) {
678 dev->targets = kmemdup(targets,
679 n_targets * sizeof(struct nfc_target),
680 GFP_ATOMIC);
681
682 if (!dev->targets) {
683 dev->n_targets = 0;
684 device_unlock(&dev->dev);
685 return -ENOMEM;
686 }
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300687 }
688
689 dev->n_targets = n_targets;
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200690 device_unlock(&dev->dev);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300691
692 nfc_genl_targets_found(dev);
693
694 return 0;
695}
696EXPORT_SYMBOL(nfc_targets_found);
697
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200698/**
699 * nfc_target_lost - inform that an activated target went out of field
700 *
701 * @dev: The nfc device that had the activated target in field
702 * @target_idx: the nfc index of the target
703 *
704 * The device driver must call this function when the activated target
705 * goes out of the field.
706 * IMPORTANT: this function must not be called from an atomic context.
707 * In addition, it must also not be called from a context that would prevent
708 * the NFC Core to call other nfc ops entry point concurrently.
709 */
Eric Lapuyadee1da0ef2012-04-10 19:43:05 +0200710int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
711{
712 struct nfc_target *tg;
713 int i;
714
715 pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx);
716
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200717 device_lock(&dev->dev);
Eric Lapuyadee1da0ef2012-04-10 19:43:05 +0200718
719 for (i = 0; i < dev->n_targets; i++) {
720 tg = &dev->targets[i];
721 if (tg->idx == target_idx)
722 break;
723 }
724
725 if (i == dev->n_targets) {
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200726 device_unlock(&dev->dev);
Eric Lapuyadee1da0ef2012-04-10 19:43:05 +0200727 return -EINVAL;
728 }
729
730 dev->targets_generation++;
731 dev->n_targets--;
Eric Lapuyade90099432012-05-07 12:31:13 +0200732 dev->active_target = NULL;
Eric Lapuyadee1da0ef2012-04-10 19:43:05 +0200733
734 if (dev->n_targets) {
735 memcpy(&dev->targets[i], &dev->targets[i + 1],
736 (dev->n_targets - i) * sizeof(struct nfc_target));
737 } else {
738 kfree(dev->targets);
739 dev->targets = NULL;
740 }
741
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200742 device_unlock(&dev->dev);
Eric Lapuyadee1da0ef2012-04-10 19:43:05 +0200743
744 nfc_genl_target_lost(dev, target_idx);
745
746 return 0;
747}
748EXPORT_SYMBOL(nfc_target_lost);
749
Eric Lapuyade9eb334a2012-06-11 15:52:38 +0200750inline void nfc_driver_failure(struct nfc_dev *dev, int err)
Eric Lapuyade456411c2012-06-11 13:49:51 +0200751{
Eric Lapuyade9eb334a2012-06-11 15:52:38 +0200752 nfc_targets_found(dev, NULL, 0);
Eric Lapuyade456411c2012-06-11 13:49:51 +0200753}
754EXPORT_SYMBOL(nfc_driver_failure);
755
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300756static void nfc_release(struct device *d)
757{
758 struct nfc_dev *dev = to_nfc_dev(d);
759
Joe Perches20c239c2011-11-29 11:37:33 -0800760 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300761
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300762 nfc_genl_data_exit(&dev->genl_data);
763 kfree(dev->targets);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300764 kfree(dev);
765}
766
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200767static void nfc_check_pres_work(struct work_struct *work)
768{
769 struct nfc_dev *dev = container_of(work, struct nfc_dev,
770 check_pres_work);
771 int rc;
772
773 device_lock(&dev->dev);
774
Eric Lapuyade90099432012-05-07 12:31:13 +0200775 if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
776 rc = dev->ops->check_presence(dev, dev->active_target);
Eric Lapuyade632c0162012-10-02 17:27:36 +0200777 if (rc == -EOPNOTSUPP)
778 goto exit;
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100779 if (rc) {
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200780 u32 active_target_idx = dev->active_target->idx;
781 device_unlock(&dev->dev);
782 nfc_target_lost(dev, active_target_idx);
783 return;
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200784 }
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100785
786 if (!dev->shutting_down)
787 mod_timer(&dev->check_pres_timer, jiffies +
788 msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200789 }
790
Eric Lapuyade632c0162012-10-02 17:27:36 +0200791exit:
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200792 device_unlock(&dev->dev);
793}
794
795static void nfc_check_pres_timeout(unsigned long data)
796{
797 struct nfc_dev *dev = (struct nfc_dev *)data;
798
Linus Torvalds916082b2012-10-02 16:01:31 -0700799 schedule_work(&dev->check_pres_work);
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200800}
801
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300802struct class nfc_class = {
803 .name = "nfc",
804 .dev_release = nfc_release,
805};
806EXPORT_SYMBOL(nfc_class);
807
Michał Mirosław9f3b7952013-02-01 20:40:17 +0100808static int match_idx(struct device *d, const void *data)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300809{
810 struct nfc_dev *dev = to_nfc_dev(d);
Michał Mirosław9f3b7952013-02-01 20:40:17 +0100811 const unsigned int *idx = data;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300812
813 return dev->idx == *idx;
814}
815
Eric Dumazet95c96172012-04-15 05:58:06 +0000816struct nfc_dev *nfc_get_device(unsigned int idx)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300817{
818 struct device *d;
819
820 d = class_find_device(&nfc_class, NULL, &idx, match_idx);
821 if (!d)
822 return NULL;
823
824 return to_nfc_dev(d);
825}
826
827/**
828 * nfc_allocate_device - allocate a new nfc device
829 *
830 * @ops: device operations
831 * @supported_protocols: NFC protocols supported by the device
832 */
833struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100834 u32 supported_protocols,
Samuel Ortiz390a1bd2012-12-19 19:11:32 +0100835 u32 supported_se,
Samuel Ortiz0a40acb2012-03-05 01:03:53 +0100836 int tx_headroom, int tx_tailroom)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300837{
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300838 struct nfc_dev *dev;
839
840 if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200841 !ops->deactivate_target || !ops->im_transceive)
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300842 return NULL;
843
844 if (!supported_protocols)
845 return NULL;
846
847 dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL);
848 if (!dev)
849 return NULL;
850
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300851 dev->ops = ops;
852 dev->supported_protocols = supported_protocols;
Samuel Ortiz390a1bd2012-12-19 19:11:32 +0100853 dev->supported_se = supported_se;
854 dev->active_se = NFC_SE_NONE;
Samuel Ortize8753042011-08-19 15:47:11 +0200855 dev->tx_headroom = tx_headroom;
856 dev->tx_tailroom = tx_tailroom;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300857
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300858 nfc_genl_data_init(&dev->genl_data);
859
Thierry Escande5bcf0992012-10-05 11:05:45 +0200860 dev->rf_mode = NFC_RF_NONE;
Eric Lapuyaded4ccb132012-05-07 12:31:15 +0200861
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300862 /* first generation must not be 0 */
863 dev->targets_generation = 1;
864
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200865 if (ops->check_presence) {
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200866 init_timer(&dev->check_pres_timer);
867 dev->check_pres_timer.data = (unsigned long)dev;
868 dev->check_pres_timer.function = nfc_check_pres_timeout;
869
870 INIT_WORK(&dev->check_pres_work, nfc_check_pres_work);
Eric Lapuyadec8d56ae2012-04-10 19:43:12 +0200871 }
872
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300873 return dev;
874}
875EXPORT_SYMBOL(nfc_allocate_device);
876
877/**
878 * nfc_register_device - register a nfc device in the nfc subsystem
879 *
880 * @dev: The nfc device to register
881 */
882int nfc_register_device(struct nfc_dev *dev)
883{
884 int rc;
885
Joe Perches20c239c2011-11-29 11:37:33 -0800886 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300887
Samuel Ortiz7eda8b8e92012-10-22 15:57:58 +0200888 dev->idx = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
889 if (dev->idx < 0)
890 return dev->idx;
891
892 dev->dev.class = &nfc_class;
893 dev_set_name(&dev->dev, "nfc%d", dev->idx);
894 device_initialize(&dev->dev);
895
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300896 mutex_lock(&nfc_devlist_mutex);
897 nfc_devlist_generation++;
898 rc = device_add(&dev->dev);
899 mutex_unlock(&nfc_devlist_mutex);
900
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300901 if (rc < 0)
902 return rc;
903
Samuel Ortizd6469602011-12-14 16:43:12 +0100904 rc = nfc_llcp_register_device(dev);
905 if (rc)
906 pr_err("Could not register llcp device\n");
907
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300908 rc = nfc_genl_device_added(dev);
909 if (rc)
Joe Perches20c239c2011-11-29 11:37:33 -0800910 pr_debug("The userspace won't be notified that the device %s was added\n",
911 dev_name(&dev->dev));
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300912
Samuel Ortizbe055b22013-04-11 11:52:20 +0200913 dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
914 RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
915 if (dev->rfkill) {
916 if (rfkill_register(dev->rfkill) < 0) {
917 rfkill_destroy(dev->rfkill);
918 dev->rfkill = NULL;
919 }
920 }
921
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300922 return 0;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300923}
924EXPORT_SYMBOL(nfc_register_device);
925
926/**
927 * nfc_unregister_device - unregister a nfc device in the nfc subsystem
928 *
929 * @dev: The nfc device to unregister
930 */
931void nfc_unregister_device(struct nfc_dev *dev)
932{
Samuel Ortiz7eda8b8e92012-10-22 15:57:58 +0200933 int rc, id;
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300934
Joe Perches20c239c2011-11-29 11:37:33 -0800935 pr_debug("dev_name=%s\n", dev_name(&dev->dev));
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300936
Samuel Ortiz7eda8b8e92012-10-22 15:57:58 +0200937 id = dev->idx;
938
Samuel Ortizbe055b22013-04-11 11:52:20 +0200939 if (dev->rfkill) {
940 rfkill_unregister(dev->rfkill);
941 rfkill_destroy(dev->rfkill);
942 }
943
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100944 if (dev->ops->check_presence) {
945 device_lock(&dev->dev);
946 dev->shutting_down = true;
947 device_unlock(&dev->dev);
948 del_timer_sync(&dev->check_pres_timer);
949 cancel_work_sync(&dev->check_pres_work);
950 }
Samuel Ortizd6469602011-12-14 16:43:12 +0100951
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300952 rc = nfc_genl_device_removed(dev);
953 if (rc)
Eric Lapuyadef0c91032012-11-26 18:06:27 +0100954 pr_debug("The userspace won't be notified that the device %s "
955 "was removed\n", dev_name(&dev->dev));
956
957 nfc_llcp_unregister_device(dev);
958
959 mutex_lock(&nfc_devlist_mutex);
960 nfc_devlist_generation++;
961 device_del(&dev->dev);
962 mutex_unlock(&nfc_devlist_mutex);
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300963
Samuel Ortiz7eda8b8e92012-10-22 15:57:58 +0200964 ida_simple_remove(&nfc_index_ida, id);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300965}
966EXPORT_SYMBOL(nfc_unregister_device);
967
968static int __init nfc_init(void)
969{
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300970 int rc;
971
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800972 pr_info("NFC Core ver %s\n", VERSION);
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -0300973
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300974 rc = class_register(&nfc_class);
975 if (rc)
976 return rc;
977
978 rc = nfc_genl_init();
979 if (rc)
980 goto err_genl;
981
982 /* the first generation must not be 0 */
983 nfc_devlist_generation = 1;
984
Lauro Ramos Venancio23b78692011-07-01 19:31:36 -0300985 rc = rawsock_init();
986 if (rc)
987 goto err_rawsock;
988
Samuel Ortizd6469602011-12-14 16:43:12 +0100989 rc = nfc_llcp_init();
990 if (rc)
991 goto err_llcp_sock;
992
Aloisio Almeida Jrc7fe3b52011-07-01 19:31:35 -0300993 rc = af_nfc_init();
994 if (rc)
995 goto err_af_nfc;
996
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -0300997 return 0;
998
Aloisio Almeida Jrc7fe3b52011-07-01 19:31:35 -0300999err_af_nfc:
Samuel Ortizd6469602011-12-14 16:43:12 +01001000 nfc_llcp_exit();
1001err_llcp_sock:
Lauro Ramos Venancio23b78692011-07-01 19:31:36 -03001002 rawsock_exit();
1003err_rawsock:
Aloisio Almeida Jrc7fe3b52011-07-01 19:31:35 -03001004 nfc_genl_exit();
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001005err_genl:
1006 class_unregister(&nfc_class);
1007 return rc;
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -03001008}
1009
1010static void __exit nfc_exit(void)
1011{
Aloisio Almeida Jrc7fe3b52011-07-01 19:31:35 -03001012 af_nfc_exit();
Samuel Ortizd6469602011-12-14 16:43:12 +01001013 nfc_llcp_exit();
Lauro Ramos Venancio23b78692011-07-01 19:31:36 -03001014 rawsock_exit();
Lauro Ramos Venancio4d12b8b2011-07-01 19:31:34 -03001015 nfc_genl_exit();
Lauro Ramos Venancio3e256b82011-07-01 19:31:33 -03001016 class_unregister(&nfc_class);
1017}
1018
1019subsys_initcall(nfc_init);
1020module_exit(nfc_exit);
1021
1022MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
1023MODULE_DESCRIPTION("NFC Core ver " VERSION);
1024MODULE_VERSION(VERSION);
1025MODULE_LICENSE("GPL");
Samuel Ortiz1155bb62012-06-12 00:35:50 +02001026MODULE_ALIAS_NETPROTO(PF_NFC);
Samuel Ortiz5df16ca2012-06-12 16:54:16 +02001027MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME);