/* * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * Copyright (c) 2022 Pol Henarejos. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3. * * 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include "pico_keys.h" #if defined(PICO_PLATFORM) #include "pico/stdlib.h" #include "pico/multicore.h" #include "bsp/board.h" #endif #include "usb.h" #include "apdu.h" #ifndef ENABLE_EMULATION #include "tusb.h" #else #include "emulation.h" #endif // For memcpy #include #include // Device specific functions static uint32_t *timeout_counter = NULL; static uint8_t card_locked_itf = 0; // no locked static void *(*card_locked_func)(void *) = NULL; #ifndef ENABLE_EMULATION static mutex_t mutex; extern void usb_desc_setup(); #endif #if !defined(PICO_PLATFORM) && !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) #ifdef _MSC_VER #include "pthread_win32.h" #endif pthread_t hcore0, hcore1; #endif #ifdef USB_ITF_HID uint8_t ITF_HID_CTAP = ITF_INVALID, ITF_HID_KB = ITF_INVALID; uint8_t ITF_HID = ITF_INVALID, ITF_KEYBOARD = ITF_INVALID; uint8_t ITF_HID_TOTAL = 0; extern void hid_init(); #endif #ifdef USB_ITF_CCID uint8_t ITF_SC_CCID = ITF_INVALID, ITF_SC_WCID = ITF_INVALID; uint8_t ITF_CCID = ITF_INVALID, ITF_WCID = ITF_INVALID; uint8_t ITF_SC_TOTAL = 0; extern void ccid_init(); #endif uint8_t ITF_TOTAL = 0; void usb_set_timeout_counter(uint8_t itf, uint32_t v) { timeout_counter[itf] = v; } queue_t usb_to_card_q = {0}; queue_t card_to_usb_q = {0}; #ifndef ENABLE_EMULATION extern tusb_desc_device_t desc_device; #endif void usb_init() { #ifndef ENABLE_EMULATION if (phy_data.vidpid_present) { desc_device.idVendor = phy_data.vid; desc_device.idProduct = phy_data.pid; } else { phy_data.vid = desc_device.idVendor; phy_data.pid = desc_device.idProduct; } mutex_init(&mutex); #endif queue_init(&card_to_usb_q, sizeof(uint32_t), 64); queue_init(&usb_to_card_q, sizeof(uint32_t), 64); uint8_t enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB; #ifndef ENABLE_EMULATION if (phy_data.enabled_usb_itf_present) { enabled_usb_itf = phy_data.enabled_usb_itf; } #endif #ifdef USB_ITF_HID ITF_HID_TOTAL = 0; #endif #ifdef USB_ITF_CCID ITF_SC_TOTAL = 0; #endif ITF_TOTAL = 0; #ifdef USB_ITF_HID if (enabled_usb_itf & PHY_USB_ITF_HID) { ITF_HID_CTAP = ITF_HID_TOTAL++; ITF_HID = ITF_TOTAL++; } if (enabled_usb_itf & PHY_USB_ITF_KB) { ITF_HID_KB = ITF_HID_TOTAL++; ITF_KEYBOARD = ITF_TOTAL++; } #endif #ifdef USB_ITF_CCID if (enabled_usb_itf & PHY_USB_ITF_CCID) { ITF_SC_CCID = ITF_SC_TOTAL++; ITF_CCID = ITF_TOTAL++; } if (enabled_usb_itf & PHY_USB_ITF_WCID) { ITF_SC_WCID = ITF_SC_TOTAL++; ITF_WCID = ITF_TOTAL++; } #endif card_locked_itf = ITF_TOTAL; if (timeout_counter == NULL) { timeout_counter = (uint32_t *)calloc(ITF_TOTAL, sizeof(uint32_t)); } #ifdef USB_ITF_HID if (ITF_HID_TOTAL > 0) { hid_init(); } #endif #ifdef USB_ITF_CCID if (ITF_SC_TOTAL > 0) { ccid_init(); } #endif #ifdef ESP_PLATFORM usb_desc_setup(); #endif } uint32_t timeout = 0; void timeout_stop() { timeout = 0; } void timeout_start() { timeout = board_millis(); } bool is_busy() { return timeout > 0; } void usb_send_event(uint32_t flag) { #ifndef ENABLE_EMULATION mutex_enter_blocking(&mutex); #endif queue_add_blocking(&usb_to_card_q, &flag); if (flag == EV_CMD_AVAILABLE) { timeout_start(); } uint32_t m; queue_remove_blocking(&card_to_usb_q , &m); #ifndef ENABLE_EMULATION mutex_exit(&mutex); #endif } extern void low_flash_init(); void card_init_core1() { low_flash_init_core1(); } uint16_t finished_data_size = 0; void card_start(uint8_t itf, void *(*func)(void *)) { timeout_start(); if (card_locked_itf != itf || card_locked_func != func) { if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) { card_exit(); } if (func) { multicore_reset_core1(); multicore_launch_core1(func); } led_set_mode(MODE_MOUNTED); card_locked_itf = itf; card_locked_func = func; } } void card_exit() { if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) { usb_send_event(EV_EXIT); uint32_t m; while (queue_is_empty(&usb_to_card_q) == false) { if (queue_try_remove(&usb_to_card_q, &m) == false) { break; } } while (queue_is_empty(&card_to_usb_q) == false) { #ifndef ENABLE_EMULATION mutex_enter_blocking(&mutex); #endif if (queue_try_remove(&card_to_usb_q, &m) == false) { break; } #ifndef ENABLE_EMULATION mutex_exit(&mutex); #endif } led_set_mode(MODE_SUSPENDED); #ifdef ESP_PLATFORM hcore1 = NULL; #endif } card_locked_itf = ITF_TOTAL; card_locked_func = NULL; } extern void hid_task(); extern void ccid_task(); extern void emul_task(); void usb_task() { #ifdef USB_ITF_HID hid_task(); #endif #ifdef ENABLE_EMULATION emul_task(); #else #ifdef USB_ITF_CCID ccid_task(); #endif #endif } int card_status(uint8_t itf) { if (card_locked_itf == itf) { uint32_t m = 0x0; #ifndef ENABLE_EMULATION mutex_enter_blocking(&mutex); #endif bool has_m = queue_try_remove(&card_to_usb_q, &m); #ifndef ENABLE_EMULATION mutex_exit(&mutex); #endif //if (m != 0) // printf("\n ------ M = %lu\n",m); if (has_m) { if (m == EV_EXEC_FINISHED) { timeout_stop(); led_set_mode(MODE_MOUNTED); return PICOKEY_OK; } #ifndef ENABLE_EMULATION else if (m == EV_PRESS_BUTTON) { uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED; queue_try_add(&usb_to_card_q, &flag); } #endif return PICOKEY_ERR_FILE_NOT_FOUND; } else { if (timeout > 0) { if (timeout + timeout_counter[itf] < board_millis()) { timeout = board_millis(); return PICOKEY_ERR_BLOCKED; } } } } return PICOKEY_ERR_FILE_NOT_FOUND; } #ifndef USB_ITF_CCID #include "device/usbd_pvt.h" usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { *driver_count = 0; return NULL; } #endif