X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Flpc%2Fao_usb_lpc.c;h=594114b62ed856a8b4babc8f9ccf47f3597d9624;hp=4e6b9c664b7e2d6e1d207fbd58d89e539f88cba0;hb=0686a7b8aec524d81bda4c572549a3a068ce0eed;hpb=9081d881bc48bf7fdce617d300ac02c1a5962239 diff --git a/src/lpc/ao_usb_lpc.c b/src/lpc/ao_usb_lpc.c index 4e6b9c66..594114b6 100644 --- a/src/lpc/ao_usb_lpc.c +++ b/src/lpc/ao_usb_lpc.c @@ -3,7 +3,8 @@ * * This program 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; version 2 of the License. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,6 +20,16 @@ #include "ao_usb.h" #include "ao_product.h" +#ifndef USE_USB_STDIO +#define USE_USB_STDIO 1 +#endif + +#if USE_USB_STDIO +#define AO_USB_OUT_SLEEP_ADDR (&ao_stdin_ready) +#else +#define AO_USB_OUT_SLEEP_ADDR (&ao_usb_out_avail) +#endif + #define USB_DEBUG 0 #define USB_DEBUG_DATA 0 #define USB_ECHO 0 @@ -48,6 +59,7 @@ static uint8_t ao_usb_ep0_state; /* Pending EP0 IN data */ static const uint8_t *ao_usb_ep0_in_data; /* Remaining data */ static uint8_t ao_usb_ep0_in_len; /* Remaining amount */ +static uint16_t ao_usb_ep0_in_max; /* Requested amount from host */ /* Temp buffer for smaller EP0 in data */ static uint8_t ao_usb_ep0_in_buf[2]; @@ -69,14 +81,12 @@ static uint8_t *ao_usb_ep0_setup_buffer; static uint8_t *ao_usb_ep0_rx_buffer; /* Pointer to bulk data tx/rx buffers in USB memory */ -static uint8_t *ao_usb_in_tx_buffer; -static uint8_t *ao_usb_out_rx_buffer; - -/* Our data buffers */ -static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE]; +static uint8_t *ao_usb_in_tx_buffer[2]; +static uint8_t ao_usb_in_tx_cur; static uint8_t ao_usb_tx_count; -static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE]; +static uint8_t *ao_usb_out_rx_buffer[2]; +static uint8_t ao_usb_out_rx_cur; static uint8_t ao_usb_rx_count, ao_usb_rx_pos; extern struct lpc_usb_endpoint lpc_usb_endpoint; @@ -98,9 +108,8 @@ static uint8_t ao_usb_in_pending; * but not pulled to the shadow buffer. */ static uint8_t ao_usb_out_avail; -static uint8_t ao_usb_running; +uint8_t ao_usb_running; static uint8_t ao_usb_configuration; -static uint8_t ueienx_0; #define AO_USB_EP0_GOT_RESET 1 #define AO_USB_EP0_GOT_SETUP 2 @@ -224,48 +233,47 @@ ao_usb_ep0_in(void) } static inline vuint32_t * -ao_usb_epn_out(uint8_t n) +ao_usb_epn_out(uint8_t n, uint8_t i) { - return &lpc_usb_endpoint.epn[n-1].out[0]; + return &lpc_usb_endpoint.epn[n-1].out[i]; } static inline vuint32_t * -ao_usb_epn_in(uint8_t n) +ao_usb_epn_in(uint8_t n, uint8_t i) { - return &lpc_usb_endpoint.epn[n-1].in[0]; + return &lpc_usb_endpoint.epn[n-1].in[i]; } +#if UNUSED static void ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes) { ao_usb_set_ep(ao_usb_epn_in(n), addr, nbytes); } +#endif static void ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes) { - ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes); + ao_usb_set_ep(ao_usb_epn_out(n, 0), addr, nbytes); } static inline uint16_t ao_usb_epn_out_count(uint8_t n) { - return ao_usb_ep_count(ao_usb_epn_out(n)); + return ao_usb_ep_count(ao_usb_epn_out(n, 0)); } static inline uint16_t ao_usb_epn_in_count(uint8_t n) { - return ao_usb_ep_count(ao_usb_epn_in(n)); + return ao_usb_ep_count(ao_usb_epn_in(n, 0)); } -static uint8_t * -ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes) +static void +ao_usb_enable_ep(vuint32_t *ep, uint8_t *addr, uint16_t set_nbytes) { - uint8_t *addr = ao_usb_alloc_sram(nbytes); - ao_usb_set_ep(ep, addr, set_nbytes); - return addr; } static void @@ -282,28 +290,39 @@ ao_usb_disable_ep(vuint32_t *ep) } static void -ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr) +ao_usb_enable_epn(uint8_t n, + uint16_t out_bytes, uint8_t *out_addr, + uint8_t *in_addr) { - uint8_t *addr; + ao_usb_enable_ep(ao_usb_epn_out(n, 0), out_addr, out_bytes); + ao_usb_disable_ep(ao_usb_epn_out(n, 1)); - addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes); - if (out_addr) - *out_addr = addr; - ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); - - addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0); - if (in_addr) - *in_addr = addr; - ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); + ao_usb_enable_ep(ao_usb_epn_in(n, 0), in_addr, 0); + ao_usb_disable_ep(ao_usb_epn_in(n, 1)); } static void ao_usb_disable_epn(uint8_t n) { - ao_usb_disable_ep(ao_usb_epn_out(n)); - ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); - ao_usb_disable_ep(ao_usb_epn_in(n)); - ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); + ao_usb_disable_ep(ao_usb_epn_out(n, 0)); + ao_usb_disable_ep(ao_usb_epn_out(n, 1)); + ao_usb_disable_ep(ao_usb_epn_in(n, 0)); + ao_usb_disable_ep(ao_usb_epn_in(n, 1)); +} + +static void +ao_usb_reset(void) +{ + ao_usb_set_address(0); + ao_usb_configuration = 0; + + ao_usb_ep0_state = AO_USB_EP0_IDLE; + ao_usb_ep0_in_data = NULL; + ao_usb_ep0_in_len = 0; + ao_usb_ep0_in_max = 0; + + ao_usb_ep0_out_data = NULL; + ao_usb_ep0_out_len = 0; } static void @@ -316,27 +335,21 @@ ao_usb_set_ep0(void) lpc_usb.epinuse = 0; lpc_usb.epskip = 0xffffffff; - ao_usb_set_address(0); lpc_usb.intstat = 0xc00003ff; - ao_usb_configuration = 0; - - ao_usb_sram = lpc_usb_sram; - lpc_usb.epliststart = (uint32_t) (intptr_t) &lpc_usb_endpoint; lpc_usb.databufstart = ((uint32_t) (intptr_t) ao_usb_sram) & 0xffc00000; /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */ - ao_usb_ep0_rx_buffer = ao_usb_enable_ep(ao_usb_ep0_out(), AO_USB_CONTROL_SIZE, AO_USB_CONTROL_SIZE); - ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE); + ao_usb_enable_ep(ao_usb_ep0_out(), ao_usb_ep0_rx_buffer, AO_USB_CONTROL_SIZE); lpc_usb_endpoint.setup = ao_usb_sram_offset(ao_usb_ep0_setup_buffer); - ao_usb_ep0_tx_buffer = ao_usb_enable_ep(ao_usb_ep0_in(), AO_USB_CONTROL_SIZE, 0); + ao_usb_enable_ep(ao_usb_ep0_in(), ao_usb_ep0_tx_buffer, 0); /* Clear all of the other endpoints */ for (e = 1; e <= 4; e++) ao_usb_disable_epn(e); - + ao_usb_reset(); } static void @@ -345,15 +358,29 @@ ao_usb_set_configuration(void) debug ("ao_usb_set_configuration\n"); /* Set up the INT end point */ - ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL); - + ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, NULL); + /* Set up the OUT end point */ - ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL); + ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, ao_usb_out_rx_buffer[0], NULL); + + /* Set the current RX pointer to the *other* buffer so that when buffer 0 gets + * data, we'll switch to it and pull bytes from there + */ + ao_usb_out_rx_cur = 1; /* Set up the IN end point */ - ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer); + ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, ao_usb_in_tx_buffer[0]); + ao_usb_in_tx_cur = 0; + + ao_usb_in_flushed = 0; + ao_usb_in_pending = 0; + ao_wakeup(&ao_usb_in_pending); + + ao_usb_out_avail = 0; + ao_usb_configuration = 0; ao_usb_running = 1; + ao_wakeup(&ao_usb_running); } /* Send an IN data packet */ @@ -366,10 +393,11 @@ ao_usb_ep0_flush(void) if (this_len > AO_USB_CONTROL_SIZE) this_len = AO_USB_CONTROL_SIZE; - if (this_len < AO_USB_CONTROL_SIZE) - ao_usb_ep0_state = AO_USB_EP0_IDLE; - ao_usb_ep0_in_len -= this_len; + ao_usb_ep0_in_max -= this_len; + + if (this_len < AO_USB_CONTROL_SIZE || ao_usb_ep0_in_max == 0) + ao_usb_ep0_state = AO_USB_EP0_IDLE; debug_data ("Flush EP0 len %d:", this_len); memcpy(ao_usb_ep0_tx_buffer, ao_usb_ep0_in_data, this_len); @@ -440,20 +468,21 @@ ao_usb_ep0_out_set(uint8_t *data, uint8_t len) } static void -ao_usb_ep0_in_start(uint8_t max) +ao_usb_ep0_in_start(uint16_t max) { + ao_usb_ep0_in_max = max; /* Don't send more than asked for */ if (ao_usb_ep0_in_len > max) ao_usb_ep0_in_len = max; ao_usb_ep0_flush(); } -static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; +struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; /* Walk through the list of descriptors and find a match */ static void -ao_usb_get_descriptor(uint16_t value) +ao_usb_get_descriptor(uint16_t value, uint16_t length) { const uint8_t *descriptor; uint8_t type = value >> 8; @@ -467,6 +496,8 @@ ao_usb_get_descriptor(uint16_t value) len = descriptor[2]; else len = descriptor[0]; + if (len > length) + len = length; ao_usb_ep0_in_set(descriptor, len); break; } @@ -511,7 +542,7 @@ ao_usb_ep0_setup(void) break; case AO_USB_REQ_GET_DESCRIPTOR: debug ("get descriptor %d\n", ao_usb_setup.value); - ao_usb_get_descriptor(ao_usb_setup.value); + ao_usb_get_descriptor(ao_usb_setup.value, ao_usb_setup.length); break; case AO_USB_REQ_GET_CONFIGURATION: debug ("get configuration %d\n", ao_usb_configuration); @@ -580,7 +611,7 @@ ao_usb_ep0_handle(uint8_t receive) if (receive & AO_USB_EP0_GOT_RESET) { debug ("\treset\n"); - ao_usb_set_ep0(); + ao_usb_reset(); return; } if (receive & AO_USB_EP0_GOT_SETUP) { @@ -616,11 +647,12 @@ ao_usb_ep0_handle(uint8_t receive) } } -static uint16_t control_count; +#if USB_DEBUG static uint16_t int_count; static uint16_t in_count; static uint16_t out_count; static uint16_t reset_count; +#endif void lpc_usb_irq_isr(void) @@ -648,17 +680,21 @@ lpc_usb_irq_isr(void) /* Handle OUT packets */ if (intstat & (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP))) { +#if USB_DEBUG ++out_count; +#endif _rx_dbg1("RX ISR", *ao_usb_epn_out(AO_USB_OUT_EP)); ao_usb_out_avail = 1; _rx_dbg0("out avail set"); - ao_wakeup(&ao_stdin_ready); + ao_wakeup(AO_USB_OUT_SLEEP_ADDR) _rx_dbg0("stdin awoken"); } /* Handle IN packets */ if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP))) { +#if USB_DEBUG ++in_count; +#endif _tx_dbg1("TX ISR", *ao_usb_epn_in(AO_USB_IN_EP)); ao_usb_in_pending = 0; ao_wakeup(&ao_usb_in_pending); @@ -693,8 +729,8 @@ _ao_usb_in_send(void) ao_usb_in_pending = 1; if (ao_usb_tx_count != AO_USB_IN_SIZE) ao_usb_in_flushed = 1; - memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count); - ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count); + ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP, 0), ao_usb_in_tx_buffer[ao_usb_in_tx_cur], ao_usb_tx_count); + ao_usb_in_tx_cur = 1 - ao_usb_in_tx_cur; ao_usb_tx_count = 0; _tx_dbg0("in_send end"); } @@ -748,7 +784,7 @@ ao_usb_putchar(char c) _ao_usb_in_wait(); ao_usb_in_flushed = 0; - ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; + ao_usb_in_tx_buffer[ao_usb_in_tx_cur][ao_usb_tx_count++] = (uint8_t) c; /* Send the packet when full */ if (ao_usb_tx_count == AO_USB_IN_SIZE) { @@ -769,13 +805,12 @@ _ao_usb_out_recv(void) _rx_dbg1("out_recv count", ao_usb_rx_count); debug ("recv %d\n", ao_usb_rx_count); - debug_data("Fill OUT len %d:", ao_usb_rx_count); - memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count); - debug_data("\n"); + debug_data("Fill OUT len %d\n", ao_usb_rx_count); ao_usb_rx_pos = 0; + ao_usb_out_rx_cur = 1 - ao_usb_out_rx_cur; /* ACK the packet */ - ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE); + ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer[1-ao_usb_out_rx_cur], AO_USB_OUT_SIZE); } int @@ -800,7 +835,7 @@ _ao_usb_pollchar(void) } /* Pull a character out of the fifo */ - c = ao_usb_rx_buffer[ao_usb_rx_pos++]; + c = ao_usb_out_rx_buffer[ao_usb_out_rx_cur][ao_usb_rx_pos++]; return c; } @@ -811,7 +846,7 @@ ao_usb_getchar(void) ao_arch_block_interrupts(); while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) - ao_sleep(&ao_stdin_ready); + ao_sleep(AO_USB_OUT_SLEEP_ADDR); ao_arch_release_interrupts(); return c; } @@ -821,6 +856,9 @@ ao_usb_disable(void) { ao_arch_block_interrupts(); +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 0); +#endif /* Disable interrupts */ lpc_usb.inten = 0; @@ -849,7 +887,7 @@ ao_usb_enable(void) int t; /* Enable USB pins */ -#if HAS_USB_CONNECT +#if HAS_LPC_USB_CONNECT lpc_ioconf.pio0_6 = ((LPC_IOCONF_FUNC_USB_CONNECT << LPC_IOCONF_FUNC) | (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | (0 << LPC_IOCONF_HYS) | @@ -871,7 +909,7 @@ ao_usb_enable(void) /* Enable USB PHY */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD); - + /* Turn on USB PLL */ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD); @@ -923,7 +961,22 @@ ao_usb_enable(void) for (t = 0; t < 1000; t++) ao_arch_nop(); + ao_usb_sram = lpc_usb_sram; + + ao_usb_ep0_rx_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE); + ao_usb_ep0_tx_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE); + ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE); + + ao_usb_out_rx_buffer[0] = ao_usb_alloc_sram(AO_USB_OUT_SIZE); + ao_usb_out_rx_buffer[1] = ao_usb_alloc_sram(AO_USB_OUT_SIZE); + ao_usb_in_tx_buffer[0] = ao_usb_alloc_sram(AO_USB_IN_SIZE); + ao_usb_in_tx_buffer[1] = ao_usb_alloc_sram(AO_USB_IN_SIZE); + ao_usb_set_ep0(); + +#if HAS_USB_PULLUP + ao_gpio_set(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 1); +#endif } #if USB_ECHO @@ -950,7 +1003,7 @@ ao_usb_irq(void) control_count, out_count, in_count, int_count, reset_count); } -__code struct ao_cmds ao_usb_cmds[] = { +const struct ao_cmds ao_usb_cmds[] = { { ao_usb_irq, "I\0Show USB interrupt counts" }, { 0, NULL } }; @@ -959,6 +1012,13 @@ __code struct ao_cmds ao_usb_cmds[] = { void ao_usb_init(void) { +#if HAS_USB_PULLUP + int i; + ao_enable_output(AO_USB_PULLUP_PORT, AO_USB_PULLUP_PIN, 0); + + for (i = 0; i < 40000; i++) + ao_arch_nop(); +#endif ao_usb_enable(); debug ("ao_usb_init\n"); @@ -968,7 +1028,7 @@ ao_usb_init(void) #if USB_DEBUG ao_cmd_register(&ao_usb_cmds[0]); #endif -#if !USB_ECHO +#if USE_USB_STDIO ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); #endif } @@ -1010,7 +1070,7 @@ static void _dbg(int line, char *msg, uint32_t value) dbg[dbg_i].primask = primask; #if TX_DBG dbg[dbg_i].in_count = in_count; - dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP); + dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP, 0); dbg[dbg_i].in_pending = ao_usb_in_pending; dbg[dbg_i].tx_count = ao_usb_tx_count; dbg[dbg_i].in_flushed = ao_usb_in_flushed; @@ -1019,7 +1079,7 @@ static void _dbg(int line, char *msg, uint32_t value) dbg[dbg_i].rx_count = ao_usb_rx_count; dbg[dbg_i].rx_pos = ao_usb_rx_pos; dbg[dbg_i].out_avail = ao_usb_out_avail; - dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP); + dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP, 0); #endif if (++dbg_i == NUM_USB_DBG) dbg_i = 0;