Experimental Ack-button feature added (not yet finished).
This commit is contained in:
@@ -51,6 +51,7 @@ endif
|
|||||||
|
|
||||||
ifeq ($(CHIP),stm32f103)
|
ifeq ($(CHIP),stm32f103)
|
||||||
CSRC += mcu-stm32f103.c
|
CSRC += mcu-stm32f103.c
|
||||||
|
CSRC += ack-button.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
|
|||||||
35
src/ack-button.c
Normal file
35
src/ack-button.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <chopstx.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "mcu/stm32f103.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_init (chopstx_intr_t *intr)
|
||||||
|
{
|
||||||
|
chopstx_claim_irq (intr, INTR_REQ_EXTI);
|
||||||
|
|
||||||
|
/* Configure EXTI line */
|
||||||
|
#ifdef AFIO_EXTICR_INDEX
|
||||||
|
AFIO->EXTICR[AFIO_EXTICR_INDEX] = AFIO_EXTICR1_EXTIx_Py;
|
||||||
|
#endif
|
||||||
|
EXTI->IMR &= ~EXTI_IMR;
|
||||||
|
EXTI->RTSR |= EXTI_RTSR_TR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_enable (void)
|
||||||
|
{
|
||||||
|
EXTI->PR |= EXTI_PR;
|
||||||
|
EXTI->IMR |= EXTI_IMR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_disable (void)
|
||||||
|
{
|
||||||
|
EXTI->IMR &= ~EXTI_IMR;
|
||||||
|
EXTI->PR |= EXTI_PR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
29
src/gnuk.h
29
src/gnuk.h
@@ -26,8 +26,9 @@ void ccid_card_change_signal (int how);
|
|||||||
/* CCID thread */
|
/* CCID thread */
|
||||||
#define EV_RX_DATA_READY 1 /* USB Rx data available */
|
#define EV_RX_DATA_READY 1 /* USB Rx data available */
|
||||||
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
|
#define EV_EXEC_FINISHED 2 /* OpenPGP Execution finished */
|
||||||
#define EV_TX_FINISHED 4 /* CCID Tx finished */
|
#define EV_EXEC_FINISHED_ACK 4 /* OpenPGP Execution finished, requires ACK */
|
||||||
#define EV_CARD_CHANGE 8
|
#define EV_TX_FINISHED 8 /* CCID Tx finished */
|
||||||
|
#define EV_CARD_CHANGE 16
|
||||||
|
|
||||||
/* OpenPGPcard thread */
|
/* OpenPGPcard thread */
|
||||||
#define EV_PINPAD_INPUT_DONE 1
|
#define EV_PINPAD_INPUT_DONE 1
|
||||||
@@ -53,12 +54,12 @@ enum ccid_state {
|
|||||||
CCID_STATE_NOCARD, /* No card available */
|
CCID_STATE_NOCARD, /* No card available */
|
||||||
CCID_STATE_START, /* Initial */
|
CCID_STATE_START, /* Initial */
|
||||||
CCID_STATE_WAIT, /* Waiting APDU */
|
CCID_STATE_WAIT, /* Waiting APDU */
|
||||||
/* Busy1, Busy2, Busy3, Busy5 */
|
CCID_STATE_EXECUTE, /* Executing command */
|
||||||
CCID_STATE_EXECUTE, /* Busy4 */
|
CCID_STATE_CONFIRM_ACK, /* Execution finished, waiting user's ACK */
|
||||||
CCID_STATE_RECEIVE, /* APDU Received Partially */
|
CCID_STATE_RECEIVE, /* APDU Received Partially */
|
||||||
CCID_STATE_SEND, /* APDU Sent Partially */
|
CCID_STATE_SEND, /* APDU Sent Partially */
|
||||||
|
|
||||||
CCID_STATE_EXITED, /* ICC Thread Terminated */
|
CCID_STATE_EXITED, /* CCID Thread Terminated */
|
||||||
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -378,7 +379,17 @@ extern uint8_t admin_authorized;
|
|||||||
#define NR_KEY_ALGO_ATTR_DEC 0xf2
|
#define NR_KEY_ALGO_ATTR_DEC 0xf2
|
||||||
#define NR_KEY_ALGO_ATTR_AUT 0xf3
|
#define NR_KEY_ALGO_ATTR_AUT 0xf3
|
||||||
/*
|
/*
|
||||||
* NR_UINT_SOMETHING could be here... Use 0xf[456789abcd]
|
* Representation of User Interaction Flag:
|
||||||
|
* 0 (UIF disabled): No record in flash memory
|
||||||
|
* 1 (UIF enabled): 0xf?ff
|
||||||
|
* 2 (UIF permanently enabled): 0xf?00
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define NR_DO_UIF_SIG 0xf6
|
||||||
|
#define NR_DO_UIF_DEC 0xf7
|
||||||
|
#define NR_DO_UIF_AUT 0xf8
|
||||||
|
/*
|
||||||
|
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
|
||||||
*/
|
*/
|
||||||
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
|
||||||
/*
|
/*
|
||||||
@@ -461,6 +472,12 @@ int pinpad_getline (int msg_code, uint32_t timeout_usec);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct chx_intr;
|
||||||
|
void ackbtn_init (struct chx_intr *intr);
|
||||||
|
void ackbtn_enable (void);
|
||||||
|
void ackbtn_disable (void);
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t _regnual_start, __heap_end__[];
|
extern uint8_t _regnual_start, __heap_end__[];
|
||||||
|
|
||||||
uint8_t * sram_address (uint32_t offset);
|
uint8_t * sram_address (uint32_t offset);
|
||||||
|
|||||||
@@ -135,6 +135,12 @@ static const uint8_t extended_capabilities[] __attribute__ ((aligned (1))) = {
|
|||||||
0x01, 0x00,
|
0x01, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* General Feature Management */
|
||||||
|
static const uint8_t feature_mngmnt[] __attribute__ ((aligned (1))) = {
|
||||||
|
3,
|
||||||
|
0x81, 0x01, 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
/* Algorithm Attributes */
|
/* Algorithm Attributes */
|
||||||
#define OPENPGP_ALGO_RSA 0x01
|
#define OPENPGP_ALGO_RSA 0x01
|
||||||
#define OPENPGP_ALGO_ECDH 0x12
|
#define OPENPGP_ALGO_ECDH 0x12
|
||||||
@@ -1614,18 +1620,20 @@ static const uint16_t cmp_ch_data[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_app_data[] = {
|
static const uint16_t cmp_app_data[] = {
|
||||||
3,
|
4,
|
||||||
GPG_DO_AID,
|
GPG_DO_AID,
|
||||||
GPG_DO_HIST_BYTES,
|
GPG_DO_HIST_BYTES,
|
||||||
GPG_DO_DISCRETIONARY,
|
GPG_DO_DISCRETIONARY,
|
||||||
|
GPG_DO_FEATURE_MNGMNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_discretionary[] = {
|
static const uint16_t cmp_discretionary[] = {
|
||||||
8,
|
11,
|
||||||
GPG_DO_EXTCAP,
|
GPG_DO_EXTCAP,
|
||||||
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
GPG_DO_ALG_SIG, GPG_DO_ALG_DEC, GPG_DO_ALG_AUT,
|
||||||
GPG_DO_PW_STATUS,
|
GPG_DO_PW_STATUS,
|
||||||
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL
|
GPG_DO_FP_ALL, GPG_DO_CAFP_ALL, GPG_DO_KGTIME_ALL,
|
||||||
|
GPG_DO_UIF_SIG, GPG_DO_UIF_DEC, GPG_DO_UIF_AUT
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
static const uint16_t cmp_ss_temp[] = { 1, GPG_DO_DS_COUNT };
|
||||||
@@ -1664,11 +1672,15 @@ gpg_do_table[] = {
|
|||||||
rw_algorithm_attr },
|
rw_algorithm_attr },
|
||||||
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
{ GPG_DO_ALG_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||||
rw_algorithm_attr },
|
rw_algorithm_attr },
|
||||||
|
{ GPG_DO_UIF_SIG, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
|
{ GPG_DO_UIF_DEC, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
|
{ GPG_DO_UIF_AUT, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED, rw_uif },
|
||||||
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
{ GPG_DO_KDF, DO_PROC_READWRITE, AC_ALWAYS, AC_ADMIN_AUTHORIZED,
|
||||||
rw_kdf },
|
rw_kdf },
|
||||||
/* Fixed data */
|
/* Fixed data */
|
||||||
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
|
{ GPG_DO_HIST_BYTES, DO_FIXED, AC_ALWAYS, AC_NEVER, historical_bytes },
|
||||||
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
{ GPG_DO_EXTCAP, DO_FIXED, AC_ALWAYS, AC_NEVER, extended_capabilities },
|
||||||
|
{ GPG_DO_FEATURE_MNGMNT, DO_FIXED, AC_ALWAYS, AC_NEVER, feature_mngmnt },
|
||||||
/* Compound data: Read access only */
|
/* Compound data: Read access only */
|
||||||
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
|
{ GPG_DO_CH_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_ch_data },
|
||||||
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
|
{ GPG_DO_APP_DATA, DO_CMP_READ, AC_ALWAYS, AC_NEVER, cmp_app_data },
|
||||||
|
|||||||
@@ -1501,7 +1501,7 @@ const struct command cmds[] = {
|
|||||||
};
|
};
|
||||||
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
|
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
|
||||||
|
|
||||||
static void
|
static int
|
||||||
process_command_apdu (void)
|
process_command_apdu (void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -1536,6 +1536,8 @@ process_command_apdu (void)
|
|||||||
DEBUG_BYTE (cmd);
|
DEBUG_BYTE (cmd);
|
||||||
GPG_NO_INS ();
|
GPG_NO_INS ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (cmd == INS_PSO) | (cmd == INS_INTERNAL_AUTHENTICATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
@@ -1553,6 +1555,7 @@ openpgp_card_thread (void *arg)
|
|||||||
int len, pw_len, newpw_len;
|
int len, pw_len, newpw_len;
|
||||||
#endif
|
#endif
|
||||||
eventmask_t m = eventflag_wait (openpgp_comm);
|
eventmask_t m = eventflag_wait (openpgp_comm);
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
DEBUG_INFO ("GPG!: ");
|
DEBUG_INFO ("GPG!: ");
|
||||||
|
|
||||||
@@ -1640,10 +1643,11 @@ openpgp_card_thread (void *arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
led_blink (LED_START_COMMAND);
|
led_blink (LED_START_COMMAND);
|
||||||
process_command_apdu ();
|
r = process_command_apdu ();
|
||||||
|
if (!r)
|
||||||
led_blink (LED_FINISH_COMMAND);
|
led_blink (LED_FINISH_COMMAND);
|
||||||
done:
|
done:
|
||||||
eventflag_signal (ccid_comm, EV_EXEC_FINISHED);
|
eventflag_signal (ccid_comm, r? EV_EXEC_FINISHED_ACK : EV_EXEC_FINISHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpg_fini ();
|
gpg_fini ();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* usb-ccid.c -- USB CCID protocol handling
|
* usb-ccid.c -- USB CCID protocol handling
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
@@ -1076,7 +1076,9 @@ ccid_send_data_block (struct ccid *c)
|
|||||||
static void
|
static void
|
||||||
ccid_send_data_block_time_extension (struct ccid *c)
|
ccid_send_data_block_time_extension (struct ccid *c)
|
||||||
{
|
{
|
||||||
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, 1);
|
ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT,
|
||||||
|
(c->ccid_state == CCID_STATE_CONFIRM_ACK?
|
||||||
|
0xff : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1461,6 +1463,7 @@ ccid_handle_data (struct ccid *c)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CCID_STATE_EXECUTE:
|
case CCID_STATE_EXECUTE:
|
||||||
|
case CCID_STATE_CONFIRM_ACK:
|
||||||
if (c->ccid_header.msg_type == CCID_POWER_OFF)
|
if (c->ccid_header.msg_type == CCID_POWER_OFF)
|
||||||
next_state = ccid_power_off (c);
|
next_state = ccid_power_off (c);
|
||||||
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
|
else if (c->ccid_header.msg_type == CCID_SLOT_STATUS)
|
||||||
@@ -1489,6 +1492,7 @@ ccid_handle_timeout (struct ccid *c)
|
|||||||
switch (c->ccid_state)
|
switch (c->ccid_state)
|
||||||
{
|
{
|
||||||
case CCID_STATE_EXECUTE:
|
case CCID_STATE_EXECUTE:
|
||||||
|
case CCID_STATE_CONFIRM_ACK:
|
||||||
ccid_send_data_block_time_extension (c);
|
ccid_send_data_block_time_extension (c);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1561,7 +1565,8 @@ extern int usb_get_descriptor (struct usb_dev *dev);
|
|||||||
extern void random_init (void);
|
extern void random_init (void);
|
||||||
extern void random_fini (void);
|
extern void random_fini (void);
|
||||||
|
|
||||||
static chopstx_intr_t interrupt;
|
static chopstx_intr_t ack_intr;
|
||||||
|
static chopstx_intr_t usb_intr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return 0 for normal USB event
|
* Return 0 for normal USB event
|
||||||
@@ -1576,7 +1581,7 @@ usb_event_handle (struct usb_dev *dev)
|
|||||||
|
|
||||||
e = usb_lld_event_handler (dev);
|
e = usb_lld_event_handler (dev);
|
||||||
ep_num = USB_EVENT_ENDP (e);
|
ep_num = USB_EVENT_ENDP (e);
|
||||||
chopstx_intr_done (&interrupt);
|
chopstx_intr_done (&usb_intr);
|
||||||
|
|
||||||
/* Transfer to endpoint (not control endpoint) */
|
/* Transfer to endpoint (not control endpoint) */
|
||||||
if (ep_num != 0)
|
if (ep_num != 0)
|
||||||
@@ -1678,7 +1683,8 @@ usb_event_handle (struct usb_dev *dev)
|
|||||||
|
|
||||||
static chopstx_poll_cond_t ccid_event_poll_desc;
|
static chopstx_poll_cond_t ccid_event_poll_desc;
|
||||||
static struct chx_poll_head *const ccid_poll[] = {
|
static struct chx_poll_head *const ccid_poll[] = {
|
||||||
(struct chx_poll_head *const)&interrupt,
|
(struct chx_poll_head *const)&ack_intr,
|
||||||
|
(struct chx_poll_head *const)&usb_intr,
|
||||||
(struct chx_poll_head *const)&ccid_event_poll_desc
|
(struct chx_poll_head *const)&ccid_event_poll_desc
|
||||||
};
|
};
|
||||||
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
#define CCID_POLL_NUM (sizeof (ccid_poll)/sizeof (struct chx_poll_head *))
|
||||||
@@ -1697,9 +1703,10 @@ ccid_thread (void *arg)
|
|||||||
eventflag_init (&ccid.openpgp_comm);
|
eventflag_init (&ccid.openpgp_comm);
|
||||||
|
|
||||||
usb_lld_init (&dev, USB_INITIAL_FEATURE);
|
usb_lld_init (&dev, USB_INITIAL_FEATURE);
|
||||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||||
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
usb_event_handle (&dev); /* For old SYS < 3.0 */
|
||||||
|
|
||||||
|
ackbtn_init (&ack_intr);
|
||||||
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
eventflag_prepare_poll (&c->ccid_comm, &ccid_event_poll_desc);
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
@@ -1732,7 +1739,7 @@ ccid_thread (void *arg)
|
|||||||
|
|
||||||
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
chopstx_poll (timeout_p, CCID_POLL_NUM, ccid_poll);
|
||||||
|
|
||||||
if (interrupt.ready)
|
if (usb_intr.ready)
|
||||||
{
|
{
|
||||||
if (usb_event_handle (&dev) == 0)
|
if (usb_event_handle (&dev) == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -1752,6 +1759,15 @@ ccid_thread (void *arg)
|
|||||||
goto reset;
|
goto reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ack_intr.ready)
|
||||||
|
{
|
||||||
|
ackbtn_disable ();
|
||||||
|
chopstx_intr_done (&ack_intr);
|
||||||
|
led_blink (LED_FINISH_COMMAND);
|
||||||
|
if (c->ccid_state == CCID_STATE_CONFIRM_ACK)
|
||||||
|
goto exec_done;
|
||||||
|
}
|
||||||
|
|
||||||
timeout = USB_CCID_TIMEOUT;
|
timeout = USB_CCID_TIMEOUT;
|
||||||
m = eventflag_get (&c->ccid_comm);
|
m = eventflag_get (&c->ccid_comm);
|
||||||
|
|
||||||
@@ -1779,6 +1795,7 @@ ccid_thread (void *arg)
|
|||||||
else if (m == EV_EXEC_FINISHED)
|
else if (m == EV_EXEC_FINISHED)
|
||||||
if (c->ccid_state == CCID_STATE_EXECUTE)
|
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||||
{
|
{
|
||||||
|
exec_done:
|
||||||
if (c->a->sw == GPG_THREAD_TERMINATED)
|
if (c->a->sw == GPG_THREAD_TERMINATED)
|
||||||
{
|
{
|
||||||
c->sw1sw2[0] = 0x90;
|
c->sw1sw2[0] = 0x90;
|
||||||
@@ -1810,7 +1827,17 @@ ccid_thread (void *arg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_INFO ("ERR07\r\n");
|
DEBUG_INFO ("ERR05\r\n");
|
||||||
|
}
|
||||||
|
else if (m == EV_EXEC_FINISHED_ACK)
|
||||||
|
if (c->ccid_state == CCID_STATE_EXECUTE)
|
||||||
|
{
|
||||||
|
ackbtn_enable ();
|
||||||
|
c->ccid_state = CCID_STATE_CONFIRM_ACK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_INFO ("ERR06\r\n");
|
||||||
}
|
}
|
||||||
else if (m == EV_TX_FINISHED)
|
else if (m == EV_TX_FINISHED)
|
||||||
{
|
{
|
||||||
@@ -1842,7 +1869,7 @@ ccid_thread (void *arg)
|
|||||||
/* Loading reGNUal. */
|
/* Loading reGNUal. */
|
||||||
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
while (bDeviceState != USB_DEVICE_STATE_UNCONNECTED)
|
||||||
{
|
{
|
||||||
chopstx_intr_wait (&interrupt);
|
chopstx_intr_wait (&usb_intr);
|
||||||
usb_event_handle (&dev);
|
usb_event_handle (&dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
* usb_ctrl.c - USB control pipe device specific code for Gnuk
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017
|
* Copyright (C) 2010, 2011, 2012, 2013, 2015, 2016, 2017, 2018
|
||||||
* Free Software Initiative of Japan
|
* Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user