diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/chaoskey-v0.1/ao_pins.h | 2 | ||||
| -rw-r--r-- | src/drivers/ao_trng_send.c | 149 | ||||
| -rw-r--r-- | src/kernel/ao_product.c | 14 | ||||
| -rw-r--r-- | src/kernel/ao_usb.h | 5 | ||||
| -rw-r--r-- | src/stmf0/ao_arch_funcs.h | 3 | ||||
| -rw-r--r-- | src/stmf0/ao_usb_stm.c | 195 | 
6 files changed, 321 insertions, 47 deletions
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 <ao_exti.h>  #include <ao_power.h> +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();  | 
