diff options
Diffstat (limited to 'net/nfc/digital_dep.c')
-rw-r--r-- | net/nfc/digital_dep.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index be984c4204d2..810d00c9cd5d 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -379,3 +379,349 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
379 | return digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | 379 | return digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, |
380 | data_exch); | 380 | data_exch); |
381 | } | 381 | } |
382 | |||
383 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | ||
384 | struct sk_buff *resp) | ||
385 | { | ||
386 | int rc; | ||
387 | struct digital_dep_req_res *dep_req; | ||
388 | size_t size; | ||
389 | |||
390 | if (IS_ERR(resp)) { | ||
391 | rc = PTR_ERR(resp); | ||
392 | resp = NULL; | ||
393 | goto exit; | ||
394 | } | ||
395 | |||
396 | rc = ddev->skb_check_crc(resp); | ||
397 | if (rc) { | ||
398 | PROTOCOL_ERR("14.4.1.6"); | ||
399 | goto exit; | ||
400 | } | ||
401 | |||
402 | rc = digital_skb_pull_dep_sod(ddev, resp); | ||
403 | if (rc) { | ||
404 | PROTOCOL_ERR("14.4.1.2"); | ||
405 | goto exit; | ||
406 | } | ||
407 | |||
408 | size = sizeof(struct digital_dep_req_res); | ||
409 | dep_req = (struct digital_dep_req_res *)resp->data; | ||
410 | |||
411 | if (resp->len < size || dep_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || | ||
412 | dep_req->cmd != DIGITAL_CMD_DEP_REQ) { | ||
413 | rc = -EIO; | ||
414 | goto exit; | ||
415 | } | ||
416 | |||
417 | if (DIGITAL_NFC_DEP_DID_BIT_SET(dep_req->pfb)) | ||
418 | size++; | ||
419 | |||
420 | if (resp->len < size) { | ||
421 | rc = -EIO; | ||
422 | goto exit; | ||
423 | } | ||
424 | |||
425 | switch (DIGITAL_NFC_DEP_PFB_TYPE(dep_req->pfb)) { | ||
426 | case DIGITAL_NFC_DEP_PFB_I_PDU: | ||
427 | PR_DBG("DIGITAL_NFC_DEP_PFB_I_PDU"); | ||
428 | ddev->curr_nfc_dep_pni = DIGITAL_NFC_DEP_PFB_PNI(dep_req->pfb); | ||
429 | break; | ||
430 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | ||
431 | PR_ERR("Received a ACK/NACK PDU"); | ||
432 | rc = -EINVAL; | ||
433 | goto exit; | ||
434 | break; | ||
435 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | ||
436 | PR_ERR("Received a SUPERVISOR PDU"); | ||
437 | rc = -EINVAL; | ||
438 | goto exit; | ||
439 | break; | ||
440 | } | ||
441 | |||
442 | skb_pull(resp, size); | ||
443 | |||
444 | rc = nfc_tm_data_received(ddev->nfc_dev, resp); | ||
445 | |||
446 | exit: | ||
447 | if (rc) | ||
448 | kfree_skb(resp); | ||
449 | } | ||
450 | |||
451 | int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) | ||
452 | { | ||
453 | struct digital_dep_req_res *dep_res; | ||
454 | |||
455 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
456 | dep_res = (struct digital_dep_req_res *)skb->data; | ||
457 | |||
458 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
459 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | ||
460 | dep_res->pfb = ddev->curr_nfc_dep_pni; | ||
461 | |||
462 | digital_skb_push_dep_sod(ddev, skb); | ||
463 | |||
464 | ddev->skb_add_crc(skb); | ||
465 | |||
466 | return digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | ||
467 | NULL); | ||
468 | } | ||
469 | |||
470 | static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev, | ||
471 | void *arg, struct sk_buff *resp) | ||
472 | { | ||
473 | u8 rf_tech = PTR_ERR(arg); | ||
474 | |||
475 | if (IS_ERR(resp)) | ||
476 | return; | ||
477 | |||
478 | digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech); | ||
479 | |||
480 | digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL); | ||
481 | |||
482 | dev_kfree_skb(resp); | ||
483 | } | ||
484 | |||
485 | static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did, | ||
486 | u8 rf_tech) | ||
487 | { | ||
488 | struct digital_psl_res *psl_res; | ||
489 | struct sk_buff *skb; | ||
490 | int rc; | ||
491 | |||
492 | skb = digital_skb_alloc(ddev, sizeof(struct digital_psl_res)); | ||
493 | if (!skb) | ||
494 | return -ENOMEM; | ||
495 | |||
496 | skb_put(skb, sizeof(struct digital_psl_res)); | ||
497 | |||
498 | psl_res = (struct digital_psl_res *)skb->data; | ||
499 | |||
500 | psl_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
501 | psl_res->cmd = DIGITAL_CMD_PSL_RES; | ||
502 | psl_res->did = did; | ||
503 | |||
504 | digital_skb_push_dep_sod(ddev, skb); | ||
505 | |||
506 | ddev->skb_add_crc(skb); | ||
507 | |||
508 | rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete, | ||
509 | ERR_PTR(rf_tech)); | ||
510 | |||
511 | if (rc) | ||
512 | kfree_skb(skb); | ||
513 | |||
514 | return rc; | ||
515 | } | ||
516 | |||
517 | static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg, | ||
518 | struct sk_buff *resp) | ||
519 | { | ||
520 | int rc; | ||
521 | struct digital_psl_req *psl_req; | ||
522 | u8 rf_tech; | ||
523 | u8 dsi; | ||
524 | |||
525 | if (IS_ERR(resp)) { | ||
526 | rc = PTR_ERR(resp); | ||
527 | resp = NULL; | ||
528 | goto exit; | ||
529 | } | ||
530 | |||
531 | rc = ddev->skb_check_crc(resp); | ||
532 | if (rc) { | ||
533 | PROTOCOL_ERR("14.4.1.6"); | ||
534 | goto exit; | ||
535 | } | ||
536 | |||
537 | rc = digital_skb_pull_dep_sod(ddev, resp); | ||
538 | if (rc) { | ||
539 | PROTOCOL_ERR("14.4.1.2"); | ||
540 | goto exit; | ||
541 | } | ||
542 | |||
543 | psl_req = (struct digital_psl_req *)resp->data; | ||
544 | |||
545 | if (resp->len != sizeof(struct digital_psl_req) || | ||
546 | psl_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || | ||
547 | psl_req->cmd != DIGITAL_CMD_PSL_REQ) { | ||
548 | rc = -EIO; | ||
549 | goto exit; | ||
550 | } | ||
551 | |||
552 | dsi = (psl_req->brs >> 3) & 0x07; | ||
553 | switch (dsi) { | ||
554 | case 0: | ||
555 | rf_tech = NFC_DIGITAL_RF_TECH_106A; | ||
556 | break; | ||
557 | case 1: | ||
558 | rf_tech = NFC_DIGITAL_RF_TECH_212F; | ||
559 | break; | ||
560 | case 2: | ||
561 | rf_tech = NFC_DIGITAL_RF_TECH_424F; | ||
562 | break; | ||
563 | default: | ||
564 | PR_ERR("Unsuported dsi value %d", dsi); | ||
565 | goto exit; | ||
566 | } | ||
567 | |||
568 | rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech); | ||
569 | |||
570 | exit: | ||
571 | kfree_skb(resp); | ||
572 | } | ||
573 | |||
574 | static void digital_tg_send_atr_res_complete(struct nfc_digital_dev *ddev, | ||
575 | void *arg, struct sk_buff *resp) | ||
576 | { | ||
577 | int offset; | ||
578 | |||
579 | if (IS_ERR(resp)) { | ||
580 | digital_poll_next_tech(ddev); | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | offset = 2; | ||
585 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) | ||
586 | offset++; | ||
587 | |||
588 | if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) | ||
589 | digital_tg_recv_psl_req(ddev, arg, resp); | ||
590 | else | ||
591 | digital_tg_recv_dep_req(ddev, arg, resp); | ||
592 | } | ||
593 | |||
594 | static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev, | ||
595 | struct digital_atr_req *atr_req) | ||
596 | { | ||
597 | struct digital_atr_res *atr_res; | ||
598 | struct sk_buff *skb; | ||
599 | u8 *gb; | ||
600 | size_t gb_len; | ||
601 | int rc; | ||
602 | |||
603 | gb = nfc_get_local_general_bytes(ddev->nfc_dev, &gb_len); | ||
604 | if (!gb) | ||
605 | gb_len = 0; | ||
606 | |||
607 | skb = digital_skb_alloc(ddev, sizeof(struct digital_atr_res) + gb_len); | ||
608 | if (!skb) | ||
609 | return -ENOMEM; | ||
610 | |||
611 | skb_put(skb, sizeof(struct digital_atr_res)); | ||
612 | atr_res = (struct digital_atr_res *)skb->data; | ||
613 | |||
614 | memset(atr_res, 0, sizeof(struct digital_atr_res)); | ||
615 | |||
616 | atr_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
617 | atr_res->cmd = DIGITAL_CMD_ATR_RES; | ||
618 | memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3)); | ||
619 | atr_res->to = 8; | ||
620 | atr_res->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B; | ||
621 | if (gb_len) { | ||
622 | skb_put(skb, gb_len); | ||
623 | |||
624 | atr_res->pp |= DIGITAL_GB_BIT; | ||
625 | memcpy(atr_res->gb, gb, gb_len); | ||
626 | } | ||
627 | |||
628 | digital_skb_push_dep_sod(ddev, skb); | ||
629 | |||
630 | ddev->skb_add_crc(skb); | ||
631 | |||
632 | rc = digital_tg_send_cmd(ddev, skb, 999, | ||
633 | digital_tg_send_atr_res_complete, NULL); | ||
634 | if (rc) { | ||
635 | kfree_skb(skb); | ||
636 | return rc; | ||
637 | } | ||
638 | |||
639 | return rc; | ||
640 | } | ||
641 | |||
642 | void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, | ||
643 | struct sk_buff *resp) | ||
644 | { | ||
645 | int rc; | ||
646 | struct digital_atr_req *atr_req; | ||
647 | size_t gb_len, min_size; | ||
648 | |||
649 | if (IS_ERR(resp)) { | ||
650 | rc = PTR_ERR(resp); | ||
651 | resp = NULL; | ||
652 | goto exit; | ||
653 | } | ||
654 | |||
655 | if (!resp->len) { | ||
656 | rc = -EIO; | ||
657 | goto exit; | ||
658 | } | ||
659 | |||
660 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) { | ||
661 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2; | ||
662 | |||
663 | ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_106A; | ||
664 | ddev->skb_add_crc = digital_skb_add_crc_a; | ||
665 | ddev->skb_check_crc = digital_skb_check_crc_a; | ||
666 | } else { | ||
667 | min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1; | ||
668 | |||
669 | ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_212F; | ||
670 | ddev->skb_add_crc = digital_skb_add_crc_f; | ||
671 | ddev->skb_check_crc = digital_skb_check_crc_f; | ||
672 | } | ||
673 | |||
674 | if (resp->len < min_size) { | ||
675 | rc = -EIO; | ||
676 | goto exit; | ||
677 | } | ||
678 | |||
679 | if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) { | ||
680 | ddev->skb_add_crc = digital_skb_add_crc_none; | ||
681 | ddev->skb_check_crc = digital_skb_check_crc_none; | ||
682 | } | ||
683 | |||
684 | rc = ddev->skb_check_crc(resp); | ||
685 | if (rc) { | ||
686 | PROTOCOL_ERR("14.4.1.6"); | ||
687 | goto exit; | ||
688 | } | ||
689 | |||
690 | rc = digital_skb_pull_dep_sod(ddev, resp); | ||
691 | if (rc) { | ||
692 | PROTOCOL_ERR("14.4.1.2"); | ||
693 | goto exit; | ||
694 | } | ||
695 | |||
696 | atr_req = (struct digital_atr_req *)resp->data; | ||
697 | |||
698 | if (atr_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT || | ||
699 | atr_req->cmd != DIGITAL_CMD_ATR_REQ) { | ||
700 | rc = -EINVAL; | ||
701 | goto exit; | ||
702 | } | ||
703 | |||
704 | rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, | ||
705 | NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED); | ||
706 | if (rc) | ||
707 | goto exit; | ||
708 | |||
709 | rc = digital_tg_send_atr_res(ddev, atr_req); | ||
710 | if (rc) | ||
711 | goto exit; | ||
712 | |||
713 | gb_len = resp->len - sizeof(struct digital_atr_req); | ||
714 | rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, | ||
715 | NFC_COMM_PASSIVE, atr_req->gb, gb_len); | ||
716 | if (rc) | ||
717 | goto exit; | ||
718 | |||
719 | ddev->poll_tech_count = 0; | ||
720 | |||
721 | rc = 0; | ||
722 | exit: | ||
723 | if (rc) | ||
724 | digital_poll_next_tech(ddev); | ||
725 | |||
726 | dev_kfree_skb(resp); | ||
727 | } | ||