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
   *
   * @size: size to allocate
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
668
   */
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
669
  struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
0a40acb24   Samuel Ortiz   NFC: Core code id...
670
671
  				   unsigned int flags, unsigned int size,
  				   unsigned int *err)
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
  {
  	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...
693
694
695
696
697
698
699
700
701
702
703
704
  {
  	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...
705
  EXPORT_SYMBOL(nfc_alloc_recv_skb);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
706

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
707
708
709
710
711
  /**
   * nfc_targets_found - inform that targets were found
   *
   * @dev: The nfc device that found the targets
   * @targets: array of nfc targets found
ffbab1c93   Andrew Lunn   net: nfc: kerneld...
712
   * @n_targets: targets array size
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
713
714
715
716
   *
   * 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_...
717
718
   * 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...
719
720
721
   * 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...
722
   */
0a40acb24   Samuel Ortiz   NFC: Core code id...
723
724
  int nfc_targets_found(struct nfc_dev *dev,
  		      struct nfc_target *targets, int n_targets)
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
725
  {
c4fbb6515   Samuel Ortiz   NFC: The core par...
726
  	int i;
20c239c13   Joe Perches   nfc: Convert nfc_...
727
728
  	pr_debug("dev_name=%s n_targets=%d
  ", dev_name(&dev->dev), n_targets);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
729

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

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

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

d94f9c55f   Eric Lapuyade   NFC: nfc_targets_...
746
747
748
749
750
751
752
753
754
755
  	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...
756
757
758
  	}
  
  	dev->n_targets = n_targets;
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
759
  	device_unlock(&dev->dev);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
760
761
762
763
764
765
  
  	nfc_genl_targets_found(dev);
  
  	return 0;
  }
  EXPORT_SYMBOL(nfc_targets_found);
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
766
767
768
769
770
771
772
773
774
775
776
777
  /**
   * 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...
778
779
780
781
782
783
784
  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...
785
  	device_lock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
786
787
788
789
790
791
792
793
  
  	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...
794
  		device_unlock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
795
796
797
798
799
  		return -EINVAL;
  	}
  
  	dev->targets_generation++;
  	dev->n_targets--;
900994332   Eric Lapuyade   NFC: Cache the co...
800
  	dev->active_target = NULL;
e1da0efa2   Eric Lapuyade   NFC: Export targe...
801
802
803
804
805
806
807
808
  
  	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...
809
  	device_unlock(&dev->dev);
e1da0efa2   Eric Lapuyade   NFC: Export targe...
810
811
812
813
814
815
  
  	nfc_genl_target_lost(dev, target_idx);
  
  	return 0;
  }
  EXPORT_SYMBOL(nfc_target_lost);
9eb334ac1   Eric Lapuyade   NFC: nfc_driver_f...
816
  inline void nfc_driver_failure(struct nfc_dev *dev, int err)
456411ca8   Eric Lapuyade   NFC: Driver failu...
817
  {
9eb334ac1   Eric Lapuyade   NFC: nfc_driver_f...
818
  	nfc_targets_found(dev, NULL, 0);
456411ca8   Eric Lapuyade   NFC: Driver failu...
819
820
  }
  EXPORT_SYMBOL(nfc_driver_failure);
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
821
822
  int nfc_add_se(struct nfc_dev *dev, u32 se_idx, u16 type)
  {
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
823
  	struct nfc_se *se;
2757c3723   Samuel Ortiz   NFC: Send netlink...
824
  	int rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
825
826
827
  
  	pr_debug("%s se index %d
  ", dev_name(&dev->dev), se_idx);
d8eb18eec   Arron Wang   NFC: Export nfc_f...
828
  	se = nfc_find_se(dev, se_idx);
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
829
830
  	if (se)
  		return -EALREADY;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
831
832
833
834
835
836
837
838
839
840
841
  
  	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...
842
843
844
845
846
847
848
  	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...
849
850
851
852
853
854
855
  	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...
856
  	int rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
857
858
859
860
861
862
  
  	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...
863
864
865
  			rc = nfc_genl_se_removed(dev, se_idx);
  			if (rc < 0)
  				return rc;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
866
867
868
869
870
871
872
873
874
  			list_del(&se->list);
  			kfree(se);
  
  			return 0;
  		}
  
  	return -EINVAL;
  }
  EXPORT_SYMBOL(nfc_remove_se);
447b27c4f   Christophe Ricard   NFC: Forward NFC_...
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
  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...
896
897
898
899
900
901
902
903
904
905
906
907
908
  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...
909
910
911
  static void nfc_release(struct device *d)
  {
  	struct nfc_dev *dev = to_nfc_dev(d);
ee656e9d0   Samuel Ortiz   NFC: Remove and f...
912
  	struct nfc_se *se, *n;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
913

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

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
917
918
  	nfc_genl_data_exit(&dev->genl_data);
  	kfree(dev->targets);
ee656e9d0   Samuel Ortiz   NFC: Remove and f...
919
920
921
922
923
924
  
  	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...
925
  	ida_simple_remove(&nfc_index_ida, dev->idx);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
926
927
  	kfree(dev);
  }
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
928
929
930
931
932
933
934
  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...
935
936
  	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...
937
938
  		if (rc == -EOPNOTSUPP)
  			goto exit;
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
939
  		if (rc) {
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
940
941
942
943
  			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...
944
  		}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
945
946
947
948
  
  		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...
949
  	}
632c016ab   Eric Lapuyade   NFC: HCI check pr...
950
  exit:
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
951
952
  	device_unlock(&dev->dev);
  }
4b519bb49   Allen Pais   NFC: Convert time...
953
  static void nfc_check_pres_timeout(struct timer_list *t)
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
954
  {
4b519bb49   Allen Pais   NFC: Convert time...
955
  	struct nfc_dev *dev = from_timer(dev, t, check_pres_timer);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
956

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

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

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1022
1023
  	/* first generation must not be 0 */
  	dev->targets_generation = 1;
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1024
  	if (ops->check_presence) {
4b519bb49   Allen Pais   NFC: Convert time...
1025
  		timer_setup(&dev->check_pres_timer, nfc_check_pres_timeout, 0);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1026
  		INIT_WORK(&dev->check_pres_work, nfc_check_pres_work);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1027
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1028
  	return dev;
20777bc57   Johan Hovold   NFC: fix broken d...
1029
1030
1031
  
  err_free_dev:
  	kfree(dev);
c45e3e4c5   Johan Hovold   NFC: fix device-a...
1032
  	return NULL;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  }
  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_...
1044
1045
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1046
1047
1048
1049
1050
  
  	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...
1051
1052
  	if (rc < 0)
  		return rc;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1053
1054
1055
1056
  	rc = nfc_llcp_register_device(dev);
  	if (rc)
  		pr_err("Could not register llcp device
  ");
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1057
1058
  	rc = nfc_genl_device_added(dev);
  	if (rc)
20c239c13   Joe Perches   nfc: Convert nfc_...
1059
1060
1061
  		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...
1062

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1063
1064
1065
1066
1067
1068
1069
1070
  	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...
1071
  	return 0;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  }
  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...
1082
  	int rc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1083

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

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1087
1088
1089
1090
  	if (dev->rfkill) {
  		rfkill_unregister(dev->rfkill);
  		rfkill_destroy(dev->rfkill);
  	}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1091
1092
1093
1094
1095
1096
1097
  	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...
1098

f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1099
1100
1101
1102
1103
  	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...
1104

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

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	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 ...
1129
1130
1131
  	rc = rawsock_init();
  	if (rc)
  		goto err_rawsock;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1132
1133
1134
  	rc = nfc_llcp_init();
  	if (rc)
  		goto err_llcp_sock;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1135
1136
1137
  	rc = af_nfc_init();
  	if (rc)
  		goto err_af_nfc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1138
  	return 0;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1139
  err_af_nfc:
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1140
1141
  	nfc_llcp_exit();
  err_llcp_sock:
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1142
1143
  	rawsock_exit();
  err_rawsock:
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1144
  	nfc_genl_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1145
1146
1147
  err_genl:
  	class_unregister(&nfc_class);
  	return rc;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1148
1149
1150
1151
  }
  
  static void __exit nfc_exit(void)
  {
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1152
  	af_nfc_exit();
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1153
  	nfc_llcp_exit();
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1154
  	rawsock_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1155
  	nfc_genl_exit();
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  	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 ...
1166
  MODULE_ALIAS_NETPROTO(PF_NFC);
5df16cad4   Samuel Ortiz   NFC: Add netlink ...
1167
  MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME);