From f2d3202de9a5847923f72afe2969eb7ccd7342c7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Jan 2016 00:14:36 -0800 Subject: altos/chaoskey: Add support for flipping between raw and cooked bits Plug the 'force bootloader' thing onto the board while it's running and it will generate raw bits instead of running them through the CRC to whiten. Useful for validating the raw hardware. Signed-off-by: Keith Packard --- src/drivers/ao_trng_send.c | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index bac6035c..64c016b2 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -19,17 +19,48 @@ #include #include #include +#include static void -ao_trng_send(void) +ao_trng_send_raw(uint16_t *buf) +{ + uint16_t i; + uint16_t t; + uint16_t *rnd = (uint16_t *) ao_adc_ring; + + t = ao_adc_get(AO_USB_IN_SIZE>>1); /* one 16-bit value per two output bytes */ + for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { + *buf++ = rnd[t]; + t = (t + 1) & (AO_ADC_RING_SIZE - 1); + } +} + +static void +ao_trng_send_cooked(uint16_t *buf) { - static uint16_t *buffer[2]; - int usb_buf_id; uint16_t i; - uint16_t *buf; uint16_t t; uint32_t *rnd = (uint32_t *) ao_adc_ring; + t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ + for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { + *buf++ = ao_crc_in_32_out_16(rnd[t]); + t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1); + } +} + +static inline int +ao_send_raw(void) +{ + return !ao_gpio_get(AO_RAW_PORT, AO_RAW_BIT, AO_RAW_PIN); +} + +static void +ao_trng_send(void) +{ + static uint16_t *buffer[2]; + int usb_buf_id; + if (!buffer[0]) { buffer[0] = ao_usb_alloc(); buffer[1] = ao_usb_alloc(); @@ -42,15 +73,16 @@ ao_trng_send(void) ao_crc_reset(); for (;;) { - ao_led_on(AO_LED_TRNG_ACTIVE); - t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ - buf = buffer[usb_buf_id]; - for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { - *buf++ = ao_crc_in_32_out_16(rnd[t]); - t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1); + if (ao_send_raw()) { + ao_led_on(AO_LED_TRNG_RAW); + ao_trng_send_raw(buffer[usb_buf_id]); + ao_led_off(AO_LED_TRNG_RAW); + } else { + ao_led_on(AO_LED_TRNG_COOKED); + ao_trng_send_cooked(buffer[usb_buf_id]); + ao_led_off(AO_LED_TRNG_COOKED); } ao_adc_ack(AO_USB_IN_SIZE); - ao_led_off(AO_LED_TRNG_ACTIVE); ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); usb_buf_id = 1-usb_buf_id; } @@ -61,5 +93,6 @@ static struct ao_task ao_trng_send_task; void ao_trng_send_init(void) { + ao_enable_input(AO_RAW_PORT, AO_RAW_BIT, AO_EXTI_MODE_PULL_UP); ao_add_task(&ao_trng_send_task, ao_trng_send, "trng_send"); } -- cgit v1.2.3 From 35407e664886bed21dcef7764843aac03be8490c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 28 Jan 2016 13:58:43 -0800 Subject: altos/chaoskey: Delay ADC reading for 250ms at startup This lets the HV supply stabilize before we start sampling values. Signed-off-by: Keith Packard --- src/drivers/ao_trng_send.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 64c016b2..99994900 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -72,6 +72,11 @@ ao_trng_send(void) ao_crc_reset(); + /* Delay long enough for the HV power supply to stabilize so that the + * first bits we read aren't of poor quality + */ + ao_delay(AO_MS_TO_TICKS(250)); + for (;;) { if (ao_send_raw()) { ao_led_on(AO_LED_TRNG_RAW); -- cgit v1.2.3 From 235198b85f1583d2792c7028decace61d1b4229e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Feb 2016 00:14:22 +1100 Subject: altos: Add power management to TRNG driver Support suspend/resume of the TRNG power supply, delaying after resume to wait for it to stabilize. Signed-off-by: Keith Packard --- src/drivers/ao_trng_send.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 99994900..63366d3e 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -20,6 +20,9 @@ #include #include #include +#include + +static uint8_t trng_running; static void ao_trng_send_raw(uint16_t *buf) @@ -72,12 +75,15 @@ ao_trng_send(void) ao_crc_reset(); - /* Delay long enough for the HV power supply to stabilize so that the - * first bits we read aren't of poor quality - */ - ao_delay(AO_MS_TO_TICKS(250)); - for (;;) { + if (!trng_running) { + /* Delay long enough for the HV power supply + * to stabilize so that the first bits we read + * aren't of poor quality + */ + ao_delay(AO_MS_TO_TICKS(10)); + trng_running = TRUE; + } if (ao_send_raw()) { ao_led_on(AO_LED_TRNG_RAW); ao_trng_send_raw(buffer[usb_buf_id]); @@ -95,9 +101,39 @@ ao_trng_send(void) static struct ao_task ao_trng_send_task; +#if AO_POWER_MANAGEMENT + +static void ao_trng_suspend(void *arg) +{ + (void) arg; +#ifdef AO_TRNG_ENABLE_PORT + ao_gpio_set(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 0); +#endif + trng_running = FALSE; +} + +static void ao_trng_resume(void *arg) +{ + (void) arg; +#ifdef AO_TRNG_ENABLE_PORT + ao_gpio_set(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 1); +#endif +} + +static struct ao_power ao_trng_power = { + .suspend = ao_trng_suspend, + .resume = ao_trng_resume +}; + +#endif + void ao_trng_send_init(void) { +#ifdef AO_TRNG_ENABLE_PORT + ao_enable_output(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 1); + ao_power_register(&ao_trng_power); +#endif ao_enable_input(AO_RAW_PORT, AO_RAW_BIT, AO_EXTI_MODE_PULL_UP); ao_add_task(&ao_trng_send_task, ao_trng_send, "trng_send"); } -- cgit v1.2.3 From 147f0df6a29b37fbfb0824ecd276482f0eecb397 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Feb 2016 15:33:42 -0800 Subject: altos: Delay TRNG ADC long enough for HV supply to stabilize Looks like it takes about 70ms for the supply to start running right, so delay after powering it up for that long. Signed-off-by: Keith Packard --- src/drivers/ao_trng_send.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 63366d3e..11f441f8 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -22,7 +22,8 @@ #include #include -static uint8_t trng_running; +static uint8_t trng_running; +static AO_TICK_TYPE trng_power_time; static void ao_trng_send_raw(uint16_t *buf) @@ -45,7 +46,7 @@ ao_trng_send_cooked(uint16_t *buf) uint16_t t; uint32_t *rnd = (uint32_t *) ao_adc_ring; - t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ + t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* two 16-bit values per two output bytes */ for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { *buf++ = ao_crc_in_32_out_16(rnd[t]); t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1); @@ -73,15 +74,26 @@ ao_trng_send(void) usb_buf_id = 0; +#ifdef AO_TRNG_ENABLE_PORT + ao_gpio_set(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 1); +#endif + trng_power_time = ao_time(); + ao_crc_reset(); for (;;) { if (!trng_running) { + AO_TICK_TYPE delay; + + delay = trng_power_time + AO_MS_TO_TICKS(100) - ao_time(); + if (delay > AO_MS_TO_TICKS(100)) + delay = AO_MS_TO_TICKS(100); + /* Delay long enough for the HV power supply * to stabilize so that the first bits we read * aren't of poor quality */ - ao_delay(AO_MS_TO_TICKS(10)); + ao_delay(delay); trng_running = TRUE; } if (ao_send_raw()) { @@ -118,6 +130,7 @@ static void ao_trng_resume(void *arg) #ifdef AO_TRNG_ENABLE_PORT ao_gpio_set(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 1); #endif + trng_power_time = ao_time(); } static struct ao_power ao_trng_power = { @@ -131,7 +144,7 @@ void ao_trng_send_init(void) { #ifdef AO_TRNG_ENABLE_PORT - ao_enable_output(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 1); + ao_enable_output(AO_TRNG_ENABLE_PORT, AO_TRNG_ENABLE_BIT, AO_TRNG_ENABLE_PIN, 0); ao_power_register(&ao_trng_power); #endif ao_enable_input(AO_RAW_PORT, AO_RAW_BIT, AO_EXTI_MODE_PULL_UP); -- cgit v1.2.3 From bab082605e3fca6b6d11447c45cd948ddfe74bb9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 7 Feb 2016 22:28:34 -0800 Subject: altos: Add simple stats test to TRNG code This detects broken hardware by making sure the standard deviation in the raw values used to compute each buffer is at least 128. Signed-off-by: Keith Packard --- src/drivers/ao_trng_send.c | 76 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 14 deletions(-) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 11f441f8..f8222993 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -25,32 +25,68 @@ static uint8_t trng_running; static AO_TICK_TYPE trng_power_time; -static void +/* Make sure there's at least 8 bits of variance in the samples */ +#define MIN_VARIANCE (128 * 128) + +#define DECLARE_STATS int32_t sum = 0, sum2 = 0 + +#define ADD_STATS(value) do { \ + sum += (value); \ + sum2 += (value) * (value); \ + } while(0) + +#define GOOD_STATS(i) (((sum2 - (sum * sum) / i) / i) >= MIN_VARIANCE) + +#define TRNG_ENABLE_DELAY AO_MS_TO_TICKS(100) + +static int ao_trng_send_raw(uint16_t *buf) { uint16_t i; uint16_t t; - uint16_t *rnd = (uint16_t *) ao_adc_ring; + uint16_t v; + + DECLARE_STATS; t = ao_adc_get(AO_USB_IN_SIZE>>1); /* one 16-bit value per two output bytes */ for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { - *buf++ = rnd[t]; + v = ao_adc_ring[t]; + *buf++ = v; t = (t + 1) & (AO_ADC_RING_SIZE - 1); + + ADD_STATS(v); } + return GOOD_STATS(AO_USB_IN_SIZE / sizeof (uint16_t)); } -static void +static int ao_trng_send_cooked(uint16_t *buf) { uint16_t i; uint16_t t; uint32_t *rnd = (uint32_t *) ao_adc_ring; - t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* two 16-bit values per two output bytes */ + DECLARE_STATS; + + t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ + for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { - *buf++ = ao_crc_in_32_out_16(rnd[t]); - t = (t + 1) & ((AO_ADC_RING_SIZE>>1) - 1); + uint32_t v; + uint16_t v1, v2; + + /* Fetch two values in one operation */ + v = rnd[t]; + t = (t + 1) & ((AO_ADC_RING_SIZE >> 1) - 1); + + *buf++ = ao_crc_in_32_out_16(v); + + v1 = v; + v2 = v >> 16; + + ADD_STATS(v1); + ADD_STATS(v2); } + return GOOD_STATS(2 * AO_USB_IN_SIZE / sizeof (uint16_t)); } static inline int @@ -64,6 +100,8 @@ ao_trng_send(void) { static uint16_t *buffer[2]; int usb_buf_id; + int good_bits; + int failed = 0; if (!buffer[0]) { buffer[0] = ao_usb_alloc(); @@ -85,9 +123,9 @@ ao_trng_send(void) if (!trng_running) { AO_TICK_TYPE delay; - delay = trng_power_time + AO_MS_TO_TICKS(100) - ao_time(); - if (delay > AO_MS_TO_TICKS(100)) - delay = AO_MS_TO_TICKS(100); + delay = trng_power_time + TRNG_ENABLE_DELAY - ao_time(); + if (delay > TRNG_ENABLE_DELAY) + delay = TRNG_ENABLE_DELAY; /* Delay long enough for the HV power supply * to stabilize so that the first bits we read @@ -98,16 +136,26 @@ ao_trng_send(void) } if (ao_send_raw()) { ao_led_on(AO_LED_TRNG_RAW); - ao_trng_send_raw(buffer[usb_buf_id]); + good_bits = ao_trng_send_raw(buffer[usb_buf_id]); ao_led_off(AO_LED_TRNG_RAW); } else { ao_led_on(AO_LED_TRNG_COOKED); - ao_trng_send_cooked(buffer[usb_buf_id]); + good_bits = ao_trng_send_cooked(buffer[usb_buf_id]); ao_led_off(AO_LED_TRNG_COOKED); } ao_adc_ack(AO_USB_IN_SIZE); - ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); - usb_buf_id = 1-usb_buf_id; + if (good_bits) { + ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); + usb_buf_id = 1-usb_buf_id; + failed = 0; + } else { + failed++; + ao_delay(AO_MS_TO_TICKS(10)); + if (failed > 10) { + ao_usb_disable(); + ao_panic(AO_PANIC_DMA); + } + } } } -- cgit v1.2.3 From 05fcb717bfc44aba3c1cfd43281e323505a46402 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Mar 2016 13:54:58 -0800 Subject: altos/chaoskey: Add another USB endpoint to read raw data This replaces having the single output switch based on a pin value and allows us to box the device and still fetch raw data. For now, this will use a special libusb2 program, ao-chaosread, to pull bits as I haven't figure out how to make linux provide two /dev entries for one USB device. Signed-off-by: Keith Packard --- src/chaoskey-v0.1/ao_pins.h | 2 + src/drivers/ao_trng_send.c | 149 +++++++++++++++++++++++---------- src/kernel/ao_product.c | 14 +++- src/kernel/ao_usb.h | 5 ++ src/stmf0/ao_arch_funcs.h | 3 + src/stmf0/ao_usb_stm.c | 195 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 321 insertions(+), 47 deletions(-) (limited to 'src/drivers/ao_trng_send.c') diff --git a/src/chaoskey-v0.1/ao_pins.h b/src/chaoskey-v0.1/ao_pins.h index 6ec582a9..73f76307 100644 --- a/src/chaoskey-v0.1/ao_pins.h +++ b/src/chaoskey-v0.1/ao_pins.h @@ -50,7 +50,9 @@ #define AO_USB_INTERFACE_CLASS_DATA 0xff #define AO_USB_HAS_OUT 0 #define AO_USB_HAS_IN 1 +#define AO_USB_HAS_IN2 1 #define AO_USB_HAS_INT 0 +#define USE_USB_STDIO 0 #define AO_USB_SELF_POWER 0 #define AO_USB_DEVICE_ID_SERIAL 1 diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index f8222993..171a345f 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -22,54 +22,97 @@ #include #include +static struct ao_task ao_trng_send_task, ao_trng_send_raw_task; static uint8_t trng_running; static AO_TICK_TYPE trng_power_time; -/* Make sure there's at least 8 bits of variance in the samples */ -#define MIN_VARIANCE (128 * 128) - -#define DECLARE_STATS int32_t sum = 0, sum2 = 0 - -#define ADD_STATS(value) do { \ - sum += (value); \ - sum2 += (value) * (value); \ - } while(0) - -#define GOOD_STATS(i) (((sum2 - (sum * sum) / i) / i) >= MIN_VARIANCE) - #define TRNG_ENABLE_DELAY AO_MS_TO_TICKS(100) -static int -ao_trng_send_raw(uint16_t *buf) +static uint8_t random_mutex; + +static void +ao_trng_get_raw(uint16_t *buf) { uint16_t i; uint16_t t; uint16_t v; - DECLARE_STATS; - t = ao_adc_get(AO_USB_IN_SIZE>>1); /* one 16-bit value per two output bytes */ for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { v = ao_adc_ring[t]; *buf++ = v; t = (t + 1) & (AO_ADC_RING_SIZE - 1); + } + ao_adc_ack(AO_USB_IN_SIZE>>1); +} + +static void +ao_trng_send_raw(void) +{ + static uint16_t *buffer[2]; + int usb_buf_id; - ADD_STATS(v); + if (!buffer[0]) { + buffer[0] = ao_usb_alloc(); + buffer[1] = ao_usb_alloc(); + if (!buffer[0]) + ao_exit(); + } + + usb_buf_id = 0; + + for (;;) { + ao_mutex_get(&random_mutex); + if (!trng_running) { + AO_TICK_TYPE delay; + + delay = trng_power_time + TRNG_ENABLE_DELAY - ao_time(); + if (delay > TRNG_ENABLE_DELAY) + delay = TRNG_ENABLE_DELAY; + + /* Delay long enough for the HV power supply + * to stabilize so that the first bits we read + * aren't of poor quality + */ + ao_delay(delay); + trng_running = TRUE; + } +#ifdef AO_LED_TRNG_RAW + ao_led_on(AO_LED_TRNG_RAW); +#endif + ao_trng_get_raw(buffer[usb_buf_id]); +#ifdef AO_LED_TRNG_RAW + ao_led_off(AO_LED_TRNG_RAW); +#endif + ao_mutex_put(&random_mutex); + ao_usb_write2(buffer[usb_buf_id], AO_USB_IN_SIZE); + usb_buf_id = 1-usb_buf_id; } - return GOOD_STATS(AO_USB_IN_SIZE / sizeof (uint16_t)); } +/* Make sure there's at least 8 bits of variance in the samples */ +#define MIN_VARIANCE (128 * 128) + +/* Make sure the signal is spread around a bit */ +#define MAX_VARIANCE (512 * 512) + +#define ADD_STATS(value) do { \ + sum += (value); \ + sum2 += (value) * (value); \ + } while(0) + +#define VARIANCE(n) ((sum2 - (sum / (n) * sum)) / (n)) + static int -ao_trng_send_cooked(uint16_t *buf) +ao_trng_get_cooked(uint16_t *buf) { uint16_t i; uint16_t t; uint32_t *rnd = (uint32_t *) ao_adc_ring; + int32_t sum, sum2, var; - DECLARE_STATS; - + sum = sum2 = 0; t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ - for (i = 0; i < AO_USB_IN_SIZE / sizeof (uint16_t); i++) { uint32_t v; uint16_t v1, v2; @@ -86,14 +129,13 @@ ao_trng_send_cooked(uint16_t *buf) ADD_STATS(v1); ADD_STATS(v2); } - return GOOD_STATS(2 * AO_USB_IN_SIZE / sizeof (uint16_t)); + ao_adc_ack(AO_USB_IN_SIZE); + var = VARIANCE(2 * AO_USB_IN_SIZE / sizeof (uint16_t)); + return var >= MIN_VARIANCE && var <= MAX_VARIANCE; } -static inline int -ao_send_raw(void) -{ - return !ao_gpio_get(AO_RAW_PORT, AO_RAW_BIT, AO_RAW_PIN); -} +#define AO_TRNG_START_WAIT 1024 +#define AO_TRNG_START_CHECK 32 static void ao_trng_send(void) @@ -101,13 +143,14 @@ ao_trng_send(void) static uint16_t *buffer[2]; int usb_buf_id; int good_bits; - int failed = 0; + int failed; + int s; if (!buffer[0]) { buffer[0] = ao_usb_alloc(); buffer[1] = ao_usb_alloc(); if (!buffer[0]) - return; + ao_exit(); } usb_buf_id = 0; @@ -119,7 +162,33 @@ ao_trng_send(void) ao_crc_reset(); + ao_delay(TRNG_ENABLE_DELAY); + + for (s = 0; s < AO_TRNG_START_WAIT; s++) { + if (ao_trng_get_cooked(buffer[0])) + break; + ao_delay(AO_MS_TO_TICKS(10)); + } + + /* Validate the hardware before enabling USB */ + failed = 0; + for (s = 0; s < AO_TRNG_START_CHECK; s++) { + if (!ao_trng_get_cooked(buffer[0])) { + failed++; + ao_delay(AO_MS_TO_TICKS(10)); + } + } + if (failed > AO_TRNG_START_CHECK / 4) + ao_panic(AO_PANIC_DMA); + + ao_add_task(&ao_trng_send_raw_task, ao_trng_send_raw, "trng_send_raw"); + +#ifdef AO_USB_START_DISABLED + ao_usb_enable(); +#endif + for (;;) { + ao_mutex_get(&random_mutex); if (!trng_running) { AO_TICK_TYPE delay; @@ -134,16 +203,14 @@ ao_trng_send(void) ao_delay(delay); trng_running = TRUE; } - if (ao_send_raw()) { - ao_led_on(AO_LED_TRNG_RAW); - good_bits = ao_trng_send_raw(buffer[usb_buf_id]); - ao_led_off(AO_LED_TRNG_RAW); - } else { - ao_led_on(AO_LED_TRNG_COOKED); - good_bits = ao_trng_send_cooked(buffer[usb_buf_id]); - ao_led_off(AO_LED_TRNG_COOKED); - } - ao_adc_ack(AO_USB_IN_SIZE); +#ifdef AO_LED_TRNG_COOKED + ao_led_on(AO_LED_TRNG_COOKED); +#endif + good_bits = ao_trng_get_cooked(buffer[usb_buf_id]); +#ifdef AO_LED_TRNG_COOKED + ao_led_off(AO_LED_TRNG_COOKED); +#endif + ao_mutex_put(&random_mutex); if (good_bits) { ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); usb_buf_id = 1-usb_buf_id; @@ -159,8 +226,6 @@ ao_trng_send(void) } } -static struct ao_task ao_trng_send_task; - #if AO_POWER_MANAGEMENT static void ao_trng_suspend(void *arg) diff --git a/src/kernel/ao_product.c b/src/kernel/ao_product.c index 4769d86e..3a829b3a 100644 --- a/src/kernel/ao_product.c +++ b/src/kernel/ao_product.c @@ -54,7 +54,7 @@ const char ao_product[] = AO_iProduct_STRING; #define HEADER_LEN 9 #define CONTROL_CLASS_LEN 35 -#define DATA_LEN (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN) +#define DATA_LEN (9 + 7 * AO_USB_HAS_OUT + 7 * AO_USB_HAS_IN + 7 * AO_USB_HAS_IN2) #define TOTAL_LENGTH (HEADER_LEN + AO_USB_HAS_INT * CONTROL_CLASS_LEN + DATA_LEN) #define NUM_INTERFACES (AO_USB_HAS_INT + 1) @@ -140,7 +140,7 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = AO_USB_DESC_INTERFACE, AO_USB_HAS_INT, /* bInterfaceNumber */ 0x00, /* bAlternateSetting */ - AO_USB_HAS_OUT + AO_USB_HAS_IN, /* bNumEndPoints */ + AO_USB_HAS_OUT + AO_USB_HAS_IN + AO_USB_HAS_IN2, /* bNumEndPoints */ AO_USB_INTERFACE_CLASS_DATA, /* bInterfaceClass = data */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ @@ -166,6 +166,16 @@ AO_ROMCONFIG_SYMBOL(0x00aa) uint8_t ao_usb_descriptors [] = 0x00, /* bInterval */ #endif +#if AO_USB_HAS_IN2 + /* Data EP in 2 */ + 0x07, + AO_USB_DESC_ENDPOINT, + AO_USB_IN2_EP|0x80, /* bEndpointAddress */ + 0x02, /* bmAttributes = bulk */ + LE_WORD(AO_USB_IN_SIZE),/* wMaxPacketSize */ + 0x00, /* bInterval */ +#endif + /* String descriptors */ 0x04, AO_USB_DESC_STRING, diff --git a/src/kernel/ao_usb.h b/src/kernel/ao_usb.h index 773b5cb7..8f3e7813 100644 --- a/src/kernel/ao_usb.h +++ b/src/kernel/ao_usb.h @@ -105,6 +105,7 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; #ifndef AO_USB_OUT_EP #define AO_USB_OUT_EP 4 #define AO_USB_IN_EP 5 +#define AO_USB_IN2_EP 6 #endif #ifndef AO_USB_HAS_OUT @@ -119,6 +120,10 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors []; #define AO_USB_HAS_INT 1 #endif +#ifndef AO_USB_HAS_IN2 +#define AO_USB_HAS_IN2 0 +#endif + /* * USB bulk packets can only come in 8, 16, 32 and 64 * byte sizes, so we'll use 64 for everything diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 8d585f80..4e3ef018 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -413,6 +413,9 @@ ao_usb_free(uint16_t *buffer); void ao_usb_write(uint16_t *buffer, uint16_t len); + +void +ao_usb_write2(uint16_t *buffer, uint16_t len); #endif /* AO_USB_DIRECTIO */ #endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index 17e8709c..e68da8eb 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -89,23 +89,42 @@ static uint16_t ao_usb_sram_addr; static uint16_t *ao_usb_ep0_tx_buffer; static uint16_t *ao_usb_ep0_rx_buffer; +#if AO_USB_HAS_INT /* Pointer to interrupt buffer in USB memory */ static uint16_t ao_usb_int_tx_offset; +#endif /* Pointer to bulk data tx/rx buffers in USB memory */ +#if AO_USB_HAS_IN static uint16_t ao_usb_in_tx_offset; static uint16_t *ao_usb_in_tx_buffer; -static uint16_t ao_usb_out_rx_offset; -static uint16_t *ao_usb_out_rx_buffer; /* System ram shadow of USB buffer; writing individual bytes is * too much of a pain (sigh) */ static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE]; static uint8_t ao_usb_tx_count; +#endif +#if AO_USB_HAS_OUT +static uint16_t ao_usb_out_rx_offset; +static uint16_t *ao_usb_out_rx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE]; static uint8_t ao_usb_rx_count, ao_usb_rx_pos; +#endif +#if AO_USB_HAS_IN2 +static uint16_t ao_usb_in2_tx_offset; +static uint16_t *ao_usb_in2_tx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ +static uint8_t ao_usb_tx2_buffer[AO_USB_IN_SIZE]; +static uint8_t ao_usb_tx2_count; +#endif + /* * End point register indices */ @@ -114,6 +133,7 @@ static uint8_t ao_usb_rx_count, ao_usb_rx_pos; #define AO_USB_INT_EPR 1 #define AO_USB_OUT_EPR 2 #define AO_USB_IN_EPR 3 +#define AO_USB_IN2_EPR 4 /* Marks when we don't need to send an IN packet. * This happens only when the last IN packet is not full, @@ -128,6 +148,16 @@ static uint8_t ao_usb_in_flushed; */ static uint8_t ao_usb_in_pending; +#if AO_USB_HAS_IN2 +/* Marks when we have delivered an IN packet to the hardware + * and it has not been received yet. ao_sleep on this address + * to wait for it to be delivered. + */ +static uint8_t ao_usb_in2_pending; +static uint16_t in2_count; +static uint8_t ao_usb_in2_flushed; +#endif + /* Marks when an OUT packet has been received by the hardware * but not pulled to the shadow buffer. */ @@ -343,16 +373,29 @@ ao_usb_alloc_buffers(void) ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + +#if AO_USB_HAS_INT ao_usb_int_tx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_INT_SIZE; +#endif +#if AO_USB_HAS_OUT ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_out_rx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_OUT_SIZE; +#endif +#if AO_USB_HAS_IN ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); ao_usb_in_tx_offset = ao_usb_sram_addr; ao_usb_sram_addr += AO_USB_IN_SIZE; +#endif + +#if AO_USB_HAS_IN2 + ao_usb_in2_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); + ao_usb_in2_tx_offset = ao_usb_sram_addr; + ao_usb_sram_addr += AO_USB_IN_SIZE; +#endif } static void @@ -438,6 +481,18 @@ ao_usb_set_configuration(void) STM_USB_EPR_STAT_TX_NAK); #endif +#if AO_USB_HAS_IN2 + /* Set up the IN2 end point */ + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in2_tx_offset; + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = 0; + + ao_usb_init_ep(AO_USB_IN2_EPR, + AO_USB_IN2_EP, + STM_USB_EPR_EP_TYPE_BULK, + STM_USB_EPR_STAT_RX_DISABLED, + STM_USB_EPR_STAT_TX_NAK); +#endif + ao_usb_running = 1; #if AO_USB_DIRECTIO ao_wakeup(&ao_usb_running); @@ -581,7 +636,7 @@ hex_to_ucs2(uint32_t in, uint8_t *out) for (i = 28; i >= 0; i -= 4) { uint8_t bits = (in >> i) & 0xf; - *out++ = (bits < 10) ? ('0' + bits) : ('a' + bits); + *out++ = ((bits < 10) ? '0' : ('a' - 10)) + bits; *out++ = 0; } } @@ -835,6 +890,16 @@ stm_usb_isr(void) ao_wakeup(&ao_usb_in_pending); } break; +#if AO_USB_HAS_IN2 + case AO_USB_IN2_EPR: + ++in2_count; + _tx_dbg1("TX2 ISR", epr); + if (ao_usb_epr_ctr_tx(epr)) { + ao_usb_in2_pending = 0; + ao_wakeup(&ao_usb_in2_pending); + } + break; +#endif case AO_USB_INT_EPR: ++int_count; if (ao_usb_epr_ctr_tx(epr)) @@ -861,6 +926,7 @@ stm_usb_isr(void) #endif } +#if AO_USB_HAS_IN /* Queue the current IN buffer for transmission */ static void _ao_usb_in_send(void) @@ -939,7 +1005,90 @@ ao_usb_putchar(char c) } ao_arch_release_interrupts(); } +#endif + +#if AO_USB_HAS_IN +/* Queue the current IN buffer for transmission */ +static void +_ao_usb_in2_send(void) +{ + _tx_dbg0("in2_send start"); + debug ("send2 %d\n", ao_usb_tx_count); + while (ao_usb_in2_pending) + ao_sleep(&ao_usb_in2_pending); + ao_usb_in2_pending = 1; + if (ao_usb_tx2_count != AO_USB_IN_SIZE) + ao_usb_in2_flushed = 1; + ao_usb_copy_tx(ao_usb_tx2_buffer, ao_usb_in2_tx_buffer, ao_usb_tx2_count); + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_in_tx_offset; + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = ao_usb_tx_count; + ao_usb_tx2_count = 0; + _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID); + _tx_dbg0("in2_send end"); +} + +/* Wait for a free IN buffer. Interrupts are blocked */ +static void +_ao_usb_in2_wait(void) +{ + for (;;) { + /* Check if the current buffer is writable */ + if (ao_usb_tx2_count < AO_USB_IN_SIZE) + break; + + _tx_dbg0("in2_wait top"); + /* Wait for an IN buffer to be ready */ + while (ao_usb_in2_pending) + ao_sleep(&ao_usb_in2_pending); + _tx_dbg0("in_wait bottom"); + } +} + +void +ao_usb_flush2(void) +{ + if (!ao_usb_running) + return; + + /* Anytime we've sent a character since + * the last time we flushed, we'll need + * to send a packet -- the only other time + * we would send a packet is when that + * packet was full, in which case we now + * want to send an empty packet + */ + ao_arch_block_interrupts(); + while (!ao_usb_in2_flushed) { + _tx_dbg0("flush2 top"); + _ao_usb_in2_send(); + _tx_dbg0("flush2 end"); + } + ao_arch_release_interrupts(); +} + +void +ao_usb_putchar2(char c) +{ + if (!ao_usb_running) + return; + + ao_arch_block_interrupts(); + _ao_usb_in2_wait(); + + ao_usb_in2_flushed = 0; + ao_usb_tx2_buffer[ao_usb_tx2_count++] = (uint8_t) c; + + /* Send the packet when full */ + if (ao_usb_tx2_count == AO_USB_IN_SIZE) { + _tx_dbg0("putchar2 full"); + _ao_usb_in2_send(); + _tx_dbg0("putchar2 flushed"); + } + ao_arch_release_interrupts(); +} +#endif +#if AO_USB_HAS_OUT static void _ao_usb_out_recv(void) { @@ -996,6 +1145,7 @@ ao_usb_getchar(void) ao_arch_release_interrupts(); return c; } +#endif #if AO_USB_DIRECTIO uint16_t * @@ -1050,6 +1200,43 @@ ao_usb_write(uint16_t *buffer, uint16_t len) _ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); ao_arch_release_interrupts(); } + +#if AO_USB_HAS_IN2 +void +ao_usb_write2(uint16_t *buffer, uint16_t len) +{ + ao_arch_block_interrupts(); + + /* Wait for everything to be ready at the same time */ + for (;;) { + /* Make sure USB is connected */ + if (!ao_usb_running) { + ao_sleep(&ao_usb_running); + continue; + } + + /* Flush any pending regular I/O */ + if (ao_usb_tx2_count) { + _ao_usb_in2_send(); + continue; + } + + /* Wait for an idle IN buffer */ + if (ao_usb_in2_pending) { + ao_sleep(&ao_usb_in2_pending); + continue; + } + break; + } + + ao_usb_in2_pending = 1; + ao_usb_in2_flushed = (len != AO_USB_IN_SIZE); + ao_usb_bdt[AO_USB_IN2_EPR].single.addr_tx = ao_usb_packet_buffer_offset(buffer); + ao_usb_bdt[AO_USB_IN2_EPR].single.count_tx = len; + _ao_usb_set_stat_tx(AO_USB_IN2_EPR, STM_USB_EPR_STAT_TX_VALID); + ao_arch_release_interrupts(); +} +#endif #endif void @@ -1180,7 +1367,9 @@ ao_usb_init(void) /* Set PA11/PA12 remapping bit */ stm_syscfg.cfgr1 |= (AO_PA11_PA12_RMP << STM_SYSCFG_CFGR1_PA11_PA12_RMP); +#ifndef AO_USB_START_DISABLED ao_usb_enable(); +#endif #if AO_USB_DEVICE_ID_SERIAL ao_usb_serial_init(); -- cgit v1.2.3