diff --git a/CMakeLists.txt b/CMakeLists.txt index 87cdf61..39ecce6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,6 @@ set_source_files_properties( target_sources(pico_ccid PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c - ${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c ${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c ${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c ${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c @@ -67,4 +66,4 @@ pico_add_extra_outputs(pico_ccid) #target_compile_definitions(pico_ccid PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1) -target_link_libraries(pico_ccid PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc) +target_link_libraries(pico_ccid PRIVATE pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc) diff --git a/src/ccid/ccid2040.c b/src/ccid/ccid2040.c index 76aa668..0b941c1 100644 --- a/src/ccid/ccid2040.c +++ b/src/ccid/ccid2040.c @@ -15,20 +15,25 @@ * along with this program. If not, see . */ - #include // Pico #include "pico/stdlib.h" -#include // For memcpy #include -#include "bsp/board.h" -#include "tusb.h" -#include "usb_descriptors.h" -#include "device/usbd_pvt.h" +// Include descriptor struct definitions +#include "usb_common.h" +// USB register definitions from pico-sdk +#include "hardware/regs/usb.h" +// USB hardware struct definitions from pico-sdk +#include "hardware/structs/usb.h" +// For interrupt enable and numbers +#include "hardware/irq.h" +// For resetting the USB controller +#include "hardware/resets.h" + #include "pico/multicore.h" #include "random.h" #include "ccid2040.h" @@ -271,105 +276,8 @@ static void ccid_notify_slot_change(struct ccid *c) #define USB_CCID_TIMEOUT (50) -#define GPG_THREAD_TERMINATED 0xffff -#define GPG_ACK_TIMEOUT 0x6600 - -static void ccid_init_cb(void) { - struct ccid *c = &ccid; - TU_LOG1("-------- CCID INIT\r\n"); - vendord_init(); - - //ccid_notify_slot_change(c); -} - -static void ccid_reset_cb(uint8_t rhport) { - TU_LOG1("-------- CCID RESET\r\n"); - itf_num = 0; - vendord_reset(rhport); -} - -static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { - uint8_t *itf_vendor = (uint8_t *)malloc(sizeof(uint8_t)*max_len); - TU_LOG1("-------- CCID OPEN\r\n"); - TU_VERIFY(itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0); - - //vendord_open expects a CLASS_VENDOR interface class - memcpy(itf_vendor, itf_desc, sizeof(uint8_t)*max_len); - ((tusb_desc_interface_t *)itf_vendor)->bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC; - vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len); - free(itf_vendor); - - uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t); - TU_VERIFY(max_len >= drv_len, 0); - - itf_num = itf_desc->bInterfaceNumber; - return drv_len; -} - -// Support for parameterized reset via vendor interface control request -static bool ccid_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const * request) { - // nothing to do with DATA & ACK stage - TU_LOG2("-------- CCID CTRL XFER\r\n"); - if (stage != CONTROL_STAGE_SETUP) return true; - - if (request->wIndex == itf_num) - { - TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\r\n",request->bmRequestType,request->bRequest, request->wValue, request->wLength); -/* -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL - if (request->bRequest == RESET_REQUEST_BOOTSEL) { -#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; -#else - uint gpio_mask = 0u; -#endif -#if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED - if (request->wValue & 0x100) { - gpio_mask = 1u << (request->wValue >> 9u); - } -#endif - reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); - // does not return, otherwise we'd return true - } -#endif - -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT - if (request->bRequest == RESET_REQUEST_FLASH) { - watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); - return true; - } -#endif -*/ - return true; - } - return false; -} - -static bool ccid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - //TU_LOG2("------ CALLED XFER_CB\r\n"); - return vendord_xfer_cb(rhport, ep_addr, result, xferred_bytes); - //return true; -} - - -static usbd_class_driver_t const ccid_driver = { -#if CFG_TUSB_DEBUG >= 2 - .name = "CCID", -#endif - .init = ccid_init_cb, - .reset = ccid_reset_cb, - .open = ccid_open, - .control_xfer_cb = ccid_control_xfer_cb, - .xfer_cb = ccid_xfer_cb, - .sof = NULL -}; - -// Implement callback to add our custom driver -usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { - *driver_count = 1; - return &ccid_driver; -} - +#define CCID_THREAD_TERMINATED 0xffff +#define CCID_ACK_TIMEOUT 0x6600 static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; @@ -379,6 +287,44 @@ void led_set_blink(uint32_t mode) { void execute_tasks(); +#include "hardware/structs/ioqspi.h" +#define BUTTON_STATE_ACTIVE 0 + +bool __no_inline_not_in_flash_func(get_bootsel_button)() { + const uint CS_PIN_INDEX = 1; + + // Must disable interrupts, as interrupt handlers may be in flash, and we + // are about to temporarily disable flash access! + uint32_t flags = save_and_disable_interrupts(); + + // Set chip select to Hi-Z + hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, + GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, + IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); + + // Note we can't call into any sleep functions in flash right now + for (volatile int i = 0; i < 1000; ++i); + + // The HI GPIO registers in SIO can observe and control the 6 QSPI pins. + // Note the button pulls the pin *low* when pressed. + bool button_state = (sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX)); + + // Need to restore the state of chip select, else we are going to have a + // bad time when we return to code in flash! + hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl, + GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB, + IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS); + + restore_interrupts(flags); + + return button_state; +} + +static uint32_t board_button_read(void) +{ + return BUTTON_STATE_ACTIVE == get_bootsel_button(); +} + static bool wait_button() { uint32_t start_button = board_millis(); bool timeout = false; @@ -406,12 +352,12 @@ static bool wait_button() { return timeout; } -void usb_tx_enable(const uint8_t *buf, uint32_t len) { +void usb_tx_enable(const uint8_t *wbuf, uint32_t len) { if (len > 0) { - if (buf[0] != 0x81) - DEBUG_PAYLOAD(buf,len); - //DEBUG_PAYLOAD(buf,len); - tud_vendor_write(buf, len); + //if (wbuf[0] != 0x81) + DEBUG_PAYLOAD(wbuf,len); + //DEBUG_PAYLOAD(wbuf,len); + usb_write(wbuf, len); } } @@ -439,7 +385,7 @@ static const uint8_t ATR_head[] = { /* Send back ATR (Answer To Reset) */ static enum ccid_state ccid_power_on(struct ccid *c) { - TU_LOG1("!!! CCID POWER ON %d\r\n",c->application); + printf("!!! CCID POWER ON %d\r\n",c->application); uint8_t p[CCID_MSG_HEADER_SIZE+1]; /* >= size of historical_bytes -1 */ size_t size_atr = (ccid_atr ? ccid_atr[0] : 0); if (c->application == 0) { @@ -499,8 +445,10 @@ static void ccid_send_status(struct ccid *c) { /* This is a single packet Bulk-IN transaction */ c->epi->buf = NULL; c->epi->tx_done = 1; + memcpy(endp1_tx_buf, ccid_reply, CCID_MSG_HEADER_SIZE); + usb_tx_enable(endp1_tx_buf, CCID_MSG_HEADER_SIZE); c->tx_busy = 1; } @@ -786,7 +734,7 @@ static enum ccid_state ccid_handle_data(struct ccid *c) { enum ccid_state next_state = c->ccid_state; - TU_LOG3("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_header.msg_type,CCID_STATE_START); + printf("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_header.msg_type,CCID_STATE_START); if (c->err != 0) { ccid_reset(c); ccid_error(c, CCID_OFFSET_DATA_LEN); @@ -952,7 +900,7 @@ static int end_abdata(struct ep_out *epo, size_t orig_len) { if (orig_len == USB_LL_BUF_SIZE && len < c->ccid_header.data_len) /* more packet comes */ return 1; - +printf("!!end_abdata len %d %d\r\n",len,c->ccid_header.data_len); if (len != c->ccid_header.data_len) epo->err = 1; @@ -963,7 +911,7 @@ static int end_cmd_apdu_head(struct ep_out *epo, size_t orig_len) { struct ccid *c = (struct ccid *)epo->priv; (void)orig_len; - +printf("!!end_cmd_apdu_head len %d %d %d\r\n",epo->cnt,c->ccid_header.data_len,epo->cnt); if (epo->cnt < 4 || epo->cnt != c->ccid_header.data_len) { epo->err = 1; return 0; @@ -1173,6 +1121,7 @@ static void ccid_rx_ready(uint16_t len) { int offset = 0; int cont; size_t orig_len = len; + printf("epo buf_len %d\r\n",epo->buf_len); while (epo->err == 0) { if (len == 0) break; @@ -1257,13 +1206,13 @@ static void ccid_tx_done () { } static int usb_event_handle(struct ccid *c) { - TU_LOG3("!!! tx %d, vendor %d, cfg %d, rx %d\r\n",c->tx_busy,tud_vendor_n_write_available(0),CFG_TUD_VENDOR_TX_BUFSIZE,tud_vendor_available()); - if (c->tx_busy == 1 && tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE) { + //printf("!!! tx %d, rx %d\r\n",c->tx_busy,usb_read_available()); + //if (c->tx_busy == 1 && tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE) { + if (c->tx_busy == 1) ccid_tx_done (); - } - if (tud_vendor_available() && c->epo->ready) { - uint32_t count = tud_vendor_read(endp1_rx_buf, sizeof(endp1_rx_buf)); - if (endp1_rx_buf[0] != 0x65) + if (usb_read_available() && c->epo->ready) { + uint32_t count = usb_read(endp1_rx_buf, sizeof(endp1_rx_buf)); + //if (endp1_rx_buf[0] != 0x65) DEBUG_PAYLOAD(endp1_rx_buf, count); //DEBUG_PAYLOAD(endp1_rx_buf, count); ccid_rx_ready(count); @@ -1349,9 +1298,9 @@ void card_thread() { void ccid_task(void) { struct ccid *c = &ccid; - if (tud_vendor_mounted()) { + if (usb_is_configured()) { // connected and there are data available - if ((c->epo->ready && tud_vendor_available()) || (tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE && c->tx_busy == 1)) { + if ((c->epo->ready && usb_read_available()) || (c->tx_busy == 1)) { if (usb_event_handle (c) != 0) { if (c->application) { uint32_t flag = EV_EXIT; @@ -1369,7 +1318,7 @@ void ccid_task(void) { uint32_t m = 0x0; bool has_m = queue_try_remove(&c->ccid_comm, &m); if (m != 0) - TU_LOG3("\r\n ------ M = %d\r\n",m); + printf("\r\n ------ M = %d\r\n",m); if (has_m) { if (m == EV_CARD_CHANGE) { if (c->ccid_state == CCID_STATE_NOCARD) @@ -1393,7 +1342,7 @@ void ccid_task(void) { else if (m == EV_EXEC_FINISHED) { if (c->ccid_state == CCID_STATE_EXECUTE) { exec_done: - if (c->a->sw == GPG_THREAD_TERMINATED) { + if (c->a->sw == CCID_THREAD_TERMINATED) { c->sw1sw2[0] = 0x90; c->sw1sw2[1] = 0x00; c->state = APDU_STATE_RESULT; @@ -1441,9 +1390,7 @@ void ccid_task(void) { timeout -= MIN(board_millis()-prev_millis,timeout); if (timeout == 0) { if (c->timeout_cnt == 7 && c->ccid_state == CCID_STATE_ACK_REQUIRED_1) { - c->a->sw = GPG_ACK_TIMEOUT; - c->a->res_apdu_data_len = 0; - c->a->sw = GPG_ACK_TIMEOUT; + c->a->sw = CCID_ACK_TIMEOUT; c->a->res_apdu_data_len = 0; goto exec_done; @@ -1455,10 +1402,6 @@ void ccid_task(void) { } } -void tud_mount_cb() { - ccid_prepare_receive (&ccid); -} - void led_blinking_task() { #ifdef PICO_DEFAULT_LED_PIN static uint32_t start_ms = 0; @@ -1567,7 +1510,7 @@ pico_unique_board_id_t unique_id; void execute_tasks() { prev_millis = board_millis(); ccid_task(); - tud_task(); // tinyusb device task + //tud_task(); // tinyusb device task led_blinking_task(); } @@ -1575,7 +1518,8 @@ int main(void) { struct apdu *a = &apdu; struct ccid *c = &ccid; - board_init(); + //board_init(); + stdio_init_all(); #ifdef PIMORONI_TINY2040 gpio_init(TINY2040_LED_R_PIN); @@ -1590,11 +1534,10 @@ int main(void) { gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); #endif #endif - led_off_all(); - tusb_init(); + usb_init(); prepare_ccid(); @@ -1603,6 +1546,8 @@ int main(void) { low_flash_init(); init_rtc(); + + ccid_prepare_receive(&ccid); while (1) { execute_tasks(); diff --git a/src/ccid/ccid2040.h b/src/ccid/ccid2040.h index e9ef919..2fa1d2f 100644 --- a/src/ccid/ccid2040.h +++ b/src/ccid/ccid2040.h @@ -18,11 +18,16 @@ #ifndef _CCID2040_H_ #define _CCID2040_H_ -#include "ccid.h" -#include "tusb.h" #include "file.h" #include "pico/unique_id.h" #include "pico/util/queue.h" +#include + +#include "pico/time.h" +static inline uint32_t board_millis(void) +{ + return to_ms_since_boot(get_absolute_time()); +} #define USB_REQ_CCID 0xA1 diff --git a/src/fs/file.c b/src/fs/file.c index ca54ca8..1e082ea 100644 --- a/src/fs/file.c +++ b/src/fs/file.c @@ -16,9 +16,9 @@ */ #include "file.h" -#include "tusb.h" #include "ccid2040.h" #include +#include extern const uintptr_t end_data_pool; extern const uintptr_t start_data_pool; diff --git a/src/fs/flash.c b/src/fs/flash.c index e298cb6..f901494 100644 --- a/src/fs/flash.c +++ b/src/fs/flash.c @@ -22,7 +22,6 @@ #include "pico/stdlib.h" #include "hardware/flash.h" #include "ccid2040.h" -#include "tusb.h" #include "file.h" /* diff --git a/src/rng/neug.c b/src/rng/neug.c index 63c731a..df0ade5 100644 --- a/src/rng/neug.c +++ b/src/rng/neug.c @@ -27,9 +27,14 @@ #include "hardware/structs/rosc.h" #include "hardware/gpio.h" #include "hardware/adc.h" -#include "bsp/board.h" #include "pico/unique_id.h" +#include "pico/time.h" +static inline uint32_t board_millis(void) +{ + return to_ms_since_boot(get_absolute_time()); +} + void adc_start() { adc_init(); adc_gpio_init(27); diff --git a/src/usb/usb.c b/src/usb/usb.c index d786adc..f7aa65d 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -23,7 +23,7 @@ // For resetting the USB controller #include "hardware/resets.h" - +extern void led_blinking_task(); // Device descriptors @@ -327,6 +327,27 @@ void usb_bus_reset(void) { configured = false; } +bool usb_is_configured(void) { + return configured; +} + +uint32_t usb_write(uint8_t *buffer, size_t buffer_size) { + struct usb_endpoint_configuration *ep = usb_get_endpoint_configuration(EP2_IN_ADDR); + usb_start_transfer(ep, buffer, MIN(buffer_size, 64)); + return MIN(buffer_size, 64); +} + +void usb_init() { + usb_device_init(); + + // Wait until configured + while (!usb_is_configured()) { + tight_loop_contents(); + led_blinking_task(); + } + usb_start_transfer(usb_get_endpoint_configuration(EP1_OUT_ADDR), NULL, 64); +} + /** * @brief Send the requested string descriptor to the host. * @@ -564,30 +585,45 @@ void ep0_out_handler(uint8_t *buf, uint16_t len) { ; } -#define DEBUG_PAYLOAD(p,s) { \ - printf("Payload %s (%d bytes):\r\n", #p,s);\ - for (int i = 0; i < s; i += 16) {\ - printf("%07Xh : ",i+p);\ - for (int j = 0; j < 16; j++) {\ - if (j < s-i) printf("%02X ",(p)[i+j]);\ - else printf(" ");\ - if (j == 7) printf(" ");\ - } printf(": "); \ - for (int j = 0; j < MIN(16,s-i); j++) {\ - printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\ - if (j == 7) printf(" ");\ - }\ - printf("\r\n");\ - } printf("\r\n"); \ - } - - // Device specific functions +static uint8_t rx_buffer[4096]; +static uint16_t w_offset = 0, r_offset = 0; void ep1_out_handler(uint8_t *buf, uint16_t len) { printf("RX %d bytes from host\n", len); // Send data back to host - struct usb_endpoint_configuration *ep = usb_get_endpoint_configuration(EP2_IN_ADDR); - DEBUG_PAYLOAD(buf,len); + uint16_t size = MIN(sizeof(rx_buffer)-w_offset,len); + if (size > 0) { + memcpy(rx_buffer+w_offset, buf, size); + w_offset += size; + } + /* + do { + uint16_t size = MIN(sizeof(rx_buffer)-w_offset,len); + memcpy(rx_buffer+w_offset, buf, size); + len -= size; + w_offset += size; + if (w_offset == sizeof(rx_buffer)) + w_offset = 0; + buf += size; + } while (len > 0); + */ +} + +uint16_t usb_read_available() { + return w_offset - r_offset; +} + +uint16_t usb_read(uint8_t *buffer, size_t buffer_size) { + if (w_offset-r_offset > 0) { + uint16_t size = MIN(buffer_size, w_offset-r_offset); + memcpy(buffer, rx_buffer+r_offset, size); + r_offset += size; + if (r_offset == w_offset) { + r_offset = w_offset = 0; + } + return size; + } + return 0; } void ep2_in_handler(uint8_t *buf, uint16_t len) { @@ -595,7 +631,7 @@ void ep2_in_handler(uint8_t *buf, uint16_t len) { // Get ready to rx again from host usb_start_transfer(usb_get_endpoint_configuration(EP1_OUT_ADDR), NULL, 64); } - +/* int main(void) { stdio_init_all(); printf("USB Device Low-Level hardware example\n"); @@ -639,3 +675,4 @@ int main(void) { return 0; } +*/ diff --git a/src/usb/usb_common.h b/src/usb/usb_common.h index 66c8a26..cb53609 100644 --- a/src/usb/usb_common.h +++ b/src/usb/usb_common.h @@ -315,6 +315,11 @@ static const unsigned char *descriptor_strings[] = { #define USB_REQ_CCID 0xA1 +extern uint16_t usb_read(uint8_t *buffer, size_t buffer_size); +extern uint16_t usb_read_available(); +extern uint32_t usb_write(uint8_t *buffer, size_t buffer_size); +extern bool usb_is_configured(); +extern void usb_init(); #endif