diff --git a/ChangeLog b/ChangeLog index 7be47e7..974378b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2021-02-17 NIIBE Yutaka + + Backport from master. + * contrib/ackbtn-gnu-linux.c: New. + * mcu/usb-usbip.c (usbip_run_server): Add start-up message. + 2021-02-12 NIIBE Yutaka Backport from 2.1. diff --git a/contrib/ackbtn-gnu-linux.c b/contrib/ackbtn-gnu-linux.c new file mode 100644 index 0000000..32e3589 --- /dev/null +++ b/contrib/ackbtn-gnu-linux.c @@ -0,0 +1,232 @@ +/* + * ackbtn-gnu-linux.c - Acknowledge button support for GNU/Linux + * + * Copyright (C) 2021 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Chopstx, a thread library for embedded. + * + * Chopstx 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, either version 3 of the License, or + * (at your option) any later version. + * + * Chopstx is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * As additional permission under GNU GPL version 3 section 7, you may + * distribute non-source form of the Program without the copy of the + * GNU GPL normally required by section 4, provided you inform the + * recipients of GNU GPL by a written offer. + * + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static pthread_t tid_main; +static pthread_t tid_ui; + +static pthread_mutex_t mutex; +static pthread_cond_t cond; +static int enabled; +static int event_fd; + +static void +ackbtn_intr (int signum, siginfo_t *siginfo, void *arg) +{ + extern void chx_sigmask (ucontext_t *uc); + extern void chx_handle_intr (int signum); + + ucontext_t *uc = arg; + (void)signum; + (void)siginfo; + chx_handle_intr (SIGUSR2); + chx_sigmask (uc); +} + + +#define ACKBTN_ACKED (1 << 0) +#define ACKBTN_TIMEOUT (1 << 2) + +static void * +user_interaction (void *arg) +{ + struct pollfd pollfds[2]; + + (void)arg; + + pollfds[0].fd = 0; /* standard input */ + pollfds[0].events = POLLIN; + + pollfds[1].fd = event_fd; + pollfds[1].events = POLLIN; + + fputs ("User interaction thread for AckBtn started.\n", stdout); + + while (1) + { + unsigned int acked_or_timeout = 0; + char buf[256]; + + pthread_mutex_lock (&mutex); + while (!enabled) + pthread_cond_wait (&cond, &mutex); + pthread_mutex_unlock (&mutex); + + /* Consume all input if any. */ + while (1) + { + int r; + + pollfds[0].revents = 0; + + r = poll (pollfds, 1, 0); + if (r < 0) + { + if (errno == EINTR) + continue; + + perror ("poll"); + exit (1); + } + + if (r == 0) + break; + + if ((pollfds[0].revents & POLLIN)) + read (0, buf, sizeof buf); + } + + fputs ("Type RET to acknowledge (or wait for timeout) > ", stdout); + fflush (stdout); + + while (!acked_or_timeout) + { + pollfds[0].revents = 0; + pollfds[1].revents = 0; + + if (poll (pollfds, 2, -1) < 0) + { + if (errno == EINTR) + continue; + + perror ("poll"); + exit (1); + } + + if ((pollfds[0].revents & POLLIN)) + { + read (0, buf, sizeof buf); + acked_or_timeout |= ACKBTN_ACKED; + } + + if ((pollfds[1].revents & POLLIN)) + acked_or_timeout |= ACKBTN_TIMEOUT; + } + + pthread_mutex_lock (&mutex); + if ((acked_or_timeout & ACKBTN_ACKED)) + { + if ((acked_or_timeout & ACKBTN_TIMEOUT)) + /* No output of newline, as it follows timeout message. */ + fputs ("Input ignored", stdout); + else + { + pthread_kill (tid_main, SIGUSR2); + fputs ("Acknowledged\n", stdout); + } + } + + if ((acked_or_timeout & ACKBTN_TIMEOUT)) + fputs ("\nTimeout\n", stdout); + + while (enabled) + pthread_cond_wait (&cond, &mutex); + + read (event_fd, buf, sizeof (uint64_t)); + pthread_mutex_unlock (&mutex); + } +} + +void +ackbtn_init (chopstx_intr_t *intr) +{ + int r; + sigset_t sigset; + struct sigaction act; + + event_fd = eventfd (0, EFD_CLOEXEC); + if (event_fd < 0) + { + perror ("eventfd"); + exit (1); + } + + pthread_mutex_init (&mutex, NULL); + pthread_cond_init (&cond, NULL); + enabled = 0; + + sigemptyset (&sigset); + sigaddset (&sigset, SIGUSR2); + sigaddset (&sigset, SIGALRM); + + tid_main = pthread_self (); + + /* Launch the thread for user interaction. */ + pthread_sigmask (SIG_BLOCK, &sigset, NULL); + + r = pthread_create (&tid_ui, NULL, user_interaction, NULL); + if (r) + { + fprintf (stderr, "ackbtn_init: %s\n", strerror (r)); + exit (1); + } + + act.sa_sigaction = ackbtn_intr; + sigfillset (&act.sa_mask); + act.sa_flags = SA_SIGINFO|SA_RESTART; + sigaction (SIGUSR2, &act, NULL); + + pthread_sigmask (SIG_UNBLOCK, &sigset, NULL); + + chopstx_claim_irq (intr, SIGUSR2); +} + +void +ackbtn_enable (void) +{ + pthread_mutex_lock (&mutex); + enabled = 1; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&mutex); +} + +void +ackbtn_disable (void) +{ + const uint64_t l = 1; + + pthread_mutex_lock (&mutex); + enabled = 0; + write (event_fd, &l, sizeof (l)); + pthread_cond_signal (&cond); + pthread_mutex_unlock (&mutex); +} diff --git a/mcu/usb-usbip.c b/mcu/usb-usbip.c index 307b988..2ee3522 100644 --- a/mcu/usb-usbip.c +++ b/mcu/usb-usbip.c @@ -1,7 +1,7 @@ /* * usb-usbip.c - USB Device Emulation (server side) by USBIP * - * Copyright (C) 2017, 2018 g10 Code GmbH + * Copyright (C) 2017, 2018, 2021 g10 Code GmbH * Author: NIIBE Yutaka * * This file is a part of Chopstx, a thread library for embedded. @@ -1080,6 +1080,11 @@ usbip_run_server (void *arg) exit (1); } + fputs ("USBIP thread started.\n", stdout); + fputs ("You can use this by attaching following commands:\n", stdout); + fputs (" # modprobe vhci_hcd\n", stdout); + fputs (" # usbip attach -r 127.0.0.1 -b 1-1\n", stdout); + pollfds[1].fd = shutdown_notify_fd; pollfds[1].events = POLLIN; pollfds[1].revents = 0;