se.c (2b5dbe089f619f995faf2fe6beb7efb705eed302) | se.c (3648dc6d27f648b8e3ce9b48874627a833d53c3a) |
---|---|
1/* 2 * Secure Element driver for STMicroelectronics NFC NCI chip 3 * 4 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. --- 405 unchanged lines hidden (view full) --- 414 ndev->hci_dev->count_pipes = 0; 415 complete(&info->se_info.req_completion); 416 } 417 break; 418 } 419} 420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received); 421 | 1/* 2 * Secure Element driver for STMicroelectronics NFC NCI chip 3 * 4 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. --- 405 unchanged lines hidden (view full) --- 414 ndev->hci_dev->count_pipes = 0; 415 complete(&info->se_info.req_completion); 416 } 417 break; 418 } 419} 420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received); 421 |
422/* 423 * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0) 424 * is rejected 425 */ | |
426static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, | 422static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx, |
427 u8 state) | 423 u8 state) |
428{ 429 struct st_nci_info *info = nci_get_drvdata(ndev); 430 int r; 431 struct sk_buff *sk_host_list; 432 u8 host_id; 433 434 switch (se_idx) { 435 case ST_NCI_UICC_HOST_ID: --- 8 unchanged lines hidden (view full) --- 444 return -EINVAL; 445 } 446 447 /* 448 * Wait for an EVT_HOT_PLUG in order to 449 * retrieve a relevant host list. 450 */ 451 reinit_completion(&info->se_info.req_completion); | 424{ 425 struct st_nci_info *info = nci_get_drvdata(ndev); 426 int r; 427 struct sk_buff *sk_host_list; 428 u8 host_id; 429 430 switch (se_idx) { 431 case ST_NCI_UICC_HOST_ID: --- 8 unchanged lines hidden (view full) --- 440 return -EINVAL; 441 } 442 443 /* 444 * Wait for an EVT_HOT_PLUG in order to 445 * retrieve a relevant host list. 446 */ 447 reinit_completion(&info->se_info.req_completion); |
452 r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE); | 448 r = nci_nfcee_mode_set(ndev, se_idx, state); |
453 if (r != NCI_STATUS_OK) 454 return r; 455 456 mod_timer(&info->se_info.se_active_timer, jiffies + 457 msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG)); 458 info->se_info.se_active = true; 459 460 /* Ignore return value and check in any case the host_list */ 461 wait_for_completion_interruptible(&info->se_info.req_completion); 462 463 /* There might be some "collision" after receiving a HOT_PLUG event 464 * This may cause the CLF to not answer to the next hci command. 465 * There is no possible synchronization to prevent this. 466 * Adding a small delay is the only way to solve the issue. 467 */ | 449 if (r != NCI_STATUS_OK) 450 return r; 451 452 mod_timer(&info->se_info.se_active_timer, jiffies + 453 msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG)); 454 info->se_info.se_active = true; 455 456 /* Ignore return value and check in any case the host_list */ 457 wait_for_completion_interruptible(&info->se_info.req_completion); 458 459 /* There might be some "collision" after receiving a HOT_PLUG event 460 * This may cause the CLF to not answer to the next hci command. 461 * There is no possible synchronization to prevent this. 462 * Adding a small delay is the only way to solve the issue. 463 */ |
468 usleep_range(3000, 5000); | 464 if (info->se_info.se_status->is_ese_present && 465 info->se_info.se_status->is_uicc_present) 466 usleep_range(3000, 5000); |
469 470 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, 471 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); 472 if (r != NCI_HCI_ANY_OK) 473 return r; 474 475 host_id = sk_host_list->data[sk_host_list->len - 1]; 476 kfree_skb(sk_host_list); --- 6 unchanged lines hidden (view full) --- 483} 484 485int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx) 486{ 487 int r; 488 489 pr_debug("st_nci_disable_se\n"); 490 | 467 468 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE, 469 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list); 470 if (r != NCI_HCI_ANY_OK) 471 return r; 472 473 host_id = sk_host_list->data[sk_host_list->len - 1]; 474 kfree_skb(sk_host_list); --- 6 unchanged lines hidden (view full) --- 481} 482 483int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx) 484{ 485 int r; 486 487 pr_debug("st_nci_disable_se\n"); 488 |
491 if (se_idx == NFC_SE_EMBEDDED) { 492 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 493 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); 494 if (r < 0) 495 return r; | 489 /* 490 * According to upper layer, se_idx == NFC_SE_UICC when 491 * info->se_info.se_status->is_uicc_enable is true should never happen 492 * Same for eSE. 493 */ 494 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF); 495 if (r < 0) { 496 /* Do best effort to release SWP */ 497 if (se_idx == NFC_SE_EMBEDDED) { 498 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 499 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, 500 NULL, 0); 501 } 502 return r; |
496 } 497 498 return 0; 499} 500EXPORT_SYMBOL_GPL(st_nci_disable_se); 501 502int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx) 503{ 504 int r; 505 506 pr_debug("st_nci_enable_se\n"); 507 | 503 } 504 505 return 0; 506} 507EXPORT_SYMBOL_GPL(st_nci_disable_se); 508 509int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx) 510{ 511 int r; 512 513 pr_debug("st_nci_enable_se\n"); 514 |
508 if (se_idx == ST_NCI_HCI_HOST_ID_ESE) { | 515 /* 516 * According to upper layer, se_idx == NFC_SE_UICC when 517 * info->se_info.se_status->is_uicc_enable is true should never happen. 518 * Same for eSE. 519 */ 520 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON); 521 if (r == ST_NCI_HCI_HOST_ID_ESE) { 522 st_nci_se_get_atr(ndev); |
509 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 510 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); | 523 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE, 524 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0); |
511 if (r < 0) 512 return r; | |
513 } 514 | 525 } 526 |
527 if (r < 0) { 528 /* 529 * The activation procedure failed, the secure element 530 * is not connected. Remove from the list. 531 */ 532 nfc_remove_se(ndev->nfc_dev, se_idx); 533 return r; 534 } 535 |
|
515 return 0; 516} 517EXPORT_SYMBOL_GPL(st_nci_enable_se); 518 519static int st_nci_hci_network_init(struct nci_dev *ndev) 520{ 521 struct st_nci_info *info = nci_get_drvdata(ndev); 522 struct core_conn_create_dest_spec_params *dest_params; --- 64 unchanged lines hidden (view full) --- 587 kfree(dest_params); 588 589exit: 590 return r; 591} 592 593int st_nci_discover_se(struct nci_dev *ndev) 594{ | 536 return 0; 537} 538EXPORT_SYMBOL_GPL(st_nci_enable_se); 539 540static int st_nci_hci_network_init(struct nci_dev *ndev) 541{ 542 struct st_nci_info *info = nci_get_drvdata(ndev); 543 struct core_conn_create_dest_spec_params *dest_params; --- 64 unchanged lines hidden (view full) --- 608 kfree(dest_params); 609 610exit: 611 return r; 612} 613 614int st_nci_discover_se(struct nci_dev *ndev) 615{ |
595 u8 param[2]; 596 int r; | 616 u8 white_list[2]; 617 int r, wl_size = 0; |
597 int se_count = 0; 598 struct st_nci_info *info = nci_get_drvdata(ndev); 599 600 pr_debug("st_nci_discover_se\n"); 601 602 r = st_nci_hci_network_init(ndev); 603 if (r != 0) 604 return r; 605 606 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags)) 607 return 0; 608 | 618 int se_count = 0; 619 struct st_nci_info *info = nci_get_drvdata(ndev); 620 621 pr_debug("st_nci_discover_se\n"); 622 623 r = st_nci_hci_network_init(ndev); 624 if (r != 0) 625 return r; 626 627 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags)) 628 return 0; 629 |
609 param[0] = ST_NCI_UICC_HOST_ID; 610 param[1] = ST_NCI_HCI_HOST_ID_ESE; 611 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, 612 NCI_HCI_ADMIN_PARAM_WHITELIST, 613 param, sizeof(param)); 614 if (r != NCI_HCI_ANY_OK) 615 return r; | 630 if (info->se_info.se_status->is_ese_present && 631 info->se_info.se_status->is_uicc_present) { 632 white_list[wl_size++] = ST_NCI_UICC_HOST_ID; 633 white_list[wl_size++] = ST_NCI_ESE_HOST_ID; 634 } else if (!info->se_info.se_status->is_ese_present && 635 info->se_info.se_status->is_uicc_present) { 636 white_list[wl_size++] = ST_NCI_UICC_HOST_ID; 637 } else if (info->se_info.se_status->is_ese_present && 638 !info->se_info.se_status->is_uicc_present) { 639 white_list[wl_size++] = ST_NCI_ESE_HOST_ID; 640 } |
616 | 641 |
617 r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID, 618 ST_NCI_SE_MODE_ON); 619 if (r == ST_NCI_UICC_HOST_ID) { | 642 if (wl_size) { 643 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE, 644 NCI_HCI_ADMIN_PARAM_WHITELIST, 645 white_list, wl_size); 646 if (r != NCI_HCI_ANY_OK) 647 return r; 648 } 649 650 if (info->se_info.se_status->is_uicc_present) { |
620 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC); 621 se_count++; 622 } 623 | 651 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC); 652 se_count++; 653 } 654 |
624 /* Try to enable eSE in order to check availability */ 625 r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE, 626 ST_NCI_SE_MODE_ON); 627 if (r == ST_NCI_HCI_HOST_ID_ESE) { 628 nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE, 629 NFC_SE_EMBEDDED); | 655 if (info->se_info.se_status->is_ese_present) { 656 nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED); |
630 se_count++; | 657 se_count++; |
631 st_nci_se_get_atr(ndev); | |
632 } 633 634 return !se_count; 635} 636EXPORT_SYMBOL_GPL(st_nci_discover_se); 637 638int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, 639 u8 *apdu, size_t apdu_length, --- 56 unchanged lines hidden (view full) --- 696 697 pr_debug("\n"); 698 699 info->se_info.se_active = false; 700 701 complete(&info->se_info.req_completion); 702} 703 | 658 } 659 660 return !se_count; 661} 662EXPORT_SYMBOL_GPL(st_nci_discover_se); 663 664int st_nci_se_io(struct nci_dev *ndev, u32 se_idx, 665 u8 *apdu, size_t apdu_length, --- 56 unchanged lines hidden (view full) --- 722 723 pr_debug("\n"); 724 725 info->se_info.se_active = false; 726 727 complete(&info->se_info.req_completion); 728} 729 |
704int st_nci_se_init(struct nci_dev *ndev) | 730int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status) |
705{ 706 struct st_nci_info *info = nci_get_drvdata(ndev); 707 708 init_completion(&info->se_info.req_completion); 709 /* initialize timers */ 710 init_timer(&info->se_info.bwi_timer); 711 info->se_info.bwi_timer.data = (unsigned long)info; 712 info->se_info.bwi_timer.function = st_nci_se_wt_timeout; --- 5 unchanged lines hidden (view full) --- 718 st_nci_se_activation_timeout; 719 info->se_info.se_active = false; 720 721 info->se_info.xch_error = false; 722 723 info->se_info.wt_timeout = 724 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI); 725 | 731{ 732 struct st_nci_info *info = nci_get_drvdata(ndev); 733 734 init_completion(&info->se_info.req_completion); 735 /* initialize timers */ 736 init_timer(&info->se_info.bwi_timer); 737 info->se_info.bwi_timer.data = (unsigned long)info; 738 info->se_info.bwi_timer.function = st_nci_se_wt_timeout; --- 5 unchanged lines hidden (view full) --- 744 st_nci_se_activation_timeout; 745 info->se_info.se_active = false; 746 747 info->se_info.xch_error = false; 748 749 info->se_info.wt_timeout = 750 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI); 751 |
752 info->se_info.se_status = se_status; 753 |
|
726 return 0; 727} 728EXPORT_SYMBOL(st_nci_se_init); 729 730void st_nci_se_deinit(struct nci_dev *ndev) 731{ 732 struct st_nci_info *info = nci_get_drvdata(ndev); 733 734 if (info->se_info.bwi_active) 735 del_timer_sync(&info->se_info.bwi_timer); 736 if (info->se_info.se_active) 737 del_timer_sync(&info->se_info.se_active_timer); 738 739 info->se_info.se_active = false; 740 info->se_info.bwi_active = false; 741} 742EXPORT_SYMBOL(st_nci_se_deinit); 743 | 754 return 0; 755} 756EXPORT_SYMBOL(st_nci_se_init); 757 758void st_nci_se_deinit(struct nci_dev *ndev) 759{ 760 struct st_nci_info *info = nci_get_drvdata(ndev); 761 762 if (info->se_info.bwi_active) 763 del_timer_sync(&info->se_info.bwi_timer); 764 if (info->se_info.se_active) 765 del_timer_sync(&info->se_info.se_active_timer); 766 767 info->se_info.se_active = false; 768 info->se_info.bwi_active = false; 769} 770EXPORT_SYMBOL(st_nci_se_deinit); 771 |