more impl.

This commit is contained in:
NIIBE Yutaka
2010-08-19 17:09:59 +09:00
parent 4a7dfc5cd3
commit a68663cb5b
6 changed files with 308 additions and 86 deletions

View File

@@ -78,7 +78,7 @@ CSRC = $(PORTSRC) \
$(CHIBIOS)/os/various/syscalls.c \ $(CHIBIOS)/os/various/syscalls.c \
$(STMUSBSRC) \ $(STMUSBSRC) \
$(USBCDCSRC) \ $(USBCDCSRC) \
main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb.c main.c hw_config.c usb_lld.c usb_desc.c usb_prop.c usb-icc.c gpg.c
# List ASM source files here # List ASM source files here
ASMSRC = $(PORTASM) \ ASMSRC = $(PORTASM) \

9
src/gnuk.h Normal file
View File

@@ -0,0 +1,9 @@
extern Thread *blinker_thread;
extern Thread *icc_thread;
extern Thread *gpg_thread;
#define EV_EXEC_FINISHED (eventmask_t)2 /* GPG Execution finished */
#define put_string(STR)
extern void _write (char *, int);

View File

@@ -1,5 +1,5 @@
/* /*
* gpg.c -- * gpg.c -- OpenPGP card protocol support
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -21,7 +21,11 @@
* *
*/ */
#define RSA_SIGNATURE_LENGTH 128 /* 128 byte == 1024-bit */ #include "ch.h"
#include "hal.h"
#include "gnuk.h"
#define RSA_SIGNATURE_LENGTH 256 /* 256 byte == 2048-bit */
extern unsigned char *rsa_sign (unsigned char *); extern unsigned char *rsa_sign (unsigned char *);
#define INS_PUT_DATA 0xDA #define INS_PUT_DATA 0xDA
@@ -207,19 +211,20 @@ const char const do_5f50[] =
* 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ... * 6e L-6e [47 3 x x x ] [4f L-4f ...] [c0 L-c0 ...] ...
* 7a L-7a [93 L-93 ... ] * 7a L-7a [93 L-93 ... ]
*/ */
#if 0
static byte static byte
process_command_adpu (void) process_command_adpu (void)
{ {
if (icc_read_buf[1] == INS_GET_RESPONSE) if (icc_read_buf[1] == INS_GET_RESPONSE)
{ {
stx_put_string (" - GET Response\r\n"); put_string (" - GET Response\r\n");
if ((icc_result_flag & ICC_RESULT_BUF)) if ((icc_result_flag & ICC_RESULT_BUF))
return 0; return 0;
else else
{ {
stx_put_string ("Wrong GET Response\r\n"); put_string ("Wrong GET Response\r\n");
return 1; return 1;
} }
} }
@@ -239,7 +244,7 @@ INS_VERIFY
if (icc_read_buf[1] == INS_PUT_DATA) if (icc_read_buf[1] == INS_PUT_DATA)
{ {
stx_put_string (" - PUT DATA\r\n"); put_string (" - PUT DATA\r\n");
icc_result_value = 0x9000; /* 6a88: No record */ icc_result_value = 0x9000; /* 6a88: No record */
icc_result_len = 0; icc_result_len = 0;
icc_result_flag = 0; icc_result_flag = 0;
@@ -248,7 +253,7 @@ INS_VERIFY
if (icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR) if (icc_read_buf[1] == INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR)
{ {
stx_put_string (" - Generate Asymmetric Key Pair\r\n"); put_string (" - Generate Asymmetric Key Pair\r\n");
if (icc_read_buf[2] == 0x81) if (icc_read_buf[2] == 0x81)
{ {
@@ -346,7 +351,7 @@ INS_VERIFY
} }
else if (icc_read_buf[1] == INS_READ_BINARY) else if (icc_read_buf[1] == INS_READ_BINARY)
{ /* it must be for DF 0x2f02 */ { /* it must be for DF 0x2f02 */
stx_put_string (" - Read binary\r\n"); put_string (" - Read binary\r\n");
if (icc_read_buf[3] >= 6) if (icc_read_buf[3] >= 6)
{ {
@@ -369,7 +374,7 @@ INS_VERIFY
{ {
if (icc_read_buf[2] == 4) /* Selection by DF name */ if (icc_read_buf[2] == 4) /* Selection by DF name */
{ {
stx_put_string (" - select DF by name\r\n"); put_string (" - select DF by name\r\n");
/* /*
* XXX: Should return contents. * XXX: Should return contents.
*/ */
@@ -385,7 +390,7 @@ INS_VERIFY
&& icc_read_buf[5] == 0x2f && icc_read_buf[5] == 0x2f
&& icc_read_buf[6] == 02) && icc_read_buf[6] == 02)
{ {
stx_put_string (" - select 0x2f02 EF\r\n"); put_string (" - select 0x2f02 EF\r\n");
/* /*
* MF.EF-GDO -- Serial number of the card and name of the owner * MF.EF-GDO -- Serial number of the card and name of the owner
*/ */
@@ -398,7 +403,7 @@ INS_VERIFY
&& icc_read_buf[5] == 0x3f && icc_read_buf[5] == 0x3f
&& icc_read_buf[6] == 0) && icc_read_buf[6] == 0)
{ {
stx_put_string (" - select ROOT MF\r\n"); put_string (" - select ROOT MF\r\n");
if (icc_read_buf[3] == 0x0c) if (icc_read_buf[3] == 0x0c)
{ {
icc_result_value = 0x9000; icc_result_value = 0x9000;
@@ -414,7 +419,7 @@ INS_VERIFY
} }
else else
{ {
stx_put_string (" - select ?? \r\n"); put_string (" - select ?? \r\n");
icc_result_value = 0x6a82; /* File missing */ icc_result_value = 0x6a82; /* File missing */
icc_result_len = 0; icc_result_len = 0;
@@ -423,7 +428,7 @@ INS_VERIFY
} }
else if (icc_read_buf[1] == INS_GET_DATA) else if (icc_read_buf[1] == INS_GET_DATA)
{ {
stx_put_string (" - Get Data\r\n"); put_string (" - Get Data\r\n");
switch (((icc_read_buf[2]<<8) | icc_read_buf[3])) switch (((icc_read_buf[2]<<8) | icc_read_buf[3]))
{ {
@@ -535,12 +540,12 @@ INS_VERIFY
} }
else if (icc_read_buf[1] == INS_PSO) else if (icc_read_buf[1] == INS_PSO)
{ {
stx_put_string (" - PSO\r\n"); put_string (" - PSO\r\n");
if (icc_read_buf[2] == 0x9E && icc_read_buf[3] == 0x9A) if (icc_read_buf[2] == 0x9E && icc_read_buf[3] == 0x9A)
{ {
if (icc_read_len != 5 + 35 && icc_read_len != 5 + 35 + 1) if (icc_read_len != 5 + 35 && icc_read_len != 5 + 35 + 1)
stx_put_string (" wrong length\r\n"); put_string (" wrong length\r\n");
else else
{ {
icc_result_value = rsa_sign (&icc_read_buf[5]); icc_result_value = rsa_sign (&icc_read_buf[5]);
@@ -548,11 +553,11 @@ INS_VERIFY
icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_RAM; icc_result_flag = ICC_RESULT_BUF | ICC_RESULT_BUF_RAM;
} }
stx_put_string ("done.\r\n"); put_string ("done.\r\n");
} }
else else
{ {
stx_put_string (" - ???\r\n"); put_string (" - ???\r\n");
icc_result_value = 0x9000; icc_result_value = 0x9000;
icc_result_len = 0; icc_result_len = 0;
icc_result_flag = 0; icc_result_flag = 0;
@@ -560,7 +565,7 @@ INS_VERIFY
} }
else else
{ {
stx_put_string (" - ???\r\n"); put_string (" - ???\r\n");
icc_result_value = 0x9000; icc_result_value = 0x9000;
icc_result_len = 0; icc_result_len = 0;
icc_result_flag = 0; icc_result_flag = 0;
@@ -568,3 +573,37 @@ INS_VERIFY
return 0; return 0;
} }
#endif
Thread *gpg_thread;
msg_t
GPGthread (void *arg)
{
(void)arg;
gpg_thread = chThdSelf ();
chEvtClear (ALL_EVENTS);
while (1)
{
eventmask_t m;
m = chEvtWaitOne (ALL_EVENTS);
_write ("GPG!\r\n", 6);
#if 0
receive_command_adpu ();
#endif
#if 0
process_command_adpu ();
#endif
#if 0
send_result_adpu ();
#endif
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}
return 0;
}

View File

@@ -35,19 +35,23 @@
#include "hw_config.h" #include "hw_config.h"
#include "usb_pwr.h" #include "usb_pwr.h"
Thread *blinker_thread;
/* /*
* Red LEDs blinker thread, times are in milliseconds. * Red LEDs blinker thread, times are in milliseconds.
*/ */
static WORKING_AREA(waThread1, 128); static WORKING_AREA(waThread1, 128);
static msg_t Thread1(void *arg) { static msg_t
Thread1 (void *arg)
{
(void)arg; (void)arg;
while (TRUE) { blinker_thread = chThdSelf ();
palClearPad (IOPORT3, GPIOC_LED); while (1)
chThdSleepMilliseconds (1000); {
palSetPad (IOPORT3, GPIOC_LED); palClearPad (IOPORT3, GPIOC_LED);
chThdSleepMilliseconds (1000); chEvtWaitOne (ALL_EVENTS);
} palSetPad (IOPORT3, GPIOC_LED);
chEvtWaitOne (ALL_EVENTS);
}
return 0; return 0;
} }
@@ -160,8 +164,11 @@ static msg_t Thread2 (void *arg)
return 0; return 0;
} }
static WORKING_AREA(waUSBThread, 128*2); static WORKING_AREA(waUSBthread, 128*2);
extern msg_t USBThread (void *arg); extern msg_t USBthread (void *arg);
static WORKING_AREA(waGPGthread, 128*4);
extern msg_t GPGthread (void *arg);
/* /*
* Entry point, note, the main() function is already a thread in the system * Entry point, note, the main() function is already a thread in the system
@@ -188,7 +195,8 @@ int main(int argc, char **argv)
*/ */
chThdCreateStatic (waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL); chThdCreateStatic (waThread2, sizeof(waThread2), NORMALPRIO, Thread2, NULL);
chThdCreateStatic (waUSBThread, sizeof(waUSBThread), NORMALPRIO, USBThread, NULL); chThdCreateStatic (waUSBthread, sizeof(waUSBthread), NORMALPRIO, USBthread, NULL);
chThdCreateStatic (waGPGthread, sizeof(waGPGthread), NORMALPRIO, GPGthread, NULL);
while (1) while (1)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* usb.c -- * usb-icc.c -- USB CCID/ICCD protocol handling
* *
* Copyright (C) 2010 Free Software Initiative of Japan * Copyright (C) 2010 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org> * Author: NIIBE Yutaka <gniibe@fsij.org>
@@ -24,31 +24,42 @@
#include "ch.h" #include "ch.h"
#include "hal.h" #include "hal.h"
#include "gnuk.h"
#include "usb_lib.h" #include "usb_lib.h"
#include "usb_desc.h" #include "usb_desc.h"
#include "usb_mem.h" #include "usb_mem.h"
#include "hw_config.h" #include "hw_config.h"
#include "usb_istr.h" #include "usb_istr.h"
Mutex icc_in_mutex;
static uint8_t icc_buffer_out[64]; static uint8_t icc_buffer_out[64];
static uint8_t icc_buffer_in[64]; static uint8_t icc_buffer_in[64];
static __IO uint32_t icc_count_out = 0; static __IO uint32_t icc_count_out = 0;
static uint32_t icc_count_in = 0; static uint32_t icc_count_in = 0;
Thread *icc_thread;
#define EV_RX_DATA_READY (eventmask_t)1 /* USB Rx data available */
/*
* Tx done
*/
void void
EP4_IN_Callback(void) EP4_IN_Callback (void)
{ {
icc_count_in = 0; icc_count_in = 0;
} }
/*
* Rx data
*/
void void
EP5_OUT_Callback(void) EP5_OUT_Callback (void)
{ {
/* Get the received data buffer and update the counter */ /* Get the received data buffer and update the counter */
icc_count_out = USB_SIL_Read (EP5_OUT, icc_buffer_out); icc_count_out = USB_SIL_Read (EP5_OUT, icc_buffer_out);
chEvtSignalI (icc_thread, EV_RX_DATA_READY);
} }
#define ICC_POWER_ON 0x62 #define ICC_POWER_ON 0x62
@@ -168,32 +179,31 @@ HW_ERROR 0xFB The USB-ICC detected a hardware error.
all others Reserved for future use all others Reserved for future use
(0x80 and those filling the gaps) (0x80 and those filling the gaps)
extern const uchar *icc_power_on (void);
extern byte icc_get_status (void);
PC_to_RDR_IccPowerOff
RDR_to_PC_SlotStatus
PC_to_RDR_IccPowerOn
RDR_to_PC_DataBlock
PC_to_RDR_XfrBlock
RDR_to_PC_DataBlock
#endif #endif
enum icc_state
{
ICC_STATE_START, /* Initial */
ICC_STATE_WAIT, /* Waiting ADPU */
/* Busy1, Busy2, Busy3, Busy5 */
ICC_STATE_EXECUTE, /* Busy4 */
ICC_STATE_RECEIVE, /* ADPU Received Partially */
ICC_STATE_SEND /* ADPU Sent Partially */
};
static enum icc_state icc_state;
/* Direct conversion, T=1, "FSIJ" */ /* Direct conversion, T=1, "FSIJ" */
static const char ATR[] = { '\x3B', '\x84', '\x01', 'F', 'S', 'I', 'J' }; static const char ATR[] = { '\x3B', '\x84', '\x01', 'F', 'S', 'I', 'J' };
void /* Send back ATR (Answer To Reset) */
enum icc_state
icc_power_on (char *buf, int len) icc_power_on (char *buf, int len)
{ {
int i, size_atr; int i, size_atr;
size_atr = sizeof (ATR); size_atr = sizeof (ATR);
chMtxLock (&icc_in_mutex);
icc_buffer_in[0] = 0x80; icc_buffer_in[0] = 0x80;
icc_buffer_in[1] = size_atr; icc_buffer_in[1] = size_atr;
/* not including '\0' at the end */ /* not including '\0' at the end */
@@ -212,16 +222,14 @@ icc_power_on (char *buf, int len)
USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in); USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in);
SetEPTxValid (ENDP4); SetEPTxValid (ENDP4);
chMtxUnlock ();
_write ("ON\r\n", 4); _write ("ON\r\n", 4);
return ICC_STATE_WAIT;
} }
void static void
icc_power_off (char *buf, int len) icc_send_status (char *buf, int len)
{ {
chMtxLock (&icc_in_mutex);
icc_buffer_in[0] = 0x81; icc_buffer_in[0] = 0x81;
icc_buffer_in[1] = 0x00; icc_buffer_in[1] = 0x00;
icc_buffer_in[2] = 0x00; icc_buffer_in[2] = 0x00;
@@ -229,56 +237,212 @@ icc_power_off (char *buf, int len)
icc_buffer_in[4] = 0x00; icc_buffer_in[4] = 0x00;
icc_buffer_in[5] = 0x00; /* Slot */ icc_buffer_in[5] = 0x00; /* Slot */
icc_buffer_in[ICC_MSG_SEQ_OFFSET] = buf[ICC_MSG_SEQ_OFFSET]; icc_buffer_in[ICC_MSG_SEQ_OFFSET] = buf[ICC_MSG_SEQ_OFFSET];
icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 0x00; if (icc_state == ICC_STATE_START)
icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 2; /* No ICC present */
else
icc_buffer_in[ICC_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */
icc_buffer_in[ICC_MSG_ERROR_OFFSET] = 0x00; icc_buffer_in[ICC_MSG_ERROR_OFFSET] = 0x00;
icc_buffer_in[9] = 0x00; icc_buffer_in[9] = 0x00;
icc_count_in = 10; icc_count_in = 10;
USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in); USB_SIL_Write (EP4_IN, icc_buffer_in, icc_count_in);
SetEPTxValid (ENDP4); SetEPTxValid (ENDP4);
chMtxUnlock ();
_write ("OFF\r\n", 5);
} }
msg_t enum icc_state
USBThread (void *arg) icc_power_off (char *buf, int len)
{ {
icc_send_status (buf, len);
_write ("OFF\r\n", 5);
return ICC_STATE_START;
}
static enum icc_state
icc_handle_data (void)
{
enum icc_state next_state = icc_state;
#if 1
char b[3]; char b[3];
chMtxInit (&icc_in_mutex); b[0] = icc_buffer_out[0];
b[1] = '\r';
b[2] = '\n';
while (TRUE) _write (b, 3);
#endif
switch (icc_state)
{ {
while (icc_count_out == 0) case ICC_STATE_START:
chThdSleepMilliseconds (1);
b[0] = icc_buffer_out[0];
b[1] = '\r';
b[2] = '\n';
_write (b, 3);
if (icc_buffer_out[0] == ICC_POWER_ON) if (icc_buffer_out[0] == ICC_POWER_ON)
{ next_state = icc_power_on (icc_buffer_out, icc_count_out);
/* Send back ATR (Answer To Reset) */ else if (icc_buffer_out[0] == ICC_POWER_OFF)
icc_power_on (icc_buffer_out, icc_count_out); next_state = icc_power_off (icc_buffer_out, icc_count_out);
} else if (icc_buffer_out[0] == ICC_SLOT_STATUS)
else if (icc_buffer_out[0] == ICC_POWER_OFF icc_send_status (icc_buffer_out, icc_count_out);
|| icc_buffer_out[0] == ICC_SLOT_STATUS) else
{ { /* XXX: error */
/* Kill ICC thread(s) and send back slot status */ _write ("ERR01\r\n", 7);
icc_power_off (icc_buffer_out, icc_count_out);
} }
break;
case ICC_STATE_WAIT:
if (icc_buffer_out[0] == ICC_POWER_OFF)
next_state = icc_power_off (icc_buffer_out, icc_count_out);
else if (icc_buffer_out[0] == ICC_SLOT_STATUS)
icc_send_status (icc_buffer_out, icc_count_out);
else if (icc_buffer_out[0] == XFR_BLOCK) else if (icc_buffer_out[0] == XFR_BLOCK)
{ {
/* Give this message to ICC thread */ if (icc_buffer_out[8] == 0 && icc_buffer_out[9] == 0)
{
/* Give this message to GPG thread */
next_state = ICC_STATE_EXECUTE;
chEvtSignal (gpg_thread, (eventmask_t)1);
}
else if (icc_buffer_out[8] == 1 && icc_buffer_out[9] == 0)
{
/* XXX: return back RDR_to_PC_DataBlock */
/* bChainParameter = 0x10, abData=empty */
next_state = ICC_STATE_RECEIVE;
}
else
{
/* XXX: error */;
_write ("ERR02\r\n", 7);
}
} }
else else
{ { /* XXX: error */
_write ("ERR03\r\n", 7);
} }
break;
case ICC_STATE_EXECUTE:
if (icc_buffer_out[0] == ICC_POWER_OFF)
{
/* XXX: Kill GPG thread */
next_state = icc_power_off (icc_buffer_out, icc_count_out);
}
else if (icc_buffer_out[0] == ICC_SLOT_STATUS)
icc_send_status (icc_buffer_out, icc_count_out);
else
{ /* XXX: error */
_write ("ERR04\r\n", 7);
}
break;
case ICC_STATE_RECEIVE:
if (icc_buffer_out[0] == ICC_POWER_OFF)
{
/* XXX: release partial ADPU received */
next_state = icc_power_off (icc_buffer_out, icc_count_out);
}
else if (icc_buffer_out[0] == ICC_SLOT_STATUS)
icc_send_status (icc_buffer_out, icc_count_out);
else if (icc_buffer_out[0] == XFR_BLOCK)
{
if (1 /* XXX */) /* Got final block */
{
/* Give this message to GPG thread */
next_state = ICC_STATE_EXECUTE;
chEvtSignal (gpg_thread, (eventmask_t)1);
}
}
else
{ /* XXX: error */
_write ("ERR05\r\n", 7);
}
break;
case ICC_STATE_SEND:
if (icc_buffer_out[0] == ICC_POWER_OFF)
{
/* XXX: release partial ADPU sending */
next_state = icc_power_off (icc_buffer_out, icc_count_out);
}
else if (icc_buffer_out[0] == ICC_SLOT_STATUS)
icc_send_status (icc_buffer_out, icc_count_out);
else if (icc_buffer_out[0] == XFR_BLOCK)
{
/* XXX: send back to data */
/* finished?, then go ICC_STATE_WAIT */
next_state = ICC_STATE_WAIT;
}
else
{ /* XXX: error */
_write ("ERR06\r\n", 7);
}
break;
}
icc_count_out = 0; icc_count_out = 0;
SetEPRxValid (ENDP5); SetEPRxValid (ENDP5);
return next_state;
}
static enum icc_state
icc_handle_timeout (void)
{
enum icc_state next_state = icc_state;
/*
*
* XXX: ICC_STATE_EXECUTE -> kill
* XXX: ICC_STATE_RECEIVE -> cancel
* XXX: ICC_STATE_SEND -> cancel
*/
if (icc_state == ICC_STATE_START
|| icc_state == ICC_STATE_WAIT)
;
else
{
next_state = ICC_STATE_WAIT;
}
chEvtSignal (blinker_thread, (eventmask_t)1);
return next_state;
}
#define USB_ICC_TIMEOUT MS2ST(1000)
msg_t
USBthread (void *arg)
{
(void)arg;
icc_thread = chThdSelf ();
chEvtClear (ALL_EVENTS);
icc_state = ICC_STATE_START;
while (1)
{
eventmask_t m;
m = chEvtWaitOneTimeout (ALL_EVENTS, USB_ICC_TIMEOUT);
if (m == EV_RX_DATA_READY)
icc_state = icc_handle_data ();
else if (m == EV_EXEC_FINISHED)
{
if (icc_state == ICC_STATE_EXECUTE)
{
if (1/* message is short enough*/)
{
/* XXX: send back result */;
icc_state = ICC_STATE_WAIT;
}
else
{
/* XXX: send back part of result */;
icc_state = ICC_STATE_SEND;
}
}
else
{ /* XXX: error */
_write ("ERR07\r\n", 7);
}
}
else /* Timeout */
icc_state = icc_handle_timeout ();
} }
return 0; return 0;

View File

@@ -6,9 +6,11 @@ extern void USB_Istr (void);
CH_IRQ_HANDLER (Vector90) { CH_IRQ_HANDLER (Vector90) {
CH_IRQ_PROLOGUE(); CH_IRQ_PROLOGUE();
chSysLockFromIsr();
USB_Istr(); USB_Istr();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE(); CH_IRQ_EPILOGUE();
} }
@@ -17,9 +19,9 @@ void usb_lld_init (void) {
NVICEnableVector (USB_LP_CAN1_RX0_IRQn, NVICEnableVector (USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY)); CORTEX_PRIORITY_MASK (STM32_USB_IRQ_PRIORITY));
/* /*
* Note that we also have other IRQs: * Note that we also have other IRQ(s):
* USB_HP_CAN1_TX_IRQn * USB_HP_CAN1_TX_IRQn (for double-buffered or isochronous)
* USBWakeUp_IRQn * USBWakeUp_IRQn (suspend/resume)
*/ */
RCC->APB1RSTR = RCC_APB1RSTR_USBRST; RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
RCC->APB1RSTR = 0; RCC->APB1RSTR = 0;