diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-17 17:51:41 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-17 17:51:41 +0900 |
commit | dce6c70ffc2fdee9dd37fe68413babf618bb12b0 (patch) | |
tree | abf78e743f16e278c8b325b9f2959e276f2552b9 /example-cdc | |
parent | 3651aa64b48d46fa8572a94b23c291d81e9d84ea (diff) |
more fix for chopstx_poll
Diffstat (limited to 'example-cdc')
-rw-r--r-- | example-cdc/sample.c | 128 | ||||
-rw-r--r-- | example-cdc/stream.h | 26 | ||||
-rw-r--r-- | example-cdc/tty.h | 7 | ||||
-rw-r--r-- | example-cdc/usb-cdc.c | 440 |
4 files changed, 325 insertions, 276 deletions
diff --git a/example-cdc/sample.c b/example-cdc/sample.c index 9b9a4a6..699c854 100644 --- a/example-cdc/sample.c +++ b/example-cdc/sample.c @@ -5,7 +5,7 @@ #include "sys.h" /* for set_led */ #include "usb_lld.h" -#include "stream.h" +#include "tty.h" static chopstx_mutex_t mtx; static chopstx_cond_t cnd0; @@ -54,61 +54,12 @@ blk (void *arg) return NULL; } -#define INTR_REQ_USB 20 - -static void * -usb_intr (void *arg) -{ - extern void usb_lld_init (uint8_t feature); - extern void usb_interrupt_handler (void); - - chopstx_intr_t interrupt; - - (void)arg; -#if defined(OLDER_SYS_H) - /* - * Historically (before sys < 3.0), NVIC priority setting for USB - * interrupt was done in usb_lld_sys_init. Thus this code. - * - * When USB interrupt occurs between usb_lld_init (which assumes - * ISR) and chopstx_claim_irq (which clears pending interrupt), - * invocation of usb_interrupt_handler won't occur. - * - * Calling usb_interrupt_handler is no harm even if there were no - * interrupts, thus, we call it unconditionally here, just in case - * if there is a request. - * - * We can't call usb_lld_init after chopstx_claim_irq, as - * usb_lld_init does its own setting for NVIC. Calling - * chopstx_claim_irq after usb_lld_init overrides that. - * - */ - usb_lld_init (0x80); /* Bus powered. */ - chopstx_claim_irq (&interrupt, INTR_REQ_USB); - usb_interrupt_handler (); -#else - chopstx_claim_irq (&interrupt, INTR_REQ_USB); - usb_lld_init (0x80); /* Bus powered. */ -#endif - - while (1) - { - chopstx_intr_wait (&interrupt); - - /* Process interrupt. */ - usb_interrupt_handler (); - } - - return NULL; -} #define PRIO_PWM 3 #define PRIO_BLK 2 -#define PRIO_INTR 4 extern uint8_t __process1_stack_base__, __process1_stack_size__; extern uint8_t __process2_stack_base__, __process2_stack_size__; -extern uint8_t __process3_stack_base__, __process3_stack_size__; const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__; const size_t __stacksize_pwm = (size_t)&__process1_stack_size__; @@ -116,9 +67,6 @@ const size_t __stacksize_pwm = (size_t)&__process1_stack_size__; const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__; const size_t __stacksize_blk = (size_t)&__process2_stack_size__; -const uint32_t __stackaddr_intr = (uint32_t)&__process3_stack_base__; -const size_t __stacksize_intr = (size_t)&__process3_stack_size__; - static char hexchar (uint8_t x) { @@ -132,24 +80,11 @@ static char hexchar (uint8_t x) } -static int -check_recv (void *arg) -{ - struct stream *s = arg; - if ((s->flags & FLAG_CONNECTED) == 0) - return 1; - if ((s->flags & FLAG_RECV_AVAIL)) - return 1; - return 0; -} - - int main (int argc, const char *argv[]) { - struct stream *st; + struct tty *tty; uint8_t count; - extern uint32_t bDeviceState; (void)argc; (void)argv; @@ -158,14 +93,10 @@ main (int argc, const char *argv[]) chopstx_cond_init (&cnd0); chopstx_cond_init (&cnd1); - st = stream_open (); - m = 10; chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL); chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL); - chopstx_create (PRIO_INTR, __stackaddr_intr, __stacksize_intr, - usb_intr, NULL); chopstx_usec_wait (200*1000); @@ -175,67 +106,52 @@ main (int argc, const char *argv[]) chopstx_mutex_unlock (&mtx); u = 1; - while (bDeviceState != CONFIGURED) - chopstx_usec_wait (500*1000); + + tty = tty_open (); + tty_wait_configured (tty); count = 0; + m = 50; while (1) { - uint8_t s[64]; + uint8_t s[128]; u = 1; - if (stream_wait_connection (st) < 0) - { - chopstx_usec_wait (1000*1000); - continue; - } + tty_wait_connection (tty); chopstx_usec_wait (500*1000); /* Send ZLP at the beginning. */ - stream_send (st, s, 0); + tty_send (tty, s, 0); memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32); s[0] = hexchar (count >> 4); s[1] = hexchar (count & 0x0f); count++; - if (stream_send (st, s, 32) < 0) + if (tty_send (tty, s, 32) < 0) continue; while (1) { int size; uint32_t usec; - struct chx_poll_cond poll_desc; - - poll_desc.type = CHOPSTX_POLL_COND; - poll_desc.ready = 0; - poll_desc.cond = &st->cnd; - poll_desc.mutex = &st->mtx; - poll_desc.check = check_recv; - poll_desc.arg = st; - /* With chopstx_poll, we can do timed cond_wait */ usec = 3000000; /* 3.0 seconds */ - if (chopstx_poll (&usec, 1, &poll_desc)) - { - size = stream_recv (st, s + 4); + size = tty_recv (tty, s + 4, &usec); + if (size < 0) + break; - if (size < 0) + if (usec) + { + s[0] = hexchar (size >> 4); + s[1] = hexchar (size & 0x0f); + s[2] = ':'; + s[3] = ' '; + s[size + 4] = '\r'; + s[size + 5] = '\n'; + if (tty_send (tty, s, size + 6) < 0) break; - - if (size >= 0) - { - s[0] = hexchar (size >> 4); - s[1] = hexchar (size & 0x0f); - s[2] = ':'; - s[3] = ' '; - s[size + 4] = '\r'; - s[size + 5] = '\n'; - if (stream_send (st, s, size + 6) < 0) - break; - } } u ^= 1; diff --git a/example-cdc/stream.h b/example-cdc/stream.h deleted file mode 100644 index dbbfb5f..0000000 --- a/example-cdc/stream.h +++ /dev/null @@ -1,26 +0,0 @@ -#define BUFSIZE 128 -#define FLAG_CONNECTED (1 << 0) -#define FLAG_SEND_AVAIL (1 << 1) -#define FLAG_RECV_AVAIL (1 << 2) - -/* - * Current implementation is synchronous and buffers are not yet used. - */ -struct stream { - chopstx_mutex_t mtx; - chopstx_cond_t cnd; - int sending; - unsigned int recv_len; - uint8_t recv_buf[BUFSIZE]; /* Not yet used. */ - uint8_t buf_send[BUFSIZE]; /* Not yet used. */ - uint8_t cnt_send_head; /* Not yet used. */ - uint8_t cnt_send_tail; /* Not yet used. */ - uint8_t cnt_recv_head; /* Not yet used. */ - uint8_t cnt_recv_tail; /* Not yet used. */ - uint32_t flags; -}; - -struct stream *stream_open (void); -int stream_wait_connection (struct stream *st); -int stream_send (struct stream *st, uint8_t *buf, uint8_t count); -int stream_recv (struct stream *st, uint8_t *buf); diff --git a/example-cdc/tty.h b/example-cdc/tty.h new file mode 100644 index 0000000..a2cee4e --- /dev/null +++ b/example-cdc/tty.h @@ -0,0 +1,7 @@ +struct tty; + +struct tty *tty_open (void); +void tty_wait_configured (struct tty *tty); +void tty_wait_connection (struct tty *tty); +int tty_send (struct tty *tty, uint8_t *buf, int count); +int tty_recv (struct tty *tty, uint8_t *buf, uint32_t *timeout); diff --git a/example-cdc/usb-cdc.c b/example-cdc/usb-cdc.c index eadeb6e..adf2773 100644 --- a/example-cdc/usb-cdc.c +++ b/example-cdc/usb-cdc.c @@ -3,17 +3,26 @@ #include <chopstx.h> #include <string.h> #include "usb_lld.h" -#include "stream.h" - -static uint8_t send_buf[64]; -static unsigned int send_len; - -static unsigned int recv_len; - -static uint8_t inputline[64]; -static unsigned int inputline_len; +#include "tty.h" + +#define BUFSIZE 128 +#define FLAG_CONNECTED (1 << 0) +#define FLAG_SEND_READY (1 << 1) +#define FLAG_RECV_AVAIL (1 << 2) + +struct tty { + uint32_t flags; + chopstx_mutex_t mtx; + chopstx_cond_t cnd; + chopstx_intr_t intr; + uint8_t inputline[BUFSIZE]; /* Line editing is supported */ + uint8_t send_buf[BUFSIZE]; /* Sending ring buffer for echo back */ + uint32_t inputline_len : 16; + uint32_t send_head : 8; + uint32_t send_tail : 8; +}; -static struct stream stream; +static struct tty tty; #define ENDP0_RXADDR (0x40) #define ENDP0_TXADDR (0x80) @@ -166,7 +175,7 @@ static const uint8_t vcom_string3[28] = { #define NUM_INTERFACES 2 -uint32_t bDeviceState = UNCONNECTED; /* USB device status */ +static uint32_t bDeviceState = UNCONNECTED; /* USB device status */ void @@ -177,10 +186,10 @@ usb_cb_device_reset (void) /* Initialize Endpoint 0 */ usb_lld_setup_endpoint (ENDP0, EP_CONTROL, 0, ENDP0_RXADDR, ENDP0_TXADDR, 64); - chopstx_mutex_lock (&stream.mtx); - stream.flags = 0; + chopstx_mutex_lock (&tty.mtx); + tty.flags = 0; bDeviceState = ATTACHED; - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_unlock (&tty.mtx); } @@ -195,13 +204,11 @@ usb_cb_ctrl_write_finish (uint8_t req, uint8_t req_no, struct req_args *arg) && USB_SETUP_SET (req) && req_no == USB_CDC_REQ_SET_CONTROL_LINE_STATE) { /* Open/close the connection. */ - chopstx_mutex_lock (&stream.mtx); - stream.flags &= ~FLAG_CONNECTED; - stream.flags |= ((arg->value & CDC_CTRL_DTR) != 0)? FLAG_CONNECTED : 0; - chopstx_cond_signal (&stream.cnd); - recv_len = 0; - usb_lld_rx_enable (ENDP3); - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_lock (&tty.mtx); + tty.flags &= ~FLAG_CONNECTED; + tty.flags |= ((arg->value & CDC_CTRL_DTR) != 0)? FLAG_CONNECTED : 0; + chopstx_cond_signal (&tty.cnd); + chopstx_mutex_unlock (&tty.mtx); } } @@ -404,26 +411,50 @@ usb_cb_interface (uint8_t cmd, struct req_args *arg) } +/* + * Put a character into the ring buffer to be send back. + */ static void -stream_echo_char (int c) +put_char_to_ringbuffer (int c) { - chopstx_mutex_lock (&stream.mtx); - if (send_len < sizeof (send_buf)) - send_buf[send_len++] = c; - else - { - /* All that we can is ignoring the output. */ - ; - } + uint32_t next = (tty.send_tail + 1) % BUFSIZE; + + if (tty.send_head == next) + /* full */ + /* All that we can do is ignore this char. */ + return; + + tty.send_buf[tty.send_tail] = c; + tty.send_tail = next; +} - if (stream.sending == 0) +/* + * Get characters from ring buffer into S. + */ +static int +get_chars_from_ringbuffer (uint8_t *s, int len) +{ + int i = 0; + + if (tty.send_head == tty.send_tail) + /* Empty */ + return i; + + do { - usb_lld_txcpy (send_buf, ENDP1, 0, send_len); - usb_lld_tx_enable (ENDP1, send_len); - send_len = 0; - stream.sending = 1; + s[i++] = tty.send_buf[tty.send_head]; + tty.send_head = (tty.send_head + 1) % BUFSIZE; } - chopstx_mutex_unlock (&stream.mtx); + while (tty.send_head != tty.send_tail && i < len); + + return i; +} + + +static void +tty_echo_char (int c) +{ + put_char_to_ringbuffer (c); } @@ -432,24 +463,13 @@ usb_cb_tx_done (uint8_t ep_num) { if (ep_num == ENDP1) { - chopstx_mutex_lock (&stream.mtx); - stream.sending = 0; - if (send_len) + chopstx_mutex_lock (&tty.mtx); + if ((tty.flags & FLAG_SEND_READY) == 0) { - stream.sending = 1; - usb_lld_txcpy (send_buf, ENDP1, 0, send_len); - usb_lld_tx_enable (ENDP1, send_len); - send_len = 0; + tty.flags |= FLAG_SEND_READY; + chopstx_cond_signal (&tty.cnd); } - else - { - if ((stream.flags & FLAG_SEND_AVAIL)) - { - stream.flags &= ~FLAG_SEND_AVAIL; - chopstx_cond_signal (&stream.cnd); - } - } - chopstx_mutex_unlock (&stream.mtx); + chopstx_mutex_unlock (&tty.mtx); } else if (ep_num == ENDP2) { @@ -458,65 +478,62 @@ usb_cb_tx_done (uint8_t ep_num) } -static void -stream_input_char (int c) +static int +tty_input_char (int c) { unsigned int i; + int r = 0; /* Process DEL, C-U, C-R, and RET as editing command. */ + chopstx_mutex_lock (&tty.mtx); switch (c) { case 0x0d: /* Control-M */ - stream_echo_char (0x0d); - stream_echo_char (0x0a); - chopstx_mutex_lock (&stream.mtx); - if ((stream.flags & FLAG_RECV_AVAIL) == 0) - { - memcpy (stream.recv_buf, inputline, inputline_len); - stream.recv_len = inputline_len; - stream.flags |= FLAG_RECV_AVAIL; - chopstx_cond_signal (&stream.cnd); - } - chopstx_mutex_unlock (&stream.mtx); - inputline_len = 0; + tty_echo_char (0x0d); + tty_echo_char (0x0a); + tty.flags |= FLAG_RECV_AVAIL; + chopstx_cond_signal (&tty.cnd); + r = 1; break; case 0x12: /* Control-R */ - stream_echo_char ('^'); - stream_echo_char ('R'); - stream_echo_char (0x0d); - stream_echo_char (0x0a); - for (i = 0; i < inputline_len; i++) - stream_echo_char (inputline[i]); + tty_echo_char ('^'); + tty_echo_char ('R'); + tty_echo_char (0x0d); + tty_echo_char (0x0a); + for (i = 0; i < tty.inputline_len; i++) + tty_echo_char (tty.inputline[i]); break; case 0x15: /* Control-U */ - for (i = 0; i < inputline_len; i++) + for (i = 0; i < tty.inputline_len; i++) { - stream_echo_char (0x08); - stream_echo_char (0x20); - stream_echo_char (0x08); + tty_echo_char (0x08); + tty_echo_char (0x20); + tty_echo_char (0x08); } - inputline_len = 0; + tty.inputline_len = 0; break; case 0x7f: /* DEL */ - if (inputline_len > 0) + if (tty.inputline_len > 0) { - stream_echo_char (0x08); - stream_echo_char (0x20); - stream_echo_char (0x08); - inputline_len--; + tty_echo_char (0x08); + tty_echo_char (0x20); + tty_echo_char (0x08); + tty.inputline_len--; } break; default: - if (inputline_len < sizeof (inputline)) + if (tty.inputline_len < sizeof (tty.inputline)) { - stream_echo_char (c); - inputline[inputline_len++] = c; + tty_echo_char (c); + tty.inputline[tty.inputline_len++] = c; } else /* Beep */ - stream_echo_char (0x0a); + tty_echo_char (0x0a); break; } + chopstx_mutex_unlock (&tty.mtx); + return r; } void @@ -531,93 +548,228 @@ usb_cb_rx_ready (uint8_t ep_num) r = usb_lld_rx_data_len (ENDP3); usb_lld_rxcpy (recv_buf, ep_num, 0, r); for (i = 0; i < r; i++) - stream_input_char (recv_buf[i]); + if (tty_input_char (recv_buf[i])) + break; - usb_lld_rx_enable (ENDP3); + chopstx_mutex_lock (&tty.mtx); + if ((tty.flags & FLAG_RECV_AVAIL) == 0) + usb_lld_rx_enable (ENDP3); + chopstx_mutex_unlock (&tty.mtx); } } -struct stream * -stream_open (void) +static void *tty_main (void *arg); + +#define INTR_REQ_USB 20 +#define PRIO_TTY 4 + +extern uint8_t __process3_stack_base__, __process3_stack_size__; +const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__; +const size_t __stacksize_tty = (size_t)&__process3_stack_size__; + +struct tty * +tty_open (void) { - chopstx_mutex_init (&stream.mtx); - chopstx_cond_init (&stream.cnd); - return &stream; + chopstx_mutex_init (&tty.mtx); + chopstx_cond_init (&tty.cnd); + tty.flags = 0; + tty.send_head = tty.send_tail = 0; + tty.inputline_len = 0; + + chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, + tty_main, NULL); + return &tty; } -int -stream_wait_connection (struct stream *st) + +static void * +tty_main (void *arg) { - chopstx_mutex_lock (&st->mtx); - while ((stream.flags & FLAG_CONNECTED) == 0) - chopstx_cond_wait (&st->cnd, &st->mtx); - chopstx_mutex_unlock (&st->mtx); - stream.flags &= ~FLAG_SEND_AVAIL; - return 0; + (void)arg; + +#if defined(OLDER_SYS_H) + /* + * Historically (before sys < 3.0), NVIC priority setting for USB + * interrupt was done in usb_lld_sys_init. Thus this code. + * + * When USB interrupt occurs between usb_lld_init (which assumes + * ISR) and chopstx_claim_irq (which clears pending interrupt), + * invocation of usb_interrupt_handler won't occur. + * + * Calling usb_interrupt_handler is no harm even if there were no + * interrupts, thus, we call it unconditionally here, just in case + * if there is a request. + * + * We can't call usb_lld_init after chopstx_claim_irq, as + * usb_lld_init does its own setting for NVIC. Calling + * chopstx_claim_irq after usb_lld_init overrides that. + * + */ + usb_lld_init (0x80); /* Bus powered. */ + chopstx_claim_irq (&tty.intr, INTR_REQ_USB); + usb_interrupt_handler (); +#else + chopstx_claim_irq (&tty.intr, INTR_REQ_USB); + usb_lld_init (0x80); /* Bus powered. */ +#endif + + while (1) + { + chopstx_poll (NULL, 1, &tty.intr); + if (tty.intr.ready) + usb_interrupt_handler (); + + chopstx_mutex_lock (&tty.mtx); + if (bDeviceState == CONFIGURED + && (tty.flags & FLAG_CONNECTED) + && (tty.flags & FLAG_SEND_READY)) + { + uint8_t line[32]; + int len = get_chars_from_ringbuffer (line, sizeof (len)); + + if (len) + { + usb_lld_txcpy (line, ENDP1, 0, len); + usb_lld_tx_enable (ENDP1, len); + tty.flags &= ~FLAG_SEND_READY; + } + } + chopstx_mutex_unlock (&tty.mtx); + } + + return NULL; +} + + +void +tty_wait_configured (struct tty *t) +{ + chopstx_mutex_lock (&t->mtx); + while (bDeviceState != CONFIGURED) + chopstx_cond_wait (&t->cnd, &t->mtx); + chopstx_mutex_unlock (&t->mtx); } +void +tty_wait_connection (struct tty *t) +{ + chopstx_mutex_lock (&t->mtx); + while ((t->flags & FLAG_CONNECTED) == 0) + chopstx_cond_wait (&t->cnd, &t->mtx); + t->flags |= FLAG_SEND_READY; + t->flags &= ~FLAG_RECV_AVAIL; + t->send_head = t->send_tail = 0; + t->inputline_len = 0; + chopstx_mutex_unlock (&t->mtx); +} + +static int +check_tx (struct tty *t) +{ + if ((t->flags & FLAG_SEND_READY)) + /* TX done */ + return 1; + if ((t->flags & FLAG_CONNECTED) == 0) + /* Disconnected */ + return -1; + return 0; +} + int -stream_send (struct stream *st, uint8_t *buf, uint8_t count) +tty_send (struct tty *t, uint8_t *buf, int len) { - int r = 0; + int r; + uint8_t *p; + int count; - chopstx_mutex_lock (&st->mtx); - if ((stream.flags & FLAG_CONNECTED) == 0) - r = -1; - else + p = buf; + count = len >= 64 ? 64 : len; + + while (1) { - stream.sending = 1; - usb_lld_txcpy (buf, ENDP1, 0, count); - usb_lld_tx_enable (ENDP1, count); - stream.flags |= FLAG_SEND_AVAIL; - do + chopstx_mutex_lock (&t->mtx); + while ((r = check_tx (t)) == 0) + chopstx_cond_wait (&t->cnd, &t->mtx); + if (r > 0) { - chopstx_cond_wait (&st->cnd, &st->mtx); - if ((stream.flags & FLAG_SEND_AVAIL) == 0) - break; - else if ((stream.flags & FLAG_CONNECTED) == 0) - { - r = -1; - break; - } + usb_lld_txcpy (p, ENDP1, 0, count); + usb_lld_tx_enable (ENDP1, count); + t->flags &= ~FLAG_SEND_READY; } - while (1); + chopstx_mutex_unlock (&t->mtx); + + len -= count; + p += count; + if (len == 0 && count != 64) + /* + * The size of the last packet should be != 0 + * If 64, send ZLP (zelo length packet) + */ + break; + count = len >= 64 ? 64 : len; } - stream.sending = 0; - chopstx_mutex_unlock (&st->mtx); + return r; } +static int +check_rx (void *arg) +{ + struct tty *t = arg; + + if ((t->flags & FLAG_RECV_AVAIL)) + /* RX */ + return 1; + if ((t->flags & FLAG_CONNECTED) == 0) + /* Disconnected */ + return 1; + return 0; +} + int -stream_recv (struct stream *st, uint8_t *buf) +tty_recv (struct tty *t, uint8_t *buf, uint32_t *timeout) { int r; + chopstx_poll_cond_t poll_desc; + + chopstx_mutex_unlock (&t->mtx); + if ((t->flags & FLAG_RECV_AVAIL) == 0) + usb_lld_rx_enable (ENDP3); + chopstx_mutex_unlock (&t->mtx); + + poll_desc.type = CHOPSTX_POLL_COND; + poll_desc.ready = 0; + poll_desc.cond = &t->cnd; + poll_desc.mutex = &t->mtx; + poll_desc.check = check_rx; + poll_desc.arg = t; + + while (1) + { + chopstx_poll (timeout, 1, &poll_desc); + chopstx_mutex_lock (&t->mtx); + r = check_rx (t); + chopstx_mutex_unlock (&t->mtx); + if (r || (timeout != NULL && *timeout == 0)) + break; + } - chopstx_mutex_lock (&st->mtx); - if ((stream.flags & FLAG_CONNECTED) == 0) + chopstx_mutex_lock (&t->mtx); + if ((t->flags & FLAG_CONNECTED) == 0) r = -1; - else + else if ((t->flags & FLAG_RECV_AVAIL)) { - while (1) - { - if ((stream.flags & FLAG_RECV_AVAIL)) - { - r = stream.recv_len; - memcpy (buf, stream.recv_buf, r); - stream.flags &= ~FLAG_RECV_AVAIL; - break; - } - else if ((stream.flags & FLAG_CONNECTED) == 0) - { - r = -1; - break; - } - chopstx_cond_wait (&st->cnd, &st->mtx); - } + r = t->inputline_len; + memcpy (buf, t->inputline, r); + t->flags &= ~FLAG_RECV_AVAIL; + usb_lld_rx_enable (ENDP3); + t->inputline_len = 0; } - chopstx_mutex_unlock (&st->mtx); + else + r = 0; + chopstx_mutex_unlock (&t->mtx); return r; } |