Compare commits
34 Commits
release/1.
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a8e9074faf | |||
|
|
e12a7e0bb3 | ||
|
|
fdbe91600d | ||
|
|
daca396027 | ||
|
|
a6b96fe434 | ||
|
|
c5a83cb9a5 | ||
|
|
8f20122e54 | ||
|
|
c31a91947d | ||
|
|
71cc5a8f32 | ||
|
|
73d6c13d15 | ||
|
|
d43fbb140a | ||
|
|
9b822282f0 | ||
|
|
91ddc8fd02 | ||
|
|
0698bc4c9e | ||
|
|
7dda49eb40 | ||
|
|
cc49f4ef23 | ||
|
|
a0732c125a | ||
|
|
6be482413c | ||
|
|
9253777f5f | ||
|
|
63f47cede3 | ||
|
|
4c0c15588e | ||
|
|
e58e134b42 | ||
|
|
4cd47453ae | ||
|
|
89523f22bf | ||
|
|
0e5994506a | ||
|
|
bdbc84ba18 | ||
|
|
c73258138c | ||
|
|
2180ed24be | ||
|
|
b70de1b98d | ||
|
|
355482550b | ||
|
|
858a9f5d01 | ||
|
|
c7b83fd51c | ||
|
|
8e55209f33 | ||
|
|
4bde2ae1fc |
162
ChangeLog
162
ChangeLog
@@ -1,3 +1,165 @@
|
||||
2022-04-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.21.
|
||||
* doc/chopstx.texi (VERSION): 1.21.
|
||||
|
||||
2022-04-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport the changes from master.
|
||||
* chopstx.c (struct chx_pq): Use struct qh.
|
||||
(struct chx_px): Use struct qh.
|
||||
(struct chx_thread): Use struct qh.
|
||||
(FOR_QUEUE): Remove.
|
||||
(ll_dequeue): Follow the changes of above.
|
||||
(ll_prio_push): Use struct qh for the loop.
|
||||
(ll_prio_enqueue): Likewise.
|
||||
(chx_set_timer): Use struct qh for the first argument.
|
||||
(chx_timer_insert, chx_timer_dequeue): Use struct qh for the loop.
|
||||
(chx_timer_expired): Likewise.
|
||||
(chx_init, chopstx_create, chx_proxy_init): Use the address at q.
|
||||
(chx_exit): Use struct qh for the loop.
|
||||
(chx_mutex_unlock): Fix the calculation of the priority.
|
||||
* chopstx-cortex-m.c (chx_handle_intr): Not use FOR_QUEUE macro.
|
||||
* chopstx-gnu-linux.c (chx_handle_intr): Not use FOR_QUEUE macro.
|
||||
|
||||
2022-04-08 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport the changes from master.
|
||||
* chopstx.h (struct chx_qh): Change the type for next and prev.
|
||||
* chopstx.c (FOR_QUEUE): New macro.
|
||||
(ll_empty): Follow the change of struct chx_qh.
|
||||
(ll_insert): Change the type of the first argument.
|
||||
(ll_pop): Follow the change of struct chx_qh.
|
||||
(ll_prio_push): Use FOR_QUEUE macro. Follow the change of
|
||||
ll_insert.
|
||||
(ll_prio_enqueue, chx_timer_insert): Likewise.
|
||||
(chx_timer_dequeue, chx_init, chx_exit): Likewise.
|
||||
(chopstx_mutex_init, chopstx_cond_init): Likewise.
|
||||
* chopstx-cortex-m.c (chx_handle_intr): Use FOR_QUEUE macro.
|
||||
* chopstx-gnu-linux.c (chx_handle_intr): Use FOR_QUEUE macro.
|
||||
|
||||
2021-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.20.
|
||||
* doc/chopstx.texi (VERSION): 1.20.
|
||||
|
||||
2021-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from master.
|
||||
* mcu/usb-usbip.c (URB_DATA_SIZE): Tweak the value.
|
||||
|
||||
2021-02-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.19.
|
||||
* doc/chopstx.texi (VERSION): 1.19.
|
||||
|
||||
2021-02-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from master.
|
||||
* contrib/ackbtn-gnu-linux.c: New.
|
||||
* mcu/usb-usbip.c (usbip_run_server): Add start-up message.
|
||||
* contrib/adc-gnu-linux.c (adc_start_conversion): Use getrandom.
|
||||
|
||||
2021-02-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
Backport from 2.1.
|
||||
* chopstx-gnu-linux.c (chopstx_create_arch): Clear TP.
|
||||
* example-cdc-gnu-linux/usb-cdc.c (tty_recv): Cancel the input.
|
||||
* example-cdc-gnu-linux/sample.c (main): Handle timeout by canceling
|
||||
input.
|
||||
|
||||
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.18.
|
||||
* doc/chopstx.texi (VERSION): 1.18.
|
||||
|
||||
2019-12-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_poll): Call CHECK for condition
|
||||
valiable after woken up.
|
||||
|
||||
2019-12-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-gnu-linux.c (chx_thread_start): Fix return value.
|
||||
|
||||
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (chx_set_running): New.
|
||||
(chx_init_arch): Use chx_set_running.
|
||||
(preempt, svc): Remove set to running, not needed.
|
||||
|
||||
* chopstx-gnu-linux.c (chx_set_running): New.
|
||||
(chx_init_arch, chx_request_preemption, chx_sched): Use
|
||||
chx_set_running and chx_running.
|
||||
(chx_sched): Bug fix of return value handling.
|
||||
|
||||
2019-11-20 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.17.
|
||||
* doc/chopstx.texi (VERSION): 1.17.
|
||||
|
||||
* chopstx-gnu-linux.c (chx_running): New.
|
||||
(chx_init_arch): Set RUNNING.
|
||||
|
||||
2019-11-19 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (chx_running): New.
|
||||
(chx_init_arch): Set RUNNING.
|
||||
|
||||
* chopstx.c (chx_init): Don't set RUNNING here.
|
||||
(chx_timer_expired): Use chx_running.
|
||||
(chx_systick_init, chx_exit, chx_mutex_unlock, chopstx_create)
|
||||
(chopstx_mutex_lock, chopstx_mutex_unlock, chopstx_cleanup_push)
|
||||
(chopstx_cleanup_pop, chopstx_exit, chopstx_cancel)
|
||||
(chopstx_testcancel, chopstx_setcancelstate, chx_proxy_init)
|
||||
(chopstx_poll, chopstx_setpriority): Likewise.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-gnu-linux.c (chx_systick_init_arch): Rename.
|
||||
(chx_interrupt_controller_init): Rename.
|
||||
* chopstx-cortex-m.c (chx_systick_init_arch): Rename.
|
||||
(chx_interrupt_controller_init): Rename.
|
||||
* chopstx.c (chx_systick_init): Use chx_systick_init_arch.
|
||||
(chx_init): Use chx_interrupt_controller_init.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_ready_pop): Check flag_sched_rr here.
|
||||
* chopstx-cortex-m.c (chx_sched) [__ARM_ARCH_6M__]: Use
|
||||
new interface of chx_ready_pop.
|
||||
(preempt,svc): Likewise.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-cortex-m.c (ticks_to_usec): New.
|
||||
* chopstx-gnu-linux.c (ticks_to_usec): New.
|
||||
* chopstx.c (chx_snooze): Use ticks_to_usec.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* rules.mk (CSRC): Change the rule of entry*.c.
|
||||
* entry.c: It's only for Cortex-M, now.
|
||||
* entry-gnu-linux.c: New file.
|
||||
|
||||
2019-11-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* entry.c: Use chopstx-cortex-m.h.
|
||||
* chopstx.h (CHOPSTX_THREAD_SIZE): Move the definition to ...
|
||||
* chopstx-cortex-m.h (CHOPSTX_THREAD_SIZE): ... here.
|
||||
|
||||
2019-10-07 Jeremy Drake <jeremy@drastrom.science>
|
||||
|
||||
* mcu/usb-st-common.c (usb_lld_init): Move BTABLE initialization
|
||||
after clearing ISTR register.
|
||||
|
||||
2019-09-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
When it was exactly 64-byte, two ZLPs were sent wrongly.
|
||||
* mcu/usb-st-common.c (usb_lld_ctrl_send): Fix for 64-byte.
|
||||
* mcu/usb-usbip.c (usb_lld_ctrl_send): Likewise.
|
||||
* mcu/usb-mkl27z.c (usb_lld_ctrl_send): Likewise.
|
||||
|
||||
2019-05-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.16.
|
||||
|
||||
65
NEWS
65
NEWS
@@ -1,6 +1,71 @@
|
||||
NEWS - Noteworthy changes
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.21
|
||||
|
||||
Released 2022-04-22
|
||||
|
||||
** Fix of struct chx_qh and struct chx_thread/pq/px.
|
||||
|
||||
Good compiler complains/warns for possible different size of
|
||||
structures. To avoid this, access to the objects are fixed.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.20
|
||||
|
||||
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 1.19
|
||||
|
||||
Released 2021-02-18
|
||||
|
||||
** 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 GNU/Linux emulation
|
||||
When creating a thread, allocated memory for struct chx_thread was not
|
||||
initialized by chopstx_create_arch, assuming getcontext does it well.
|
||||
To make sure (getcontext would not update the area for FPU registers,
|
||||
when not used), it's now initialized by zeros.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.18
|
||||
|
||||
Released 2019-12-30
|
||||
|
||||
** Fix of chopstx_poll
|
||||
When waiting for a condition variable, we supply CHECK method with a
|
||||
descriptor. Since a condition variable may be fired for multiple
|
||||
reasons, old implementation of chopstx_poll may return with wrong
|
||||
information saying a condition of CHECK were met but actually not. It
|
||||
should not return when condition is not satisfied and it should not
|
||||
give wrong information to application. Fixed by calling the CHECK
|
||||
method again when woken up, and don't return when no condition meet.
|
||||
|
||||
** Bug fix for GNU/Linux emulation
|
||||
When woken up, return value of chx_sched was wrong. Because of this,
|
||||
timeout handling had problem. Termination value of a thread was
|
||||
wrong.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.17
|
||||
|
||||
Released 2019-11-20
|
||||
|
||||
** USB drivers bug fix for STM32 and ZLP handling for 64-byte packet.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.16
|
||||
|
||||
Released 2019-05-22
|
||||
|
||||
13
README
13
README
@@ -1,6 +1,6 @@
|
||||
Chopstx - Threads and only Threads
|
||||
Version 1.15
|
||||
2018-05-14
|
||||
Version 1.21
|
||||
2021-04-22
|
||||
Niibe Yutaka
|
||||
Flying Stone Technology
|
||||
|
||||
@@ -60,11 +60,6 @@ For STM32 Primer2, see the directory: example-primer2.
|
||||
Future Works
|
||||
============
|
||||
|
||||
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.
|
||||
RISC-V port (for GD32VF103) is available in 2.x. Please have a look
|
||||
at the master branch, and test it if possible.
|
||||
--
|
||||
|
||||
@@ -28,6 +28,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static struct chx_thread *running;
|
||||
|
||||
static struct chx_thread *
|
||||
chx_running (void)
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_running (struct chx_thread *r)
|
||||
{
|
||||
running = r;
|
||||
}
|
||||
|
||||
|
||||
/* Data Memory Barrier. */
|
||||
static void
|
||||
chx_dmb (void)
|
||||
@@ -115,7 +130,7 @@ struct SYST {
|
||||
static struct SYST *const SYST = (struct SYST *)0xE000E010;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
chx_systick_init_arch (void)
|
||||
{
|
||||
SYST->RVR = 0;
|
||||
SYST->CVR = 0;
|
||||
@@ -141,6 +156,12 @@ static uint32_t usec_to_ticks (uint32_t usec)
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ticks_to_usec (uint32_t ticks)
|
||||
{
|
||||
return ticks / MHZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt Handling
|
||||
*/
|
||||
@@ -205,7 +226,7 @@ static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
|
||||
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
chx_interrupt_controller_init (void)
|
||||
{
|
||||
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
|
||||
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
|
||||
@@ -246,7 +267,7 @@ chx_cpu_sched_unlock (void)
|
||||
void
|
||||
chx_handle_intr (void)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
register uint32_t irq_num;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
@@ -255,7 +276,10 @@ chx_handle_intr (void)
|
||||
|
||||
chx_disable_intr (irq_num);
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
|
||||
for (q = q_intr.q.next; q != &q_intr.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
@@ -265,6 +289,7 @@ chx_handle_intr (void)
|
||||
chx_request_preemption (px->master->prio);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
@@ -272,6 +297,7 @@ static void
|
||||
chx_init_arch (struct chx_thread *tp)
|
||||
{
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
chx_set_running (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -366,12 +392,6 @@ chx_sched (uint32_t yield)
|
||||
}
|
||||
|
||||
tp = chx_ready_pop ();
|
||||
if (tp && tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
tp = chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
|
||||
asm volatile (/* Now, r0 points to the thread to be switched. */
|
||||
/* Put it to *running. */
|
||||
@@ -562,19 +582,12 @@ preempt (void)
|
||||
}
|
||||
else
|
||||
chx_ready_push (tp);
|
||||
running = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
|
||||
|
||||
tp = chx_ready_pop ();
|
||||
if (tp && tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
tp = chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
|
||||
asm volatile (
|
||||
".L_CONTEXT_SWITCH:\n\t"
|
||||
@@ -688,16 +701,9 @@ svc (void)
|
||||
if (tp->flag_sched_rr)
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
running = NULL;
|
||||
}
|
||||
|
||||
tp = chx_ready_pop ();
|
||||
if (tp && tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
|
||||
asm volatile (
|
||||
"b .L_CONTEXT_SWITCH"
|
||||
|
||||
@@ -10,3 +10,5 @@ struct tcontext {
|
||||
};
|
||||
|
||||
typedef struct tcontext tcontext_t;
|
||||
|
||||
#define CHOPSTX_THREAD_SIZE 64
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||
* for GNU/Linux emulation
|
||||
*
|
||||
* Copyright (C) 2017, 2018, 2019 Flying Stone Technology
|
||||
* Copyright (C) 2017, 2018, 2019, 2021 Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
* This file is a part of Chopstx, a thread library for embedded.
|
||||
@@ -32,6 +32,21 @@
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static struct chx_thread *running;
|
||||
|
||||
static struct chx_thread *
|
||||
chx_running (void)
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_running (struct chx_thread *r)
|
||||
{
|
||||
running = r;
|
||||
}
|
||||
|
||||
|
||||
/* Data Memory Barrier. */
|
||||
static void
|
||||
chx_dmb (void)
|
||||
@@ -42,7 +57,7 @@ chx_dmb (void)
|
||||
static sigset_t ss_cur;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
chx_systick_init_arch (void)
|
||||
{
|
||||
const struct itimerval it = { {0, 0}, {0, 0} };
|
||||
|
||||
@@ -76,6 +91,11 @@ usec_to_ticks (uint32_t usec)
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ticks_to_usec (uint32_t ticks)
|
||||
{
|
||||
return ticks / MHZ;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_enable_intr (uint8_t irq_num)
|
||||
@@ -105,7 +125,7 @@ chx_set_intr_prio (uint8_t n)
|
||||
}
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
chx_interrupt_controller_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -134,11 +154,13 @@ idle (void)
|
||||
void
|
||||
chx_handle_intr (uint32_t irq_num)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
chx_disable_intr (irq_num);
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
|
||||
for (q = q_intr.q.next; q != &q_intr.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
@@ -149,6 +171,7 @@ chx_handle_intr (uint32_t irq_num)
|
||||
chx_request_preemption (px->master->prio);
|
||||
return;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
@@ -200,19 +223,22 @@ chx_init_arch (struct chx_thread *tp)
|
||||
makecontext (&idle_tc, idle, 0);
|
||||
|
||||
getcontext (&tp->tc);
|
||||
|
||||
chx_set_running (tp);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_request_preemption (uint16_t prio)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
ucontext_t *tcp;
|
||||
struct chx_thread *tp_prev;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
|
||||
if (running && (uint16_t)running->prio >= prio)
|
||||
if (tp && (uint16_t)tp->prio >= prio)
|
||||
return;
|
||||
|
||||
/* Change the context to another thread with higher priority. */
|
||||
tp = tp_prev = running;
|
||||
tp_prev = tp;
|
||||
if (tp)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
@@ -225,23 +251,15 @@ chx_request_preemption (uint16_t prio)
|
||||
}
|
||||
else
|
||||
chx_ready_push (tp);
|
||||
running = NULL;
|
||||
}
|
||||
|
||||
tp = running = chx_ready_pop ();
|
||||
tp = chx_ready_pop ();
|
||||
if (tp)
|
||||
{
|
||||
tcp = &tp->tc;
|
||||
if (tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
tp = chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
}
|
||||
else
|
||||
tcp = &idle_tc;
|
||||
|
||||
chx_set_running (tp);
|
||||
if (tp_prev)
|
||||
{
|
||||
/*
|
||||
@@ -286,10 +304,9 @@ static uintptr_t
|
||||
chx_sched (uint32_t yield)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
uintptr_t v;
|
||||
ucontext_t *tcp;
|
||||
|
||||
tp = tp_prev = running;
|
||||
tp = tp_prev = chx_running ();
|
||||
if (yield)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
@@ -297,35 +314,28 @@ chx_sched (uint32_t yield)
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
|
||||
running = tp = chx_ready_pop ();
|
||||
tp = chx_ready_pop ();
|
||||
if (tp)
|
||||
{
|
||||
v = tp->v;
|
||||
if (tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
tp = chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
tcp = &tp->tc;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = 0;
|
||||
tcp = &idle_tc;
|
||||
}
|
||||
|
||||
chx_set_running (tp);
|
||||
swapcontext (&tp_prev->tc, tcp);
|
||||
chx_cpu_sched_unlock ();
|
||||
return v;
|
||||
|
||||
tp = chx_running ();
|
||||
return tp->v;
|
||||
}
|
||||
|
||||
static void __attribute__((__noreturn__))
|
||||
chx_thread_start (voidfunc thread_entry, void *arg)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
chx_cpu_sched_unlock ();
|
||||
thread_entry (arg);
|
||||
chopstx_exit (0);
|
||||
ret = thread_entry (arg);
|
||||
chopstx_exit (ret);
|
||||
}
|
||||
|
||||
static struct chx_thread *
|
||||
@@ -342,6 +352,7 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
||||
* signal blocked. The sigmask will be cleared in chx_thread_start.
|
||||
*/
|
||||
chx_cpu_sched_lock ();
|
||||
memset (tp, 0, sizeof (struct chx_thread));
|
||||
getcontext (&tp->tc);
|
||||
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
|
||||
tp->tc.uc_stack.ss_size = stack_size;
|
||||
|
||||
210
chopstx.c
210
chopstx.c
@@ -83,14 +83,14 @@ chx_fatal (uint32_t err_code)
|
||||
int chx_allow_sleep;
|
||||
static struct chx_spinlock chx_enable_sleep_lock;
|
||||
|
||||
/* RUNNING: the current thread. */
|
||||
struct chx_thread *running;
|
||||
|
||||
struct chx_queue {
|
||||
struct chx_qh q;
|
||||
struct chx_spinlock lock;
|
||||
};
|
||||
|
||||
/* Forward declaration. */
|
||||
struct chx_pq;
|
||||
|
||||
/* READY: priority queue. */
|
||||
static struct chx_queue q_ready;
|
||||
|
||||
@@ -129,7 +129,7 @@ static void chx_spin_unlock (struct chx_spinlock *lk)
|
||||
|
||||
/**************/
|
||||
struct chx_pq {
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t : 4;
|
||||
uint32_t : 5;
|
||||
uint32_t : 6;
|
||||
@@ -141,7 +141,7 @@ struct chx_pq {
|
||||
};
|
||||
|
||||
struct chx_px { /* inherits PQ */
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t : 4;
|
||||
uint32_t : 5;
|
||||
uint32_t : 6;
|
||||
@@ -157,7 +157,7 @@ struct chx_px { /* inherits PQ */
|
||||
};
|
||||
|
||||
struct chx_thread { /* inherits PQ */
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh q;
|
||||
uint32_t state : 4;
|
||||
uint32_t flag_detached : 1;
|
||||
uint32_t flag_got_cancel : 1;
|
||||
@@ -183,63 +183,69 @@ struct chx_thread { /* inherits PQ */
|
||||
static int
|
||||
ll_empty (struct chx_qh *q)
|
||||
{
|
||||
return q == (struct chx_qh *)q->next;
|
||||
return q == q->next;
|
||||
}
|
||||
|
||||
static struct chx_pq *
|
||||
ll_dequeue (struct chx_pq *pq)
|
||||
{
|
||||
pq->next->prev = pq->prev;
|
||||
pq->prev->next = pq->next;
|
||||
pq->prev = pq->next = pq;
|
||||
pq->q.next->prev = pq->q.prev;
|
||||
pq->q.prev->next = pq->q.next;
|
||||
pq->q.prev = pq->q.next = &pq->q;
|
||||
return pq;
|
||||
}
|
||||
|
||||
static void
|
||||
ll_insert (struct chx_pq *pq0, struct chx_qh *q)
|
||||
ll_insert (struct chx_qh *q0, struct chx_qh *q)
|
||||
{
|
||||
struct chx_pq *pq = (struct chx_pq *)q;
|
||||
|
||||
pq0->next = (struct chx_pq *)pq;
|
||||
pq0->prev = pq->prev;
|
||||
pq->prev->next = (struct chx_pq *)pq0;
|
||||
pq->prev = pq0;
|
||||
q0->next = q;
|
||||
q0->prev = q->prev;
|
||||
q->prev->next = q0;
|
||||
q->prev = q0;
|
||||
}
|
||||
|
||||
|
||||
static struct chx_pq *
|
||||
ll_pop (struct chx_qh *q)
|
||||
{
|
||||
if (q == (struct chx_qh *)q->next)
|
||||
if (q == q->next)
|
||||
return NULL;
|
||||
|
||||
return ll_dequeue (q->next);
|
||||
return ll_dequeue ((struct chx_pq *)q->next);
|
||||
}
|
||||
|
||||
static void
|
||||
ll_prio_push (struct chx_pq *pq0, struct chx_qh *q0)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q0->next; q != q0; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next)
|
||||
if (p->prio <= pq0->prio)
|
||||
break;
|
||||
}
|
||||
|
||||
pq0->parent = q0;
|
||||
ll_insert (pq0, (struct chx_qh *)p);
|
||||
ll_insert (&pq0->q, q);
|
||||
}
|
||||
|
||||
static void
|
||||
ll_prio_enqueue (struct chx_pq *pq0, struct chx_qh *q0)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q0->next; q != q0; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next)
|
||||
if (p->prio < pq0->prio)
|
||||
break;
|
||||
}
|
||||
|
||||
pq0->parent = q0;
|
||||
ll_insert (pq0, (struct chx_qh *)p);
|
||||
ll_insert (&pq0->q, q);
|
||||
}
|
||||
|
||||
|
||||
@@ -271,6 +277,12 @@ chx_ready_pop (void)
|
||||
tp->state = THREAD_RUNNING;
|
||||
chx_spin_unlock (&q_ready.lock);
|
||||
|
||||
if (tp && tp->flag_sched_rr)
|
||||
{
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
chx_timer_insert (tp, PREEMPTION_USEC);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
@@ -305,29 +317,35 @@ chx_ready_enqueue (struct chx_thread *tp)
|
||||
#endif
|
||||
|
||||
static void
|
||||
chx_set_timer (struct chx_thread *tp, uint32_t ticks)
|
||||
chx_set_timer (struct chx_qh *q, uint32_t ticks)
|
||||
{
|
||||
if (tp == (struct chx_thread *)&q_timer.q)
|
||||
if (q == &q_timer.q)
|
||||
chx_systick_reload (ticks);
|
||||
else
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)q;
|
||||
|
||||
tp->v = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
static struct chx_thread *
|
||||
chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
uint32_t ticks = usec_to_ticks (usec);
|
||||
uint32_t next_ticks = chx_systick_get ();
|
||||
|
||||
for (p = q_timer.q.next; p != (struct chx_pq *)&q_timer.q; p = p->next)
|
||||
for (q = q_timer.q.next; q != &q_timer.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (ticks < next_ticks)
|
||||
{
|
||||
tp->parent = &q_timer.q;
|
||||
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p);
|
||||
chx_set_timer ((struct chx_thread *)tp->prev, ticks);
|
||||
chx_set_timer (tp, (next_ticks - ticks));
|
||||
ll_insert (&tp->q, q);
|
||||
chx_set_timer (tp->q.prev, ticks);
|
||||
chx_set_timer (&tp->q, (next_ticks - ticks));
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -337,12 +355,12 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
}
|
||||
}
|
||||
|
||||
if (p == (struct chx_pq *)&q_timer.q)
|
||||
if (q == &q_timer.q)
|
||||
{
|
||||
tp->parent = &q_timer.q;
|
||||
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p);
|
||||
chx_set_timer ((struct chx_thread *)tp->prev, ticks);
|
||||
chx_set_timer (tp, 1); /* Non-zero for the last entry. */
|
||||
ll_insert (&tp->q, q);
|
||||
chx_set_timer (tp->q.prev, ticks);
|
||||
chx_set_timer (&tp->q, 1); /* Non-zero for the last entry. */
|
||||
}
|
||||
|
||||
return tp;
|
||||
@@ -352,25 +370,30 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
static uint32_t
|
||||
chx_timer_dequeue (struct chx_thread *tp)
|
||||
{
|
||||
struct chx_thread *tp_prev;
|
||||
struct chx_qh *q_prev;
|
||||
uint32_t ticks_remained;
|
||||
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
ticks_remained = chx_systick_get ();
|
||||
tp_prev = (struct chx_thread *)tp->prev;
|
||||
if (tp_prev == (struct chx_thread *)&q_timer.q)
|
||||
q_prev = tp->q.prev;
|
||||
if (q_prev == &q_timer.q)
|
||||
{
|
||||
if (tp->next == (struct chx_pq *)&q_timer.q)
|
||||
if (tp->q.next == &q_timer.q)
|
||||
chx_systick_reload (0); /* Cancel timer. */
|
||||
else
|
||||
chx_systick_reload (ticks_remained + tp->v); /* Update timer. */
|
||||
}
|
||||
else
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_thread *tp_prev = (struct chx_thread *)q_prev;
|
||||
struct chx_qh *q;
|
||||
|
||||
for (q = q_timer.q.next; q != &q_timer.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
for (p = q_timer.q.next; p != (struct chx_pq *)tp; p = p->next)
|
||||
ticks_remained += p->v;
|
||||
}
|
||||
|
||||
tp_prev->v += tp->v;
|
||||
}
|
||||
@@ -385,6 +408,7 @@ void
|
||||
chx_timer_expired (void)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
struct chx_thread *running = chx_running ();
|
||||
uint16_t prio = 0; /* Use uint16_t here. */
|
||||
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
@@ -402,15 +426,17 @@ chx_timer_expired (void)
|
||||
|
||||
if (!ll_empty (&q_timer.q))
|
||||
{
|
||||
struct chx_thread *tp_next;
|
||||
struct chx_qh *q, *q_next;
|
||||
|
||||
for (tp = (struct chx_thread *)q_timer.q.next;
|
||||
tp != (struct chx_thread *)&q_timer.q && next_tick == 0;
|
||||
tp = tp_next)
|
||||
for (q = q_timer.q.next;
|
||||
q != &q_timer.q && next_tick == 0;
|
||||
q = q_next)
|
||||
{
|
||||
tp = (struct chx_thread *)q;
|
||||
|
||||
next_tick = tp->v;
|
||||
tp->v = (uintptr_t)0;
|
||||
tp_next = (struct chx_thread *)tp->next;
|
||||
q_next = tp->q.next;
|
||||
ll_dequeue ((struct chx_pq *)tp);
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp == running)
|
||||
@@ -421,7 +447,7 @@ chx_timer_expired (void)
|
||||
}
|
||||
|
||||
if (!ll_empty (&q_timer.q))
|
||||
chx_set_timer ((struct chx_thread *)&q_timer.q, next_tick);
|
||||
chx_set_timer (&q_timer.q, next_tick);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,10 +459,12 @@ chx_timer_expired (void)
|
||||
void
|
||||
chx_systick_init (void)
|
||||
{
|
||||
chx_systick_reset ();
|
||||
chx_systick_init_arch ();
|
||||
|
||||
if ((CHX_FLAGS_MAIN & CHOPSTX_SCHED_RR))
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_timer.lock);
|
||||
chx_timer_insert (running, PREEMPTION_USEC);
|
||||
@@ -450,19 +478,19 @@ chopstx_t chopstx_main;
|
||||
void
|
||||
chx_init (struct chx_thread *tp)
|
||||
{
|
||||
chx_prio_init ();
|
||||
chx_interrupt_controller_init ();
|
||||
chx_init_arch (tp);
|
||||
chx_spin_init (&chx_enable_sleep_lock);
|
||||
|
||||
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q;
|
||||
q_ready.q.next = q_ready.q.prev = &q_ready.q;
|
||||
chx_spin_init (&q_ready.lock);
|
||||
q_timer.q.next = q_timer.q.prev = (struct chx_pq *)&q_timer.q;
|
||||
q_timer.q.next = q_timer.q.prev = &q_timer.q;
|
||||
chx_spin_init (&q_timer.lock);
|
||||
q_join.q.next = q_join.q.prev = (struct chx_pq *)&q_join.q;
|
||||
q_join.q.next = q_join.q.prev = &q_join.q;
|
||||
chx_spin_init (&q_join.lock);
|
||||
q_intr.q.next = q_intr.q.prev = (struct chx_pq *)&q_intr.q;
|
||||
q_intr.q.next = q_intr.q.prev = &q_intr.q;
|
||||
chx_spin_init (&q_intr.lock);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->q.next = tp->q.prev = &tp->q;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
tp->state = THREAD_RUNNING;
|
||||
@@ -475,7 +503,6 @@ chx_init (struct chx_thread *tp)
|
||||
tp->prio = 0;
|
||||
tp->parent = NULL;
|
||||
tp->v = 0;
|
||||
running = tp;
|
||||
|
||||
if (CHX_PRIO_MAIN_INIT >= CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
chx_cpu_sched_lock ();
|
||||
@@ -497,6 +524,7 @@ chx_wakeup (struct chx_pq *pq)
|
||||
{
|
||||
int yield = 0;
|
||||
struct chx_thread *tp;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
if (pq->flag_is_proxy)
|
||||
{
|
||||
@@ -536,19 +564,24 @@ chx_wakeup (struct chx_pq *pq)
|
||||
static void __attribute__((noreturn))
|
||||
chx_exit (void *retval)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
struct chx_qh *q;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
if (running->flag_join_req)
|
||||
{ /* wake up a thread which requests to join */
|
||||
chx_spin_lock (&q_join.lock);
|
||||
for (p = q_join.q.next; p != (struct chx_pq *)&q_join.q; p = p->next)
|
||||
for (q = q_join.q.next; q != &q_join.q; q = q->next)
|
||||
{
|
||||
struct chx_pq *p = (struct chx_pq *)q;
|
||||
|
||||
if (p->v == (uintptr_t)running)
|
||||
{ /* should be one at most. */
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&q_join.lock);
|
||||
}
|
||||
|
||||
@@ -573,6 +606,7 @@ static chopstx_prio_t
|
||||
chx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
mutex->owner = NULL;
|
||||
running->mutex_list = mutex->list;
|
||||
@@ -591,9 +625,14 @@ chx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
|
||||
/* Examine mutexes we hold, and determine new priority for running. */
|
||||
for (m = running->mutex_list; m; m = m->list)
|
||||
if (!ll_empty (&m->q)
|
||||
&& ((struct chx_thread *)(m->q.next))->prio > newprio)
|
||||
newprio = ((struct chx_thread *)m->q.next)->prio;
|
||||
if (!ll_empty (&m->q))
|
||||
{
|
||||
struct chx_thread *tp_m = (struct chx_thread *)m->q.next;
|
||||
uint16_t prio_m = tp_m->prio;
|
||||
|
||||
if (prio_m > newprio)
|
||||
newprio = prio_m;
|
||||
}
|
||||
/* Then, assign it. */
|
||||
running->prio = newprio;
|
||||
|
||||
@@ -620,10 +659,11 @@ chopstx_create (uint32_t flags_and_prio,
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
chopstx_prio_t prio = (flags_and_prio & CHOPSTX_PRIO_MASK);
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
tp = chopstx_create_arch (stack_addr, stack_size, thread_entry,
|
||||
arg);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->q.next = tp->q.prev = &tp->q;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
tp->state = THREAD_EXITED;
|
||||
@@ -665,6 +705,7 @@ chopstx_create (uint32_t flags_and_prio,
|
||||
static int
|
||||
chx_snooze (uint32_t state, uint32_t *usec_p)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
uint32_t usec = *usec_p;
|
||||
uint32_t usec0;
|
||||
int r;
|
||||
@@ -688,7 +729,7 @@ chx_snooze (uint32_t state, uint32_t *usec_p)
|
||||
*usec_p -= usec0;
|
||||
else if (r > 0)
|
||||
{
|
||||
*usec_p -= (usec0 - r / MHZ);
|
||||
*usec_p -= (usec0 - ticks_to_usec (r));
|
||||
r = 1;
|
||||
}
|
||||
|
||||
@@ -734,7 +775,7 @@ void
|
||||
chopstx_mutex_init (chopstx_mutex_t *mutex)
|
||||
{
|
||||
chx_spin_init (&mutex->lock);
|
||||
mutex->q.next = mutex->q.prev = (struct chx_pq *)&mutex->q;
|
||||
mutex->q.next = mutex->q.prev = &mutex->q;
|
||||
mutex->list = NULL;
|
||||
mutex->owner = NULL;
|
||||
}
|
||||
@@ -787,7 +828,7 @@ requeue (struct chx_thread *tp)
|
||||
void
|
||||
chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -846,6 +887,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
void
|
||||
chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
chopstx_prio_t prio;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
@@ -869,7 +911,7 @@ void
|
||||
chopstx_cond_init (chopstx_cond_t *cond)
|
||||
{
|
||||
chx_spin_init (&cond->lock);
|
||||
cond->q.next = cond->q.prev = (struct chx_pq *)&cond->q;
|
||||
cond->q.next = cond->q.prev = &cond->q;
|
||||
}
|
||||
|
||||
|
||||
@@ -883,7 +925,7 @@ chopstx_cond_init (chopstx_cond_t *cond)
|
||||
void
|
||||
chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
int r;
|
||||
|
||||
chopstx_testcancel ();
|
||||
@@ -1091,6 +1133,8 @@ chopstx_intr_done (chopstx_intr_t *intr)
|
||||
void
|
||||
chopstx_cleanup_push (struct chx_cleanup *clp)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
clp->next = running->clp;
|
||||
running->clp = clp;
|
||||
}
|
||||
@@ -1105,6 +1149,7 @@ chopstx_cleanup_push (struct chx_cleanup *clp)
|
||||
void
|
||||
chopstx_cleanup_pop (int execute)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_cleanup *clp = running->clp;
|
||||
|
||||
if (clp)
|
||||
@@ -1129,6 +1174,7 @@ void
|
||||
chopstx_exit (void *retval)
|
||||
{
|
||||
struct chx_mtx *m, *m_next;
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_cleanup *clp = running->clp;
|
||||
|
||||
running->clp = NULL;
|
||||
@@ -1165,6 +1211,7 @@ chopstx_exit (void *retval)
|
||||
int
|
||||
chopstx_join (chopstx_t thd, void **ret)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
int r = 0;
|
||||
|
||||
@@ -1268,6 +1315,7 @@ void
|
||||
chopstx_cancel (chopstx_t thd)
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
tp->flag_got_cancel = 1;
|
||||
@@ -1324,6 +1372,8 @@ chopstx_cancel (chopstx_t thd)
|
||||
void
|
||||
chopstx_testcancel (void)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
if (running->flag_cancelable && running->flag_got_cancel)
|
||||
chopstx_exit (CHOPSTX_CANCELED);
|
||||
}
|
||||
@@ -1340,6 +1390,7 @@ chopstx_testcancel (void)
|
||||
int
|
||||
chopstx_setcancelstate (int cancel_disable)
|
||||
{
|
||||
struct chx_thread *running = chx_running ();
|
||||
int old_state = !running->flag_cancelable;
|
||||
|
||||
running->flag_cancelable = (cancel_disable == 0);
|
||||
@@ -1350,7 +1401,9 @@ chopstx_setcancelstate (int cancel_disable)
|
||||
static void
|
||||
chx_proxy_init (struct chx_px *px, uint32_t *cp)
|
||||
{
|
||||
px->next = px->prev = (struct chx_pq *)px;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
px->q.next = px->q.prev = &px->q;
|
||||
px->flag_is_proxy = 1;
|
||||
px->prio = running->prio;
|
||||
px->parent = NULL;
|
||||
@@ -1381,6 +1434,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
struct chx_px px[n];
|
||||
struct chx_poll_head *pd;
|
||||
int r = 0;
|
||||
struct chx_thread *running = chx_running ();
|
||||
|
||||
chx_dmb ();
|
||||
chopstx_testcancel ();
|
||||
@@ -1388,6 +1442,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
for (i = 0; i < n; i++)
|
||||
chx_proxy_init (&px[i], &counter);
|
||||
|
||||
again:
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
pd = pd_array[i];
|
||||
@@ -1450,6 +1505,20 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
ll_dequeue ((struct chx_pq *)&px[i]);
|
||||
chx_spin_unlock (&pc->cond->lock);
|
||||
}
|
||||
else
|
||||
{ /* Check the condition again after woken up. */
|
||||
if (pc->mutex)
|
||||
chopstx_mutex_lock (pc->mutex);
|
||||
|
||||
if ((*pc->check) (pc->arg) == 0)
|
||||
{ /* Condition doesn't met. */
|
||||
pc->ready = 0;
|
||||
counter--;
|
||||
}
|
||||
|
||||
if (pc->mutex)
|
||||
chopstx_mutex_unlock (pc->mutex);
|
||||
}
|
||||
}
|
||||
else if (pd->type == CHOPSTX_POLL_INTR)
|
||||
{
|
||||
@@ -1481,6 +1550,9 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
if (r < 0)
|
||||
chopstx_exit (CHOPSTX_CANCELED);
|
||||
|
||||
if (counter == 0 && (usec_p == NULL || *usec_p))
|
||||
goto again;
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
@@ -1501,7 +1573,7 @@ chopstx_poll (uint32_t *usec_p, int n, struct chx_poll_head *const pd_array[])
|
||||
chopstx_prio_t
|
||||
chopstx_setpriority (chopstx_prio_t prio_new)
|
||||
{
|
||||
struct chx_thread *tp = running;
|
||||
struct chx_thread *tp = chx_running ();
|
||||
chopstx_prio_t prio_orig, prio_cur;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
struct chx_qh {
|
||||
struct chx_pq *next, *prev;
|
||||
struct chx_qh *next, *prev;
|
||||
};
|
||||
|
||||
typedef uintptr_t chopstx_t;
|
||||
@@ -163,5 +163,3 @@ int chopstx_poll (uint32_t *usec_p, int n,
|
||||
struct chx_poll_head *const pd_array[]);
|
||||
|
||||
int chopstx_conf_idle (int enable_sleep);
|
||||
|
||||
#define CHOPSTX_THREAD_SIZE 64
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -66,6 +66,15 @@ ackbtn_init (chopstx_intr_t *intr)
|
||||
pin_config |= PINCFG_EDGE_RISING;
|
||||
break;
|
||||
|
||||
case BOARD_ID_ST_DONGLE:
|
||||
/* PA5 is connected to a switch */
|
||||
afio_exticr_index = 0;
|
||||
afio_exticr_extiX_pY = AFIO_EXTICR2_EXTI5_PA;
|
||||
irq_num = EXTI9_5_IRQ;
|
||||
pin_config = 0x0020; /* EXTI_PR_PR5 == EXTI_IMR_MR5 == EXTI_RTSR_TR5 */
|
||||
pin_config |= PINCFG_EDGE_RISING;
|
||||
break;
|
||||
|
||||
case BOARD_ID_FST_01SZ:
|
||||
default:
|
||||
/* PA3 is connected to a hall sensor DRV5032FA */
|
||||
|
||||
@@ -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 1.16
|
||||
@set VERSION 1.21
|
||||
@settitle Chopstx Reference Manual
|
||||
@c Unify some of the indices.
|
||||
@syncodeindex tp fn
|
||||
|
||||
45
entry-gnu-linux.c
Normal file
45
entry-gnu-linux.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* entry.c - Entry routine.
|
||||
*
|
||||
* Copyright (C) 2017, 2019
|
||||
* Flying Stone Technology
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
int emulated_main (int, const char **);
|
||||
void chx_init (struct chx_thread *);
|
||||
void chx_systick_init (void);
|
||||
extern struct chx_thread main_thread;
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chx_init (&main_thread);
|
||||
chx_systick_init ();
|
||||
emulated_main (argc, argv);
|
||||
}
|
||||
17
entry.c
17
entry.c
@@ -29,24 +29,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <chopstx-cortex-m.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
int emulated_main (int, const char **);
|
||||
void chx_init (struct chx_thread *);
|
||||
void chx_systick_init (void);
|
||||
extern struct chx_thread main_thread;
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chx_init (&main_thread);
|
||||
chx_systick_init ();
|
||||
emulated_main (argc, argv);
|
||||
}
|
||||
#else
|
||||
#if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
|
||||
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
|
||||
#include "sys.h"
|
||||
@@ -258,4 +244,3 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -179,7 +179,14 @@ main (int argc, const char *argv[])
|
||||
if (size < 0)
|
||||
goto connection_loop;
|
||||
|
||||
if (size == 1)
|
||||
if (size == 0)
|
||||
/* Timeout */
|
||||
{
|
||||
if (tty_send (tty, "\r\n", 2) < 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
else if (size == 1)
|
||||
/* Do nothing but prompt again. */
|
||||
break;
|
||||
else if (size)
|
||||
|
||||
@@ -768,7 +768,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
@@ -904,8 +904,18 @@ tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
r = check_rx (t);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
if (r || (timeout != NULL && *timeout == 0))
|
||||
if (r)
|
||||
break;
|
||||
else if (timeout != NULL && *timeout == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Cancel the input. */
|
||||
for (i = 0; i < t->inputline_len; i++)
|
||||
tty_send (t, "\x08\x20\x08", 3);
|
||||
t->inputline_len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
|
||||
@@ -780,7 +780,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
|
||||
@@ -768,7 +768,7 @@ tty_main (void *arg)
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (line));
|
||||
|
||||
if (len)
|
||||
{
|
||||
|
||||
@@ -956,7 +956,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
|
||||
@@ -235,10 +235,9 @@ usb_lld_init (struct usb_dev *dev, uint8_t feature)
|
||||
USB->CNTR = CNTR_FRES;
|
||||
USB->CNTR = 0;
|
||||
|
||||
USB->BTABLE = 0;
|
||||
|
||||
/* Clear Interrupt Status Register, and enable interrupt for USB */
|
||||
USB->ISTR = 0;
|
||||
USB->BTABLE = 0;
|
||||
USB->CNTR = (CNTR_CTRM | CNTR_OVRM | CNTR_ERRM
|
||||
| CNTR_WKUPM | CNTR_SUSPM | CNTR_RESETM);
|
||||
}
|
||||
@@ -329,7 +328,7 @@ handle_datastage_out (struct usb_dev *dev)
|
||||
static void
|
||||
handle_datastage_in (struct usb_dev *dev)
|
||||
{
|
||||
uint32_t len = USB_MAX_PACKET_SIZE;;
|
||||
uint32_t len = USB_MAX_PACKET_SIZE;
|
||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||
|
||||
if ((data_p->len == 0) && (dev->state == LAST_IN_DATA))
|
||||
@@ -887,14 +886,14 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
data_p->addr = (void *)buf;
|
||||
data_p->len = buflen;
|
||||
|
||||
/* Restrict the data length to be the one host asks for */
|
||||
/* Restrict the data length to be the one which host asks for. */
|
||||
if (data_p->len >= len_asked)
|
||||
data_p->len = len_asked;
|
||||
/* ZLP is only required when host doesn't expect the end of packets. */
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
|
||||
135
mcu/usb-usbip.c
135
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;
|
||||
@@ -2175,7 +2258,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
|
||||
data_p->require_zlp = 1;
|
||||
|
||||
if (data_p->len < USB_MAX_PACKET_SIZE)
|
||||
if (data_p->len <= USB_MAX_PACKET_SIZE)
|
||||
{
|
||||
len = data_p->len;
|
||||
dev->state = LAST_IN_DATA;
|
||||
|
||||
Reference in New Issue
Block a user