34 Commits

Author SHA1 Message Date
a8e9074faf Add switch pin for ST-Dongle 2022-07-30 12:35:28 +02:00
NIIBE Yutaka
e12a7e0bb3 Version 1.21.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2022-04-22 11:11:05 +09:00
NIIBE Yutaka
fdbe91600d Backport struct qh changes from master.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2022-04-21 13:01:30 +09:00
NIIBE Yutaka
daca396027 Backport struct chx_qh changes from master.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2022-04-08 19:50:21 +09:00
NIIBE Yutaka
a6b96fe434 Version 1.20.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-12 11:19:41 +09:00
NIIBE Yutaka
c5a83cb9a5 usbip: Fix the value of URB_DATA_SIZE again.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-11 10:22:49 +09:00
NIIBE Yutaka
8f20122e54 more fix for libccid.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-04 13:56:32 +09:00
NIIBE Yutaka
c31a91947d Fix USB emulation driver for GNU/Linux.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-10-04 10:09:15 +09:00
NIIBE Yutaka
71cc5a8f32 Version 1.19.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-18 11:02:06 +09:00
NIIBE Yutaka
73d6c13d15 Backport ADC driver from master.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 16:27:17 +09:00
NIIBE Yutaka
d43fbb140a Backport AckBtn driver and USBIP driver for GNU/Linux from master.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-17 10:51:12 +09:00
NIIBE Yutaka
9b822282f0 GNU/Linux: Backport from 2.1.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-16 14:53:24 +09:00
NIIBE Yutaka
91ddc8fd02 GNU/Linux: Clear TP.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2021-02-12 09:07:06 +09:00
NIIBE Yutaka
0698bc4c9e Revert "Fix EP0 receiving more packets."
This reverts commit e58e134b42.

--

The fix was no-op, because following code does not use LEN at all.
For other machines, it uses LEN for hardware USB core.
2020-01-06 09:55:13 +09:00
NIIBE Yutaka
7dda49eb40 Revert "Add a ChangeLog entry for USB fix."
This reverts commit 4c0c15588e.
2020-01-06 09:54:22 +09:00
NIIBE Yutaka
cc49f4ef23 Version 1.18.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-30 10:43:35 +09:00
NIIBE Yutaka
a0732c125a Add ChangeLog entry.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:20:27 +09:00
NIIBE Yutaka
6be482413c chopstx_poll: More change.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:20:07 +09:00
NIIBE Yutaka
9253777f5f Fix chopstx_poll for condition variables, check after woken up.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-27 10:19:50 +09:00
NIIBE Yutaka
63f47cede3 example-cdc,etc.: Bug fix of examples.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 14:39:38 +09:00
NIIBE Yutaka
4c0c15588e Add a ChangeLog entry for USB fix.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 08:27:33 +09:00
NIIBE Yutaka
e58e134b42 Fix EP0 receiving more packets.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-20 08:26:49 +09:00
NIIBE Yutaka
4cd47453ae Fix GNU/Linux emulation about termination of a thread.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-12-04 13:44:57 +09:00
NIIBE Yutaka
89523f22bf more clean up.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-21 08:01:25 +09:00
NIIBE Yutaka
0e5994506a Version 1.17.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-20 11:32:27 +09:00
NIIBE Yutaka
bdbc84ba18 chx_running for GNU/Linux port.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-20 11:24:21 +09:00
NIIBE Yutaka
c73258138c Use chx_running function.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-19 08:40:38 +09:00
NIIBE Yutaka
2180ed24be Rename internal functions to express meaning well.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 13:04:12 +09:00
NIIBE Yutaka
b70de1b98d Change chx_ready_pop implementation.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 11:55:22 +09:00
NIIBE Yutaka
355482550b New: ticks_to_usec.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:28:05 +09:00
NIIBE Yutaka
858a9f5d01 Have a entry-gnu-linux.c.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:25:56 +09:00
NIIBE Yutaka
c7b83fd51c Move CHOPSTX_THREAD_SIZE, it's core specific.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-11-18 08:13:33 +09:00
Jeremy Drake
8e55209f33 Fix USB driver. 2019-10-07 16:07:31 +09:00
NIIBE Yutaka
4bde2ae1fc Fix USB drivers.
Thanks to Jeremy Drake for the report.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2019-09-04 08:57:47 +09:00
23 changed files with 919 additions and 234 deletions

162
ChangeLog
View File

@@ -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> 2019-05-22 NIIBE Yutaka <gniibe@fsij.org>
* VERSION: 1.16. * VERSION: 1.16.

65
NEWS
View File

@@ -1,6 +1,71 @@
NEWS - Noteworthy changes 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 * Major changes in Chopstx 1.16
Released 2019-05-22 Released 2019-05-22

13
README
View File

@@ -1,6 +1,6 @@
Chopstx - Threads and only Threads Chopstx - Threads and only Threads
Version 1.15 Version 1.21
2018-05-14 2021-04-22
Niibe Yutaka Niibe Yutaka
Flying Stone Technology Flying Stone Technology
@@ -60,11 +60,6 @@ For STM32 Primer2, see the directory: example-primer2.
Future Works Future Works
============ ============
Convenience function to determine the bottom of thread stack, RISC-V port (for GD32VF103) is available in 2.x. Please have a look
configuration of thread size by compiler's output would be next things at the master branch, and test it if possible.
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.
-- --

View File

@@ -1 +1 @@
release/1.16 release/1.21

View File

@@ -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. */ /* Data Memory Barrier. */
static void static void
chx_dmb (void) chx_dmb (void)
@@ -115,7 +130,7 @@ struct SYST {
static struct SYST *const SYST = (struct SYST *)0xE000E010; static struct SYST *const SYST = (struct SYST *)0xE000E010;
static void static void
chx_systick_reset (void) chx_systick_init_arch (void)
{ {
SYST->RVR = 0; SYST->RVR = 0;
SYST->CVR = 0; SYST->CVR = 0;
@@ -141,6 +156,12 @@ static uint32_t usec_to_ticks (uint32_t usec)
return usec * MHZ; return usec * MHZ;
} }
static uint32_t
ticks_to_usec (uint32_t ticks)
{
return ticks / MHZ;
}
/* /*
* Interrupt Handling * Interrupt Handling
*/ */
@@ -205,7 +226,7 @@ static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20; static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
static void static void
chx_prio_init (void) chx_interrupt_controller_init (void)
{ {
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */ *AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24); *SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
@@ -246,7 +267,7 @@ chx_cpu_sched_unlock (void)
void void
chx_handle_intr (void) chx_handle_intr (void)
{ {
struct chx_pq *p; struct chx_qh *q;
register uint32_t irq_num; register uint32_t irq_num;
asm volatile ("mrs %0, IPSR\n\t" asm volatile ("mrs %0, IPSR\n\t"
@@ -255,16 +276,20 @@ chx_handle_intr (void)
chx_disable_intr (irq_num); chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock); 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)
if (p->v == irq_num) {
{ /* should be one at most. */ struct chx_pq *p = (struct chx_pq *)q;
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p); if (p->v == irq_num)
chx_wakeup (p); { /* should be one at most. */
chx_request_preemption (px->master->prio); struct chx_px *px = (struct chx_px *)p;
break;
} ll_dequeue (p);
chx_wakeup (p);
chx_request_preemption (px->master->prio);
break;
}
}
chx_spin_unlock (&q_intr.lock); chx_spin_unlock (&q_intr.lock);
} }
@@ -272,6 +297,7 @@ static void
chx_init_arch (struct chx_thread *tp) chx_init_arch (struct chx_thread *tp)
{ {
memset (&tp->tc, 0, sizeof (tp->tc)); memset (&tp->tc, 0, sizeof (tp->tc));
chx_set_running (tp);
} }
static void static void
@@ -366,12 +392,6 @@ chx_sched (uint32_t yield)
} }
tp = chx_ready_pop (); 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. */ asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */ /* Put it to *running. */
@@ -562,19 +582,12 @@ preempt (void)
} }
else else
chx_ready_push (tp); chx_ready_push (tp);
running = NULL;
} }
} }
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */ /* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
tp = chx_ready_pop (); 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 ( asm volatile (
".L_CONTEXT_SWITCH:\n\t" ".L_CONTEXT_SWITCH:\n\t"
@@ -688,16 +701,9 @@ svc (void)
if (tp->flag_sched_rr) if (tp->flag_sched_rr)
chx_timer_dequeue (tp); chx_timer_dequeue (tp);
chx_ready_enqueue (tp); chx_ready_enqueue (tp);
running = NULL;
} }
tp = chx_ready_pop (); 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 ( asm volatile (
"b .L_CONTEXT_SWITCH" "b .L_CONTEXT_SWITCH"

View File

@@ -10,3 +10,5 @@ struct tcontext {
}; };
typedef struct tcontext tcontext_t; typedef struct tcontext tcontext_t;
#define CHOPSTX_THREAD_SIZE 64

View File

@@ -2,7 +2,7 @@
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code * chopstx-gnu-linux.c - Threads and only threads: Arch specific code
* for GNU/Linux emulation * 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> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Chopstx, a thread library for embedded. * This file is a part of Chopstx, a thread library for embedded.
@@ -32,6 +32,21 @@
#include <signal.h> #include <signal.h>
#include <sys/time.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. */ /* Data Memory Barrier. */
static void static void
chx_dmb (void) chx_dmb (void)
@@ -42,7 +57,7 @@ chx_dmb (void)
static sigset_t ss_cur; static sigset_t ss_cur;
static void static void
chx_systick_reset (void) chx_systick_init_arch (void)
{ {
const struct itimerval it = { {0, 0}, {0, 0} }; const struct itimerval it = { {0, 0}, {0, 0} };
@@ -76,6 +91,11 @@ usec_to_ticks (uint32_t usec)
return usec * MHZ; return usec * MHZ;
} }
static uint32_t
ticks_to_usec (uint32_t ticks)
{
return ticks / MHZ;
}
static void static void
chx_enable_intr (uint8_t irq_num) chx_enable_intr (uint8_t irq_num)
@@ -105,7 +125,7 @@ chx_set_intr_prio (uint8_t n)
} }
static void static void
chx_prio_init (void) chx_interrupt_controller_init (void)
{ {
} }
@@ -134,21 +154,24 @@ idle (void)
void void
chx_handle_intr (uint32_t irq_num) chx_handle_intr (uint32_t irq_num)
{ {
struct chx_pq *p; struct chx_qh *q;
chx_disable_intr (irq_num); chx_disable_intr (irq_num);
chx_spin_lock (&q_intr.lock); 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)
if (p->v == irq_num) {
{ /* should be one at most. */ struct chx_pq *p = (struct chx_pq *)q;
struct chx_px *px = (struct chx_px *)p; if (p->v == irq_num)
{ /* should be one at most. */
struct chx_px *px = (struct chx_px *)p;
ll_dequeue (p); ll_dequeue (p);
chx_wakeup (p); chx_wakeup (p);
chx_spin_unlock (&q_intr.lock); chx_spin_unlock (&q_intr.lock);
chx_request_preemption (px->master->prio); chx_request_preemption (px->master->prio);
return; return;
} }
}
chx_spin_unlock (&q_intr.lock); chx_spin_unlock (&q_intr.lock);
} }
@@ -200,19 +223,22 @@ chx_init_arch (struct chx_thread *tp)
makecontext (&idle_tc, idle, 0); makecontext (&idle_tc, idle, 0);
getcontext (&tp->tc); getcontext (&tp->tc);
chx_set_running (tp);
} }
static void static void
chx_request_preemption (uint16_t prio) chx_request_preemption (uint16_t prio)
{ {
struct chx_thread *tp, *tp_prev;
ucontext_t *tcp; 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; return;
/* Change the context to another thread with higher priority. */ /* Change the context to another thread with higher priority. */
tp = tp_prev = running; tp_prev = tp;
if (tp) if (tp)
{ {
if (tp->flag_sched_rr) if (tp->flag_sched_rr)
@@ -225,23 +251,15 @@ chx_request_preemption (uint16_t prio)
} }
else else
chx_ready_push (tp); chx_ready_push (tp);
running = NULL;
} }
tp = running = chx_ready_pop (); tp = chx_ready_pop ();
if (tp) if (tp)
{ tcp = &tp->tc;
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 else
tcp = &idle_tc; tcp = &idle_tc;
chx_set_running (tp);
if (tp_prev) if (tp_prev)
{ {
/* /*
@@ -286,10 +304,9 @@ static uintptr_t
chx_sched (uint32_t yield) chx_sched (uint32_t yield)
{ {
struct chx_thread *tp, *tp_prev; struct chx_thread *tp, *tp_prev;
uintptr_t v;
ucontext_t *tcp; ucontext_t *tcp;
tp = tp_prev = running; tp = tp_prev = chx_running ();
if (yield) if (yield)
{ {
if (tp->flag_sched_rr) if (tp->flag_sched_rr)
@@ -297,35 +314,28 @@ chx_sched (uint32_t yield)
chx_ready_enqueue (tp); chx_ready_enqueue (tp);
} }
running = tp = chx_ready_pop (); tp = chx_ready_pop ();
if (tp) if (tp)
{ tcp = &tp->tc;
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 else
{ tcp = &idle_tc;
v = 0;
tcp = &idle_tc;
}
chx_set_running (tp);
swapcontext (&tp_prev->tc, tcp); swapcontext (&tp_prev->tc, tcp);
chx_cpu_sched_unlock (); chx_cpu_sched_unlock ();
return v;
tp = chx_running ();
return tp->v;
} }
static void __attribute__((__noreturn__)) static void __attribute__((__noreturn__))
chx_thread_start (voidfunc thread_entry, void *arg) chx_thread_start (voidfunc thread_entry, void *arg)
{ {
void *ret;
chx_cpu_sched_unlock (); chx_cpu_sched_unlock ();
thread_entry (arg); ret = thread_entry (arg);
chopstx_exit (0); chopstx_exit (ret);
} }
static struct chx_thread * 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. * signal blocked. The sigmask will be cleared in chx_thread_start.
*/ */
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
memset (tp, 0, sizeof (struct chx_thread));
getcontext (&tp->tc); getcontext (&tp->tc);
tp->tc.uc_stack.ss_sp = (void *)stack_addr; tp->tc.uc_stack.ss_sp = (void *)stack_addr;
tp->tc.uc_stack.ss_size = stack_size; tp->tc.uc_stack.ss_size = stack_size;

234
chopstx.c
View File

@@ -83,14 +83,14 @@ chx_fatal (uint32_t err_code)
int chx_allow_sleep; int chx_allow_sleep;
static struct chx_spinlock chx_enable_sleep_lock; static struct chx_spinlock chx_enable_sleep_lock;
/* RUNNING: the current thread. */
struct chx_thread *running;
struct chx_queue { struct chx_queue {
struct chx_qh q; struct chx_qh q;
struct chx_spinlock lock; struct chx_spinlock lock;
}; };
/* Forward declaration. */
struct chx_pq;
/* READY: priority queue. */ /* READY: priority queue. */
static struct chx_queue q_ready; 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 {
struct chx_pq *next, *prev; struct chx_qh q;
uint32_t : 4; uint32_t : 4;
uint32_t : 5; uint32_t : 5;
uint32_t : 6; uint32_t : 6;
@@ -141,7 +141,7 @@ struct chx_pq {
}; };
struct chx_px { /* inherits PQ */ struct chx_px { /* inherits PQ */
struct chx_pq *next, *prev; struct chx_qh q;
uint32_t : 4; uint32_t : 4;
uint32_t : 5; uint32_t : 5;
uint32_t : 6; uint32_t : 6;
@@ -157,7 +157,7 @@ struct chx_px { /* inherits PQ */
}; };
struct chx_thread { /* inherits PQ */ struct chx_thread { /* inherits PQ */
struct chx_pq *next, *prev; struct chx_qh q;
uint32_t state : 4; uint32_t state : 4;
uint32_t flag_detached : 1; uint32_t flag_detached : 1;
uint32_t flag_got_cancel : 1; uint32_t flag_got_cancel : 1;
@@ -183,63 +183,69 @@ struct chx_thread { /* inherits PQ */
static int static int
ll_empty (struct chx_qh *q) ll_empty (struct chx_qh *q)
{ {
return q == (struct chx_qh *)q->next; return q == q->next;
} }
static struct chx_pq * static struct chx_pq *
ll_dequeue (struct chx_pq *pq) ll_dequeue (struct chx_pq *pq)
{ {
pq->next->prev = pq->prev; pq->q.next->prev = pq->q.prev;
pq->prev->next = pq->next; pq->q.prev->next = pq->q.next;
pq->prev = pq->next = pq; pq->q.prev = pq->q.next = &pq->q;
return pq; return pq;
} }
static void 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; q0->next = q;
q0->prev = q->prev;
pq0->next = (struct chx_pq *)pq; q->prev->next = q0;
pq0->prev = pq->prev; q->prev = q0;
pq->prev->next = (struct chx_pq *)pq0;
pq->prev = pq0;
} }
static struct chx_pq * static struct chx_pq *
ll_pop (struct chx_qh *q) ll_pop (struct chx_qh *q)
{ {
if (q == (struct chx_qh *)q->next) if (q == q->next)
return NULL; return NULL;
return ll_dequeue (q->next); return ll_dequeue ((struct chx_pq *)q->next);
} }
static void static void
ll_prio_push (struct chx_pq *pq0, struct chx_qh *q0) ll_prio_push (struct chx_pq *pq0, struct chx_qh *q0)
{ {
struct chx_pq *p; struct chx_qh *q;
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next) for (q = q0->next; q != q0; q = q->next)
if (p->prio <= pq0->prio) {
break; struct chx_pq *p = (struct chx_pq *)q;
if (p->prio <= pq0->prio)
break;
}
pq0->parent = q0; pq0->parent = q0;
ll_insert (pq0, (struct chx_qh *)p); ll_insert (&pq0->q, q);
} }
static void static void
ll_prio_enqueue (struct chx_pq *pq0, struct chx_qh *q0) ll_prio_enqueue (struct chx_pq *pq0, struct chx_qh *q0)
{ {
struct chx_pq *p; struct chx_qh *q;
for (p = q0->next; p != (struct chx_pq *)q0; p = p->next) for (q = q0->next; q != q0; q = q->next)
if (p->prio < pq0->prio) {
break; struct chx_pq *p = (struct chx_pq *)q;
if (p->prio < pq0->prio)
break;
}
pq0->parent = q0; 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; tp->state = THREAD_RUNNING;
chx_spin_unlock (&q_ready.lock); 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; return tp;
} }
@@ -305,29 +317,35 @@ chx_ready_enqueue (struct chx_thread *tp)
#endif #endif
static void 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); chx_systick_reload (ticks);
else else
tp->v = ticks; {
struct chx_thread *tp = (struct chx_thread *)q;
tp->v = ticks;
}
} }
static struct chx_thread * static struct chx_thread *
chx_timer_insert (struct chx_thread *tp, uint32_t usec) 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 ticks = usec_to_ticks (usec);
uint32_t next_ticks = chx_systick_get (); 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) if (ticks < next_ticks)
{ {
tp->parent = &q_timer.q; tp->parent = &q_timer.q;
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p); ll_insert (&tp->q, q);
chx_set_timer ((struct chx_thread *)tp->prev, ticks); chx_set_timer (tp->q.prev, ticks);
chx_set_timer (tp, (next_ticks - ticks)); chx_set_timer (&tp->q, (next_ticks - ticks));
break; break;
} }
else 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; tp->parent = &q_timer.q;
ll_insert ((struct chx_pq *)tp, (struct chx_qh *)p); ll_insert (&tp->q, q);
chx_set_timer ((struct chx_thread *)tp->prev, ticks); chx_set_timer (tp->q.prev, ticks);
chx_set_timer (tp, 1); /* Non-zero for the last entry. */ chx_set_timer (&tp->q, 1); /* Non-zero for the last entry. */
} }
return tp; return tp;
@@ -352,25 +370,30 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
static uint32_t static uint32_t
chx_timer_dequeue (struct chx_thread *tp) chx_timer_dequeue (struct chx_thread *tp)
{ {
struct chx_thread *tp_prev; struct chx_qh *q_prev;
uint32_t ticks_remained; uint32_t ticks_remained;
chx_spin_lock (&q_timer.lock); chx_spin_lock (&q_timer.lock);
ticks_remained = chx_systick_get (); ticks_remained = chx_systick_get ();
tp_prev = (struct chx_thread *)tp->prev; q_prev = tp->q.prev;
if (tp_prev == (struct chx_thread *)&q_timer.q) 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. */ chx_systick_reload (0); /* Cancel timer. */
else else
chx_systick_reload (ticks_remained + tp->v); /* Update timer. */ chx_systick_reload (ticks_remained + tp->v); /* Update timer. */
} }
else else
{ {
struct chx_pq *p; struct chx_thread *tp_prev = (struct chx_thread *)q_prev;
struct chx_qh *q;
for (p = q_timer.q.next; p != (struct chx_pq *)tp; p = p->next) for (q = q_timer.q.next; q != &q_timer.q; q = q->next)
ticks_remained += p->v; {
struct chx_pq *p = (struct chx_pq *)q;
ticks_remained += p->v;
}
tp_prev->v += tp->v; tp_prev->v += tp->v;
} }
@@ -385,6 +408,7 @@ void
chx_timer_expired (void) chx_timer_expired (void)
{ {
struct chx_thread *tp; struct chx_thread *tp;
struct chx_thread *running = chx_running ();
uint16_t prio = 0; /* Use uint16_t here. */ uint16_t prio = 0; /* Use uint16_t here. */
chx_spin_lock (&q_timer.lock); chx_spin_lock (&q_timer.lock);
@@ -402,15 +426,17 @@ chx_timer_expired (void)
if (!ll_empty (&q_timer.q)) 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; for (q = q_timer.q.next;
tp != (struct chx_thread *)&q_timer.q && next_tick == 0; q != &q_timer.q && next_tick == 0;
tp = tp_next) q = q_next)
{ {
tp = (struct chx_thread *)q;
next_tick = tp->v; next_tick = tp->v;
tp->v = (uintptr_t)0; tp->v = (uintptr_t)0;
tp_next = (struct chx_thread *)tp->next; q_next = tp->q.next;
ll_dequeue ((struct chx_pq *)tp); ll_dequeue ((struct chx_pq *)tp);
chx_ready_enqueue (tp); chx_ready_enqueue (tp);
if (tp == running) if (tp == running)
@@ -421,7 +447,7 @@ chx_timer_expired (void)
} }
if (!ll_empty (&q_timer.q)) 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 void
chx_systick_init (void) chx_systick_init (void)
{ {
chx_systick_reset (); chx_systick_init_arch ();
if ((CHX_FLAGS_MAIN & CHOPSTX_SCHED_RR)) if ((CHX_FLAGS_MAIN & CHOPSTX_SCHED_RR))
{ {
struct chx_thread *running = chx_running ();
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
chx_spin_lock (&q_timer.lock); chx_spin_lock (&q_timer.lock);
chx_timer_insert (running, PREEMPTION_USEC); chx_timer_insert (running, PREEMPTION_USEC);
@@ -450,19 +478,19 @@ chopstx_t chopstx_main;
void void
chx_init (struct chx_thread *tp) chx_init (struct chx_thread *tp)
{ {
chx_prio_init (); chx_interrupt_controller_init ();
chx_init_arch (tp); chx_init_arch (tp);
chx_spin_init (&chx_enable_sleep_lock); 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); 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); 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); 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); 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->mutex_list = NULL;
tp->clp = NULL; tp->clp = NULL;
tp->state = THREAD_RUNNING; tp->state = THREAD_RUNNING;
@@ -475,7 +503,6 @@ chx_init (struct chx_thread *tp)
tp->prio = 0; tp->prio = 0;
tp->parent = NULL; tp->parent = NULL;
tp->v = 0; tp->v = 0;
running = tp;
if (CHX_PRIO_MAIN_INIT >= CHOPSTX_PRIO_INHIBIT_PREEMPTION) if (CHX_PRIO_MAIN_INIT >= CHOPSTX_PRIO_INHIBIT_PREEMPTION)
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
@@ -497,6 +524,7 @@ chx_wakeup (struct chx_pq *pq)
{ {
int yield = 0; int yield = 0;
struct chx_thread *tp; struct chx_thread *tp;
struct chx_thread *running = chx_running ();
if (pq->flag_is_proxy) if (pq->flag_is_proxy)
{ {
@@ -536,19 +564,24 @@ chx_wakeup (struct chx_pq *pq)
static void __attribute__((noreturn)) static void __attribute__((noreturn))
chx_exit (void *retval) chx_exit (void *retval)
{ {
struct chx_pq *p; struct chx_qh *q;
struct chx_thread *running = chx_running ();
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
if (running->flag_join_req) if (running->flag_join_req)
{ /* wake up a thread which requests to join */ { /* wake up a thread which requests to join */
chx_spin_lock (&q_join.lock); 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)
if (p->v == (uintptr_t)running) {
{ /* should be one at most. */ struct chx_pq *p = (struct chx_pq *)q;
ll_dequeue (p);
chx_wakeup (p); if (p->v == (uintptr_t)running)
break; { /* should be one at most. */
} ll_dequeue (p);
chx_wakeup (p);
break;
}
}
chx_spin_unlock (&q_join.lock); chx_spin_unlock (&q_join.lock);
} }
@@ -573,6 +606,7 @@ static chopstx_prio_t
chx_mutex_unlock (chopstx_mutex_t *mutex) chx_mutex_unlock (chopstx_mutex_t *mutex)
{ {
struct chx_thread *tp; struct chx_thread *tp;
struct chx_thread *running = chx_running ();
mutex->owner = NULL; mutex->owner = NULL;
running->mutex_list = mutex->list; 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. */ /* Examine mutexes we hold, and determine new priority for running. */
for (m = running->mutex_list; m; m = m->list) for (m = running->mutex_list; m; m = m->list)
if (!ll_empty (&m->q) if (!ll_empty (&m->q))
&& ((struct chx_thread *)(m->q.next))->prio > newprio) {
newprio = ((struct chx_thread *)m->q.next)->prio; 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. */ /* Then, assign it. */
running->prio = newprio; running->prio = newprio;
@@ -620,10 +659,11 @@ chopstx_create (uint32_t flags_and_prio,
{ {
struct chx_thread *tp; struct chx_thread *tp;
chopstx_prio_t prio = (flags_and_prio & CHOPSTX_PRIO_MASK); 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, tp = chopstx_create_arch (stack_addr, stack_size, thread_entry,
arg); arg);
tp->next = tp->prev = (struct chx_pq *)tp; tp->q.next = tp->q.prev = &tp->q;
tp->mutex_list = NULL; tp->mutex_list = NULL;
tp->clp = NULL; tp->clp = NULL;
tp->state = THREAD_EXITED; tp->state = THREAD_EXITED;
@@ -665,6 +705,7 @@ chopstx_create (uint32_t flags_and_prio,
static int static int
chx_snooze (uint32_t state, uint32_t *usec_p) chx_snooze (uint32_t state, uint32_t *usec_p)
{ {
struct chx_thread *running = chx_running ();
uint32_t usec = *usec_p; uint32_t usec = *usec_p;
uint32_t usec0; uint32_t usec0;
int r; int r;
@@ -688,7 +729,7 @@ chx_snooze (uint32_t state, uint32_t *usec_p)
*usec_p -= usec0; *usec_p -= usec0;
else if (r > 0) else if (r > 0)
{ {
*usec_p -= (usec0 - r / MHZ); *usec_p -= (usec0 - ticks_to_usec (r));
r = 1; r = 1;
} }
@@ -734,7 +775,7 @@ void
chopstx_mutex_init (chopstx_mutex_t *mutex) chopstx_mutex_init (chopstx_mutex_t *mutex)
{ {
chx_spin_init (&mutex->lock); 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->list = NULL;
mutex->owner = NULL; mutex->owner = NULL;
} }
@@ -787,7 +828,7 @@ requeue (struct chx_thread *tp)
void void
chopstx_mutex_lock (chopstx_mutex_t *mutex) chopstx_mutex_lock (chopstx_mutex_t *mutex)
{ {
struct chx_thread *tp = running; struct chx_thread *tp = chx_running ();
while (1) while (1)
{ {
@@ -846,6 +887,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
void void
chopstx_mutex_unlock (chopstx_mutex_t *mutex) chopstx_mutex_unlock (chopstx_mutex_t *mutex)
{ {
struct chx_thread *running = chx_running ();
chopstx_prio_t prio; chopstx_prio_t prio;
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
@@ -869,7 +911,7 @@ void
chopstx_cond_init (chopstx_cond_t *cond) chopstx_cond_init (chopstx_cond_t *cond)
{ {
chx_spin_init (&cond->lock); 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 void
chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex) chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
{ {
struct chx_thread *tp = running; struct chx_thread *tp = chx_running ();
int r; int r;
chopstx_testcancel (); chopstx_testcancel ();
@@ -1091,6 +1133,8 @@ chopstx_intr_done (chopstx_intr_t *intr)
void void
chopstx_cleanup_push (struct chx_cleanup *clp) chopstx_cleanup_push (struct chx_cleanup *clp)
{ {
struct chx_thread *running = chx_running ();
clp->next = running->clp; clp->next = running->clp;
running->clp = clp; running->clp = clp;
} }
@@ -1105,6 +1149,7 @@ chopstx_cleanup_push (struct chx_cleanup *clp)
void void
chopstx_cleanup_pop (int execute) chopstx_cleanup_pop (int execute)
{ {
struct chx_thread *running = chx_running ();
struct chx_cleanup *clp = running->clp; struct chx_cleanup *clp = running->clp;
if (clp) if (clp)
@@ -1129,6 +1174,7 @@ void
chopstx_exit (void *retval) chopstx_exit (void *retval)
{ {
struct chx_mtx *m, *m_next; struct chx_mtx *m, *m_next;
struct chx_thread *running = chx_running ();
struct chx_cleanup *clp = running->clp; struct chx_cleanup *clp = running->clp;
running->clp = NULL; running->clp = NULL;
@@ -1165,6 +1211,7 @@ chopstx_exit (void *retval)
int int
chopstx_join (chopstx_t thd, void **ret) chopstx_join (chopstx_t thd, void **ret)
{ {
struct chx_thread *running = chx_running ();
struct chx_thread *tp = (struct chx_thread *)thd; struct chx_thread *tp = (struct chx_thread *)thd;
int r = 0; int r = 0;
@@ -1268,6 +1315,7 @@ void
chopstx_cancel (chopstx_t thd) chopstx_cancel (chopstx_t thd)
{ {
struct chx_thread *tp = (struct chx_thread *)thd; struct chx_thread *tp = (struct chx_thread *)thd;
struct chx_thread *running = chx_running ();
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
tp->flag_got_cancel = 1; tp->flag_got_cancel = 1;
@@ -1324,6 +1372,8 @@ chopstx_cancel (chopstx_t thd)
void void
chopstx_testcancel (void) chopstx_testcancel (void)
{ {
struct chx_thread *running = chx_running ();
if (running->flag_cancelable && running->flag_got_cancel) if (running->flag_cancelable && running->flag_got_cancel)
chopstx_exit (CHOPSTX_CANCELED); chopstx_exit (CHOPSTX_CANCELED);
} }
@@ -1340,6 +1390,7 @@ chopstx_testcancel (void)
int int
chopstx_setcancelstate (int cancel_disable) chopstx_setcancelstate (int cancel_disable)
{ {
struct chx_thread *running = chx_running ();
int old_state = !running->flag_cancelable; int old_state = !running->flag_cancelable;
running->flag_cancelable = (cancel_disable == 0); running->flag_cancelable = (cancel_disable == 0);
@@ -1350,7 +1401,9 @@ chopstx_setcancelstate (int cancel_disable)
static void static void
chx_proxy_init (struct chx_px *px, uint32_t *cp) 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->flag_is_proxy = 1;
px->prio = running->prio; px->prio = running->prio;
px->parent = NULL; 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_px px[n];
struct chx_poll_head *pd; struct chx_poll_head *pd;
int r = 0; int r = 0;
struct chx_thread *running = chx_running ();
chx_dmb (); chx_dmb ();
chopstx_testcancel (); 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++) for (i = 0; i < n; i++)
chx_proxy_init (&px[i], &counter); chx_proxy_init (&px[i], &counter);
again:
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
pd = pd_array[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]); ll_dequeue ((struct chx_pq *)&px[i]);
chx_spin_unlock (&pc->cond->lock); 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) 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) if (r < 0)
chopstx_exit (CHOPSTX_CANCELED); chopstx_exit (CHOPSTX_CANCELED);
if (counter == 0 && (usec_p == NULL || *usec_p))
goto again;
return counter; 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_prio_t
chopstx_setpriority (chopstx_prio_t prio_new) 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; chopstx_prio_t prio_orig, prio_cur;
chx_cpu_sched_lock (); chx_cpu_sched_lock ();

View File

@@ -27,7 +27,7 @@
*/ */
struct chx_qh { struct chx_qh {
struct chx_pq *next, *prev; struct chx_qh *next, *prev;
}; };
typedef uintptr_t chopstx_t; 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[]); struct chx_poll_head *const pd_array[]);
int chopstx_conf_idle (int enable_sleep); int chopstx_conf_idle (int enable_sleep);
#define CHOPSTX_THREAD_SIZE 64

232
contrib/ackbtn-gnu-linux.c Normal file
View 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);
}

View File

@@ -66,6 +66,15 @@ ackbtn_init (chopstx_intr_t *intr)
pin_config |= PINCFG_EDGE_RISING; pin_config |= PINCFG_EDGE_RISING;
break; 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: case BOARD_ID_FST_01SZ:
default: default:
/* PA3 is connected to a hall sensor DRV5032FA */ /* PA3 is connected to a hall sensor DRV5032FA */

View File

@@ -3,7 +3,7 @@
* This ADC driver just fills pseudo random values. * This ADC driver just fills pseudo random values.
* It's completely useless other than for NeuG. * 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> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Chopstx, a thread library for embedded. * This file is a part of Chopstx, a thread library for embedded.
@@ -33,7 +33,7 @@
#include <chopstx.h> #include <chopstx.h>
#include "adc.h" #include "adc.h"
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */ #include <sys/random.h>
/* /*
* Do calibration for ADC. * Do calibration for ADC.
@@ -41,7 +41,6 @@
int int
adc_init (void) adc_init (void)
{ {
srandom (ADC_RANDOM_SEED);
return 0; return 0;
} }
@@ -55,8 +54,7 @@ uint32_t adc_buf[64];
void void
adc_start_conversion (int offset, int count) adc_start_conversion (int offset, int count)
{ {
while (count--) getrandom (adc_buf+offset, count, 0);
adc_buf[offset++] = random ();
} }

View File

@@ -1,7 +1,7 @@
\input texinfo @c -*-texinfo-*- \input texinfo @c -*-texinfo-*-
@c %**start of header @c %**start of header
@setfilename chopstx.info @setfilename chopstx.info
@set VERSION 1.16 @set VERSION 1.21
@settitle Chopstx Reference Manual @settitle Chopstx Reference Manual
@c Unify some of the indices. @c Unify some of the indices.
@syncodeindex tp fn @syncodeindex tp fn

45
entry-gnu-linux.c Normal file
View 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
View File

@@ -29,24 +29,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <chopstx.h> #include <chopstx-cortex-m.h>
#include "board.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) #if defined(USE_SYS3) || defined(USE_SYS_CLOCK_GPIO_SETTING)
#define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS #define REQUIRE_CLOCK_GPIO_SETTING_IN_SYS
#include "sys.h" #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, chx_handle_intr, chx_handle_intr, chx_handle_intr, chx_handle_intr,
#endif #endif
}; };
#endif

View File

@@ -179,7 +179,14 @@ main (int argc, const char *argv[])
if (size < 0) if (size < 0)
goto connection_loop; 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. */ /* Do nothing but prompt again. */
break; break;
else if (size) else if (size)

View File

@@ -768,7 +768,7 @@ tty_main (void *arg)
&& t->flag_send_ready) && t->flag_send_ready)
{ {
uint8_t line[32]; 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) if (len)
{ {
@@ -904,8 +904,18 @@ tty_recv (struct tty *t, char *buf, uint32_t *timeout)
chopstx_mutex_lock (&t->mtx); chopstx_mutex_lock (&t->mtx);
r = check_rx (t); r = check_rx (t);
chopstx_mutex_unlock (&t->mtx); chopstx_mutex_unlock (&t->mtx);
if (r || (timeout != NULL && *timeout == 0)) if (r)
break; 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); chopstx_mutex_lock (&t->mtx);

View File

@@ -780,7 +780,7 @@ tty_main (void *arg)
&& t->flag_send_ready) && t->flag_send_ready)
{ {
uint8_t line[32]; 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) if (len)
{ {

View File

@@ -768,7 +768,7 @@ tty_main (void *arg)
&& t->flag_send_ready) && t->flag_send_ready)
{ {
uint8_t line[32]; 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) if (len)
{ {

View File

@@ -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) else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
data_p->require_zlp = 1; 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; len = data_p->len;
dev->state = LAST_IN_DATA; dev->state = LAST_IN_DATA;

View File

@@ -235,10 +235,9 @@ usb_lld_init (struct usb_dev *dev, uint8_t feature)
USB->CNTR = CNTR_FRES; USB->CNTR = CNTR_FRES;
USB->CNTR = 0; USB->CNTR = 0;
USB->BTABLE = 0;
/* Clear Interrupt Status Register, and enable interrupt for USB */ /* Clear Interrupt Status Register, and enable interrupt for USB */
USB->ISTR = 0; USB->ISTR = 0;
USB->BTABLE = 0;
USB->CNTR = (CNTR_CTRM | CNTR_OVRM | CNTR_ERRM USB->CNTR = (CNTR_CTRM | CNTR_OVRM | CNTR_ERRM
| CNTR_WKUPM | CNTR_SUSPM | CNTR_RESETM); | CNTR_WKUPM | CNTR_SUSPM | CNTR_RESETM);
} }
@@ -329,7 +328,7 @@ handle_datastage_out (struct usb_dev *dev)
static void static void
handle_datastage_in (struct usb_dev *dev) 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; struct ctrl_data *data_p = &dev->ctrl_data;
if ((data_p->len == 0) && (dev->state == LAST_IN_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->addr = (void *)buf;
data_p->len = buflen; 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) if (data_p->len >= len_asked)
data_p->len = len_asked; data_p->len = len_asked;
/* ZLP is only required when host doesn't expect the end of packets. */ /* 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) else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
data_p->require_zlp = 1; 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; len = data_p->len;
dev->state = LAST_IN_DATA; dev->state = LAST_IN_DATA;

View File

@@ -1,7 +1,7 @@
/* /*
* usb-usbip.c - USB Device Emulation (server side) by USBIP * 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> * Author: NIIBE Yutaka <gniibe@fsij.org>
* *
* This file is a part of Chopstx, a thread library for embedded. * This file is a part of Chopstx, a thread library for embedded.
@@ -22,10 +22,26 @@
*/ */
/* /*
FIXME: * This driver is intended to emulate USB full-speed device, which
RESET handling * maximum packet size is 64.
USB Shutdown *
Use reply structure of its own * "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> #include <pthread.h>
@@ -96,7 +112,7 @@ struct urb {
struct urb *next; struct urb *next;
struct urb *prev; struct urb *prev;
uint16_t remain; uint32_t remain;
char *data_p; char *data_p;
pthread_t tid; pthread_t tid;
@@ -236,7 +252,67 @@ attach_device (char busid[32], size_t *len_p)
return (const char *)&usbip_usb_device; 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 { struct usbip_msg_cmd {
uint32_t devid; 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, static int read_data_transaction (struct usb_control *usbc_p,
int ep_num, char *buf, uint16_t count); int ep_num, char *buf, uint16_t count);
#define USB_MAX_PACKET_SIZE 64 /* For USB fullspeed device. */
static int static int
hc_handle_control_urb (struct urb *urb) hc_handle_control_urb (struct urb *urb)
{ {
int r; int r;
uint16_t count; uint16_t count;
uint16_t remain = urb->len; uint32_t remain = urb->len;
uint64_t l; uint64_t l;
if ((debug & DEBUG_USB)) if ((debug & DEBUG_USB))
@@ -325,10 +403,10 @@ hc_handle_control_urb (struct urb *urb)
while (r == 0) while (r == 0)
{ {
if (remain > 64) if (remain > USB_MAX_PACKET_SIZE)
count = 64; count = USB_MAX_PACKET_SIZE;
else else
count = remain; count = (uint16_t)remain;
read (usbc_ep0.eventfd, &l, sizeof (l)); read (usbc_ep0.eventfd, &l, sizeof (l));
r = control_write_data_transaction (urb->data_p, count); r = control_write_data_transaction (urb->data_p, count);
@@ -337,7 +415,7 @@ hc_handle_control_urb (struct urb *urb)
urb->data_p += count; urb->data_p += count;
remain -= count; remain -= count;
if (count < 64) if (count < USB_MAX_PACKET_SIZE)
break; break;
} }
if (r >= 0) if (r >= 0)
@@ -353,10 +431,10 @@ hc_handle_control_urb (struct urb *urb)
while (1) while (1)
{ {
if (remain > 64) if (remain > USB_MAX_PACKET_SIZE)
count = 64; count = USB_MAX_PACKET_SIZE;
else else
count = remain; count = (uint16_t)remain;
read (usbc_ep0.eventfd, &l, sizeof (l)); read (usbc_ep0.eventfd, &l, sizeof (l));
r = control_read_data_transaction (urb->data_p, count); r = control_read_data_transaction (urb->data_p, count);
@@ -368,7 +446,7 @@ hc_handle_control_urb (struct urb *urb)
remain -= r; remain -= r;
urb->data_p += r; urb->data_p += r;
if (r < 64) if (r < USB_MAX_PACKET_SIZE)
break; break;
} }
@@ -516,10 +594,10 @@ hc_handle_data_urb (struct usb_control *usbc_p)
if ((debug & DEBUG_USB)) if ((debug & DEBUG_USB))
puts ("hc_hdu 0"); puts ("hc_hdu 0");
if (urb->remain > 64) if (urb->remain > USB_MAX_PACKET_SIZE)
count = 64; count = USB_MAX_PACKET_SIZE;
else else
count = urb->remain; count = (uint16_t)urb->remain;
if (urb->dir == USBIP_DIR_OUT) if (urb->dir == USBIP_DIR_OUT)
{ /* Output from host to device. */ { /* Output from host to device. */
@@ -533,7 +611,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
urb->data_p += count; urb->data_p += count;
urb->remain -= 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; size_t len = urb->len - urb->remain;
@@ -565,7 +643,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
urb->remain -= r; urb->remain -= r;
urb->data_p += 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; size_t len = urb->len - urb->remain;
@@ -596,7 +674,7 @@ issue_get_desc (void)
{ {
struct urb *urb; struct urb *urb;
urb = malloc (sizeof (struct urb) + 64); urb = malloc (sizeof (struct urb) + USB_MAX_PACKET_SIZE);
urb->next = urb->prev = urb; urb->next = urb->prev = urb;
@@ -606,14 +684,14 @@ issue_get_desc (void)
urb->setup[3] = 1; /* Value H: desc_type */ urb->setup[3] = 1; /* Value H: desc_type */
urb->setup[4] = 0; /* Index */ urb->setup[4] = 0; /* Index */
urb->setup[5] = 0; urb->setup[5] = 0;
urb->setup[6] = 64; /* Length */ urb->setup[6] = USB_MAX_PACKET_SIZE; /* Length */
urb->setup[7] = 0; urb->setup[7] = 0;
urb->data_p = urb->data; urb->data_p = urb->data;
urb->seq = 0; urb->seq = 0;
urb->devid = 0; urb->devid = 0;
urb->dir = USBIP_DIR_IN; urb->dir = USBIP_DIR_IN;
urb->ep = 0; urb->ep = 0;
urb->remain = urb->len = 64; urb->remain = urb->len = USB_MAX_PACKET_SIZE;
hc_handle_control_urb (urb); hc_handle_control_urb (urb);
return urb; return urb;
} }
@@ -729,7 +807,7 @@ usbip_handle_urb (uint32_t seq)
leave: leave:
msg.cmd = htonl (REP_URB_SUBMIT); msg.cmd = htonl (REP_URB_SUBMIT);
msg.seq = htonl (urb->seq); msg.seq = htonl (seq);
memset (&msg_rep, 0, sizeof (msg_rep)); memset (&msg_rep, 0, sizeof (msg_rep));
msg_rep.status = htonl (r); msg_rep.status = htonl (r);
@@ -1080,6 +1158,11 @@ usbip_run_server (void *arg)
exit (1); 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].fd = shutdown_notify_fd;
pollfds[1].events = POLLIN; pollfds[1].events = POLLIN;
pollfds[1].revents = 0; 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) else if (data_p->len != 0 && (data_p->len % USB_MAX_PACKET_SIZE) == 0)
data_p->require_zlp = 1; 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; len = data_p->len;
dev->state = LAST_IN_DATA; dev->state = LAST_IN_DATA;

View File

@@ -1,6 +1,12 @@
# Chopstx make rules. # Chopstx make rules.
CSRC += $(CHOPSTX)/entry.c $(CHOPSTX)/chopstx.c ifeq ($(EMULATION),)
CSRC += $(CHOPSTX)/entry.c
else
CSRC += $(CHOPSTX)/entry-gnu-linux.c
endif
CSRC += $(CHOPSTX)/chopstx.c
ifneq ($(USE_EVENTFLAG),) ifneq ($(USE_EVENTFLAG),)
CSRC += $(CHOPSTX)/eventflag.c CSRC += $(CHOPSTX)/eventflag.c