Blame view

net/nfc/core.c 24.9 KB
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Copyright (C) 2011 Instituto Nokia de Tecnologia
   *
   * Authors:
   *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
   *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
98b32decc   Jeff Kirsher   nfc: Fix FSF addr...
19
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
20
   */
52858b51b   Samuel Ortiz   NFC: Add function...
21
  #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
ed1e0ad88   Joe Perches   nfc: Use standard...
22

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
23
24
25
26
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/slab.h>
be055b2f8   Samuel Ortiz   NFC: RFKILL support
27
  #include <linux/rfkill.h>
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
28
  #include <linux/nfc.h>
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
29

5df16cad4   Samuel Ortiz   NFC: Add netlink ...
30
  #include <net/genetlink.h>
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
31
32
33
  #include "nfc.h"
  
  #define VERSION "0.1"
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
34
  #define NFC_CHECK_PRES_FREQ_MS	2000
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
35
36
  int nfc_devlist_generation;
  DEFINE_MUTEX(nfc_devlist_mutex);
7eda8b8e9   Samuel Ortiz   NFC: Use IDR libr...
37
38
  /* NFC device ID bitmap */
  static DEFINE_IDA(nfc_index_ida);
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
39
  int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
9674da875   Eric Lapuyade   NFC: Add firmware...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  {
  	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...
57
  	if (!dev->ops->fw_download) {
9674da875   Eric Lapuyade   NFC: Add firmware...
58
59
60
  		rc = -EOPNOTSUPP;
  		goto error;
  	}
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
61
62
  	dev->fw_download_in_progress = true;
  	rc = dev->ops->fw_download(dev, firmware_name);
9674da875   Eric Lapuyade   NFC: Add firmware...
63
  	if (rc)
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
64
  		dev->fw_download_in_progress = false;
9674da875   Eric Lapuyade   NFC: Add firmware...
65
66
67
68
69
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
352a5f5fb   Eric Lapuyade   NFC: netlink: Add...
70
71
72
73
74
75
76
77
78
  /**
   * 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...
79
  {
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
80
  	dev->fw_download_in_progress = false;
9674da875   Eric Lapuyade   NFC: Add firmware...
81

352a5f5fb   Eric Lapuyade   NFC: netlink: Add...
82
  	return nfc_genl_fw_download_done(dev, firmware_name, result);
9674da875   Eric Lapuyade   NFC: Add firmware...
83
  }
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
84
  EXPORT_SYMBOL(nfc_fw_download_done);
9674da875   Eric Lapuyade   NFC: Add firmware...
85

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
86
  /**
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
87
88
89
90
91
92
93
94
95
   * 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_...
96
97
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
98
99
  
  	device_lock(&dev->dev);
be055b2f8   Samuel Ortiz   NFC: RFKILL support
100
101
102
103
  	if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
  		rc = -ERFKILL;
  		goto error;
  	}
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
104
105
106
107
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
9ea7187c5   Samuel Ortiz   NFC: netlink: Ren...
108
  	if (dev->fw_download_in_progress) {
9674da875   Eric Lapuyade   NFC: Add firmware...
109
110
111
  		rc = -EBUSY;
  		goto error;
  	}
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
112
113
114
115
116
117
118
119
120
121
  	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...
122
  	/* We have to enable the device before discovering SEs */
a434c2407   Samuel Ortiz   NFC: Only warn on...
123
124
125
  	if (dev->ops->discover_se && dev->ops->discover_se(dev))
  		pr_err("SE discovery failed
  ");
0a946301c   Samuel Ortiz   NFC: Extend and f...
126

8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
127
128
129
130
131
132
133
134
135
136
137
138
139
  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_...
140
141
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
142
143
144
145
146
147
148
149
150
151
152
153
  
  	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...
154
  	if (dev->polling || dev->active_target) {
8b3fe7b59   Ilan Elias   NFC: Add dev_up a...
155
156
157
158
159
160
161
162
163
164
165
166
167
  		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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  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...
185
  /**
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
186
187
188
189
190
191
192
193
   * 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...
194
  int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
195
196
  {
  	int rc;
fe7c58007   Samuel Ortiz   NFC: Add target m...
197
198
199
  	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...
200

fe7c58007   Samuel Ortiz   NFC: Add target m...
201
  	if (!im_protocols && !tm_protocols)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
202
203
204
205
206
207
208
209
  		return -EINVAL;
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
7757dc8a3   Samuel Ortiz   NFC: Prevent poll...
210
211
212
213
  	if (!dev->dev_up) {
  		rc = -ENODEV;
  		goto error;
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
214
215
216
217
  	if (dev->polling) {
  		rc = -EBUSY;
  		goto error;
  	}
fe7c58007   Samuel Ortiz   NFC: Add target m...
218
  	rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
219
  	if (!rc) {
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
220
  		dev->polling = true;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
221
222
  		dev->rf_mode = NFC_RF_NONE;
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  
  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_...
237
238
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  
  	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 ...
254
  	dev->rf_mode = NFC_RF_NONE;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
255
256
257
258
259
  
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
900994332   Eric Lapuyade   NFC: Cache the co...
260
261
262
  static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
  {
  	int i;
0f4507722   Szymon Janc   NFC: Fix some cod...
263
  	for (i = 0; i < dev->n_targets; i++) {
900994332   Eric Lapuyade   NFC: Cache the co...
264
265
266
267
268
269
  		if (dev->targets[i].idx == target_idx)
  			return &dev->targets[i];
  	}
  
  	return NULL;
  }
47807d3db   Samuel Ortiz   NFC: Remove the r...
270
  int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
271
272
  {
  	int rc = 0;
47807d3db   Samuel Ortiz   NFC: Remove the r...
273
274
  	u8 *gb;
  	size_t gb_len;
900994332   Eric Lapuyade   NFC: Cache the co...
275
  	struct nfc_target *target;
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
276

47807d3db   Samuel Ortiz   NFC: Remove the r...
277
278
  	pr_debug("dev_name=%s comm %d
  ", dev_name(&dev->dev), comm_mode);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  
  	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...
294
295
296
297
298
  	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...
299
300
301
302
303
304
305
  	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 ...
306
  	if (!rc) {
900994332   Eric Lapuyade   NFC: Cache the co...
307
  		dev->active_target = target;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
308
309
  		dev->rf_mode = NFC_RF_INITIATOR;
  	}
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  
  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...
337
338
339
  	rc = dev->ops->dep_link_down(dev);
  	if (!rc) {
  		dev->dep_link_up = false;
900994332   Eric Lapuyade   NFC: Cache the co...
340
  		dev->active_target = NULL;
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
341
  		dev->rf_mode = NFC_RF_NONE;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
342
  		nfc_llcp_mac_is_down(dev);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
343
344
345
346
347
  		nfc_genl_dep_link_down_event(dev);
  	}
  
  error:
  	device_unlock(&dev->dev);
5bcf099c1   Thierry Escande   NFC: Set rf_mode ...
348

1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
349
350
351
352
  	return rc;
  }
  
  int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
0a40acb24   Samuel Ortiz   NFC: Core code id...
353
  		       u8 comm_mode, u8 rf_mode)
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
354
355
  {
  	dev->dep_link_up = true;
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
356

d31652a26   Arron Wang   NFC: Fix target m...
357
  	if (!dev->active_target && rf_mode == NFC_RF_INITIATOR) {
e29a9e2ae   Samuel Ortiz   NFC: Set active t...
358
359
360
361
362
363
364
365
366
367
368
  		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...
369
  	nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
1ed28f610   Samuel Ortiz   NFC: Add a DEP li...
370
371
372
  	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...
373
374
375
376
377
378
379
380
381
382
  /**
   * 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...
383
  	struct nfc_target *target;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
384

20c239c13   Joe Perches   nfc: Convert nfc_...
385
386
387
  	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...
388
389
390
391
392
393
394
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
395
396
397
398
399
400
401
402
403
404
405
406
  	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...
407
  	if (!rc) {
900994332   Eric Lapuyade   NFC: Cache the co...
408
  		dev->active_target = target;
f212ad5e9   Samuel Ortiz   NFC: Set the NFC ...
409
  		dev->rf_mode = NFC_RF_INITIATOR;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
410

f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
411
  		if (dev->ops->check_presence && !dev->shutting_down)
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
412
413
414
  			mod_timer(&dev->check_pres_timer, jiffies +
  				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
415
416
417
418
419
420
421
422
423
424
425
426
  
  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...
427
  int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx, u8 mode)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
428
429
  {
  	int rc = 0;
20c239c13   Joe Perches   nfc: Convert nfc_...
430
431
432
  	pr_debug("dev_name=%s target_idx=%u
  ",
  		 dev_name(&dev->dev), target_idx);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
433
434
435
436
437
438
439
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		goto error;
  	}
900994332   Eric Lapuyade   NFC: Cache the co...
440
441
442
443
444
445
446
447
448
  	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...
449
450
  	if (dev->ops->check_presence)
  		del_timer_sync(&dev->check_pres_timer);
96d4581f0   Christophe Ricard   NFC: netlink: Add...
451
  	dev->ops->deactivate_target(dev, dev->active_target, mode);
900994332   Eric Lapuyade   NFC: Cache the co...
452
  	dev->active_target = NULL;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  
  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...
470
471
  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...
472
473
  {
  	int rc;
20c239c13   Joe Perches   nfc: Convert nfc_...
474
475
476
  	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...
477
478
479
480
481
482
483
484
  
  	device_lock(&dev->dev);
  
  	if (!device_is_registered(&dev->dev)) {
  		rc = -ENODEV;
  		kfree_skb(skb);
  		goto error;
  	}
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
485
486
487
488
489
490
  	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...
491

be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
492
493
494
495
496
  		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...
497
  		if (!rc && dev->ops->check_presence && !dev->shutting_down)
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
498
499
500
501
502
503
  			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...
504
505
506
  		kfree_skb(skb);
  		goto error;
  	}
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
507

3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
508
509
510
511
  error:
  	device_unlock(&dev->dev);
  	return rc;
  }
d8eb18eec   Arron Wang   NFC: Export nfc_f...
512
  struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx)
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
513
  {
156cef80f   Axel Lin   NFC: Use list_for...
514
  	struct nfc_se *se;
c531c9ec2   Samuel Ortiz   NFC: Add secure e...
515

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

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
619
  	return nfc_llcp_set_remote_gb(dev, gb, gb_len);
541d920b0   Samuel Ortiz   NFC: Set and get ...
620
621
  }
  EXPORT_SYMBOL(nfc_set_remote_general_bytes);
ab73b7513   Samuel Ortiz   NFC: Export LLCP ...
622
623
624
625
626
627
628
629
  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...
630
631
632
633
634
635
636
637
638
639
640
  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...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
  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 ...
655
  	dev->rf_mode = NFC_RF_TARGET;
fc40a8c1a   Samuel Ortiz   NFC: Add target m...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  	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 ...
671
  	dev->rf_mode = NFC_RF_NONE;
fc40a8c1a   Samuel Ortiz   NFC: Add target m...
672
673
674
675
  
  	return nfc_genl_tm_deactivated(dev);
  }
  EXPORT_SYMBOL(nfc_tm_deactivated);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
676
  /**
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
677
   * nfc_alloc_send_skb - allocate a skb for data exchange responses
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
678
679
680
681
   *
   * @size: size to allocate
   * @gfp: gfp flags
   */
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
682
  struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
0a40acb24   Samuel Ortiz   NFC: Core code id...
683
684
  				   unsigned int flags, unsigned int size,
  				   unsigned int *err)
7c7cd3bfe   Samuel Ortiz   NFC: Add tx skb a...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  {
  	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...
706
707
708
709
710
711
712
713
714
715
716
717
  {
  	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...
718
  EXPORT_SYMBOL(nfc_alloc_recv_skb);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
719

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
720
721
722
723
724
725
726
727
728
729
  /**
   * 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_...
730
731
   * 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...
732
733
734
   * 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...
735
   */
0a40acb24   Samuel Ortiz   NFC: Core code id...
736
737
  int nfc_targets_found(struct nfc_dev *dev,
  		      struct nfc_target *targets, int n_targets)
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
738
  {
c4fbb6515   Samuel Ortiz   NFC: The core par...
739
  	int i;
20c239c13   Joe Perches   nfc: Convert nfc_...
740
741
  	pr_debug("dev_name=%s n_targets=%d
  ", dev_name(&dev->dev), n_targets);
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
742

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

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

8668fdd6e   Eric Lapuyade   NFC: Core must te...
748
749
750
751
752
753
  	if (dev->polling == false) {
  		device_unlock(&dev->dev);
  		return 0;
  	}
  
  	dev->polling = false;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
754
755
756
  	dev->targets_generation++;
  
  	kfree(dev->targets);
d94f9c55f   Eric Lapuyade   NFC: nfc_targets_...
757
  	dev->targets = NULL;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
758

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

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

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
930
931
  	nfc_genl_data_exit(&dev->genl_data);
  	kfree(dev->targets);
ee656e9d0   Samuel Ortiz   NFC: Remove and f...
932
933
934
935
936
937
  
  	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...
938
  	ida_simple_remove(&nfc_index_ida, dev->idx);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
939
940
  	kfree(dev);
  }
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
941
942
943
944
945
946
947
  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...
948
949
  	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...
950
951
  		if (rc == -EOPNOTSUPP)
  			goto exit;
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
952
  		if (rc) {
d4ccb1328   Eric Lapuyade   NFC: Specify usag...
953
954
955
956
  			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...
957
  		}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
958
959
960
961
  
  		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...
962
  	}
632c016ab   Eric Lapuyade   NFC: HCI check pr...
963
  exit:
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
964
965
966
967
968
969
  	device_unlock(&dev->dev);
  }
  
  static void nfc_check_pres_timeout(unsigned long data)
  {
  	struct nfc_dev *dev = (struct nfc_dev *)data;
916082b07   Linus Torvalds   workqueue: avoid ...
970
  	schedule_work(&dev->check_pres_work);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
971
  }
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
972
973
974
975
976
  struct class nfc_class = {
  	.name = "nfc",
  	.dev_release = nfc_release,
  };
  EXPORT_SYMBOL(nfc_class);
9f3b795a6   Michał Mirosław   driver-core: cons...
977
  static int match_idx(struct device *d, const void *data)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
978
979
  {
  	struct nfc_dev *dev = to_nfc_dev(d);
9f3b795a6   Michał Mirosław   driver-core: cons...
980
  	const unsigned int *idx = data;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
981
982
983
  
  	return dev->idx == *idx;
  }
95c961747   Eric Dumazet   net: cleanup unsi...
984
  struct nfc_dev *nfc_get_device(unsigned int idx)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  {
  	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...
1002
1003
  				    u32 supported_protocols,
  				    int tx_headroom, int tx_tailroom)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1004
  {
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1005
  	struct nfc_dev *dev;
20777bc57   Johan Hovold   NFC: fix broken d...
1006
  	int rc;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1007
1008
  
  	if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
be9ae4ce4   Samuel Ortiz   NFC: Introduce ta...
1009
  	    !ops->deactivate_target || !ops->im_transceive)
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1010
1011
1012
1013
1014
1015
1016
1017
  		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...
1018
1019
1020
1021
1022
1023
1024
1025
  	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...
1026
1027
  	dev->ops = ops;
  	dev->supported_protocols = supported_protocols;
e8753043f   Samuel Ortiz   NFC: Reserve tx h...
1028
1029
  	dev->tx_headroom = tx_headroom;
  	dev->tx_tailroom = tx_tailroom;
fed7c25ec   Samuel Ortiz   NFC: Add secure e...
1030
  	INIT_LIST_HEAD(&dev->secure_elements);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1031

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

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1035
1036
  	/* first generation must not be 0 */
  	dev->targets_generation = 1;
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1037
  	if (ops->check_presence) {
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1038
1039
1040
1041
1042
  		init_timer(&dev->check_pres_timer);
  		dev->check_pres_timer.data = (unsigned long)dev;
  		dev->check_pres_timer.function = nfc_check_pres_timeout;
  
  		INIT_WORK(&dev->check_pres_work, nfc_check_pres_work);
c8d56ae78   Eric Lapuyade   NFC: Add Core sup...
1043
  	}
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1044
  	return dev;
20777bc57   Johan Hovold   NFC: fix broken d...
1045
1046
1047
  
  err_free_dev:
  	kfree(dev);
eb2499b39   Johan Hovold   NFC: fix device-a...
1048
  	return NULL;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  }
  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_...
1060
1061
  	pr_debug("dev_name=%s
  ", dev_name(&dev->dev));
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1062
1063
1064
1065
1066
  
  	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...
1067
1068
  	if (rc < 0)
  		return rc;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1069
1070
1071
1072
  	rc = nfc_llcp_register_device(dev);
  	if (rc)
  		pr_err("Could not register llcp device
  ");
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1073
1074
  	rc = nfc_genl_device_added(dev);
  	if (rc)
20c239c13   Joe Perches   nfc: Convert nfc_...
1075
1076
1077
  		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...
1078

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1079
1080
1081
1082
1083
1084
1085
1086
  	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...
1087
  	return 0;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
  }
  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...
1098
  	int rc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1099

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

be055b2f8   Samuel Ortiz   NFC: RFKILL support
1103
1104
1105
1106
  	if (dev->rfkill) {
  		rfkill_unregister(dev->rfkill);
  		rfkill_destroy(dev->rfkill);
  	}
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1107
1108
1109
1110
1111
1112
1113
  	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...
1114

f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1115
1116
1117
1118
1119
  	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...
1120

d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1121
  	nfc_llcp_unregister_device(dev);
f0c910381   Eric Lapuyade   NFC: Fixed nfc co...
1122
1123
1124
1125
  	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...
1126
1127
1128
1129
1130
  }
  EXPORT_SYMBOL(nfc_unregister_device);
  
  static int __init nfc_init(void)
  {
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1131
  	int rc;
ed1e0ad88   Joe Perches   nfc: Use standard...
1132
1133
  	pr_info("NFC Core ver %s
  ", VERSION);
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1134

4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
  	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 ...
1145
1146
1147
  	rc = rawsock_init();
  	if (rc)
  		goto err_rawsock;
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1148
1149
1150
  	rc = nfc_llcp_init();
  	if (rc)
  		goto err_llcp_sock;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1151
1152
1153
  	rc = af_nfc_init();
  	if (rc)
  		goto err_af_nfc;
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1154
  	return 0;
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1155
  err_af_nfc:
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1156
1157
  	nfc_llcp_exit();
  err_llcp_sock:
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1158
1159
  	rawsock_exit();
  err_rawsock:
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1160
  	nfc_genl_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1161
1162
1163
  err_genl:
  	class_unregister(&nfc_class);
  	return rc;
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1164
1165
1166
1167
  }
  
  static void __exit nfc_exit(void)
  {
c7fe3b52c   Aloisio Almeida Jr   NFC: add NFC sock...
1168
  	af_nfc_exit();
d646960f7   Samuel Ortiz   NFC: Initial LLCP...
1169
  	nfc_llcp_exit();
23b7869c0   Lauro Ramos Venancio   NFC: add the NFC ...
1170
  	rawsock_exit();
4d12b8b12   Lauro Ramos Venancio   NFC: add nfc gene...
1171
  	nfc_genl_exit();
3e256b8f8   Lauro Ramos Venancio   NFC: add nfc subs...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  	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 ...
1182
  MODULE_ALIAS_NETPROTO(PF_NFC);
5df16cad4   Samuel Ortiz   NFC: Add netlink ...
1183
  MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME);