Commit | Line | Data |
---|---|---|
4b10884e TE |
1 | /* |
2 | * NFC Digital Protocol stack | |
3 | * Copyright (c) 2013, Intel Corporation. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | ||
18 | #include "digital.h" | |
19 | ||
59ee2361 TE |
20 | #define DIGITAL_PROTO_NFCA_RF_TECH \ |
21 | (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK) | |
22 | ||
23 | struct digital_cmd { | |
24 | struct list_head queue; | |
25 | ||
26 | u8 type; | |
27 | u8 pending; | |
28 | ||
29 | u16 timeout; | |
30 | struct sk_buff *req; | |
31 | struct sk_buff *resp; | |
32 | ||
33 | nfc_digital_cmd_complete_t cmd_cb; | |
34 | void *cb_context; | |
35 | }; | |
36 | ||
37 | struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev, | |
38 | unsigned int len) | |
39 | { | |
40 | struct sk_buff *skb; | |
41 | ||
42 | skb = alloc_skb(len + ddev->tx_headroom + ddev->tx_tailroom, | |
43 | GFP_KERNEL); | |
44 | if (skb) | |
45 | skb_reserve(skb, ddev->tx_headroom); | |
46 | ||
47 | return skb; | |
48 | } | |
49 | ||
50 | static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on) | |
51 | { | |
52 | ddev->ops->switch_rf(ddev, on); | |
53 | } | |
54 | ||
55 | static inline void digital_abort_cmd(struct nfc_digital_dev *ddev) | |
56 | { | |
57 | ddev->ops->abort_cmd(ddev); | |
58 | } | |
59 | ||
60 | static void digital_wq_cmd_complete(struct work_struct *work) | |
61 | { | |
62 | struct digital_cmd *cmd; | |
63 | struct nfc_digital_dev *ddev = container_of(work, | |
64 | struct nfc_digital_dev, | |
65 | cmd_complete_work); | |
66 | ||
67 | mutex_lock(&ddev->cmd_lock); | |
68 | ||
69 | cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd, | |
70 | queue); | |
71 | if (!cmd) { | |
72 | mutex_unlock(&ddev->cmd_lock); | |
73 | return; | |
74 | } | |
75 | ||
76 | list_del(&cmd->queue); | |
77 | ||
78 | mutex_unlock(&ddev->cmd_lock); | |
79 | ||
80 | if (!IS_ERR(cmd->resp)) | |
81 | print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1, | |
82 | cmd->resp->data, cmd->resp->len, false); | |
83 | ||
84 | cmd->cmd_cb(ddev, cmd->cb_context, cmd->resp); | |
85 | ||
86 | kfree(cmd); | |
87 | ||
88 | schedule_work(&ddev->cmd_work); | |
89 | } | |
90 | ||
91 | static void digital_send_cmd_complete(struct nfc_digital_dev *ddev, | |
92 | void *arg, struct sk_buff *resp) | |
93 | { | |
94 | struct digital_cmd *cmd = arg; | |
95 | ||
96 | cmd->resp = resp; | |
97 | ||
98 | schedule_work(&ddev->cmd_complete_work); | |
99 | } | |
100 | ||
101 | static void digital_wq_cmd(struct work_struct *work) | |
102 | { | |
103 | int rc; | |
104 | struct digital_cmd *cmd; | |
105 | struct nfc_digital_dev *ddev = container_of(work, | |
106 | struct nfc_digital_dev, | |
107 | cmd_work); | |
108 | ||
109 | mutex_lock(&ddev->cmd_lock); | |
110 | ||
111 | cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd, | |
112 | queue); | |
113 | if (!cmd || cmd->pending) { | |
114 | mutex_unlock(&ddev->cmd_lock); | |
115 | return; | |
116 | } | |
117 | ||
118 | mutex_unlock(&ddev->cmd_lock); | |
119 | ||
120 | if (cmd->req) | |
121 | print_hex_dump_debug("DIGITAL TX: ", DUMP_PREFIX_NONE, 16, 1, | |
122 | cmd->req->data, cmd->req->len, false); | |
123 | ||
124 | switch (cmd->type) { | |
125 | case DIGITAL_CMD_IN_SEND: | |
126 | rc = ddev->ops->in_send_cmd(ddev, cmd->req, cmd->timeout, | |
127 | digital_send_cmd_complete, cmd); | |
128 | break; | |
129 | default: | |
130 | PR_ERR("Unknown cmd type %d", cmd->type); | |
131 | return; | |
132 | } | |
133 | ||
134 | if (!rc) | |
135 | return; | |
136 | ||
137 | PR_ERR("in_send_command returned err %d", rc); | |
138 | ||
139 | mutex_lock(&ddev->cmd_lock); | |
140 | list_del(&cmd->queue); | |
141 | mutex_unlock(&ddev->cmd_lock); | |
142 | ||
143 | kfree_skb(cmd->req); | |
144 | kfree(cmd); | |
145 | ||
146 | schedule_work(&ddev->cmd_work); | |
147 | } | |
148 | ||
149 | int digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type, | |
150 | struct sk_buff *skb, u16 timeout, | |
151 | nfc_digital_cmd_complete_t cmd_cb, void *cb_context) | |
152 | { | |
153 | struct digital_cmd *cmd; | |
154 | ||
155 | cmd = kzalloc(sizeof(struct digital_cmd), GFP_KERNEL); | |
156 | if (!cmd) | |
157 | return -ENOMEM; | |
158 | ||
159 | cmd->type = cmd_type; | |
160 | cmd->timeout = timeout; | |
161 | cmd->req = skb; | |
162 | cmd->cmd_cb = cmd_cb; | |
163 | cmd->cb_context = cb_context; | |
164 | INIT_LIST_HEAD(&cmd->queue); | |
165 | ||
166 | mutex_lock(&ddev->cmd_lock); | |
167 | list_add_tail(&cmd->queue, &ddev->cmd_queue); | |
168 | mutex_unlock(&ddev->cmd_lock); | |
169 | ||
170 | schedule_work(&ddev->cmd_work); | |
171 | ||
172 | return 0; | |
173 | } | |
174 | ||
175 | int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param) | |
176 | { | |
177 | int rc; | |
178 | ||
179 | rc = ddev->ops->in_configure_hw(ddev, type, param); | |
180 | if (rc) | |
181 | PR_ERR("in_configure_hw failed: %d", rc); | |
182 | ||
183 | return rc; | |
184 | } | |
185 | ||
186 | void digital_poll_next_tech(struct nfc_digital_dev *ddev) | |
187 | { | |
188 | digital_switch_rf(ddev, 0); | |
189 | ||
190 | mutex_lock(&ddev->poll_lock); | |
191 | ||
192 | if (!ddev->poll_tech_count) { | |
193 | mutex_unlock(&ddev->poll_lock); | |
194 | return; | |
195 | } | |
196 | ||
197 | ddev->poll_tech_index = (ddev->poll_tech_index + 1) % | |
198 | ddev->poll_tech_count; | |
199 | ||
200 | mutex_unlock(&ddev->poll_lock); | |
201 | ||
202 | schedule_work(&ddev->poll_work); | |
203 | } | |
204 | ||
205 | static void digital_wq_poll(struct work_struct *work) | |
206 | { | |
207 | int rc; | |
208 | struct digital_poll_tech *poll_tech; | |
209 | struct nfc_digital_dev *ddev = container_of(work, | |
210 | struct nfc_digital_dev, | |
211 | poll_work); | |
212 | mutex_lock(&ddev->poll_lock); | |
213 | ||
214 | if (!ddev->poll_tech_count) { | |
215 | mutex_unlock(&ddev->poll_lock); | |
216 | return; | |
217 | } | |
218 | ||
219 | poll_tech = &ddev->poll_techs[ddev->poll_tech_index]; | |
220 | ||
221 | mutex_unlock(&ddev->poll_lock); | |
222 | ||
223 | rc = poll_tech->poll_func(ddev, poll_tech->rf_tech); | |
224 | if (rc) | |
225 | digital_poll_next_tech(ddev); | |
226 | } | |
227 | ||
228 | static void digital_add_poll_tech(struct nfc_digital_dev *ddev, u8 rf_tech, | |
229 | digital_poll_t poll_func) | |
230 | { | |
231 | struct digital_poll_tech *poll_tech; | |
232 | ||
233 | if (ddev->poll_tech_count >= NFC_DIGITAL_POLL_MODE_COUNT_MAX) | |
234 | return; | |
235 | ||
236 | poll_tech = &ddev->poll_techs[ddev->poll_tech_count++]; | |
237 | ||
238 | poll_tech->rf_tech = rf_tech; | |
239 | poll_tech->poll_func = poll_func; | |
240 | } | |
241 | ||
242 | /** | |
243 | * start_poll operation | |
244 | * | |
245 | * For every supported protocol, the corresponding polling function is added | |
246 | * to the table of polling technologies (ddev->poll_techs[]) using | |
247 | * digital_add_poll_tech(). | |
248 | * When a polling function fails (by timeout or protocol error) the next one is | |
249 | * schedule by digital_poll_next_tech() on the poll workqueue (ddev->poll_work). | |
250 | */ | |
4b10884e TE |
251 | static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, |
252 | __u32 tm_protocols) | |
253 | { | |
59ee2361 TE |
254 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
255 | u32 matching_im_protocols, matching_tm_protocols; | |
256 | ||
257 | PR_DBG("protocols: im 0x%x, tm 0x%x, supported 0x%x", im_protocols, | |
258 | tm_protocols, ddev->protocols); | |
259 | ||
260 | matching_im_protocols = ddev->protocols & im_protocols; | |
261 | matching_tm_protocols = ddev->protocols & tm_protocols; | |
262 | ||
263 | if (!matching_im_protocols && !matching_tm_protocols) { | |
264 | PR_ERR("No known protocol"); | |
265 | return -EINVAL; | |
266 | } | |
267 | ||
268 | if (ddev->poll_tech_count) { | |
269 | PR_ERR("Already polling"); | |
270 | return -EBUSY; | |
271 | } | |
272 | ||
273 | if (ddev->curr_protocol) { | |
274 | PR_ERR("A target is already active"); | |
275 | return -EBUSY; | |
276 | } | |
277 | ||
278 | ddev->poll_tech_count = 0; | |
279 | ddev->poll_tech_index = 0; | |
280 | ||
281 | if (matching_im_protocols & DIGITAL_PROTO_NFCA_RF_TECH) | |
282 | digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, | |
283 | digital_in_send_sens_req); | |
284 | ||
285 | if (!ddev->poll_tech_count) { | |
286 | PR_ERR("Unsupported protocols: im=0x%x, tm=0x%x", | |
287 | matching_im_protocols, matching_tm_protocols); | |
288 | return -EINVAL; | |
289 | } | |
290 | ||
291 | schedule_work(&ddev->poll_work); | |
292 | ||
293 | return 0; | |
4b10884e TE |
294 | } |
295 | ||
296 | static void digital_stop_poll(struct nfc_dev *nfc_dev) | |
297 | { | |
59ee2361 TE |
298 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
299 | ||
300 | mutex_lock(&ddev->poll_lock); | |
301 | ||
302 | if (!ddev->poll_tech_count) { | |
303 | PR_ERR("Polling operation was not running"); | |
304 | mutex_unlock(&ddev->poll_lock); | |
305 | return; | |
306 | } | |
307 | ||
308 | ddev->poll_tech_count = 0; | |
309 | ||
310 | mutex_unlock(&ddev->poll_lock); | |
311 | ||
312 | cancel_work_sync(&ddev->poll_work); | |
313 | ||
314 | digital_abort_cmd(ddev); | |
4b10884e TE |
315 | } |
316 | ||
317 | static int digital_dev_up(struct nfc_dev *nfc_dev) | |
318 | { | |
59ee2361 TE |
319 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
320 | ||
321 | digital_switch_rf(ddev, 1); | |
322 | ||
323 | return 0; | |
4b10884e TE |
324 | } |
325 | ||
326 | static int digital_dev_down(struct nfc_dev *nfc_dev) | |
327 | { | |
59ee2361 TE |
328 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
329 | ||
330 | digital_switch_rf(ddev, 0); | |
331 | ||
332 | return 0; | |
4b10884e TE |
333 | } |
334 | ||
335 | static int digital_dep_link_up(struct nfc_dev *nfc_dev, | |
336 | struct nfc_target *target, | |
337 | __u8 comm_mode, __u8 *gb, size_t gb_len) | |
338 | { | |
339 | return -EOPNOTSUPP; | |
340 | } | |
341 | ||
342 | static int digital_dep_link_down(struct nfc_dev *nfc_dev) | |
343 | { | |
344 | return -EOPNOTSUPP; | |
345 | } | |
346 | ||
347 | static int digital_activate_target(struct nfc_dev *nfc_dev, | |
348 | struct nfc_target *target, __u32 protocol) | |
349 | { | |
59ee2361 | 350 | return 0; |
4b10884e TE |
351 | } |
352 | ||
353 | static void digital_deactivate_target(struct nfc_dev *nfc_dev, | |
354 | struct nfc_target *target) | |
355 | { | |
59ee2361 TE |
356 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
357 | ||
358 | ddev->curr_protocol = 0; | |
4b10884e TE |
359 | } |
360 | ||
361 | static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb) | |
362 | { | |
363 | return -EOPNOTSUPP; | |
364 | } | |
365 | ||
366 | static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, | |
367 | struct sk_buff *skb, data_exchange_cb_t cb, | |
368 | void *cb_context) | |
369 | { | |
370 | return -EOPNOTSUPP; | |
371 | } | |
372 | ||
373 | static struct nfc_ops digital_nfc_ops = { | |
374 | .dev_up = digital_dev_up, | |
375 | .dev_down = digital_dev_down, | |
376 | .start_poll = digital_start_poll, | |
377 | .stop_poll = digital_stop_poll, | |
378 | .dep_link_up = digital_dep_link_up, | |
379 | .dep_link_down = digital_dep_link_down, | |
380 | .activate_target = digital_activate_target, | |
381 | .deactivate_target = digital_deactivate_target, | |
382 | .tm_send = digital_tg_send, | |
383 | .im_transceive = digital_in_send, | |
384 | }; | |
385 | ||
386 | struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, | |
387 | __u32 supported_protocols, | |
388 | __u32 driver_capabilities, | |
389 | int tx_headroom, int tx_tailroom) | |
390 | { | |
391 | struct nfc_digital_dev *ddev; | |
392 | ||
393 | if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen || | |
394 | !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd || | |
395 | !ops->switch_rf) | |
396 | return NULL; | |
397 | ||
398 | ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL); | |
399 | if (!ddev) { | |
400 | PR_ERR("kzalloc failed"); | |
401 | return NULL; | |
402 | } | |
403 | ||
404 | ddev->driver_capabilities = driver_capabilities; | |
405 | ddev->ops = ops; | |
406 | ||
59ee2361 TE |
407 | mutex_init(&ddev->cmd_lock); |
408 | INIT_LIST_HEAD(&ddev->cmd_queue); | |
409 | ||
410 | INIT_WORK(&ddev->cmd_work, digital_wq_cmd); | |
411 | INIT_WORK(&ddev->cmd_complete_work, digital_wq_cmd_complete); | |
412 | ||
413 | mutex_init(&ddev->poll_lock); | |
414 | INIT_WORK(&ddev->poll_work, digital_wq_poll); | |
415 | ||
416 | if (supported_protocols & NFC_PROTO_JEWEL_MASK) | |
417 | ddev->protocols |= NFC_PROTO_JEWEL_MASK; | |
418 | if (supported_protocols & NFC_PROTO_MIFARE_MASK) | |
419 | ddev->protocols |= NFC_PROTO_MIFARE_MASK; | |
420 | ||
421 | ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; | |
422 | ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; | |
4b10884e TE |
423 | |
424 | ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols, | |
425 | ddev->tx_headroom, | |
426 | ddev->tx_tailroom); | |
427 | if (!ddev->nfc_dev) { | |
428 | PR_ERR("nfc_allocate_device failed"); | |
429 | goto free_dev; | |
430 | } | |
431 | ||
432 | nfc_set_drvdata(ddev->nfc_dev, ddev); | |
433 | ||
434 | return ddev; | |
435 | ||
436 | free_dev: | |
437 | kfree(ddev); | |
438 | ||
439 | return NULL; | |
440 | } | |
441 | EXPORT_SYMBOL(nfc_digital_allocate_device); | |
442 | ||
443 | void nfc_digital_free_device(struct nfc_digital_dev *ddev) | |
444 | { | |
445 | nfc_free_device(ddev->nfc_dev); | |
4b10884e TE |
446 | kfree(ddev); |
447 | } | |
448 | EXPORT_SYMBOL(nfc_digital_free_device); | |
449 | ||
450 | int nfc_digital_register_device(struct nfc_digital_dev *ddev) | |
451 | { | |
452 | return nfc_register_device(ddev->nfc_dev); | |
453 | } | |
454 | EXPORT_SYMBOL(nfc_digital_register_device); | |
455 | ||
456 | void nfc_digital_unregister_device(struct nfc_digital_dev *ddev) | |
457 | { | |
59ee2361 TE |
458 | struct digital_cmd *cmd, *n; |
459 | ||
4b10884e | 460 | nfc_unregister_device(ddev->nfc_dev); |
59ee2361 TE |
461 | |
462 | mutex_lock(&ddev->poll_lock); | |
463 | ddev->poll_tech_count = 0; | |
464 | mutex_unlock(&ddev->poll_lock); | |
465 | ||
466 | cancel_work_sync(&ddev->poll_work); | |
467 | cancel_work_sync(&ddev->cmd_work); | |
468 | cancel_work_sync(&ddev->cmd_complete_work); | |
469 | ||
470 | list_for_each_entry_safe(cmd, n, &ddev->cmd_queue, queue) { | |
471 | list_del(&cmd->queue); | |
472 | kfree(cmd); | |
473 | } | |
4b10884e TE |
474 | } |
475 | EXPORT_SYMBOL(nfc_digital_unregister_device); | |
476 | ||
477 | MODULE_LICENSE("GPL"); |