diff options
-rw-r--r-- | drivers/nfc/pn533.c | 102 |
1 files changed, 85 insertions, 17 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index d606f52fec84..7ceea111439b 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -356,6 +356,7 @@ struct pn533 { | |||
356 | 356 | ||
357 | struct workqueue_struct *wq; | 357 | struct workqueue_struct *wq; |
358 | struct work_struct cmd_work; | 358 | struct work_struct cmd_work; |
359 | struct work_struct cmd_complete_work; | ||
359 | struct work_struct poll_work; | 360 | struct work_struct poll_work; |
360 | struct work_struct mi_work; | 361 | struct work_struct mi_work; |
361 | struct work_struct tg_work; | 362 | struct work_struct tg_work; |
@@ -383,6 +384,19 @@ struct pn533 { | |||
383 | u8 tgt_mode; | 384 | u8 tgt_mode; |
384 | 385 | ||
385 | u32 device_type; | 386 | u32 device_type; |
387 | |||
388 | struct list_head cmd_queue; | ||
389 | u8 cmd_pending; | ||
390 | }; | ||
391 | |||
392 | struct pn533_cmd { | ||
393 | struct list_head queue; | ||
394 | struct pn533_frame *out_frame; | ||
395 | struct pn533_frame *in_frame; | ||
396 | int in_frame_len; | ||
397 | pn533_cmd_complete_t cmd_complete; | ||
398 | void *arg; | ||
399 | gfp_t flags; | ||
386 | }; | 400 | }; |
387 | 401 | ||
388 | struct pn533_frame { | 402 | struct pn533_frame { |
@@ -487,7 +501,7 @@ static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd) | |||
487 | 501 | ||
488 | static void pn533_wq_cmd_complete(struct work_struct *work) | 502 | static void pn533_wq_cmd_complete(struct work_struct *work) |
489 | { | 503 | { |
490 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); | 504 | struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work); |
491 | struct pn533_frame *in_frame; | 505 | struct pn533_frame *in_frame; |
492 | int rc; | 506 | int rc; |
493 | 507 | ||
@@ -502,7 +516,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work) | |||
502 | PN533_FRAME_CMD_PARAMS_LEN(in_frame)); | 516 | PN533_FRAME_CMD_PARAMS_LEN(in_frame)); |
503 | 517 | ||
504 | if (rc != -EINPROGRESS) | 518 | if (rc != -EINPROGRESS) |
505 | mutex_unlock(&dev->cmd_lock); | 519 | queue_work(dev->wq, &dev->cmd_work); |
506 | } | 520 | } |
507 | 521 | ||
508 | static void pn533_recv_response(struct urb *urb) | 522 | static void pn533_recv_response(struct urb *urb) |
@@ -550,7 +564,7 @@ static void pn533_recv_response(struct urb *urb) | |||
550 | dev->wq_in_frame = in_frame; | 564 | dev->wq_in_frame = in_frame; |
551 | 565 | ||
552 | sched_wq: | 566 | sched_wq: |
553 | queue_work(dev->wq, &dev->cmd_work); | 567 | queue_work(dev->wq, &dev->cmd_complete_work); |
554 | } | 568 | } |
555 | 569 | ||
556 | static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) | 570 | static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags) |
@@ -606,7 +620,7 @@ static void pn533_recv_ack(struct urb *urb) | |||
606 | 620 | ||
607 | sched_wq: | 621 | sched_wq: |
608 | dev->wq_in_frame = NULL; | 622 | dev->wq_in_frame = NULL; |
609 | queue_work(dev->wq, &dev->cmd_work); | 623 | queue_work(dev->wq, &dev->cmd_complete_work); |
610 | } | 624 | } |
611 | 625 | ||
612 | static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) | 626 | static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags) |
@@ -669,6 +683,31 @@ error: | |||
669 | return rc; | 683 | return rc; |
670 | } | 684 | } |
671 | 685 | ||
686 | static void pn533_wq_cmd(struct work_struct *work) | ||
687 | { | ||
688 | struct pn533 *dev = container_of(work, struct pn533, cmd_work); | ||
689 | struct pn533_cmd *cmd; | ||
690 | |||
691 | mutex_lock(&dev->cmd_lock); | ||
692 | |||
693 | if (list_empty(&dev->cmd_queue)) { | ||
694 | dev->cmd_pending = 0; | ||
695 | mutex_unlock(&dev->cmd_lock); | ||
696 | return; | ||
697 | } | ||
698 | |||
699 | cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); | ||
700 | |||
701 | mutex_unlock(&dev->cmd_lock); | ||
702 | |||
703 | __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, | ||
704 | cmd->in_frame_len, cmd->cmd_complete, | ||
705 | cmd->arg, cmd->flags); | ||
706 | |||
707 | list_del(&cmd->queue); | ||
708 | kfree(cmd); | ||
709 | } | ||
710 | |||
672 | static int pn533_send_cmd_frame_async(struct pn533 *dev, | 711 | static int pn533_send_cmd_frame_async(struct pn533 *dev, |
673 | struct pn533_frame *out_frame, | 712 | struct pn533_frame *out_frame, |
674 | struct pn533_frame *in_frame, | 713 | struct pn533_frame *in_frame, |
@@ -676,22 +715,44 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev, | |||
676 | pn533_cmd_complete_t cmd_complete, | 715 | pn533_cmd_complete_t cmd_complete, |
677 | void *arg, gfp_t flags) | 716 | void *arg, gfp_t flags) |
678 | { | 717 | { |
718 | struct pn533_cmd *cmd; | ||
679 | int rc; | 719 | int rc; |
680 | 720 | ||
681 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 721 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
682 | 722 | ||
683 | if (!mutex_trylock(&dev->cmd_lock)) | 723 | mutex_lock(&dev->cmd_lock); |
684 | return -EBUSY; | ||
685 | 724 | ||
686 | rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, | 725 | if (!dev->cmd_pending) { |
687 | in_frame_len, cmd_complete, arg, flags); | 726 | rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame, |
688 | if (rc) | 727 | in_frame_len, cmd_complete, |
689 | goto error; | 728 | arg, flags); |
729 | if (!rc) | ||
730 | dev->cmd_pending = 1; | ||
731 | |||
732 | mutex_unlock(&dev->cmd_lock); | ||
733 | |||
734 | return rc; | ||
735 | } | ||
736 | |||
737 | nfc_dev_dbg(&dev->interface->dev, "%s Queueing command", __func__); | ||
738 | |||
739 | cmd = kzalloc(sizeof(struct pn533_cmd), flags); | ||
740 | if (!cmd) | ||
741 | return -ENOMEM; | ||
742 | |||
743 | INIT_LIST_HEAD(&cmd->queue); | ||
744 | cmd->out_frame = out_frame; | ||
745 | cmd->in_frame = in_frame; | ||
746 | cmd->in_frame_len = in_frame_len; | ||
747 | cmd->cmd_complete = cmd_complete; | ||
748 | cmd->arg = arg; | ||
749 | cmd->flags = flags; | ||
750 | |||
751 | list_add_tail(&cmd->queue, &dev->cmd_queue); | ||
690 | 752 | ||
691 | return 0; | ||
692 | error: | ||
693 | mutex_unlock(&dev->cmd_lock); | 753 | mutex_unlock(&dev->cmd_lock); |
694 | return rc; | 754 | |
755 | return 0; | ||
695 | } | 756 | } |
696 | 757 | ||
697 | struct pn533_sync_cmd_response { | 758 | struct pn533_sync_cmd_response { |
@@ -1305,8 +1366,6 @@ static void pn533_listen_mode_timer(unsigned long data) | |||
1305 | 1366 | ||
1306 | dev->cancel_listen = 1; | 1367 | dev->cancel_listen = 1; |
1307 | 1368 | ||
1308 | mutex_unlock(&dev->cmd_lock); | ||
1309 | |||
1310 | pn533_poll_next_mod(dev); | 1369 | pn533_poll_next_mod(dev); |
1311 | 1370 | ||
1312 | queue_work(dev->wq, &dev->poll_work); | 1371 | queue_work(dev->wq, &dev->poll_work); |
@@ -2131,7 +2190,7 @@ error_cmd: | |||
2131 | 2190 | ||
2132 | kfree(arg); | 2191 | kfree(arg); |
2133 | 2192 | ||
2134 | mutex_unlock(&dev->cmd_lock); | 2193 | queue_work(dev->wq, &dev->cmd_work); |
2135 | } | 2194 | } |
2136 | 2195 | ||
2137 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, | 2196 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, |
@@ -2330,7 +2389,8 @@ static int pn533_probe(struct usb_interface *interface, | |||
2330 | NULL, 0, | 2389 | NULL, 0, |
2331 | pn533_send_complete, dev); | 2390 | pn533_send_complete, dev); |
2332 | 2391 | ||
2333 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete); | 2392 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd); |
2393 | INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); | ||
2334 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); | 2394 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); |
2335 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); | 2395 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); |
2336 | INIT_WORK(&dev->poll_work, pn533_wq_poll); | 2396 | INIT_WORK(&dev->poll_work, pn533_wq_poll); |
@@ -2346,6 +2406,8 @@ static int pn533_probe(struct usb_interface *interface, | |||
2346 | 2406 | ||
2347 | skb_queue_head_init(&dev->resp_q); | 2407 | skb_queue_head_init(&dev->resp_q); |
2348 | 2408 | ||
2409 | INIT_LIST_HEAD(&dev->cmd_queue); | ||
2410 | |||
2349 | usb_set_intfdata(interface, dev); | 2411 | usb_set_intfdata(interface, dev); |
2350 | 2412 | ||
2351 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); | 2413 | pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION); |
@@ -2417,6 +2479,7 @@ error: | |||
2417 | static void pn533_disconnect(struct usb_interface *interface) | 2479 | static void pn533_disconnect(struct usb_interface *interface) |
2418 | { | 2480 | { |
2419 | struct pn533 *dev; | 2481 | struct pn533 *dev; |
2482 | struct pn533_cmd *cmd, *n; | ||
2420 | 2483 | ||
2421 | dev = usb_get_intfdata(interface); | 2484 | dev = usb_get_intfdata(interface); |
2422 | usb_set_intfdata(interface, NULL); | 2485 | usb_set_intfdata(interface, NULL); |
@@ -2433,6 +2496,11 @@ static void pn533_disconnect(struct usb_interface *interface) | |||
2433 | 2496 | ||
2434 | del_timer(&dev->listen_timer); | 2497 | del_timer(&dev->listen_timer); |
2435 | 2498 | ||
2499 | list_for_each_entry_safe(cmd, n, &dev->cmd_queue, queue) { | ||
2500 | list_del(&cmd->queue); | ||
2501 | kfree(cmd); | ||
2502 | } | ||
2503 | |||
2436 | kfree(dev->in_frame); | 2504 | kfree(dev->in_frame); |
2437 | usb_free_urb(dev->in_urb); | 2505 | usb_free_urb(dev->in_urb); |
2438 | kfree(dev->out_frame); | 2506 | kfree(dev->out_frame); |