Blame view

net/nfc/core.c 24.2 KB
1ccea77e2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
2
3
4
5
6
7
  /*
   * Copyright (C) 2011 Instituto Nokia de Tecnologia
   *
   * Authors:
   *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
   *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
8
   */
52858b51b   Samuel Ortiz   NFC: Add function...
9
  #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
ed1e0ad88   Joe Perches   nfc: Use standard...
10

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
11
12
13
14
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/slab.h>
be055b2f8   Samuel Ortiz   NFC: RFKILL support
15
  #include <linux/rfkill.h>
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
16
  #include <linux/nfc.h>
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
17

5df16cad4   Samuel Ortiz   NFC: Add netlink ...
18
  #include <net/genetlink.h>
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
19
20
21
  #include "nfc.h"
  
  #define VERSION "0.1"
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
22
  #define NFC_CHECK_PRES_FREQ_MS	2000
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
23
24
  int nfc_devlist_generation;
  DEFINE_MUTEX(nfc_devlist_mutex);
7eda8b8e9   Samuel Ortiz   NFC: Use IDR libr...
25
26
  /* NFC device ID bitmap */
  static DEFINE_IDA(nfc_index_ida);
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
27
  int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
9674da875   Eric Lapuyade   NFC: Add firmware...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  {
  	int rc = 0;
  
  	pr_debug("%s do firmware %s
  ", dev_name(&dev->dev), firmware_name);
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (dev->dev_up) {
  		rc = -EBUSY;
  		goto error;
  	}
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
45
  	if (!dev->ops->fw_download) {
9674da875   Eric Lapuyade   NFC: Add firmware...
46
47
48
  		rc = -EOPNOTSUPP;
  		goto error;
  	}
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
49
50
  	dev->fw_download_in_progress = true;
  	rc = dev->ops->fw_download(dev, firmware_name);
9674da875   Eric Lapuyade   NFC: Add firmware...
51
  	if (rc)
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
52
  		dev->fw_download_in_progress = false;
9674da875   Eric Lapuyade   NFC: Add firmware...
53
54
55
56
57
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
352a5f5fb   Eric Lapuyade   NFC: netlink: Add...
58
59
60
61
62
63
64
65
66
  /**
   * nfc_fw_download_done - inform that a firmware download was completed
   *
   * @dev: The nfc device to which firmware was downloaded
   * @firmware_name: The firmware filename
   * @result: The positive value of a standard errno value
   */
  int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
  			 u32 result)
9674da875   Eric Lapuyade   NFC: Add firmware...
67
  {
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
68
  	dev->fw_download_in_progress = false;
9674da875   Eric Lapuyade   NFC: Add firmware...
69

352a5f5fb   Eric Lapuyade   NFC: netlink: Add...
70
  	return nfc_genl_fw_download_done(dev, firmware_name, result);
9674da875   Eric Lapuyade   NFC: Add firmware...
71
  }
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
72
  EXPORT_SYMBOL(nfc_fw_download_done);
9674da875   Eric Lapuyade   NFC: Add firmware...
73

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
74
  /**
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
75
76
77
78
79
80
81
82
83
   * nfc_dev_up - turn on the NFC device
   *
   * @dev: The nfc device to be turned on
   *
   * The device remains up until the nfc_dev_down function is called.
   */
  int nfc_dev_up(struct nfc_dev *dev)
  {
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
84
85
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
86
87
  
  	device_lock(&dev->dev);
be055b2f8   Samuel Ortiz   NFC: RFKILL support
88
89
90
91
  	if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
  		rc = -ERFKILL;
  		goto error;
  	}
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
92
93
94
95
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
96
  	if (dev->fw_download_in_progress) {
9674da875   Eric Lapuyade   NFC: Add firmware...
97
98
99
  		rc = -EBUSY;
  		goto error;
  	}
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
100
101
102
103
104
105
106
107
108
109
  	if (dev->dev_up) {
  		rc = -EALREADY;
  		goto error;
  	}
  
  	if (dev->ops->dev_up)
  		rc = dev->ops->dev_up(dev);
  
  	if (!rc)
  		dev->dev_up = true;
0a946301c   Samuel Ortiz   NFC: Extend and f...
110
  	/* We have to enable the device before discovering SEs */
a434c2407   Samuel Ortiz   NFC: Only warn on...
111
112
113
  	if (dev->ops->discover_se && dev->ops->discover_se(dev))
  		pr_err("SE discovery failed
  ");
0a946301c   Samuel Ortiz   NFC: Extend and f...
114

8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
115
116
117
118
119
120
121
122
123
124
125
126
127
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  /**
   * nfc_dev_down - turn off the NFC device
   *
   * @dev: The nfc device to be turned off
   */
  int nfc_dev_down(struct nfc_dev *dev)
  {
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
128
129
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
130
131
132
133
134
135
136
137
138
139
140
141
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (!dev->dev_up) {
  		rc = -EALREADY;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
142
  	if (dev->polling || dev->active_target) {
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
143
144
145
146
147
148
149
150
151
152
153
154
155
  		rc = -EBUSY;
  		goto error;
  	}
  
  	if (dev->ops->dev_down)
  		dev->ops->dev_down(dev);
  
  	dev->dev_up = false;
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
be055b2f8   Samuel Ortiz   NFC: RFKILL support
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  static int nfc_rfkill_set_block(void *data, bool blocked)
  {
  	struct nfc_dev *dev = data;
  
  	pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
  
  	if (!blocked)
  		return 0;
  
  	nfc_dev_down(dev);
  
  	return 0;
  }
  
  static const struct rfkill_ops nfc_rfkill_ops = {
  	.set_block = nfc_rfkill_set_block,
  };
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
173
  /**
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
174
175
176
177
178
179
180
181
   * nfc_start_poll - start polling for nfc targets
   *
   * @dev: The nfc device that must start polling
   * @protocols: bitset of nfc protocols that must be used for polling
   *
   * The device remains polling for targets until a target is found or
   * the nfc_stop_poll function is called.
   */
fe7c58007   Samuel Ortiz   NFC: Add target m...
182
  int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
183
184
  {
  	int rc;
fe7c58007   Samuel Ortiz   NFC: Add target m...
185
186
187
  	pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x
  ",
  		 dev_name(&dev->dev), im_protocols, tm_protocols);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
188

fe7c58007   Samuel Ortiz   NFC: Add target m...
189
  	if (!im_protocols && !tm_protocols)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
190
191
192
193
194
195
196
197
  		return -EINVAL;
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
7757dc8a3   Samuel Ortiz   NFC: Prevent poll...
198
199
200
201
  	if (!dev->dev_up) {
  		rc = -ENODEV;
  		goto error;
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
202
203
204
205
  	if (dev->polling) {
  		rc = -EBUSY;
  		goto error;
  	}
fe7c58007   Samuel Ortiz   NFC: Add target m...
206
  	rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
207
  	if (!rc) {
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
208
  		dev->polling = true;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
209
210
  		dev->rf_mode = NFC_RF_NONE;
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  /**
   * nfc_stop_poll - stop polling for nfc targets
   *
   * @dev: The nfc device that must stop polling
   */
  int nfc_stop_poll(struct nfc_dev *dev)
  {
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
225
226
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (!dev->polling) {
  		rc = -EINVAL;
  		goto error;
  	}
  
  	dev->ops->stop_poll(dev);
  	dev->polling = false;
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
242
  	dev->rf_mode = NFC_RF_NONE;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
243
244
245
246
247
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
900994332   Eric Lapuyade   NFC: Cache the co...
248
249
250
  static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
  {
  	int i;
0f4507722   Szymon Janc   NFC: Fix some cod...
251
  	for (i = 0; i < dev->n_targets; i++) {
900994332   Eric Lapuyade   NFC: Cache the co...
252
253
254
255
256
257
  		if (dev->targets[i].idx == target_idx)
  			return &dev->targets[i];
  	}
  
  	return NULL;
  }
47807d3db   Samuel Ortiz   NFC: Remove the r...
258
  int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
259
260
  {
  	int rc = 0;
47807d3db   Samuel Ortiz   NFC: Remove the r...
261
262
  	u8 *gb;
  	size_t gb_len;
900994332   Eric Lapuyade   NFC: Cache the co...
263
  	struct nfc_target *target;
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
264

47807d3db   Samuel Ortiz   NFC: Remove the r...
265
266
  	pr_debug("dev_name=%s comm %d
  ", dev_name(&dev->dev), comm_mode);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  
  	if (!dev->ops->dep_link_up)
  		return -EOPNOTSUPP;
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (dev->dep_link_up == true) {
  		rc = -EALREADY;
  		goto error;
  	}
47807d3db   Samuel Ortiz   NFC: Remove the r...
282
283
284
285
286
  	gb = nfc_llcp_general_bytes(dev, &gb_len);
  	if (gb_len > NFC_MAX_GT_LEN) {
  		rc = -EINVAL;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
287
288
289
290
291
292
293
  	target = nfc_find_target(dev, target_index);
  	if (target == NULL) {
  		rc = -ENOTCONN;
  		goto error;
  	}
  
  	rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
294
  	if (!rc) {
900994332   Eric Lapuyade   NFC: Cache the co...
295
  		dev->active_target = target;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
296
297
  		dev->rf_mode = NFC_RF_INITIATOR;
  	}
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  int nfc_dep_link_down(struct nfc_dev *dev)
  {
  	int rc = 0;
  
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
  
  	if (!dev->ops->dep_link_down)
  		return -EOPNOTSUPP;
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (dev->dep_link_up == false) {
  		rc = -EALREADY;
  		goto error;
  	}
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
325
326
327
  	rc = dev->ops->dep_link_down(dev);
  	if (!rc) {
  		dev->dep_link_up = false;
900994332   Eric Lapuyade   NFC: Cache the co...
328
  		dev->active_target = NULL;
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
329
  		dev->rf_mode = NFC_RF_NONE;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
330
  		nfc_llcp_mac_is_down(dev);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
331
332
333
334
335
  		nfc_genl_dep_link_down_event(dev);
  	}
  
  error:
  	device_unlock(&dev->dev);
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
336

1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
337
338
339
340
  	return rc;
  }
  
  int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
0a40acb24   Samuel Ortiz   NFC: Core code id...
341
  		       u8 comm_mode, u8 rf_mode)
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
342
343
  {
  	dev->dep_link_up = true;
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
344

d31652a26   Arron Wang   NFC: Fix target m...
345
  	if (!dev->active_target && rf_mode == NFC_RF_INITIATOR) {
e29a9e2ae   Samuel Ortiz   NFC: Set active t...
346
347
348
349
350
351
352
353
354
355
356
  		struct nfc_target *target;
  
  		target = nfc_find_target(dev, target_idx);
  		if (target == NULL)
  			return -ENOTCONN;
  
  		dev->active_target = target;
  	}
  
  	dev->polling = false;
  	dev->rf_mode = rf_mode;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
357
  	nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
358
359
360
  	return nfc_genl_dep_link_up_event(dev, target_idx, comm_mode, rf_mode);
  }
  EXPORT_SYMBOL(nfc_dep_link_is_up);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
361
362
363
364
365
366
367
368
369
370
  /**
   * nfc_activate_target - prepare the target for data exchange
   *
   * @dev: The nfc device that found the target
   * @target_idx: index of the target that must be activated
   * @protocol: nfc protocol that will be used for data exchange
   */
  int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
  {
  	int rc;
900994332   Eric Lapuyade   NFC: Cache the co...
371
  	struct nfc_target *target;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
372

20c239c13   Joe Perches   nfc: Convert nfc_...
373
374
375
  	pr_debug("dev_name=%s target_idx=%u protocol=%u
  ",
  		 dev_name(&dev->dev), target_idx, protocol);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
376
377
378
379
380
381
382
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
383
384
385
386
387
388
389
390
391
392
393
394
  	if (dev->active_target) {
  		rc = -EBUSY;
  		goto error;
  	}
  
  	target = nfc_find_target(dev, target_idx);
  	if (target == NULL) {
  		rc = -ENOTCONN;
  		goto error;
  	}
  
  	rc = dev->ops->activate_target(dev, target, protocol);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
395
  	if (!rc) {
900994332   Eric Lapuyade   NFC: Cache the co...
396
  		dev->active_target = target;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
397
  		dev->rf_mode = NFC_RF_INITIATOR;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
398

f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
399
  		if (dev->ops->check_presence && !dev->shutting_down)
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
400
401
402
  			mod_timer(&dev->check_pres_timer, jiffies +
  				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
403
404
405
406
407
408
409
410
411
412
413
414
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  /**
   * nfc_deactivate_target - deactivate a nfc target
   *
   * @dev: The nfc device that found the target
   * @target_idx: index of the target that must be deactivated
   */
96d4581f0   Christophe Ricard   NFC: netlink: Add...
415
  int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx, u8 mode)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
416
417
  {
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
418
419
420
  	pr_debug("dev_name=%s target_idx=%u
  ",
  		 dev_name(&dev->dev), target_idx);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
421
422
423
424
425
426
427
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
428
429
430
431
432
433
434
435
436
  	if (dev->active_target == NULL) {
  		rc = -ENOTCONN;
  		goto error;
  	}
  
  	if (dev->active_target->idx != target_idx) {
  		rc = -ENOTCONN;
  		goto error;
  	}
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
437
438
  	if (dev->ops->check_presence)
  		del_timer_sync(&dev->check_pres_timer);
96d4581f0   Christophe Ricard   NFC: netlink: Add...
439
  	dev->ops->deactivate_target(dev, dev->active_target, mode);
900994332   Eric Lapuyade   NFC: Cache the co...
440
  	dev->active_target = NULL;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  /**
   * nfc_data_exchange - transceive data
   *
   * @dev: The nfc device that found the target
   * @target_idx: index of the target
   * @skb: data to be sent
   * @cb: callback called when the response is received
   * @cb_context: parameter for the callback function
   *
   * The user must wait for the callback before calling this function again.
   */
0a40acb24   Samuel Ortiz   NFC: Core code id...
458
459
  int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
  		      data_exchange_cb_t cb, void *cb_context)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
460
461
  {
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
462
463
464
  	pr_debug("dev_name=%s target_idx=%u skb->len=%u
  ",
  		 dev_name(&dev->dev), target_idx, skb->len);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
465
466
467
468
469
470
471
472
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		kfree_skb(skb);
  		goto error;
  	}
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
473
474
475
476
477
478
  	if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
  		if (dev->active_target->idx != target_idx) {
  			rc = -EADDRNOTAVAIL;
  			kfree_skb(skb);
  			goto error;
  		}
144612cac   Eric Lapuyade   NFC: Changed targ...
479

be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
480
481
482
483
484
  		if (dev->ops->check_presence)
  			del_timer_sync(&dev->check_pres_timer);
  
  		rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
  					     cb_context);
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
485
  		if (!rc && dev->ops->check_presence && !dev->shutting_down)
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
486
487
488
489
490
491
  			mod_timer(&dev->check_pres_timer, jiffies +
  				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
  	} else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
  		rc = dev->ops->tm_send(dev, skb);
  	} else {
  		rc = -ENOTCONN;
144612cac   Eric Lapuyade   NFC: Changed targ...
492
493
494
  		kfree_skb(skb);
  		goto error;
  	}
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
495

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
496
497
498
499
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
d8eb18eec   Arron Wang   NFC: Export nfc_f...
500
  struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx)
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
501
  {
156cef80f   Axel Lin   NFC: Use list_for...
502
  	struct nfc_se *se;
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
503

156cef80f   Axel Lin   NFC: Use list_for...
504
  	list_for_each_entry(se, &dev->secure_elements, list)
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
505
506
507
508
509
  		if (se->idx == se_idx)
  			return se;
  
  	return NULL;
  }
d8eb18eec   Arron Wang   NFC: Export nfc_f...
510
  EXPORT_SYMBOL(nfc_find_se);
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
511
512
513
  
  int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
  {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
  	struct nfc_se *se;
  	int rc;
  
  	pr_debug("%s se index %d
  ", dev_name(&dev->dev), se_idx);
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (!dev->dev_up) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (dev->polling) {
  		rc = -EBUSY;
  		goto error;
  	}
  
  	if (!dev->ops->enable_se || !dev->ops->disable_se) {
  		rc = -EOPNOTSUPP;
  		goto error;
  	}
d8eb18eec   Arron Wang   NFC: Export nfc_f...
541
  	se = nfc_find_se(dev, se_idx);
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
542
543
544
545
  	if (!se) {
  		rc = -EINVAL;
  		goto error;
  	}
2c3832834   Arron Wang   NFC: Fix secure e...
546
  	if (se->state == NFC_SE_ENABLED) {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
547
548
549
550
551
  		rc = -EALREADY;
  		goto error;
  	}
  
  	rc = dev->ops->enable_se(dev, se_idx);
39525ee1d   Arron Wang   NFC: Update secur...
552
553
  	if (rc >= 0)
  		se->state = NFC_SE_ENABLED;
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
554
555
556
557
558
559
560
561
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
  
  int nfc_disable_se(struct nfc_dev *dev, u32 se_idx)
  {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  	struct nfc_se *se;
  	int rc;
  
  	pr_debug("%s se index %d
  ", dev_name(&dev->dev), se_idx);
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (!dev->dev_up) {
  		rc = -ENODEV;
  		goto error;
  	}
  
  	if (!dev->ops->enable_se || !dev->ops->disable_se) {
  		rc = -EOPNOTSUPP;
  		goto error;
  	}
d8eb18eec   Arron Wang   NFC: Export nfc_f...
584
  	se = nfc_find_se(dev, se_idx);
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
585
586
587
588
  	if (!se) {
  		rc = -EINVAL;
  		goto error;
  	}
2c3832834   Arron Wang   NFC: Fix secure e...
589
  	if (se->state == NFC_SE_DISABLED) {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
590
591
592
593
594
  		rc = -EALREADY;
  		goto error;
  	}
  
  	rc = dev->ops->disable_se(dev, se_idx);
39525ee1d   Arron Wang   NFC: Update secur...
595
596
  	if (rc >= 0)
  		se->state = NFC_SE_DISABLED;
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
597
598
599
600
601
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
541d920b0   Samuel Ortiz   NFC: Set and get ...
602
603
  int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
  {
0a40acb24   Samuel Ortiz   NFC: Core code id...
604
605
  	pr_debug("dev_name=%s gb_len=%d
  ", dev_name(&dev->dev), gb_len);
541d920b0   Samuel Ortiz   NFC: Set and get ...
606

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
607
  	return nfc_llcp_set_remote_gb(dev, gb, gb_len);
541d920b0   Samuel Ortiz   NFC: Set and get ...
608
609
  }
  EXPORT_SYMBOL(nfc_set_remote_general_bytes);
ab73b7513   Samuel Ortiz   NFC: Export LLCP ...
610
611
612
613
614
615
616
617
  u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
  {
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
  
  	return nfc_llcp_general_bytes(dev, gb_len);
  }
  EXPORT_SYMBOL(nfc_get_local_general_bytes);
73167ced3   Samuel Ortiz   NFC: Introduce ta...
618
619
620
621
622
623
624
625
626
627
628
  int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
  {
  	/* Only LLCP target mode for now */
  	if (dev->dep_link_up == false) {
  		kfree_skb(skb);
  		return -ENOLINK;
  	}
  
  	return nfc_llcp_data_received(dev, skb);
  }
  EXPORT_SYMBOL(nfc_tm_data_received);
fc40a8c1a   Samuel Ortiz   NFC: Add target m...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
  		     u8 *gb, size_t gb_len)
  {
  	int rc;
  
  	device_lock(&dev->dev);
  
  	dev->polling = false;
  
  	if (gb != NULL) {
  		rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
  		if (rc < 0)
  			goto out;
  	}
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
643
  	dev->rf_mode = NFC_RF_TARGET;
fc40a8c1a   Samuel Ortiz   NFC: Add target m...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
  	if (protocol == NFC_PROTO_NFC_DEP_MASK)
  		nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
  
  	rc = nfc_genl_tm_activated(dev, protocol);
  
  out:
  	device_unlock(&dev->dev);
  
  	return rc;
  }
  EXPORT_SYMBOL(nfc_tm_activated);
  
  int nfc_tm_deactivated(struct nfc_dev *dev)
  {
  	dev->dep_link_up = false;
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
659
  	dev->rf_mode = NFC_RF_NONE;
fc40a8c1a   Samuel Ortiz   NFC: Add target m...
660
661
662
663
  
  	return nfc_genl_tm_deactivated(dev);
  }
  EXPORT_SYMBOL(nfc_tm_deactivated);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
664
  /**
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
665
   * nfc_alloc_send_skb - allocate a skb for data exchange responses
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
666
667
668
669
   *
   * @size: size to allocate
   * @gfp: gfp flags
   */
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
670
  struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
0a40acb24   Samuel Ortiz   NFC: Core code id...
671
672
  				   unsigned int flags, unsigned int size,
  				   unsigned int *err)
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
  {
  	struct sk_buff *skb;
  	unsigned int total_size;
  
  	total_size = size +
  		dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
  
  	skb = sock_alloc_send_skb(sk, total_size, flags & MSG_DONTWAIT, err);
  	if (skb)
  		skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
  
  	return skb;
  }
  
  /**
   * nfc_alloc_recv_skb - allocate a skb for data exchange responses
   *
   * @size: size to allocate
   * @gfp: gfp flags
   */
  struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
694
695
696
697
698
699
700
701
702
703
704
705
  {
  	struct sk_buff *skb;
  	unsigned int total_size;
  
  	total_size = size + 1;
  	skb = alloc_skb(total_size, gfp);
  
  	if (skb)
  		skb_reserve(skb, 1);
  
  	return skb;
  }
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
706
  EXPORT_SYMBOL(nfc_alloc_recv_skb);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
707

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
708
709
710
711
712
713
714
715
716
717
  /**
   * nfc_targets_found - inform that targets were found
   *
   * @dev: The nfc device that found the targets
   * @targets: array of nfc targets found
   * @ntargets: targets array size
   *
   * The device driver must call this function when one or many nfc targets
   * are found. After calling this function, the device driver must stop
   * polling for targets.
d94f9c55f   Eric Lapuyade   NFC: nfc_targets_...
718
719
   * NOTE: This function can be called with targets=NULL and n_targets=0 to
   * notify a driver error, meaning that the polling operation cannot complete.
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
720
721
722
   * IMPORTANT: this function must not be called from an atomic context.
   * In addition, it must also not be called from a context that would prevent
   * the NFC Core to call other nfc ops entry point concurrently.
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
723
   */
0a40acb24   Samuel Ortiz   NFC: Core code id...
724
725
  int nfc_targets_found(struct nfc_dev *dev,
  		      struct nfc_target *targets, int n_targets)
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
726
  {
c4fbb6515   Samuel Ortiz   NFC: The core par...
727
  	int i;
20c239c13   Joe Perches   nfc: Convert nfc_...
728
729
  	pr_debug("dev_name=%s n_targets=%d
  ", dev_name(&dev->dev), n_targets);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
730

c4fbb6515   Samuel Ortiz   NFC: The core par...
731
  	for (i = 0; i < n_targets; i++)
01ae0eea9   Eric Lapuyade   NFC: Fix next tar...
732
  		targets[i].idx = dev->target_next_idx++;
c4fbb6515   Samuel Ortiz   NFC: The core par...
733

d4ccb1328   Eric Lapuyade   NFC: Specify usag...
734
  	device_lock(&dev->dev);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
735

8668fdd6e   Eric Lapuyade   NFC: Core must te...
736
737
738
739
740
741
  	if (dev->polling == false) {
  		device_unlock(&dev->dev);
  		return 0;
  	}
  
  	dev->polling = false;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
742
743
744
  	dev->targets_generation++;
  
  	kfree(dev->targets);
d94f9c55f   Eric Lapuyade   NFC: nfc_targets_...
745
  	dev->targets = NULL;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
746

d94f9c55f   Eric Lapuyade   NFC: nfc_targets_...
747
748
749
750
751
752
753
754
755
756
  	if (targets) {
  		dev->targets = kmemdup(targets,
  				       n_targets * sizeof(struct nfc_target),
  				       GFP_ATOMIC);
  
  		if (!dev->targets) {
  			dev->n_targets = 0;
  			device_unlock(&dev->dev);
  			return -ENOMEM;
  		}
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
757
758
759
  	}
  
  	dev->n_targets = n_targets;
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
760
  	device_unlock(&dev->dev);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
761
762
763
764
765
766
  
  	nfc_genl_targets_found(dev);
  
  	return 0;
  }
  EXPORT_SYMBOL(nfc_targets_found);
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
767
768
769
770
771
772
773
774
775
776
777
778
  /**
   * nfc_target_lost - inform that an activated target went out of field
   *
   * @dev: The nfc device that had the activated target in field
   * @target_idx: the nfc index of the target
   *
   * The device driver must call this function when the activated target
   * goes out of the field.
   * IMPORTANT: this function must not be called from an atomic context.
   * In addition, it must also not be called from a context that would prevent
   * the NFC Core to call other nfc ops entry point concurrently.
   */
e1da0efa2   Eric Lapuyade   NFC: Export targe...
779
780
781
782
783
784
785
  int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
  {
  	struct nfc_target *tg;
  	int i;
  
  	pr_debug("dev_name %s n_target %d
  ", dev_name(&dev->dev), target_idx);
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
786
  	device_lock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
787
788
789
790
791
792
793
794
  
  	for (i = 0; i < dev->n_targets; i++) {
  		tg = &dev->targets[i];
  		if (tg->idx == target_idx)
  			break;
  	}
  
  	if (i == dev->n_targets) {
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
795
  		device_unlock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
796
797
798
799
800
  		return -EINVAL;
  	}
  
  	dev->targets_generation++;
  	dev->n_targets--;
900994332   Eric Lapuyade   NFC: Cache the co...
801
  	dev->active_target = NULL;
e1da0efa2   Eric Lapuyade   NFC: Export targe...
802
803
804
805
806
807
808
809
  
  	if (dev->n_targets) {
  		memcpy(&dev->targets[i], &dev->targets[i + 1],
  		       (dev->n_targets - i) * sizeof(struct nfc_target));
  	} else {
  		kfree(dev->targets);
  		dev->targets = NULL;
  	}
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
810
  	device_unlock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
811
812
813
814
815
816
  
  	nfc_genl_target_lost(dev, target_idx);
  
  	return 0;
  }
  EXPORT_SYMBOL(nfc_target_lost);
9eb334ac1   Eric Lapuyade   NFC: nfc_driver_f...
817
  inline void nfc_driver_failure(struct nfc_dev *dev, int err)
456411ca8   Eric Lapuyade   NFC: Driver failu...
818
  {
9eb334ac1   Eric Lapuyade   NFC: nfc_driver_f...
819
  	nfc_targets_found(dev, NULL, 0);
456411ca8   Eric Lapuyade   NFC: Driver failu...
820
821
  }
  EXPORT_SYMBOL(nfc_driver_failure);
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
822
823
  int nfc_add_se(struct nfc_dev *dev, u32 se_idx, u16 type)
  {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
824
  	struct nfc_se *se;
2757c3723   Samuel Ortiz   NFC: Send netlink...
825
  	int rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
826
827
828
  
  	pr_debug("%s se index %d
  ", dev_name(&dev->dev), se_idx);
d8eb18eec   Arron Wang   NFC: Export nfc_f...
829
  	se = nfc_find_se(dev, se_idx);
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
830
831
  	if (se)
  		return -EALREADY;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
832
833
834
835
836
837
838
839
840
841
842
  
  	se = kzalloc(sizeof(struct nfc_se), GFP_KERNEL);
  	if (!se)
  		return -ENOMEM;
  
  	se->idx = se_idx;
  	se->type = type;
  	se->state = NFC_SE_DISABLED;
  	INIT_LIST_HEAD(&se->list);
  
  	list_add(&se->list, &dev->secure_elements);
2757c3723   Samuel Ortiz   NFC: Send netlink...
843
844
845
846
847
848
849
  	rc = nfc_genl_se_added(dev, se_idx, type);
  	if (rc < 0) {
  		list_del(&se->list);
  		kfree(se);
  
  		return rc;
  	}
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
850
851
852
853
854
855
856
  	return 0;
  }
  EXPORT_SYMBOL(nfc_add_se);
  
  int nfc_remove_se(struct nfc_dev *dev, u32 se_idx)
  {
  	struct nfc_se *se, *n;
2757c3723   Samuel Ortiz   NFC: Send netlink...
857
  	int rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
858
859
860
861
862
863
  
  	pr_debug("%s se index %d
  ", dev_name(&dev->dev), se_idx);
  
  	list_for_each_entry_safe(se, n, &dev->secure_elements, list)
  		if (se->idx == se_idx) {
2757c3723   Samuel Ortiz   NFC: Send netlink...
864
865
866
  			rc = nfc_genl_se_removed(dev, se_idx);
  			if (rc < 0)
  				return rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
867
868
869
870
871
872
873
874
875
  			list_del(&se->list);
  			kfree(se);
  
  			return 0;
  		}
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL(nfc_remove_se);
447b27c4f   Christophe Ricard   NFC: Forward NFC_...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  int nfc_se_transaction(struct nfc_dev *dev, u8 se_idx,
  		       struct nfc_evt_transaction *evt_transaction)
  {
  	int rc;
  
  	pr_debug("transaction: %x
  ", se_idx);
  
  	device_lock(&dev->dev);
  
  	if (!evt_transaction) {
  		rc = -EPROTO;
  		goto out;
  	}
  
  	rc = nfc_genl_se_transaction(dev, se_idx, evt_transaction);
  out:
  	device_unlock(&dev->dev);
  	return rc;
  }
  EXPORT_SYMBOL(nfc_se_transaction);
9afec6d38   Christophe Ricard   nfc: netlink: HCI...
897
898
899
900
901
902
903
904
905
906
907
908
909
  int nfc_se_connectivity(struct nfc_dev *dev, u8 se_idx)
  {
  	int rc;
  
  	pr_debug("connectivity: %x
  ", se_idx);
  
  	device_lock(&dev->dev);
  	rc = nfc_genl_se_connectivity(dev, se_idx);
  	device_unlock(&dev->dev);
  	return rc;
  }
  EXPORT_SYMBOL(nfc_se_connectivity);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
910
911
912
  static void nfc_release(struct device *d)
  {
  	struct nfc_dev *dev = to_nfc_dev(d);
ee656e9d0   Samuel Ortiz   NFC: Remove and f...
913
  	struct nfc_se *se, *n;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
914

20c239c13   Joe Perches   nfc: Convert nfc_...
915
916
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
917

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
918
919
  	nfc_genl_data_exit(&dev->genl_data);
  	kfree(dev->targets);
ee656e9d0   Samuel Ortiz   NFC: Remove and f...
920
921
922
923
924
925
  
  	list_for_each_entry_safe(se, n, &dev->secure_elements, list) {
  			nfc_genl_se_removed(dev, se->idx);
  			list_del(&se->list);
  			kfree(se);
  	}
20777bc57   Johan Hovold   NFC: fix broken d...
926
  	ida_simple_remove(&nfc_index_ida, dev->idx);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
927
928
  	kfree(dev);
  }
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
929
930
931
932
933
934
935
  static void nfc_check_pres_work(struct work_struct *work)
  {
  	struct nfc_dev *dev = container_of(work, struct nfc_dev,
  					   check_pres_work);
  	int rc;
  
  	device_lock(&dev->dev);
900994332   Eric Lapuyade   NFC: Cache the co...
936
937
  	if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
  		rc = dev->ops->check_presence(dev, dev->active_target);
632c016ab   Eric Lapuyade   NFC: HCI check pr...
938
939
  		if (rc == -EOPNOTSUPP)
  			goto exit;
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
940
  		if (rc) {
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
941
942
943
944
  			u32 active_target_idx = dev->active_target->idx;
  			device_unlock(&dev->dev);
  			nfc_target_lost(dev, active_target_idx);
  			return;
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
945
  		}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
946
947
948
949
  
  		if (!dev->shutting_down)
  			mod_timer(&dev->check_pres_timer, jiffies +
  				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
950
  	}
632c016ab   Eric Lapuyade   NFC: HCI check pr...
951
  exit:
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
952
953
  	device_unlock(&dev->dev);
  }
4b519bb49   Allen Pais   NFC: Convert time...
954
  static void nfc_check_pres_timeout(struct timer_list *t)
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
955
  {
4b519bb49   Allen Pais   NFC: Convert time...
956
  	struct nfc_dev *dev = from_timer(dev, t, check_pres_timer);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
957

916082b07   Linus Torvalds   workqueue: avoid ...
958
  	schedule_work(&dev->check_pres_work);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
959
  }
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
960
961
962
963
964
  struct class nfc_class = {
  	.name = "nfc",
  	.dev_release = nfc_release,
  };
  EXPORT_SYMBOL(nfc_class);
9f3b795a6   Michał Mirosław   driver-core: cons...
965
  static int match_idx(struct device *d, const void *data)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
966
967
  {
  	struct nfc_dev *dev = to_nfc_dev(d);
9f3b795a6   Michał Mirosław   driver-core: cons...
968
  	const unsigned int *idx = data;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
969
970
971
  
  	return dev->idx == *idx;
  }
95c961747   Eric Dumazet   net: cleanup unsi...
972
  struct nfc_dev *nfc_get_device(unsigned int idx)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  {
  	struct device *d;
  
  	d = class_find_device(&nfc_class, NULL, &idx, match_idx);
  	if (!d)
  		return NULL;
  
  	return to_nfc_dev(d);
  }
  
  /**
   * nfc_allocate_device - allocate a new nfc device
   *
   * @ops: device operations
   * @supported_protocols: NFC protocols supported by the device
   */
  struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
0a40acb24   Samuel Ortiz   NFC: Core code id...
990
991
  				    u32 supported_protocols,
  				    int tx_headroom, int tx_tailroom)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
992
  {
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
993
  	struct nfc_dev *dev;
20777bc57   Johan Hovold   NFC: fix broken d...
994
  	int rc;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
995
996
  
  	if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
997
  	    !ops->deactivate_target || !ops->im_transceive)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
998
999
1000
1001
1002
1003
1004
1005
  		return NULL;
  
  	if (!supported_protocols)
  		return NULL;
  
  	dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL);
  	if (!dev)
  		return NULL;
20777bc57   Johan Hovold   NFC: fix broken d...
1006
1007
1008
1009
1010
1011
1012
1013
  	rc = ida_simple_get(&nfc_index_ida, 0, 0, GFP_KERNEL);
  	if (rc < 0)
  		goto err_free_dev;
  	dev->idx = rc;
  
  	dev->dev.class = &nfc_class;
  	dev_set_name(&dev->dev, "nfc%d", dev->idx);
  	device_initialize(&dev->dev);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1014
1015
  	dev->ops = ops;
  	dev->supported_protocols = supported_protocols;
e8753043f   Samuel Ortiz   NFC: Reserve tx h...
1016
1017
  	dev->tx_headroom = tx_headroom;
  	dev->tx_tailroom = tx_tailroom;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
1018
  	INIT_LIST_HEAD(&dev->secure_elements);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1019

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1020
  	nfc_genl_data_init(&dev->genl_data);
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
1021
  	dev->rf_mode = NFC_RF_NONE;
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
1022

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1023
1024
  	/* first generation must not be 0 */
  	dev->targets_generation = 1;
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1025
  	if (ops->check_presence) {
4b519bb49   Allen Pais   NFC: Convert time...
1026
  		timer_setup(&dev->check_pres_timer, nfc_check_pres_timeout, 0);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1027
  		INIT_WORK(&dev->check_pres_work, nfc_check_pres_work);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1028
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1029
  	return dev;
20777bc57   Johan Hovold   NFC: fix broken d...
1030
1031
1032
  
  err_free_dev:
  	kfree(dev);
c45e3e4c5   Johan Hovold   NFC: fix device-a...
1033
  	return NULL;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  }
  EXPORT_SYMBOL(nfc_allocate_device);
  
  /**
   * nfc_register_device - register a nfc device in the nfc subsystem
   *
   * @dev: The nfc device to register
   */
  int nfc_register_device(struct nfc_dev *dev)
  {
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
1045
1046
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1047
1048
1049
1050
1051
  
  	mutex_lock(&nfc_devlist_mutex);
  	nfc_devlist_generation++;
  	rc = device_add(&dev->dev);
  	mutex_unlock(&nfc_devlist_mutex);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1052
1053
  	if (rc < 0)
  		return rc;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1054
1055
1056
1057
  	rc = nfc_llcp_register_device(dev);
  	if (rc)
  		pr_err("Could not register llcp device
  ");
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1058
1059
  	rc = nfc_genl_device_added(dev);
  	if (rc)
20c239c13   Joe Perches   nfc: Convert nfc_...
1060
1061
1062
  		pr_debug("The userspace won't be notified that the device %s was added
  ",
  			 dev_name(&dev->dev));
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1063

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1064
1065
1066
1067
1068
1069
1070
1071
  	dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
  				   RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
  	if (dev->rfkill) {
  		if (rfkill_register(dev->rfkill) < 0) {
  			rfkill_destroy(dev->rfkill);
  			dev->rfkill = NULL;
  		}
  	}
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1072
  	return 0;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
  }
  EXPORT_SYMBOL(nfc_register_device);
  
  /**
   * nfc_unregister_device - unregister a nfc device in the nfc subsystem
   *
   * @dev: The nfc device to unregister
   */
  void nfc_unregister_device(struct nfc_dev *dev)
  {
20777bc57   Johan Hovold   NFC: fix broken d...
1083
  	int rc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1084

20c239c13   Joe Perches   nfc: Convert nfc_...
1085
1086
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1087

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1088
1089
1090
1091
  	if (dev->rfkill) {
  		rfkill_unregister(dev->rfkill);
  		rfkill_destroy(dev->rfkill);
  	}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1092
1093
1094
1095
1096
1097
1098
  	if (dev->ops->check_presence) {
  		device_lock(&dev->dev);
  		dev->shutting_down = true;
  		device_unlock(&dev->dev);
  		del_timer_sync(&dev->check_pres_timer);
  		cancel_work_sync(&dev->check_pres_work);
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1099

f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1100
1101
1102
1103
1104
  	rc = nfc_genl_device_removed(dev);
  	if (rc)
  		pr_debug("The userspace won't be notified that the device %s "
  			 "was removed
  ", dev_name(&dev->dev));
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1105

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1106
  	nfc_llcp_unregister_device(dev);
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1107
1108
1109
1110
  	mutex_lock(&nfc_devlist_mutex);
  	nfc_devlist_generation++;
  	device_del(&dev->dev);
  	mutex_unlock(&nfc_devlist_mutex);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1111
1112
1113
1114
1115
  }
  EXPORT_SYMBOL(nfc_unregister_device);
  
  static int __init nfc_init(void)
  {
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1116
  	int rc;
ed1e0ad88   Joe Perches   nfc: Use standard...
1117
1118
  	pr_info("NFC Core ver %s
  ", VERSION);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1119

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
  	rc = class_register(&nfc_class);
  	if (rc)
  		return rc;
  
  	rc = nfc_genl_init();
  	if (rc)
  		goto err_genl;
  
  	/* the first generation must not be 0 */
  	nfc_devlist_generation = 1;
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1130
1131
1132
  	rc = rawsock_init();
  	if (rc)
  		goto err_rawsock;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1133
1134
1135
  	rc = nfc_llcp_init();
  	if (rc)
  		goto err_llcp_sock;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1136
1137
1138
  	rc = af_nfc_init();
  	if (rc)
  		goto err_af_nfc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1139
  	return 0;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1140
  err_af_nfc:
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1141
1142
  	nfc_llcp_exit();
  err_llcp_sock:
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1143
1144
  	rawsock_exit();
  err_rawsock:
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1145
  	nfc_genl_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1146
1147
1148
  err_genl:
  	class_unregister(&nfc_class);
  	return rc;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1149
1150
1151
1152
  }
  
  static void __exit nfc_exit(void)
  {
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1153
  	af_nfc_exit();
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1154
  	nfc_llcp_exit();
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1155
  	rawsock_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1156
  	nfc_genl_exit();
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  	class_unregister(&nfc_class);
  }
  
  subsys_initcall(nfc_init);
  module_exit(nfc_exit);
  
  MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
  MODULE_DESCRIPTION("NFC Core ver " VERSION);
  MODULE_VERSION(VERSION);
  MODULE_LICENSE("GPL");
1155bb617   Samuel Ortiz   NFC: Add modules ...
1167
  MODULE_ALIAS_NETPROTO(PF_NFC);
5df16cad4   Samuel Ortiz   NFC: Add netlink ...
1168
  MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME);