Compare commits
15 Commits
release/2.
...
release/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9977bac715 | ||
|
|
446e31a7c4 | ||
|
|
f10cdce66c | ||
|
|
86ccc02be7 | ||
|
|
d36e9274b1 | ||
|
|
5a3a3e98d4 | ||
|
|
7ad2c9030a | ||
|
|
a70b1acbf6 | ||
|
|
fd8bb46b8b | ||
|
|
95fe257dc0 | ||
|
|
2fb3c1c503 | ||
|
|
f84f6c1cac | ||
|
|
68b78a0ade | ||
|
|
8c48b0d7d3 | ||
|
|
b3c35aebdd |
47
ChangeLog
47
ChangeLog
@@ -1,3 +1,50 @@
|
||||
2021-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 2.3
|
||||
* doc/chopstx.texi (VERSION): 2.3.
|
||||
|
||||
2021-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-usbip.c (URB_DATA_SIZE): Tweak the value.
|
||||
|
||||
2021-02-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 2.2
|
||||
* doc/chopstx.texi (VERSION): 2.2.
|
||||
|
||||
2021-02-25 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* rules.mk (MCFLAGS): Add -masm-syntax-unified.
|
||||
|
||||
* entry-cortex-m.c (entry): Use Thumb-16 instruction in unified
|
||||
asm syntax. This means that no output change for Cortex-M0,
|
||||
but change for Cortex-M3/M4 (shorter, different semantics).
|
||||
|
||||
* example-fsm-55/reset.c (reset): Likewise.
|
||||
|
||||
* chopstx-cortex-m.c
|
||||
[__ARM_ARCH_6M__] (involuntary_context_switch): Use unified syntax.
|
||||
[__ARM_ARCH_7M__] (involuntary_context_switch): Use Thumb-16
|
||||
instruction.
|
||||
[__ARM_ARCH_6M__] (chx_handle_intr): Use unified syntax.
|
||||
[__ARM_ARCH_7M__] (chx_handle_intr): Use Thumb-16 instruction.
|
||||
[__ARM_ARCH_6M__] (voluntary_context_switch): Use unified syntax.
|
||||
[__ARM_ARCH_7M__] (svc): Use Thumb-16 instruction.
|
||||
|
||||
2021-02-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (chx_handle_intr): Fix SUB instruction.
|
||||
|
||||
2021-02-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/adc-gnu-linux.c (adc_start_conversion): Use getrandom.
|
||||
|
||||
* mcu/usb-usbip.c (usbip_run_server): Add start-up message.
|
||||
|
||||
2021-02-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/ackbtn-gnu-linux.c: New.
|
||||
|
||||
2021-02-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 2.1
|
||||
|
||||
29
NEWS
29
NEWS
@@ -1,6 +1,33 @@
|
||||
NEWS - Noteworthy changes
|
||||
|
||||
|
||||
* Major changes in Chopstx 2.3
|
||||
|
||||
Released 2021-10-12
|
||||
|
||||
** Fix of USB driver for GNU/Linux emulation
|
||||
|
||||
Fix the value of URB_DATA_SIZE, so that Gnuk can work with PC/SC.
|
||||
|
||||
|
||||
* Major changes in Chopstx 2.2
|
||||
|
||||
Released 2021-02-25
|
||||
|
||||
** Acknowledge button support for GNU/Linux emulation
|
||||
User is asked acknowledge by RET with standard input.
|
||||
|
||||
** USB driver for GNU/Linux emulation
|
||||
It shows start-up message now.
|
||||
|
||||
** ADC driver for GNU/Linux emulation
|
||||
It uses getrandom(2), output is not deterministic any more.
|
||||
|
||||
** Bug fix for Cortex-M3/M4 Support
|
||||
In 2.1, preemption doesn't work well, because of the difference of
|
||||
assembler syntax.
|
||||
|
||||
|
||||
* Major changes in Chopstx 2.1
|
||||
|
||||
Released 2021-02-12
|
||||
@@ -17,7 +44,7 @@ In 2.0, GNU/Linux emulation doesn't work well with chx_idle when it
|
||||
handles interrupt synchronously and the waken thread is the same one
|
||||
which called chx_idle.
|
||||
|
||||
** Bug fix for Cortex-M0/Cortex-M3 Support
|
||||
** Bug fix for Cortex-M0/M3/M4 Support
|
||||
In 2.0, Cortex-M0 with no tail-chaining support (e.g. STM32F030)
|
||||
doesn't work. In 2.0, Cortex-M3/M4 may fail when two or more
|
||||
interrupts occur simultaneously; A waken thread (which is about to
|
||||
|
||||
15
README
15
README
@@ -1,6 +1,6 @@
|
||||
Chopstx - Threads and only Threads
|
||||
Version 2.0
|
||||
2020-06-26
|
||||
Version 2.3
|
||||
2021-10-12
|
||||
Niibe Yutaka
|
||||
Flying Stone Technology
|
||||
|
||||
@@ -9,7 +9,7 @@ What's Chopstx?
|
||||
|
||||
Chopstx is an RT thread library for STM32F103 and GD32F103 (ARM
|
||||
Cortex-M3), STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus),
|
||||
STM32L432 (ARM Cortex-M4), GD32V103 (RISC-V Bumblebee) and emulation
|
||||
STM32L432 (ARM Cortex-M4), GD32VF103 (RISC-V Bumblebee) and emulation
|
||||
on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and protocol
|
||||
@@ -28,7 +28,8 @@ Note that this library is _not_ related to the hand game:
|
||||
https://en.wikipedia.org/wiki/Chopsticks_(hand_game)
|
||||
|
||||
Thanks to Yao Wei and Enrico Zini for giving me an opportunity
|
||||
visiting the wiki page above, when my children were playing the game.
|
||||
visiting the wiki page above in Debconf Taiwan, when my children were
|
||||
playing the game.
|
||||
|
||||
|
||||
License
|
||||
@@ -65,7 +66,7 @@ Convenience function to determine the bottom of thread stack,
|
||||
configuration of thread size by compiler's output would be next things
|
||||
to be done.
|
||||
|
||||
Experimental SMP port for Cortex-A7 is under development. For SMP,
|
||||
more careful considerations for shared access to objects of struct
|
||||
chx_pq is needed. So, modifications required will not be small.
|
||||
We have an experimental SMP port for Cortex-A7. For SMP, more careful
|
||||
considerations for shared access to objects of struct chx_pq is
|
||||
needed. So, modifications required will not be small.
|
||||
--
|
||||
|
||||
@@ -272,7 +272,7 @@ involuntary_context_switch (struct chx_thread *tp_next)
|
||||
{
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm volatile (
|
||||
"add %0, #20\n\t"
|
||||
"adds %0, #20\n\t"
|
||||
"stm %0!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
@@ -287,7 +287,7 @@ involuntary_context_switch (struct chx_thread *tp_next)
|
||||
* works. R7 keeps its value, but having "r7" here prevents
|
||||
* use of R7 before this asm statement.
|
||||
*/
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
: "cc", "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
tp_next = chx_running_preempted (tp_next);
|
||||
}
|
||||
@@ -301,7 +301,7 @@ involuntary_context_switch (struct chx_thread *tp_next)
|
||||
/* Update running: chx_set_running */
|
||||
"str r0, [r1]\n\t"
|
||||
/**/
|
||||
"add r0, #20\n\t"
|
||||
"adds r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
@@ -319,8 +319,8 @@ involuntary_context_switch (struct chx_thread *tp_next)
|
||||
"ldr r1, [r0], #4\n\t"
|
||||
"msr PSP, r1\n\t"
|
||||
#endif
|
||||
"mov r0, #0\n\t"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"movs r0, #0\n\t"
|
||||
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0"
|
||||
: /* no output */ : "r" (tp_next) : "memory");
|
||||
}
|
||||
@@ -334,14 +334,15 @@ chx_handle_intr (void)
|
||||
register struct chx_thread *tp_next asm ("r0");;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
"sub %0, #16\n\t" /* Exception # - 16 = interrupt number. */
|
||||
/* Exception # - 16 = interrupt number. */
|
||||
"subs %0, #16\n\t"
|
||||
"bpl 0f\n\t"
|
||||
"bl chx_timer_expired\n\t"
|
||||
"b 1f\n"
|
||||
"0:\n\t"
|
||||
"bl chx_recv_irq\n"
|
||||
"1:"
|
||||
: "=r" (tp_next) : /* no input */ : "memory");
|
||||
: "=r" (tp_next) : /* no input */ : "cc", "memory");
|
||||
|
||||
if (tp_next)
|
||||
asm volatile (
|
||||
@@ -349,8 +350,8 @@ chx_handle_intr (void)
|
||||
: /*no input */ : /* no input */ : "memory");
|
||||
else
|
||||
asm volatile (
|
||||
"mov r0, #0\n\t"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"movs r0, #0\n\t"
|
||||
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0"
|
||||
: /*no input */ : /* no input */ : "memory");
|
||||
}
|
||||
@@ -392,10 +393,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
*/
|
||||
asm ("mov %0, lr\n\t"
|
||||
"ldr r2, =.L_CONTEXT_SWITCH_FINISH\n\t"
|
||||
"mov r3, #128\n\t"
|
||||
"lsl r3, #17\n\t"
|
||||
"movs r3, #128\n\t"
|
||||
"lsls r3, #17\n\t"
|
||||
"push {%0, r2, r3}\n\t"
|
||||
"mov %0, #0\n\t"
|
||||
"movs %0, #0\n\t"
|
||||
"mov r2, %0\n\t"
|
||||
"mov r3, %0\n\t"
|
||||
"push {%0, r2, r3}\n\t"
|
||||
@@ -404,10 +405,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
"push {%0, r3}\n\t"
|
||||
: "=r" (tp)
|
||||
: /* no input */
|
||||
: "r2", "r3", "memory");
|
||||
: "cc", "r2", "r3", "memory");
|
||||
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm ("add r1, #20\n\t"
|
||||
asm ("adds r1, #20\n\t"
|
||||
"stm r1!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
@@ -415,10 +416,10 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
"mov r5, r11\n\t"
|
||||
"mov r6, sp\n\t"
|
||||
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"sub r1, #56"
|
||||
"subs r1, #56"
|
||||
: /* no output */
|
||||
: "r" (tp)
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
: "cc", "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
asm volatile (/* Now, r0 points to the thread to be switched. */
|
||||
/* Put it to *running. */
|
||||
@@ -439,7 +440,7 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
|
||||
/* Normal context switch */
|
||||
"0:\n\t"
|
||||
"add r0, #20\n\t"
|
||||
"adds r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
"mov r8, r1\n\t"
|
||||
@@ -464,12 +465,12 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
[28 or 32] <-- pc
|
||||
*/
|
||||
"ldr r0, [sp, #28]\n\t"
|
||||
"lsl r1, r0, #23\n\t"
|
||||
"lsls r1, r0, #23\n\t"
|
||||
"bcc 2f\n\t"
|
||||
/**/
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"movs r1, #1\n\t"
|
||||
"orrs r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #32]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
@@ -482,8 +483,8 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
"pop {pc}\n"
|
||||
"2:\n\t"
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"movs r1, #1\n\t"
|
||||
"orrs r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #28]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
@@ -495,11 +496,11 @@ voluntary_context_switch (struct chx_thread *tp_next)
|
||||
"add sp, #12\n\t"
|
||||
"pop {pc}\n\t"
|
||||
".L_CONTEXT_SWITCH_FINISH:\n\t"
|
||||
"add r0, #16\n\t"
|
||||
"adds r0, #16\n\t"
|
||||
"ldr r0, [r0]" /* Get tp->v */
|
||||
: "=r" (result) /* Return value in R0 */
|
||||
: "0" (tp_next)
|
||||
: "memory");
|
||||
: "cc", "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
@@ -548,7 +549,7 @@ svc (void)
|
||||
|
||||
asm ("ldr r1, =running\n\t"
|
||||
"ldr r1, [r1]\n\t"
|
||||
"add r1, #20\n\t"
|
||||
"adds r1, #20\n\t"
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
"stm r1!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
@@ -558,11 +559,11 @@ svc (void)
|
||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"ldr r0, [r6]\n\t"
|
||||
"sub r1, #56\n\t"
|
||||
"subs r1, #56\n\t"
|
||||
"str r1, [r6]"
|
||||
: "=r" (tp_next)
|
||||
: /* no input */
|
||||
: "r1", "r2", "r3", "r4", "r5", "r6", "memory");
|
||||
: "cc", "r1", "r2", "r3", "r4", "r5", "r6", "memory");
|
||||
|
||||
asm volatile (
|
||||
/* Now, r0 points to the thread to be switched. */
|
||||
@@ -572,7 +573,7 @@ svc (void)
|
||||
"str r0, [r1]\n\t"
|
||||
"cbz r0, 1f\n\t"
|
||||
/**/
|
||||
"add r0, #20\n\t"
|
||||
"adds r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"ldr r8, [r0], #4\n\t"
|
||||
"ldr r9, [r0], #4\n\t"
|
||||
@@ -581,27 +582,27 @@ svc (void)
|
||||
"ldr r1, [r0], #4\n\t"
|
||||
"msr PSP, r1\n\t"
|
||||
/* Unmask interrupts. */
|
||||
"mov r0, #0\n\t"
|
||||
"movs r0, #0\n\t"
|
||||
"msr BASEPRI, r0\n\t"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0\n"
|
||||
"1:\n\t"
|
||||
/* Spawn an IDLE thread. */
|
||||
"ldr r0, =__main_stack_end__-32\n\t"
|
||||
"msr PSP, r0\n\t"
|
||||
"mov r1, #0\n\t"
|
||||
"mov r2, #0\n\t"
|
||||
"mov r3, #0\n\t"
|
||||
"movs r1, #0\n\t"
|
||||
"movs r2, #0\n\t"
|
||||
"movs r3, #0\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"ldr r1, =chx_idle\n\t" /* PC = idle */
|
||||
"mov r2, #0x010\n\t"
|
||||
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
|
||||
"movs r2, #0x010\n\t"
|
||||
"lsls r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
|
||||
"stm r0!, {r1, r2}\n\t"
|
||||
/* Unmask interrupts. */
|
||||
"mov r0, #0\n\t"
|
||||
"movs r0, #0\n\t"
|
||||
"msr BASEPRI, r0\n"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"subs r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0"
|
||||
: /* no output */ : "r" (tp_next) : "memory");
|
||||
}
|
||||
|
||||
@@ -949,7 +949,9 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
* chopstx_mutex_unlock - Unlock the mutex
|
||||
* @mutex: Mutex
|
||||
*
|
||||
* Unlock @mutex.
|
||||
* Unlock @mutex. Note that Chopstx doesn't allow unlocking by
|
||||
* non-owner of the lock. chopstx_mutex_unlock should be called
|
||||
* by a thread which did chopstx_mutex_lock.
|
||||
*/
|
||||
void
|
||||
chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
|
||||
232
contrib/ackbtn-gnu-linux.c
Normal file
232
contrib/ackbtn-gnu-linux.c
Normal file
@@ -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 <gniibe@fsij.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <pthread.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* This ADC driver just fills pseudo random values.
|
||||
* It's completely useless other than for NeuG.
|
||||
*
|
||||
* Copyright (C) 2017 Free Software Initiative of Japan
|
||||
* Copyright (C) 2017, 2021 Free Software Initiative of Japan
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -33,7 +33,7 @@
|
||||
#include <chopstx.h>
|
||||
#include "adc.h"
|
||||
|
||||
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
|
||||
#include <sys/random.h>
|
||||
|
||||
/*
|
||||
* Do calibration for ADC.
|
||||
@@ -41,7 +41,6 @@
|
||||
int
|
||||
adc_init (void)
|
||||
{
|
||||
srandom (ADC_RANDOM_SEED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -55,8 +54,7 @@ uint32_t adc_buf[64];
|
||||
void
|
||||
adc_start_conversion (int offset, int count)
|
||||
{
|
||||
while (count--)
|
||||
adc_buf[offset++] = random ();
|
||||
getrandom (adc_buf+offset, count, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename chopstx.info
|
||||
@set VERSION 2.1
|
||||
@set VERSION 2.3
|
||||
@settitle Chopstx Reference Manual
|
||||
@c Unify some of the indices.
|
||||
@syncodeindex tp fn
|
||||
|
||||
@@ -113,7 +113,7 @@ entry (void)
|
||||
{
|
||||
asm volatile ("bl clock_init\n\t"
|
||||
/* Clear BSS section. */
|
||||
"mov r0, #0\n\t"
|
||||
"movs r0, #0\n\t"
|
||||
"ldr r1, =_bss_start\n\t"
|
||||
"ldr r2, =_bss_end\n"
|
||||
"0:\n\t"
|
||||
@@ -121,7 +121,7 @@ entry (void)
|
||||
"beq 1f\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"str r0, [r1]\n\t"
|
||||
"add r1, #4\n\t"
|
||||
"adds r1, #4\n\t"
|
||||
#else
|
||||
"str r0, [r1], #4\n\t"
|
||||
#endif
|
||||
@@ -137,8 +137,8 @@ entry (void)
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"ldr r0, [r3]\n\t"
|
||||
"str r0, [r1]\n\t"
|
||||
"add r3, #4\n\t"
|
||||
"add r1, #4\n\t"
|
||||
"adds r3, #4\n\t"
|
||||
"adds r1, #4\n\t"
|
||||
#else
|
||||
"ldr r0, [r3], #4\n\t"
|
||||
"str r0, [r1], #4\n\t"
|
||||
@@ -147,9 +147,9 @@ entry (void)
|
||||
"3:\n\t"
|
||||
/* Switch to PSP. */
|
||||
"ldr r0, =__process0_stack_end__\n\t"
|
||||
COMPOSE_STATEMENT ("sub r0, #", CHOPSTX_THREAD_SIZE, "\n\t")
|
||||
COMPOSE_STATEMENT ("subs r0, #", CHOPSTX_THREAD_SIZE, "\n\t")
|
||||
"msr PSP, r0\n\t" /* Process (main routine) stack. */
|
||||
"mov r1, #2\n\t"
|
||||
"movs r1, #2\n\t"
|
||||
"msr CONTROL, r1\n\t"
|
||||
"isb\n\t"
|
||||
"bl chx_init\n\t"
|
||||
@@ -157,7 +157,7 @@ entry (void)
|
||||
"bl gpio_init\n\t"
|
||||
/* Enable interrupts. */
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
"mov r0, #0\n\t"
|
||||
"movs r0, #0\n\t"
|
||||
"msr BASEPRI, r0\n\t"
|
||||
#endif
|
||||
"cpsie i\n\t"
|
||||
|
||||
@@ -19,10 +19,10 @@ reset (void)
|
||||
{
|
||||
asm volatile ("cpsid i\n\t" /* Mask all interrupts. */
|
||||
"mov r0, pc\n\t" /* r0 = PC & ~0x0fff */
|
||||
"mov r1, #0x10\n\t"
|
||||
"lsl r1, #8\n\t"
|
||||
"sub r1, r1, #1\n\t"
|
||||
"bic r0, r0, r1\n\t"
|
||||
"movs r1, #0x10\n\t"
|
||||
"lsls r1, #8\n\t"
|
||||
"subs r1, #1\n\t"
|
||||
"bics r0, r0, r1\n\t"
|
||||
"ldr r2, [r0]\n\t"
|
||||
"msr MSP, r2\n\t" /* Main (exception handler) stack. */
|
||||
"b entry\n\t"
|
||||
|
||||
133
mcu/usb-usbip.c
133
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 <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -22,10 +22,26 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
RESET handling
|
||||
USB Shutdown
|
||||
Use reply structure of its own
|
||||
* This driver is intended to emulate USB full-speed device, which
|
||||
* maximum packet size is 64.
|
||||
*
|
||||
* "USBIP" is actually URB over network (instead of USB packet over
|
||||
* network), and its (current) naive protocol may expose possible
|
||||
* demarcation problem, which never occurs in real host-device; In
|
||||
* real host-device relationship, it is host side, which does
|
||||
* composition/decomposition of URB to/from packets. In an
|
||||
* implmentation of USB device with USBIP, it needs to be device side,
|
||||
* which does composition/decomposition of URB to/from packets.
|
||||
*
|
||||
* In this implementation of USB driver, URB_DATA_SIZE is defined as
|
||||
* (65544+10), because (major) target device intended is CCID. In the
|
||||
* CCID specification, you can find the value 65544+10.
|
||||
*/
|
||||
/*
|
||||
* FIXME:
|
||||
* RESET handling
|
||||
* USB Shutdown
|
||||
* Use reply structure of its own
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
@@ -96,7 +112,7 @@ struct urb {
|
||||
struct urb *next;
|
||||
struct urb *prev;
|
||||
|
||||
uint16_t remain;
|
||||
uint32_t remain;
|
||||
char *data_p;
|
||||
|
||||
pthread_t tid;
|
||||
@@ -236,7 +252,67 @@ attach_device (char busid[32], size_t *len_p)
|
||||
return (const char *)&usbip_usb_device;
|
||||
}
|
||||
|
||||
#define URB_DATA_SIZE 65535
|
||||
/*
|
||||
* The number 65544 comes from ISO 7816-4, which defines data format
|
||||
* of smartcard; CLS INS P1 P2 occupies four octets. Then, Lc-octet
|
||||
* to represent size of command data block, then command data block.
|
||||
* Lastly, Le-octet to represent size of response data block to be
|
||||
* returned.
|
||||
*
|
||||
* /----- for CLS INS P1 P2
|
||||
* |
|
||||
* | /-- for Lc
|
||||
* | |
|
||||
* | | /-- for data block
|
||||
* | | |
|
||||
* | | | /-- for Le
|
||||
* | | | |
|
||||
* v v v v
|
||||
* 4 + 3 + 65535 + 2 = 65544
|
||||
*
|
||||
* The number 10 comes from the CCID protocol specification; It is the
|
||||
* header size of CCID. Besides, we can find the number 65544 in the
|
||||
* CCID protocol specification, too.
|
||||
*
|
||||
* And... we have "AND ONE MORE" three times.
|
||||
*
|
||||
* We accept that, as Buddha did.
|
||||
*
|
||||
* There are different interpretations for the historical fact and the
|
||||
* idiom. Most likely, nowadays, here, third-time is considered a
|
||||
* strikeout, perhaps, due to popularity of baseball.
|
||||
*/
|
||||
#define URB_DATA_SIZE (65544+10+1+1+1)
|
||||
|
||||
/*
|
||||
* The reasons why there are "+1" three times.
|
||||
*
|
||||
* Wrong (1): +1, because of confusion of data size maximum.
|
||||
* Wrong (2): +1, because of confusion of the size for Le.
|
||||
* Wrong (3): +1, because of keeping applying old patch.
|
||||
*
|
||||
* Something like this may occur, unfortunately, in our world.
|
||||
*
|
||||
* We need to consider the real case of the max buffer size for
|
||||
* libusb_bulk_transfer with CCID (let us call this "CASE_MAX").
|
||||
*
|
||||
* (1) Although the data size maximum (for all cases) is 65536, it
|
||||
* only occurs when Le size is zero. In the particular case of
|
||||
* CASE_MAX, it is actually 65535. When just applying the max value
|
||||
* 65536, +1 occurs.
|
||||
*
|
||||
* (2) Although maximum size to represent Le is 3, it only occurs when
|
||||
* Lc size is zero. In the particular case of CASE_MAX, it is
|
||||
* actually 2. When just applying the max value 3, +1 occurs.
|
||||
*
|
||||
* (3) Fedora keeps a old patch for Ominikey 3121. The patch was
|
||||
* written when the value of CMD_BUF_SIZE in libccid was small for
|
||||
* short extended APDU exchange. In the patch, it uses the value 11
|
||||
* for the header size (instead of 10) of TPDU, for its special
|
||||
* support. Historically, CMD_BUF_SIZE in libccid was updated
|
||||
* to bigger value to handle extended APDU exchange. When just applying
|
||||
* the old patch using 11, +1 occurs.
|
||||
*/
|
||||
|
||||
struct usbip_msg_cmd {
|
||||
uint32_t devid;
|
||||
@@ -299,12 +375,14 @@ static int write_data_transaction (struct usb_control *usbc_p,
|
||||
static int read_data_transaction (struct usb_control *usbc_p,
|
||||
int ep_num, char *buf, uint16_t count);
|
||||
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For USB fullspeed device. */
|
||||
|
||||
static int
|
||||
hc_handle_control_urb (struct urb *urb)
|
||||
{
|
||||
int r;
|
||||
uint16_t count;
|
||||
uint16_t remain = urb->len;
|
||||
uint32_t remain = urb->len;
|
||||
uint64_t l;
|
||||
|
||||
if ((debug & DEBUG_USB))
|
||||
@@ -325,10 +403,10 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
while (r == 0)
|
||||
{
|
||||
if (remain > 64)
|
||||
count = 64;
|
||||
if (remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = remain;
|
||||
count = (uint16_t)remain;
|
||||
|
||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||
r = control_write_data_transaction (urb->data_p, count);
|
||||
@@ -337,7 +415,7 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
urb->data_p += count;
|
||||
remain -= count;
|
||||
if (count < 64)
|
||||
if (count < USB_MAX_PACKET_SIZE)
|
||||
break;
|
||||
}
|
||||
if (r >= 0)
|
||||
@@ -353,10 +431,10 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (remain > 64)
|
||||
count = 64;
|
||||
if (remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = remain;
|
||||
count = (uint16_t)remain;
|
||||
|
||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||
r = control_read_data_transaction (urb->data_p, count);
|
||||
@@ -368,7 +446,7 @@ hc_handle_control_urb (struct urb *urb)
|
||||
|
||||
remain -= r;
|
||||
urb->data_p += r;
|
||||
if (r < 64)
|
||||
if (r < USB_MAX_PACKET_SIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -516,10 +594,10 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
if ((debug & DEBUG_USB))
|
||||
puts ("hc_hdu 0");
|
||||
|
||||
if (urb->remain > 64)
|
||||
count = 64;
|
||||
if (urb->remain > USB_MAX_PACKET_SIZE)
|
||||
count = USB_MAX_PACKET_SIZE;
|
||||
else
|
||||
count = urb->remain;
|
||||
count = (uint16_t)urb->remain;
|
||||
|
||||
if (urb->dir == USBIP_DIR_OUT)
|
||||
{ /* Output from host to device. */
|
||||
@@ -533,7 +611,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
urb->data_p += count;
|
||||
urb->remain -= count;
|
||||
|
||||
if (urb->remain == 0 || count < 64)
|
||||
if (urb->remain == 0 || count < USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
size_t len = urb->len - urb->remain;
|
||||
|
||||
@@ -565,7 +643,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
||||
|
||||
urb->remain -= r;
|
||||
urb->data_p += r;
|
||||
if (urb->remain == 0 || r < 64)
|
||||
if (urb->remain == 0 || r < USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
size_t len = urb->len - urb->remain;
|
||||
|
||||
@@ -596,7 +674,7 @@ issue_get_desc (void)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
urb = malloc (sizeof (struct urb) + 64);
|
||||
urb = malloc (sizeof (struct urb) + USB_MAX_PACKET_SIZE);
|
||||
|
||||
urb->next = urb->prev = urb;
|
||||
|
||||
@@ -606,14 +684,14 @@ issue_get_desc (void)
|
||||
urb->setup[3] = 1; /* Value H: desc_type */
|
||||
urb->setup[4] = 0; /* Index */
|
||||
urb->setup[5] = 0;
|
||||
urb->setup[6] = 64; /* Length */
|
||||
urb->setup[6] = USB_MAX_PACKET_SIZE; /* Length */
|
||||
urb->setup[7] = 0;
|
||||
urb->data_p = urb->data;
|
||||
urb->seq = 0;
|
||||
urb->devid = 0;
|
||||
urb->dir = USBIP_DIR_IN;
|
||||
urb->ep = 0;
|
||||
urb->remain = urb->len = 64;
|
||||
urb->remain = urb->len = USB_MAX_PACKET_SIZE;
|
||||
hc_handle_control_urb (urb);
|
||||
return urb;
|
||||
}
|
||||
@@ -729,7 +807,7 @@ usbip_handle_urb (uint32_t seq)
|
||||
|
||||
leave:
|
||||
msg.cmd = htonl (REP_URB_SUBMIT);
|
||||
msg.seq = htonl (urb->seq);
|
||||
msg.seq = htonl (seq);
|
||||
|
||||
memset (&msg_rep, 0, sizeof (msg_rep));
|
||||
msg_rep.status = htonl (r);
|
||||
@@ -1080,6 +1158,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;
|
||||
|
||||
2
rules.mk
2
rules.mk
@@ -71,7 +71,7 @@ MCFLAGS = -march=rv32imac -mabi=ilp32
|
||||
LDFLAGS = $(MCFLAGS) -nodefaultlibs -nostartfiles -lc -T$(LDSCRIPT) \
|
||||
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch
|
||||
else
|
||||
MCFLAGS = -mcpu=$(MCU)
|
||||
MCFLAGS = -mcpu=$(MCU) -masm-syntax-unified
|
||||
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) \
|
||||
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections
|
||||
endif
|
||||
|
||||
Reference in New Issue
Block a user