From d63e3ead5abb3298fa58f014e7b0bad38b531343 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 19 Jan 2011 14:36:04 +0900 Subject: [PATCH] PIN input support (dial) --- ChangeLog | 18 ++++ boards/STBEE_MINI/board.c | 56 ++++++++++ boards/STBEE_MINI/board.h | 4 +- src/gnuk.h | 12 ++- src/pin-dial.c | 222 ++++++++++++++++++++++++++++++++++++++ src/usb-icc.c | 35 ++++-- src/usb_desc.c | 6 +- 7 files changed, 339 insertions(+), 14 deletions(-) create mode 100644 src/pin-dial.c diff --git a/ChangeLog b/ChangeLog index 2142adb..dd7d68c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2011-01-19 NIIBE Yutaka + + * src/pin-dial.c: New. + + * boards/STBEE_MINI/board.c (hwinit1): Add PINPAD_DIAL_SUPPORT. + (dial_sw_disable, dial_sw_enable, EXTI2_IRQHandler): New. + + * src/gnuk.h: Add PINPAD_DIAL_SUPPORT. + + * src/usb-icc.c (icc_handle_data): Handle PIN modification. + + * src/usb_desc.c (gnukConfigDescriptor): bPinSupport = 3 when + PINPAD_DIAL_SUPPORT is enabled. + +2011-01-18 NIIBE Yutaka + + * src/pin-cir.c (pin_main): Call cir_ext_disable at the end. + 2011-01-17 NIIBE Yutaka * src/gnuk.h (PIN_INPUT_CURRENT, PIN_INPUT_NEW) diff --git a/boards/STBEE_MINI/board.c b/boards/STBEE_MINI/board.c index 82a971d..edc53f7 100644 --- a/boards/STBEE_MINI/board.c +++ b/boards/STBEE_MINI/board.c @@ -21,6 +21,7 @@ hwinit1 (void) ; /* Wait for JTAG debugger connection */ palWritePort(IOPORT2, 0xffff); /* All set */ +#if defined(PINPAD_CIR_SUPPORT) /* EXTI0 <= PB0 */ AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI0_PB; EXTI->IMR = 0; @@ -46,6 +47,33 @@ hwinit1 (void) TIM3->ARR = 18000; /* 18 ms */ /* Generate UEV to upload PSC and ARR */ TIM3->EGR = TIM_EGR_UG; +#elif defined(PINPAD_DIAL_SUPPORT) + /* EXTI2 <= PB2 */ + AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI2_PB; + EXTI->IMR = 0; + EXTI->FTSR = EXTI_FTSR_TR2; + NVICEnableVector(EXTI2_IRQn, + CORTEX_PRIORITY_MASK(CORTEX_MINIMUM_PRIORITY)); + + /* TIM4 */ + RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; + RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST; + RCC->APB1RSTR = 0; + + TIM4->CR1 = TIM_CR1_URS | TIM_CR1_ARPE | TIM_CR1_CKD_1; + TIM4->CR2 = 0; + TIM4->SMCR = TIM_SMCR_SMS_0; + TIM4->DIER = 0; /* no interrupt */ + TIM4->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0 + | TIM_CCMR1_IC1F_0 | TIM_CCMR1_IC1F_1 | TIM_CCMR1_IC1F_2 | TIM_CCMR1_IC1F_3 + | TIM_CCMR1_IC2F_0 | TIM_CCMR1_IC2F_1 | TIM_CCMR1_IC2F_2 | TIM_CCMR1_IC2F_3; + TIM4->CCMR2 = 0; + TIM4->CCER = 0; + TIM4->PSC = 0; + TIM4->ARR = 31; + /* Generate UEV to upload PSC and ARR */ + TIM4->EGR = TIM_EGR_UG; +#endif #endif /* * Disable JTAG and SWD, done after hwinit1_common as HAL resets AFIO @@ -74,6 +102,7 @@ set_led (int value) } #if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) void cir_ext_disable (void) { @@ -111,4 +140,31 @@ CH_IRQ_HANDLER (TIM3_IRQHandler) chSysUnlockFromIsr(); CH_IRQ_EPILOGUE(); } +#elif defined(PINPAD_DIAL_SUPPORT) +void +dial_sw_disable (void) +{ + EXTI->PR = EXTI_PR_PR2; + EXTI->IMR &= ~EXTI_IMR_MR2; +} + +void +dial_sw_enable (void) +{ + EXTI->IMR |= EXTI_IMR_MR2; +} + +extern void dial_sw_interrupt (void); + +CH_IRQ_HANDLER (EXTI2_IRQHandler) +{ + CH_IRQ_PROLOGUE (); + chSysLockFromIsr (); + + dial_sw_interrupt (); + + chSysUnlockFromIsr (); + CH_IRQ_EPILOGUE (); +} +#endif #endif diff --git a/boards/STBEE_MINI/board.h b/boards/STBEE_MINI/board.h index 7853a0b..8238c91 100644 --- a/boards/STBEE_MINI/board.h +++ b/boards/STBEE_MINI/board.h @@ -107,8 +107,8 @@ /* Port B setup. */ #define GPIOB_CIR 0 #define GPIOB_BUTTON 2 -#define GPIOB_ROT_A 3 -#define GPIOB_ROT_B 4 +#define GPIOB_ROT_A 6 +#define GPIOB_ROT_B 7 #define GPIOB_7SEG_DP 15 #define GPIOB_7SEG_A 14 diff --git a/src/gnuk.h b/src/gnuk.h index ca4e5a2..2a025a1 100644 --- a/src/gnuk.h +++ b/src/gnuk.h @@ -312,15 +312,19 @@ extern void flash_cnt123_write_internal (const uint8_t *p, int which, int v); extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len); #if defined(PINPAD_SUPPORT) +#if defined(PINPAD_CIR_SUPPORT) extern void cir_ext_disable (void); extern void cir_ext_enable (void); - +#elif defined(PINPAD_DIAL_SUPPORT) +extern void dial_sw_disable (void); +extern void dial_sw_enable (void); +#endif +#define PIN_INPUT_CURRENT 1 +#define PIN_INPUT_NEW 2 +#define PIN_INPUT_CONFIRM 3 #define MAX_PIN_CHARS 32 extern uint8_t pin_input_buffer[MAX_PIN_CHARS]; extern uint8_t pin_input_len; -#define PIN_INPUT_CURRENT 1 -#define PIN_INPUT_NEW 2 -#define PIN_INPUT_CONFIRM 3 extern msg_t pin_main (void *arg); #endif diff --git a/src/pin-dial.c b/src/pin-dial.c new file mode 100644 index 0000000..d18ff65 --- /dev/null +++ b/src/pin-dial.c @@ -0,0 +1,222 @@ +/* + * pin-dial.c -- PIN input device support (rotary encoder + push switch) + * + * Copyright (C) 2011 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Gnuk 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 General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "config.h" +#include "ch.h" +#include "hal.h" +#include "board.h" +#include "gnuk.h" + +uint8_t pin_input_buffer[MAX_PIN_CHARS]; +uint8_t pin_input_len; + +#define LED_DISP_BLINK_INTERVAL0 MS2ST(150) +#define LED_DISP_BLINK_INTERVAL1 MS2ST(100) + +/* + * PB6 TIM4_CH1 + * PB7 TIM4_CH2 + * + * TIM4_SMCR + * SMS = 001 + * TIM4_CCER + * CC1P = 0 + * CC2P = 0 + * TIM4_CCMR1 + * CC1S= 01 + * CC2S= 01 + * TIM4_CR1 + * CEN= 1 + */ + +#define OFF '\x00' +#define ENTER '\x0a' +static struct led_pattern { uint8_t c, v; } led_pattern[] = +{ + /* char : dp a b c d e f g */ + { ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */ + { ' ', 0xff }, /* SPC : 1 1 1 1 1 1 1 1 */ + { '0', 0x81 }, /* 0 : 1 0 0 0 0 0 0 1 */ + { '1', 0xcf }, /* 1 : 1 1 0 0 1 1 1 1 */ + { '2', 0x92 }, /* 2 : 1 0 0 1 0 0 1 0 */ + { '3', 0x86 }, /* 3 : 1 0 0 0 0 1 1 0 */ + { '4', 0xcc }, /* 4 : 1 1 0 0 1 1 0 0 */ + { '5', 0xa4 }, /* 5 : 1 0 1 0 0 1 0 0 */ + { '6', 0xa0 }, /* 6 : 1 0 1 0 0 0 0 0 */ + { '7', 0x8d }, /* 7 : 1 0 0 0 1 1 0 1 */ + { '8', 0x80 }, /* 8 : 1 0 0 0 0 0 0 0 */ + { '9', 0x84 }, /* 9 : 1 0 0 0 0 1 0 0 */ + { 'A', 0x88 }, /* A : 1 0 0 0 1 0 0 0 */ + { 'B', 0xe0 }, /* b : 1 1 1 0 0 0 0 0 */ + { 'C', 0xb1 }, /* C : 1 0 1 1 0 0 0 1 */ + { 'D', 0xc2 }, /* d : 1 1 0 0 0 0 1 0 */ + { 'E', 0xb0 }, /* E : 1 0 1 1 0 0 0 0 */ + { 'F', 0xb8 }, /* F : 1 0 1 1 1 0 0 0 */ + + { 'G', 0xa1 }, /* G : 1 0 1 0 0 0 0 1 */ + { '\xff', 0xce }, /* -| : 1 1 0 0 1 1 1 0 (backspace) */ +}; + +#define LENGTH_LED_PATTERN (int)(sizeof led_pattern / sizeof (struct led_pattern)) + +static void +led_disp (uint8_t c) +{ + uint16_t v = palReadPort (IOPORT2) | 0x00ff; + + if (c == OFF) + v |= 0xff00; + else + { + int i; + + v &= 0x80ff; + for (i = 0; i < LENGTH_LED_PATTERN; i++) + if (led_pattern[i].c == c) + { + v |= ((led_pattern[i].v & 0x7f) << 8); /* Don't touch DP. */ + break; + } + else if (led_pattern[i].c > c) + { + v |= 0x7f00; /* default: SPC */ + break; + } + } + + palWritePort (IOPORT2, v); +} + +static void +blink_dp (void) +{ + uint16_t v = palReadPort (IOPORT2) | 0x00ff; + + v ^= 0x8000; + palWritePort (IOPORT2, v); +} + +static Thread *pin_thread; +#define EV_SW_PUSH (eventmask_t)1 + +void +dial_sw_interrupt (void) +{ + dial_sw_disable (); + chEvtSignalI (pin_thread, EV_SW_PUSH); + palClearPad (IOPORT1, GPIOA_LED2); +} + + +msg_t +pin_main (void *arg) +{ + int msg_code = (int)arg; + uint16_t count, count_prev; + uint8_t input_mode; + uint8_t sw_push_count; + uint8_t sw_event; + + (void)msg_code; + + pin_thread = chThdSelf (); + led_disp (' '); + + TIM4->CNT = 0; + TIM4->CR1 |= TIM_CR1_CEN; + input_mode = 0; + count = count_prev = 0; + pin_input_len = 0; + sw_push_count = 0; + sw_event = 0; + + while (!chThdShouldTerminate ()) + { + eventmask_t m; + + blink_dp (); + dial_sw_enable (); + m = chEvtWaitOneTimeout (ALL_EVENTS, LED_DISP_BLINK_INTERVAL0); + + if (m == EV_SW_PUSH || sw_push_count) + { + if (palReadPad (IOPORT2, GPIOB_BUTTON) == 0) + sw_push_count++; + else /* ignore this bounce */ + { + palSetPad (IOPORT1, GPIOA_LED2); + sw_push_count = 0; + } + } + + if (sw_push_count >= 2) + sw_event = 1; + + count = (TIM4->CNT) / 2; + + if (input_mode == 1) + { + if (count_prev != count) + input_mode = 0; + else + { + led_disp (ENTER); + if (sw_event) + { + palSetPad (IOPORT1, GPIOA_LED2); + break; + } + } + } + + if (input_mode == 0) + { + uint8_t c; + + if (count < 10) + c = count + '0'; + else + c = (count - 10) + 'A'; + + led_disp (c); + + if (sw_event) + { + pin_input_buffer[pin_input_len] = c; + if (pin_input_len < MAX_PIN_CHARS - 1) + pin_input_len++; + input_mode = 1; + sw_event = sw_push_count = 0; + palSetPad (IOPORT1, GPIOA_LED2); + } + } + + chThdSleep (LED_DISP_BLINK_INTERVAL1); + count_prev = count; + } + + led_disp (OFF); + TIM4->CR1 &= ~TIM_CR1_CEN; + dial_sw_disable (); + return 0; +} diff --git a/src/usb-icc.c b/src/usb-icc.c index 62f4ba5..43370cc 100644 --- a/src/usb-icc.c +++ b/src/usb-icc.c @@ -517,13 +517,34 @@ icc_handle_data (void) icc_send_params (); else if (icc_header->msg_type == ICC_SECURE) { - cmd_APDU[0] = icc_buffer[25]; - cmd_APDU[1] = icc_buffer[26]; - cmd_APDU[2] = icc_buffer[27]; - cmd_APDU[3] = icc_buffer[28]; - icc_data_size = 4; - chEvtSignal (gpg_thread, (eventmask_t)1); - next_state = ICC_STATE_EXECUTE; + if (icc_buffer[10] == 0x00) /* PIN verification */ + { + cmd_APDU[0] = icc_buffer[25]; + cmd_APDU[1] = icc_buffer[26]; + cmd_APDU[2] = icc_buffer[27]; + cmd_APDU[3] = icc_buffer[28]; + icc_data_size = 4; + chEvtSignal (gpg_thread, (eventmask_t)1); + next_state = ICC_STATE_EXECUTE; + } + else if (icc_buffer[10] == 0x01) /* PIN Modification */ + { + uint8_t num_msgs = icc_buffer[21]; + + if (num_msgs == 0x00) + num_msgs = 1; + else if (num_msgs == 0xff) + num_msgs = 3; + cmd_APDU[0] = icc_buffer[27 + num_msgs]; + cmd_APDU[1] = icc_buffer[28 + num_msgs]; + cmd_APDU[2] = icc_buffer[29 + num_msgs]; + cmd_APDU[3] = icc_buffer[30 + num_msgs]; + icc_data_size = 4; + chEvtSignal (gpg_thread, (eventmask_t)1); + next_state = ICC_STATE_EXECUTE; + } + else + icc_error (ICC_MSG_DATA_OFFSET); } else { diff --git a/src/usb_desc.c b/src/usb_desc.c index dbb764e..9b3b32f 100644 --- a/src/usb_desc.c +++ b/src/usb_desc.c @@ -105,7 +105,11 @@ static const uint8_t gnukConfigDescriptor[] = { 0xff, /* bClassEnvelope: */ 0, 0, /* wLCDLayout: FIXED VALUE */ #if defined(PINPAD_SUPPORT) - 1, /* bPinSupport: with PIN pad */ +#if defined(PINPAD_CIR_SUPPORT) + 1, /* bPinSupport: with PIN pad (verify) */ +#elif defined(PINPAD_DIAL_SUPPORT) + 3, /* bPinSupport: with PIN pad (verify, modify) */ +#endif #else 0, /* bPinSupport: No PIN pad */ #endif