Compare commits
30 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8df82badf | ||
|
|
f51a54e4c6 | ||
|
|
5fe5ff36c4 | ||
|
|
a4f28ee176 | ||
|
|
87767f1be5 | ||
|
|
8b018df382 | ||
|
|
5d9802388c | ||
|
|
478dd2c784 | ||
|
|
6f7a591417 | ||
|
|
d142cbbea3 | ||
|
|
f011d643e9 | ||
|
|
1fbbf66e8e | ||
|
|
1f7d4a6aac | ||
|
|
526b8fec2a | ||
|
|
5419580519 | ||
|
|
78c825afe8 | ||
|
|
1bd14d8d40 | ||
|
|
80258ba7c7 | ||
|
|
ca1b22c3eb | ||
|
|
6c68c55301 | ||
|
|
d941299149 | ||
|
|
b2b0eb7418 | ||
|
|
7798e620a6 | ||
|
|
89eb54929e | ||
|
|
a96f84ff74 | ||
|
|
9d84537c13 | ||
|
|
d448d3c678 | ||
|
|
bc664fe943 | ||
|
|
08cca6b9f8 | ||
|
|
c9d59a3f3f |
25
AUTHORS
25
AUTHORS
@@ -2,6 +2,10 @@ Aidan Thornton:
|
||||
Added Maple Mini support.
|
||||
board/board-maple-mini.h
|
||||
|
||||
Jeremy Drake:
|
||||
Modified STM32F103 support.
|
||||
mcu/sys-stm32f103.c
|
||||
|
||||
Kaz Kojima:
|
||||
Added STM32 Primer2 support.
|
||||
board/board-stm32-primer2.h
|
||||
@@ -22,18 +26,18 @@ Mateusz Zalega:
|
||||
board/board-nitrokey-start.h
|
||||
|
||||
NIIBE Yutaka:
|
||||
Write the library:
|
||||
Wrote the library:
|
||||
chopstx.c, entry.c, eventflag.c,
|
||||
chopstx.h, eventflag.h
|
||||
Write the drivers mcu/*:
|
||||
Wrote the drivers mcu/*:
|
||||
clk_gpio_init-mkl27z.c, clk_gpio_init-stm32.c,
|
||||
sys-stm32f103.c, sys-stm32f030.c, sys-mkl27z.c,
|
||||
adc-stm32f103.c, adc-mkl27z.c
|
||||
Draw the logo:
|
||||
Drew the logo:
|
||||
chopstx.svg, chopstx.png
|
||||
Write examples:
|
||||
Wrote examples:
|
||||
example-led, example-cdc, example-fsm-55, example-fs-bb48
|
||||
Write board/*:
|
||||
Wrote board/*:
|
||||
board-fst-01.h, board-fst-01-00.h,
|
||||
board-olimex-stm32-h103.h, board-stm8s-discovery.h
|
||||
board-cq-starm.h, board-stbee-mini.h, board-stbee.h,
|
||||
@@ -41,3 +45,14 @@ NIIBE Yutaka:
|
||||
board-stm32f0-discovery.h, board-fsm-55.h,
|
||||
|
||||
board-fs-bb48.h
|
||||
|
||||
Under contract of g10 Code GmbH, wrote:
|
||||
mcu/usb-usbip.c
|
||||
|
||||
Paul Fertser:
|
||||
Added Blue Pill support.
|
||||
board/board-blue-pill.h
|
||||
|
||||
Szczepan Zalega:
|
||||
Modified Nitrokey-Start support.
|
||||
board/board-nitrokey-start.h
|
||||
|
||||
122
ChangeLog
122
ChangeLog
@@ -1,3 +1,125 @@
|
||||
2017-08-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.4.
|
||||
* doc/chopstx.texi (VERSION): 1.4.
|
||||
|
||||
2017-08-03 Jeremy Drake <jeremydrake+gnuk@eacceleration.com>
|
||||
|
||||
* mcu/sys-stm32f103.c (flash_write): Allow compile time
|
||||
flash size definition by STM32F103_OVERRIDE_FLASH_SIZE_KB.
|
||||
|
||||
2017-08-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* contrib/adc-gnu-linux.c: New.
|
||||
|
||||
2017-07-07 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-usbip.c (usbip_handle_data_urb): Fix error return value.
|
||||
(notify_hostcontroller): New.
|
||||
(usb_lld_stall_tx, usb_lld_stall_rx): Notify host controller side.
|
||||
|
||||
2017-07-06 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-usbip.c (hc_handle_data_urb): Fix the condition of the
|
||||
end of transaction.
|
||||
(read_data_transaction): Allow partial read by host.
|
||||
|
||||
2017-07-05 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* example-fraucheky: New.
|
||||
|
||||
2017-06-28 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/usb-usbip.c (struct usbip_msg_cmd, struct usbip_msg_rep):
|
||||
Use different struct for command and reply.
|
||||
|
||||
2017-06-27 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* example-cdc-gnu-linux/README: New.
|
||||
|
||||
2017-06-26 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* board/board-gnu-linux.h: New.
|
||||
|
||||
* mcu/usb-usbip.c: New.
|
||||
|
||||
* rules.mk: Support EMULATION.
|
||||
|
||||
* entry.c (main): Support GNU_LINUX_EMULATION.
|
||||
|
||||
2017-06-23 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx-gnu-linux.c, chopstx-gnu-linux.h: New.
|
||||
|
||||
* chopstx.c (chx_init): Use chx_init_arch.
|
||||
(chopstx_create): Use chopstx_create_arch.
|
||||
(chx_systick_reset, chx_systick_reload, chx_systick_get)
|
||||
(usec_to_ticks, chx_enable_intr, chx_clr_intr, chx_disable_intr)
|
||||
(chx_set_intr_prio, chx_prio_init, chx_cpu_sched_lock)
|
||||
(chx_cpu_sched_unlock, idle, chx_handle_intr)
|
||||
(chx_request_preemption, chx_sched, preempt, svc): Move to...
|
||||
* chopstx-cortex-m.c: ... here.
|
||||
(chx_init_arch, chopstx_create_arch): New.
|
||||
* chopstx-cortex-m.h: New for tcontext_t.
|
||||
|
||||
2017-06-22 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_sched): Use ->V for return value.
|
||||
(svc): Ditto.
|
||||
(chx_wakeup): Set -> for the return value of chx_sched.
|
||||
(chopstx_mutex_lock, chopstx_cancel): Likewise.
|
||||
(chopstx_exit): Remove naked attribute.
|
||||
|
||||
2017-06-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (struct chx_pq): Use uintptr_t for V.
|
||||
(struct chx_px): Likewise.
|
||||
(struct chx_thread): Likewise.
|
||||
(chx_sched): Use uintptr_t for the return value.
|
||||
(chx_exit): Use the field V for holding exit value.
|
||||
(chopstx_create): Use uintptr_t for STACK_ADDR.
|
||||
(chopstx_join): Use the field V for exit value.
|
||||
|
||||
2017-06-16 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_wakeup): Fix for RUNNING==NULL.
|
||||
|
||||
* mcu/usb-mkl27z.c (std_get_status): Use staic var, not auto.
|
||||
|
||||
2017-05-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_wakeup): Fix access to REG_R0.
|
||||
|
||||
2017-02-02 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.3.
|
||||
* doc/chopstx.texi (VERSION): 1.3.
|
||||
|
||||
2017-02-01 Paul Fertser <fercerpav@gmail.com>
|
||||
|
||||
* board/board-blue-pill.h: New.
|
||||
|
||||
2016-12-08 Szczepan Zalega <szczepan@nitrokey.com>
|
||||
|
||||
* board/board-nitrokey-start.h (VAL_GPIO_USB_ODR): Switch off red
|
||||
LED for Nitrokey Start.
|
||||
|
||||
2016-10-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.2.
|
||||
* doc/chopstx.texi (VERSION): 1.2.
|
||||
|
||||
2016-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_join, chopstx_cancel): chopstx_join is
|
||||
cancellation point.
|
||||
|
||||
2016-07-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* mcu/stm32f103.h: Add more from Gnuk 1.1.9.
|
||||
* example-cdc, example-fs-bb48, example-fsm-55, example-led:
|
||||
Update for stack addr/size.
|
||||
|
||||
2016-07-01 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* VERSION: 1.1.
|
||||
|
||||
25
NEWS
25
NEWS
@@ -1,6 +1,31 @@
|
||||
NEWS - Noteworthy changes
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.4
|
||||
|
||||
Released 2017-08-11
|
||||
|
||||
** New port: Emulation on GNU/Linux
|
||||
Now, user can run Chopstx application on GNU/Linux. Its USB driver is
|
||||
by USBIP. Its ADC driver is dummy with random(3).
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.3
|
||||
|
||||
Released 2017-02-02
|
||||
|
||||
** New board support: Blue Pill
|
||||
It is contributed by Paul Fertser.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.2
|
||||
|
||||
Released 2016-10-13
|
||||
|
||||
** Fix: chopstx_join
|
||||
chopstx_join is now cancellation point.
|
||||
|
||||
|
||||
* Major changes in Chopstx 1.1
|
||||
|
||||
Released 2016-07-01
|
||||
|
||||
7
README
7
README
@@ -1,6 +1,6 @@
|
||||
Chopstx - Threads and only Threads
|
||||
Version 1.1
|
||||
2016-07-01
|
||||
Version 1.4
|
||||
2017-08-11
|
||||
Niibe Yutaka
|
||||
Flying Stone Technology
|
||||
|
||||
@@ -8,7 +8,8 @@ What's Chopstx?
|
||||
===============
|
||||
|
||||
Chopstx is an RT thread library for STM32F103 (ARM Cortex-M3),
|
||||
STM32F030 (ARM Cortex-M0), and MKL27Z (ARM Cortex-M0plus).
|
||||
STM32F030 (ARM Cortex-M0), MKL27Z (ARM Cortex-M0plus), and
|
||||
emulation on GNU/Linux.
|
||||
|
||||
While most RTOSes come with many features, drivers, and stacks,
|
||||
Chopstx just offers a simple RT thread library.
|
||||
|
||||
36
board/board-blue-pill.h
Normal file
36
board/board-blue-pill.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#define BOARD_NAME "Blue Pill"
|
||||
/* http://wiki.stm32duino.com/index.php?title=Blue_Pill */
|
||||
/* echo -n "Blue Pill" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
|
||||
#define BOARD_ID 0xa1099d43
|
||||
|
||||
#define STM32F10X_MD /* Medium-density device */
|
||||
|
||||
#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
|
||||
#define STM32_PLLMUL_VALUE 9
|
||||
#define STM32_HSECLK 8000000
|
||||
|
||||
#define GPIO_LED_BASE GPIOC_BASE
|
||||
#define GPIO_LED_CLEAR_TO_EMIT 13
|
||||
#define GPIO_USB_BASE GPIOA_BASE
|
||||
#define GPIO_USB_SET_TO_ENABLE 12
|
||||
#undef GPIO_OTHER_BASE
|
||||
|
||||
/*
|
||||
* Port A setup.
|
||||
* PA11 - Push Pull output 10MHz 0 default (until USB enabled) (USBDM)
|
||||
* PA12 - Push Pull output 10MHz 0 default (until USB enabled) (USBDP)
|
||||
* PC13 - Push pull output 50MHz (LED 1:ON 0:OFF)
|
||||
* ------------------------ Default
|
||||
* PAx - input with pull-up
|
||||
* PCx - input with pull-up
|
||||
*/
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFE7FF
|
||||
#define VAL_GPIO_USB_CRL 0x88888888 /* PA7...PA0 */
|
||||
#define VAL_GPIO_USB_CRH 0x88811888 /* PA15...PA8 */
|
||||
|
||||
#define VAL_GPIO_LED_ODR 0xFFFFFFFF
|
||||
#define VAL_GPIO_LED_CRL 0x88888888 /* PC7...PC0 */
|
||||
#define VAL_GPIO_LED_CRH 0x88388888 /* PC15...PC8 */
|
||||
|
||||
#define RCC_ENR_IOP_EN (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN)
|
||||
#define RCC_RSTR_IOP_RST (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPCRST)
|
||||
4
board/board-gnu-linux.h
Normal file
4
board/board-gnu-linux.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#define BOARD_NAME "GNU/Linux"
|
||||
/* Emulation on GNU/Linux */
|
||||
/* echo -n "GNU/Linux" | shasum -a 256 | sed -e 's/^.*\(........\) -$/\1/' */
|
||||
#define BOARD_ID 0x7ec86145
|
||||
@@ -22,7 +22,7 @@
|
||||
* PA4 - floating input
|
||||
* PA5 - floating input
|
||||
* PA6 - floating input
|
||||
* PA7 - Push pull output (LED1 1:ON 0:OFF)
|
||||
* PA7 - Push pull output (Red LED1 1:ON 0:OFF)
|
||||
* PA8 - floating input (smartcard, SCDSA)
|
||||
* PA9 - floating input
|
||||
* PA10 - floating input
|
||||
@@ -37,13 +37,13 @@
|
||||
* PA14 - input with pull-up.
|
||||
* PA15 - Push pull output (USB 1:ON 0:OFF)
|
||||
*/
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFE7FF
|
||||
#define VAL_GPIO_USB_ODR 0xFFFFE77F
|
||||
#define VAL_GPIO_USB_CRL 0x34444488 /* PA7...PA0 */
|
||||
#define VAL_GPIO_USB_CRH 0x38811444 /* PA15...PA8 */
|
||||
|
||||
/*
|
||||
* Port B setup.
|
||||
* PB0 - Push pull output (LED2 1:ON 0:OFF)
|
||||
* PB0 - Push pull output (Green LED2 1:ON 0:OFF)
|
||||
* ------------------------ Default
|
||||
* PBx - input with pull-up.
|
||||
*/
|
||||
|
||||
707
chopstx-cortex-m.c
Normal file
707
chopstx-cortex-m.c
Normal file
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
* chopstx-cortex-m.c - Threads and only threads: Arch specific code
|
||||
* for Cortex-M0/M3
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||
* 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
|
||||
* receipents of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Saved registers on the stack. */
|
||||
struct chx_stack_regs {
|
||||
uint32_t reg[8]; /* r0, r1, r2, r3, r12, lr, pc, xpsr */
|
||||
};
|
||||
|
||||
/*
|
||||
* Constants for ARM.
|
||||
*/
|
||||
#define REG_SP 8
|
||||
|
||||
#define REG_R0 0
|
||||
#define REG_LR 5
|
||||
#define REG_PC 6
|
||||
#define REG_XPSR 7
|
||||
|
||||
#define INITIAL_XPSR 0x01000000 /* T=1 */
|
||||
|
||||
/*
|
||||
* Exception priority: lower has higher precedence.
|
||||
*
|
||||
* Cortex-M3
|
||||
* =====================================
|
||||
* Prio 0x30: svc
|
||||
* ---------------------
|
||||
* Prio 0x40: thread temporarily inhibiting schedule for critical region
|
||||
* ...
|
||||
* Prio 0xb0: systick, external interrupt
|
||||
* Prio 0xc0: pendsv
|
||||
* =====================================
|
||||
*
|
||||
* Cortex-M0
|
||||
* =====================================
|
||||
* Prio 0x00: thread temporarily inhibiting schedule for critical region
|
||||
* ...
|
||||
* Prio 0x40: systick, external interrupt
|
||||
* Prio 0x80: pendsv
|
||||
* Prio 0x80: svc
|
||||
* =====================================
|
||||
*/
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_CLEAR 0
|
||||
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
|
||||
/* ... */
|
||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
|
||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
|
||||
#elif defined(__ARM_ARCH_7M__)
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
||||
/* ... */
|
||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
|
||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
|
||||
#else
|
||||
#error "no support for this arch"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lower layer architecture specific functions.
|
||||
*
|
||||
* system tick and interrupt
|
||||
*/
|
||||
|
||||
/*
|
||||
* System tick
|
||||
*/
|
||||
/* SysTick registers. */
|
||||
static volatile uint32_t *const SYST_CSR = (uint32_t *)0xE000E010;
|
||||
static volatile uint32_t *const SYST_RVR = (uint32_t *)0xE000E014;
|
||||
static volatile uint32_t *const SYST_CVR = (uint32_t *)0xE000E018;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
{
|
||||
*SYST_RVR = 0;
|
||||
*SYST_CVR = 0;
|
||||
*SYST_CSR = 7;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_systick_reload (uint32_t ticks)
|
||||
{
|
||||
*SYST_RVR = ticks;
|
||||
*SYST_CVR = 0; /* write (any) to clear the counter to reload. */
|
||||
*SYST_RVR = 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
chx_systick_get (void)
|
||||
{
|
||||
return *SYST_CVR;
|
||||
}
|
||||
|
||||
static uint32_t usec_to_ticks (uint32_t usec)
|
||||
{
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt Handling
|
||||
*/
|
||||
|
||||
/* NVIC: Nested Vectored Interrupt Controller. */
|
||||
struct NVIC {
|
||||
volatile uint32_t ISER[8];
|
||||
uint32_t unused1[24];
|
||||
volatile uint32_t ICER[8];
|
||||
uint32_t unused2[24];
|
||||
volatile uint32_t ISPR[8];
|
||||
uint32_t unused3[24];
|
||||
volatile uint32_t ICPR[8];
|
||||
uint32_t unused4[24];
|
||||
volatile uint32_t IABR[8];
|
||||
uint32_t unused5[56];
|
||||
volatile uint32_t IPR[60];
|
||||
};
|
||||
|
||||
static struct NVIC *const NVIC = (struct NVIC *)0xE000E100;
|
||||
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
|
||||
#define NVIC_ICER(n) (NVIC->ICER[n >> 5])
|
||||
#define NVIC_ICPR(n) (NVIC->ICPR[n >> 5])
|
||||
#define NVIC_IPR(n) (NVIC->IPR[n >> 2])
|
||||
|
||||
|
||||
static void
|
||||
chx_enable_intr (uint8_t irq_num)
|
||||
{
|
||||
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_clr_intr (uint8_t irq_num)
|
||||
{ /* Clear pending interrupt. */
|
||||
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_intr_prio (uint8_t n)
|
||||
{
|
||||
unsigned int sh = (n & 3) << 3;
|
||||
|
||||
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh))
|
||||
| (CPU_EXCEPTION_PRIORITY_INTERRUPT << sh);
|
||||
}
|
||||
|
||||
static volatile uint32_t *const ICSR = (uint32_t *)0xE000ED04;
|
||||
|
||||
/* Priority control. */
|
||||
static uint32_t *const AIRCR = (uint32_t *)0xE000ED0C;
|
||||
static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
|
||||
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
{
|
||||
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
|
||||
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
|
||||
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
|
||||
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chx_cpu_sched_lock (void)
|
||||
{
|
||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
{
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
#else
|
||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
|
||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chx_cpu_sched_unlock (void)
|
||||
{
|
||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
{
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
#else
|
||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
|
||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((naked, used))
|
||||
idle (void)
|
||||
{
|
||||
#if defined(USE_WFI_FOR_IDLE)
|
||||
for (;;)
|
||||
asm volatile ("wfi" : : : "memory");
|
||||
#else
|
||||
for (;;);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chx_handle_intr (void)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
register uint32_t irq_num;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
"sub %0, #16" /* Exception # - 16 = interrupt number. */
|
||||
: "=r" (irq_num) : /* no input */ : "memory");
|
||||
|
||||
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)
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
chx_request_preemption (px->master->prio);
|
||||
break;
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_init_arch (struct chx_thread *tp)
|
||||
{
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
}
|
||||
|
||||
static void
|
||||
chx_request_preemption (uint16_t prio)
|
||||
{
|
||||
if (running == NULL || (uint16_t)running->prio < prio)
|
||||
{
|
||||
*ICSR = (1 << 28);
|
||||
asm volatile ("" : : : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* chx_sched: switch to another thread.
|
||||
*
|
||||
* There are two cases:
|
||||
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
|
||||
* something (mutex, cond, intr, etc.)
|
||||
* YIELD=1 (YIELD): Current RUNNING thread is active,
|
||||
* it is needed to be enqueued to READY queue.
|
||||
*
|
||||
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
|
||||
* put "noinline" attribute.
|
||||
*
|
||||
* AAPCS: ARM Architecture Procedure Call Standard
|
||||
*
|
||||
* Returns:
|
||||
* 1 on wakeup by others.
|
||||
* 0 on normal wakeup.
|
||||
* -1 on cancellation.
|
||||
*/
|
||||
static uintptr_t __attribute__ ((naked, noinline))
|
||||
chx_sched (uint32_t yield)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
asm volatile (
|
||||
"svc #0\n\t"
|
||||
"bx lr"
|
||||
: "=r" (tp) : "0" (yield): "memory");
|
||||
#else
|
||||
register uint32_t arg_yield asm ("r1");
|
||||
|
||||
/* Build stack data as if it were an exception entry. */
|
||||
/*
|
||||
* r0: 0 scratch
|
||||
* r1: 0 scratch
|
||||
* r2: 0 scratch
|
||||
* r3: 0 scratch
|
||||
* r12: 0 scratch
|
||||
* lr as-is
|
||||
* pc: return address (= lr)
|
||||
* psr: INITIAL_XPSR scratch
|
||||
*/
|
||||
asm ("mov r1, lr\n\t"
|
||||
"mov r2, r1\n\t"
|
||||
"mov r3, #128\n\t"
|
||||
"lsl r3, #17\n\t"
|
||||
"push {r1, r2, r3}\n\t"
|
||||
"mov r1, #0\n\t"
|
||||
"mov r2, r1\n\t"
|
||||
"mov r3, r1\n\t"
|
||||
"push {r1, r2, r3}\n\t"
|
||||
"push {r1, r2}"
|
||||
: /* no output*/
|
||||
: /* no input */
|
||||
: "r1", "r2", "r3", "memory");
|
||||
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm ("mov r1, r0\n\t"
|
||||
"ldr r2, =running\n\t"
|
||||
"ldr r0, [r2]\n\t"
|
||||
"add r0, #20\n\t"
|
||||
"stm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mov r6, sp\n\t"
|
||||
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"sub r0, #56"
|
||||
: "=r" (tp), "=r" (arg_yield)
|
||||
: "0" (yield)
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
if (arg_yield)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
|
||||
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. */
|
||||
"ldr r1, =running\n\t"
|
||||
/* Update running. */
|
||||
"str r0, [r1]\n\t"
|
||||
"cmp r0, #0\n\t"
|
||||
"bne 0f\n\t"
|
||||
|
||||
/* Spawn an IDLE thread. */
|
||||
"ldr r1, =__main_stack_end__\n\t"
|
||||
"mov sp, r1\n\t"
|
||||
"ldr r0, =idle\n\t" /* PC = idle */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"cpsie i\n\t"
|
||||
"bx r0\n"
|
||||
|
||||
/* Normal context switch */
|
||||
"0:\n\t"
|
||||
"add r0, #16\n\t" /* ->V */
|
||||
"ldr r1, [r0]\n\t"
|
||||
"str r1, [sp]\n\t"
|
||||
/**/
|
||||
"add r0, #4\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
"mov r8, r1\n\t"
|
||||
"mov r9, r2\n\t"
|
||||
"mov r10, r3\n\t"
|
||||
"ldm r0!, {r1, r2}\n\t"
|
||||
"mov r11, r1\n\t"
|
||||
"mov sp, r2\n\t"
|
||||
"sub r0, #45\n\t"
|
||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
||||
"cmp r1, #247\n\t"
|
||||
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"cpsie i\n"
|
||||
/**/
|
||||
"1:\n\t"
|
||||
/*
|
||||
0: r0
|
||||
4: r1
|
||||
8: r2
|
||||
12: r3
|
||||
16: r12
|
||||
20: lr
|
||||
24: pc
|
||||
28: psr
|
||||
32: possibly exists for alignment
|
||||
[28 or 32] <-- pc
|
||||
*/
|
||||
"ldr r0, [sp, #28]\n\t"
|
||||
"lsl r1, r0, #23\n\t"
|
||||
"bcc 2f\n\t"
|
||||
/**/
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #32]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
"ldr r0, [sp, #20]\n\t"
|
||||
"mov lr, r0\n\t"
|
||||
"ldr r0, [sp, #16]\n\t"
|
||||
"mov r12, r0\n\t"
|
||||
"pop {r0, r1, r2, r3}\n\t"
|
||||
"add sp, #16\n\t"
|
||||
"pop {pc}\n"
|
||||
"2:\n\t"
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #28]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
"ldr r0, [sp, #20]\n\t"
|
||||
"mov lr, r0\n\t"
|
||||
"ldr r0, [sp, #16]\n\t"
|
||||
"mov r12, r0\n\t"
|
||||
"pop {r0, r1, r2, r3}\n\t"
|
||||
"add sp, #12\n\t"
|
||||
"pop {pc}"
|
||||
: "=r" (tp) /* Return value in R0 */
|
||||
: "0" (tp)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
return (uintptr_t)tp;
|
||||
}
|
||||
|
||||
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
|
||||
|
||||
static struct chx_thread *
|
||||
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
||||
voidfunc thread_entry, void *arg)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
void *stack;
|
||||
struct chx_stack_regs *p;
|
||||
|
||||
if (CHOPSTX_THREAD_SIZE != sizeof(struct chx_thread))
|
||||
cause_link_time_error_unexpected_size_of_struct_chx_thread ();
|
||||
|
||||
if (stack_size < sizeof (struct chx_thread) + 8 * sizeof (uint32_t))
|
||||
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
|
||||
|
||||
stack = (void *)(stack_addr + stack_size - sizeof (struct chx_thread)
|
||||
- sizeof (struct chx_stack_regs));
|
||||
memset (stack, 0, sizeof (struct chx_stack_regs));
|
||||
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
|
||||
p = (struct chx_stack_regs *)stack;
|
||||
p->reg[REG_R0] = (uint32_t)arg;
|
||||
p->reg[REG_LR] = (uint32_t)chopstx_exit;
|
||||
p->reg[REG_PC] = (uint32_t)thread_entry;
|
||||
p->reg[REG_XPSR] = INITIAL_XPSR;
|
||||
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
tp->tc.reg[REG_SP] = (uint32_t)stack;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower layer architecture specific exception handling entries.
|
||||
*
|
||||
*/
|
||||
|
||||
void __attribute__ ((naked))
|
||||
preempt (void)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
register struct chx_thread *cur asm ("r1");
|
||||
|
||||
asm volatile (
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsid i\n\t"
|
||||
#else
|
||||
"msr BASEPRI, r0\n\t"
|
||||
#endif
|
||||
"ldr r2, =running\n\t"
|
||||
"ldr r0, [r2]\n\t"
|
||||
"mov r1, r0"
|
||||
: "=r" (tp), "=r" (cur)
|
||||
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
|
||||
: "r2");
|
||||
|
||||
if (!cur)
|
||||
/* It's idle thread. It's ok to clobber registers. */
|
||||
;
|
||||
else
|
||||
{
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm volatile (
|
||||
"add %0, #20\n\t"
|
||||
"stm %0!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||
"stm %0!, {r2, r3, r4, r5, r6}"
|
||||
: "=r" (cur)
|
||||
: "0" (cur)
|
||||
/*
|
||||
* Memory clobber constraint here is not accurate, but this
|
||||
* works. R7 keeps its value, but having "r7" here prevents
|
||||
* use of R7 before this asm statement.
|
||||
*/
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
if (tp)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
{
|
||||
if (tp->state == THREAD_RUNNING)
|
||||
{
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
/*
|
||||
* It may be THREAD_READY after chx_timer_expired.
|
||||
* Then, do nothing.
|
||||
*/
|
||||
}
|
||||
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"
|
||||
/* Now, r0 points to the thread to be switched. */
|
||||
/* Put it to *running. */
|
||||
"ldr r1, =running\n\t"
|
||||
/* Update running. */
|
||||
"str r0, [r1]\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cmp r0, #0\n\t"
|
||||
"beq 1f\n\t"
|
||||
#else
|
||||
"cbz r0, 1f\n\t"
|
||||
#endif
|
||||
/**/
|
||||
"add r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
"mov r8, r1\n\t"
|
||||
"mov r9, r2\n\t"
|
||||
"mov r10, r3\n\t"
|
||||
"ldm r0!, {r1, r2}\n\t"
|
||||
"mov r11, r1\n\t"
|
||||
"msr PSP, r2\n\t"
|
||||
#else
|
||||
"ldr r8, [r0], #4\n\t"
|
||||
"ldr r9, [r0], #4\n\t"
|
||||
"ldr r10, [r0], #4\n\t"
|
||||
"ldr r11, [r0], #4\n\t"
|
||||
"ldr r1, [r0], #4\n\t"
|
||||
"msr PSP, r1\n\t"
|
||||
#endif
|
||||
"sub r0, #45\n\t"
|
||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
||||
"mov r0, #0\n\t"
|
||||
"cmp r1, #247\n\t"
|
||||
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsie i\n"
|
||||
#else
|
||||
"msr BASEPRI, r0\n"
|
||||
#endif
|
||||
/**/
|
||||
"0:\n\t"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0\n"
|
||||
"1:\n\t"
|
||||
/* Spawn an IDLE thread. */
|
||||
"ldr r0, =__main_stack_end__-32\n\t"
|
||||
"msr PSP, r0\n\t"
|
||||
"mov r1, #0\n\t"
|
||||
"mov r2, #0\n\t"
|
||||
"mov r3, #0\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"ldr r1, =idle\n\t" /* PC = idle */
|
||||
"mov r2, #0x010\n\t"
|
||||
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
|
||||
"stm r0!, {r1, r2}\n\t"
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"mov r0, #0\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsie i\n\t"
|
||||
#else
|
||||
"msr BASEPRI, r0\n"
|
||||
#endif
|
||||
/**/
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0"
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
/*
|
||||
* System call: switch to another thread.
|
||||
* There are two cases:
|
||||
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
|
||||
* something (mutex, cond, intr, etc.)
|
||||
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
|
||||
* it is needed to be enqueued to READY queue.
|
||||
*/
|
||||
void __attribute__ ((naked))
|
||||
svc (void)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
register uint32_t orig_r0 asm ("r1");
|
||||
|
||||
asm ("ldr r1, =running\n\t"
|
||||
"ldr r0, [r1]\n\t"
|
||||
"add r1, r0, #20\n\t"
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
"stm r1!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"ldr r1, [r6]"
|
||||
: "=r" (tp), "=r" (orig_r0)
|
||||
: /* no input */
|
||||
: "r2", "r3", "r4", "r5", "r6", "memory");
|
||||
|
||||
if (orig_r0) /* yield */
|
||||
{
|
||||
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 (
|
||||
"cbz r0, 0f\n\t"
|
||||
"ldr r1, [r0, #16]\n\t" /* ->V */
|
||||
"str r1, [sp]\n\t"
|
||||
"0:\n\t"
|
||||
"b .L_CONTEXT_SWITCH"
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
#endif
|
||||
12
chopstx-cortex-m.h
Normal file
12
chopstx-cortex-m.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* The thread context: specific to ARM Cortex-M0/M3.
|
||||
*
|
||||
* In this structure, it's only partial information; Other part of the
|
||||
* context is on the stack.
|
||||
*
|
||||
*/
|
||||
struct tcontext {
|
||||
uint32_t reg[9]; /* r4, r5, r6, r7, r8, r9, r10, r11, r13(sp) */
|
||||
};
|
||||
|
||||
typedef struct tcontext tcontext_t;
|
||||
344
chopstx-gnu-linux.c
Normal file
344
chopstx-gnu-linux.c
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||
* for GNU/Linux emulation
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* receipents of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <ucontext.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static sigset_t ss_cur;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
{
|
||||
const struct itimerval it = { {0, 0}, {0, 0} };
|
||||
|
||||
setitimer (ITIMER_REAL, &it, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_systick_reload (uint32_t ticks)
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = (ticks / MHZ);
|
||||
it.it_interval.tv_sec = 0;
|
||||
it.it_interval.tv_usec = 0;
|
||||
|
||||
setitimer (ITIMER_REAL, &it, 0);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
chx_systick_get (void)
|
||||
{
|
||||
struct itimerval it;
|
||||
getitimer (ITIMER_REAL, &it);
|
||||
return it.it_value.tv_usec * 72;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
usec_to_ticks (uint32_t usec)
|
||||
{
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chx_enable_intr (uint8_t irq_num)
|
||||
{
|
||||
sigdelset (&ss_cur, irq_num);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_clr_intr (uint8_t irq_num)
|
||||
{ /* Clear pending interrupt. */
|
||||
(void)irq_num;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
sigaddset (&ss_cur, irq_num);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_intr_prio (uint8_t n)
|
||||
{
|
||||
(void)n;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
chx_cpu_sched_lock (void)
|
||||
{
|
||||
sigset_t ss;
|
||||
|
||||
sigfillset (&ss);
|
||||
pthread_sigmask (SIG_BLOCK, &ss, &ss_cur);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_cpu_sched_unlock (void)
|
||||
{
|
||||
pthread_sigmask (SIG_SETMASK, &ss_cur, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
idle (void)
|
||||
{
|
||||
for (;;)
|
||||
pause ();
|
||||
}
|
||||
|
||||
void
|
||||
chx_handle_intr (uint32_t irq_num)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
|
||||
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)
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
chx_request_preemption (px->master->prio);
|
||||
return;
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
|
||||
static ucontext_t idle_tc;
|
||||
static char idle_stack[4096];
|
||||
|
||||
struct chx_thread main_thread;
|
||||
|
||||
void
|
||||
chx_sigmask (ucontext_t *uc)
|
||||
{
|
||||
/* Modify oldmask to SS_CUR, so that the signal mask will
|
||||
* be set to SS_CUR.
|
||||
*
|
||||
* In user-level, sigset_t is big, but only the first word
|
||||
* is used by the kernel.
|
||||
*/
|
||||
memcpy (&uc->uc_sigmask, &ss_cur, sizeof (uint64_t));
|
||||
}
|
||||
|
||||
static void
|
||||
sigalrm_handler (int sig, siginfo_t *siginfo, void *arg)
|
||||
{
|
||||
extern void chx_timer_expired (void);
|
||||
ucontext_t *uc = arg;
|
||||
(void)sig;
|
||||
(void)siginfo;
|
||||
chx_timer_expired ();
|
||||
chx_sigmask (uc);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_init_arch (struct chx_thread *tp)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset (&ss_cur);
|
||||
|
||||
sa.sa_sigaction = sigalrm_handler;
|
||||
sigfillset (&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
sigaction (SIGALRM, &sa, NULL);
|
||||
|
||||
getcontext (&idle_tc);
|
||||
idle_tc.uc_stack.ss_sp = idle_stack;
|
||||
idle_tc.uc_stack.ss_size = sizeof (idle_stack);
|
||||
idle_tc.uc_link = NULL;
|
||||
makecontext (&idle_tc, idle, 0);
|
||||
|
||||
getcontext (&tp->tc);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_request_preemption (uint16_t prio)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
ucontext_t *tcp;
|
||||
|
||||
if (running && (uint16_t)running->prio >= prio)
|
||||
return;
|
||||
|
||||
/* Change the context to another thread with higher priority. */
|
||||
tp = tp_prev = running;
|
||||
if (tp)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
{
|
||||
if (tp->state == THREAD_RUNNING)
|
||||
{
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
}
|
||||
else
|
||||
chx_ready_push (tp);
|
||||
running = NULL;
|
||||
}
|
||||
|
||||
tp = running = 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;
|
||||
|
||||
if (tp_prev)
|
||||
{
|
||||
/*
|
||||
* The swapcontext implementation may reset sigmask in the
|
||||
* middle of its execution, unfortunately. It is best if
|
||||
* sigmask restore is done at the end of the routine, but we
|
||||
* can't assume that.
|
||||
*
|
||||
* Thus, there might be a race condition with regards to the
|
||||
* user context TCP, if signal mask is cleared and signal comes
|
||||
* in. To avoid this situation, we block signals.
|
||||
*
|
||||
* We don't need to fill the mask here. It keeps the condition
|
||||
* of blocking signals before&after swapcontext call. It is
|
||||
* done by the signal mask for sigaction, the initial creation
|
||||
* of the thread, and the condition of chx_sched function which
|
||||
* mandates holding cpu_sched_lock.
|
||||
*/
|
||||
swapcontext (&tp_prev->tc, tcp);
|
||||
}
|
||||
else if (tp)
|
||||
{
|
||||
setcontext (tcp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* chx_sched: switch to another thread.
|
||||
*
|
||||
* There are two cases:
|
||||
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
|
||||
* something (mutex, cond, intr, etc.)
|
||||
* YIELD=1 (YIELD): Current RUNNING thread is active,
|
||||
* it is needed to be enqueued to READY queue.
|
||||
*
|
||||
* Returns:
|
||||
* 1 on wakeup by others.
|
||||
* 0 on normal wakeup.
|
||||
* -1 on cancellation.
|
||||
*/
|
||||
static uintptr_t
|
||||
chx_sched (uint32_t yield)
|
||||
{
|
||||
struct chx_thread *tp, *tp_prev;
|
||||
uintptr_t v;
|
||||
ucontext_t *tcp;
|
||||
|
||||
tp = tp_prev = running;
|
||||
if (yield)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
|
||||
running = 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;
|
||||
}
|
||||
|
||||
swapcontext (&tp_prev->tc, tcp);
|
||||
chx_cpu_sched_unlock ();
|
||||
return v;
|
||||
}
|
||||
|
||||
static void __attribute__((__noreturn__))
|
||||
chx_thread_start (voidfunc thread_entry, void *arg)
|
||||
{
|
||||
chx_cpu_sched_unlock ();
|
||||
thread_entry (arg);
|
||||
chopstx_exit (0);
|
||||
}
|
||||
|
||||
static struct chx_thread *
|
||||
chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
||||
voidfunc thread_entry, void *arg)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
tp = malloc (sizeof (struct chx_thread));
|
||||
if (!tp)
|
||||
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
|
||||
|
||||
/*
|
||||
* Calling getcontext with sched_lock held, the context is with
|
||||
* signal blocked. The sigmask will be cleared in chx_thread_start.
|
||||
*/
|
||||
chx_cpu_sched_lock ();
|
||||
getcontext (&tp->tc);
|
||||
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
|
||||
tp->tc.uc_stack.ss_size = stack_size;
|
||||
tp->tc.uc_link = NULL;
|
||||
|
||||
makecontext (&tp->tc, (void (*)(void))chx_thread_start,
|
||||
4, thread_entry, arg);
|
||||
chx_cpu_sched_unlock ();
|
||||
return tp;
|
||||
}
|
||||
10
chopstx-gnu-linux.h
Normal file
10
chopstx-gnu-linux.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <ucontext.h>
|
||||
/*
|
||||
* The thread context: specific to GNU/Linux.
|
||||
*
|
||||
* We use the type ucontext_t, which includes all registers;
|
||||
* Note that signal mask is also included in ucontext_t.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef ucontext_t tcontext_t;
|
||||
747
chopstx.c
747
chopstx.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* chopstx.c - Threads and only threads.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <chopstx.h>
|
||||
|
||||
/*
|
||||
* Thread priority: higer has higher precedence.
|
||||
* Thread priority: greater (as integer) has higher precedence.
|
||||
*/
|
||||
#if !defined(CHX_PRIO_MAIN_INIT)
|
||||
#define CHX_PRIO_MAIN_INIT 1
|
||||
@@ -50,163 +50,11 @@
|
||||
|
||||
#define MAX_PRIO (255+1)
|
||||
|
||||
/*
|
||||
* Exception priority: lower has higher precedence.
|
||||
*
|
||||
* Cortex-M3
|
||||
* =====================================
|
||||
* Prio 0x30: svc
|
||||
* ---------------------
|
||||
* Prio 0x40: thread temporarily inhibiting schedule for critical region
|
||||
* ...
|
||||
* Prio 0xb0: systick, external interrupt
|
||||
* Prio 0xc0: pendsv
|
||||
* =====================================
|
||||
*
|
||||
* Cortex-M0
|
||||
* =====================================
|
||||
* Prio 0x00: thread temporarily inhibiting schedule for critical region
|
||||
* ...
|
||||
* Prio 0x40: systick, external interrupt
|
||||
* Prio 0x80: pendsv
|
||||
* Prio 0x80: svc
|
||||
* =====================================
|
||||
*/
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_CLEAR 0
|
||||
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
|
||||
/* ... */
|
||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
|
||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
|
||||
#elif defined(__ARM_ARCH_7M__)
|
||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
||||
|
||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
||||
/* ... */
|
||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
|
||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
|
||||
#else
|
||||
#error "no support for this arch"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lower layer architecture specific functions.
|
||||
*
|
||||
* system tick and interrupt
|
||||
*/
|
||||
|
||||
/*
|
||||
* System tick
|
||||
*/
|
||||
/* SysTick registers. */
|
||||
static volatile uint32_t *const SYST_CSR = (uint32_t *)0xE000E010;
|
||||
static volatile uint32_t *const SYST_RVR = (uint32_t *)0xE000E014;
|
||||
static volatile uint32_t *const SYST_CVR = (uint32_t *)0xE000E018;
|
||||
|
||||
static void
|
||||
chx_systick_reset (void)
|
||||
{
|
||||
*SYST_RVR = 0;
|
||||
*SYST_CVR = 0;
|
||||
*SYST_CSR = 7;
|
||||
}
|
||||
|
||||
static void
|
||||
chx_systick_reload (uint32_t ticks)
|
||||
{
|
||||
*SYST_RVR = ticks;
|
||||
*SYST_CVR = 0; /* write (any) to clear the counter to reload. */
|
||||
*SYST_RVR = 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
chx_systick_get (void)
|
||||
{
|
||||
return *SYST_CVR;
|
||||
}
|
||||
|
||||
#ifndef MHZ
|
||||
#define MHZ 72
|
||||
#endif
|
||||
|
||||
static uint32_t usec_to_ticks (uint32_t usec)
|
||||
{
|
||||
return usec * MHZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt Handling
|
||||
*/
|
||||
|
||||
/* NVIC: Nested Vectored Interrupt Controller. */
|
||||
struct NVIC {
|
||||
volatile uint32_t ISER[8];
|
||||
uint32_t unused1[24];
|
||||
volatile uint32_t ICER[8];
|
||||
uint32_t unused2[24];
|
||||
volatile uint32_t ISPR[8];
|
||||
uint32_t unused3[24];
|
||||
volatile uint32_t ICPR[8];
|
||||
uint32_t unused4[24];
|
||||
volatile uint32_t IABR[8];
|
||||
uint32_t unused5[56];
|
||||
volatile uint32_t IPR[60];
|
||||
};
|
||||
|
||||
static struct NVIC *const NVIC = (struct NVIC *)0xE000E100;
|
||||
#define NVIC_ISER(n) (NVIC->ISER[n >> 5])
|
||||
#define NVIC_ICER(n) (NVIC->ICER[n >> 5])
|
||||
#define NVIC_ICPR(n) (NVIC->ICPR[n >> 5])
|
||||
#define NVIC_IPR(n) (NVIC->IPR[n >> 2])
|
||||
|
||||
|
||||
static void
|
||||
chx_enable_intr (uint8_t irq_num)
|
||||
{
|
||||
NVIC_ISER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_clr_intr (uint8_t irq_num)
|
||||
{ /* Clear pending interrupt. */
|
||||
NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_disable_intr (uint8_t irq_num)
|
||||
{
|
||||
NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f);
|
||||
}
|
||||
|
||||
static void
|
||||
chx_set_intr_prio (uint8_t n)
|
||||
{
|
||||
unsigned int sh = (n & 3) << 3;
|
||||
|
||||
NVIC_IPR (n) = (NVIC_IPR(n) & ~(0xFF << sh))
|
||||
| (CPU_EXCEPTION_PRIORITY_INTERRUPT << sh);
|
||||
}
|
||||
|
||||
static volatile uint32_t *const ICSR = (uint32_t *)0xE000ED04;
|
||||
|
||||
/* Priority control. */
|
||||
static uint32_t *const AIRCR = (uint32_t *)0xE000ED0C;
|
||||
static uint32_t *const SHPR2 = (uint32_t *)0xE000ED1C;
|
||||
static uint32_t *const SHPR3 = (uint32_t *)0xE000ED20;
|
||||
|
||||
static void
|
||||
chx_prio_init (void)
|
||||
{
|
||||
*AIRCR = 0x05FA0000 | ( 5 << 8); /* PRIGROUP = 5, 2-bit:2-bit. */
|
||||
*SHPR2 = (CPU_EXCEPTION_PRIORITY_SVC << 24);
|
||||
*SHPR3 = ((CPU_EXCEPTION_PRIORITY_SYSTICK << 24)
|
||||
| (CPU_EXCEPTION_PRIORITY_PENDSV << 16));
|
||||
}
|
||||
typedef void *(voidfunc) (void *);
|
||||
|
||||
void __attribute__((weak)) chx_fatal (uint32_t err_code);
|
||||
|
||||
@@ -224,6 +72,12 @@ chx_fatal (uint32_t err_code)
|
||||
for (;;);
|
||||
}
|
||||
|
||||
/* Include the definition of thread context structure. */
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#include "chopstx-gnu-linux.h"
|
||||
#else
|
||||
#include "chopstx-cortex-m.h"
|
||||
#endif
|
||||
|
||||
/* RUNNING: the current thread. */
|
||||
struct chx_thread *running;
|
||||
@@ -242,10 +96,15 @@ static struct chx_queue q_timer;
|
||||
/* Queue of threads which wait for the exit of some thread. */
|
||||
static struct chx_queue q_join;
|
||||
|
||||
/* Queue of threads which wait for some interrupts. */
|
||||
static struct chx_queue q_intr;
|
||||
|
||||
/* Forward declaration(s). */
|
||||
static void chx_request_preemption (uint16_t prio);
|
||||
static int chx_wakeup (struct chx_pq *p);
|
||||
static struct chx_thread * chx_timer_insert (struct chx_thread *tp, uint32_t usec);
|
||||
static void chx_timer_dequeue (struct chx_thread *tp);
|
||||
|
||||
|
||||
|
||||
/**************/
|
||||
@@ -264,29 +123,6 @@ static void chx_spin_unlock (struct chx_spinlock *lk)
|
||||
(void)lk;
|
||||
}
|
||||
|
||||
/* The thread context: specific to ARM Cortex-M3 now. */
|
||||
struct tcontext {
|
||||
uint32_t reg[9]; /* r4, r5, r6, r7, r8, r9, r10, r11, r13(sp) */
|
||||
};
|
||||
|
||||
/* Saved registers on the stack. */
|
||||
struct chx_stack_regs {
|
||||
uint32_t reg[8]; /* r0, r1, r2, r3, r12, lr, pc, xpsr */
|
||||
};
|
||||
|
||||
/*
|
||||
* Constants for ARM.
|
||||
*/
|
||||
#define REG_EXIT 4 /* R8 */
|
||||
#define REG_SP 8
|
||||
|
||||
#define REG_R0 0
|
||||
#define REG_LR 5
|
||||
#define REG_PC 6
|
||||
#define REG_XPSR 7
|
||||
|
||||
#define INITIAL_XPSR 0x01000000 /* T=1 */
|
||||
|
||||
/**************/
|
||||
struct chx_pq {
|
||||
struct chx_pq *next, *prev;
|
||||
@@ -297,7 +133,7 @@ struct chx_pq {
|
||||
uint32_t : 8;
|
||||
uint32_t prio : 8;
|
||||
struct chx_qh *parent;
|
||||
uint32_t v;
|
||||
uintptr_t v;
|
||||
};
|
||||
|
||||
struct chx_px { /* inherits PQ */
|
||||
@@ -309,7 +145,7 @@ struct chx_px { /* inherits PQ */
|
||||
uint32_t : 8;
|
||||
uint32_t prio : 8;
|
||||
struct chx_qh *parent;
|
||||
uint32_t v;
|
||||
uintptr_t v;
|
||||
struct chx_thread *master;
|
||||
uint32_t *counter_p;
|
||||
uint16_t *ready_p;
|
||||
@@ -329,42 +165,13 @@ struct chx_thread { /* inherits PQ */
|
||||
uint32_t prio_orig : 8;
|
||||
uint32_t prio : 8;
|
||||
struct chx_qh *parent;
|
||||
uint32_t v;
|
||||
struct tcontext tc;
|
||||
uintptr_t v;
|
||||
tcontext_t tc;
|
||||
struct chx_mtx *mutex_list;
|
||||
struct chx_cleanup *clp;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
chx_cpu_sched_lock (void)
|
||||
{
|
||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
{
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
#else
|
||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
|
||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chx_cpu_sched_unlock (void)
|
||||
{
|
||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
||||
{
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
#else
|
||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
|
||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Double linked list handling.
|
||||
*/
|
||||
@@ -483,18 +290,16 @@ chx_ready_enqueue (struct chx_thread *tp)
|
||||
chx_spin_unlock (&q_ready.lock);
|
||||
}
|
||||
|
||||
static void __attribute__((naked, used))
|
||||
idle (void)
|
||||
{
|
||||
#if defined(USE_WFI_FOR_IDLE)
|
||||
for (;;)
|
||||
asm volatile ("wfi" : : : "memory");
|
||||
/*
|
||||
* Here comes architecture specific code.
|
||||
*/
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#include "chopstx-gnu-linux.c"
|
||||
#else
|
||||
for (;;);
|
||||
#include "chopstx-cortex-m.c"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
chx_set_timer (struct chx_thread *tp, uint32_t ticks)
|
||||
{
|
||||
@@ -608,37 +413,10 @@ chx_timer_expired (void)
|
||||
}
|
||||
}
|
||||
|
||||
chx_request_preemption (prio);
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
chx_request_preemption (prio);
|
||||
}
|
||||
|
||||
/* Queue of threads which wait for some interrupts. */
|
||||
static struct chx_queue q_intr;
|
||||
|
||||
void
|
||||
chx_handle_intr (void)
|
||||
{
|
||||
struct chx_pq *p;
|
||||
register uint32_t irq_num;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
"sub %0, #16" /* Exception # - 16 = interrupt number. */
|
||||
: "=r" (irq_num) : /* no input */ : "memory");
|
||||
|
||||
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)
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_px *px = (struct chx_px *)p;
|
||||
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
chx_request_preemption (px->master->prio);
|
||||
break;
|
||||
}
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
void
|
||||
chx_systick_init (void)
|
||||
@@ -661,7 +439,8 @@ void
|
||||
chx_init (struct chx_thread *tp)
|
||||
{
|
||||
chx_prio_init ();
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
chx_init_arch (tp);
|
||||
|
||||
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q;
|
||||
chx_spin_init (&q_ready.lock);
|
||||
q_timer.q.next = q_timer.q.prev = (struct chx_pq *)&q_timer.q;
|
||||
@@ -693,200 +472,9 @@ chx_init (struct chx_thread *tp)
|
||||
chopstx_main = (chopstx_t)tp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
chx_request_preemption (uint16_t prio)
|
||||
{
|
||||
if (running == NULL || (uint16_t)running->prio < prio)
|
||||
{
|
||||
*ICSR = (1 << 28);
|
||||
asm volatile ("" : : : "memory");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define CHX_SLEEP 0
|
||||
#define CHX_YIELD 1
|
||||
|
||||
/*
|
||||
* chx_sched: switch to another thread.
|
||||
*
|
||||
* There are two cases:
|
||||
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
|
||||
* something (mutex, cond, intr, etc.)
|
||||
* YIELD=1 (YIELD): Current RUNNING thread is active,
|
||||
* it is needed to be enqueued to READY queue.
|
||||
*
|
||||
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
|
||||
* put "noinline" attribute.
|
||||
*
|
||||
* AAPCS: ARM Architecture Procedure Call Standard
|
||||
*
|
||||
* Returns:
|
||||
* 1 on wakeup by others.
|
||||
* 0 on normal wakeup.
|
||||
* -1 on cancellation.
|
||||
*/
|
||||
static int __attribute__ ((naked, noinline))
|
||||
chx_sched (uint32_t yield)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
asm volatile (
|
||||
"svc #0\n\t"
|
||||
"bx lr"
|
||||
: "=r" (tp) : "0" (yield): "memory");
|
||||
#else
|
||||
register uint32_t arg_yield asm ("r1");
|
||||
|
||||
/* Build stack data as if it were an exception entry. */
|
||||
/*
|
||||
* r0: 0 scratch
|
||||
* r1: 0 scratch
|
||||
* r2: 0 scratch
|
||||
* r3: 0 scratch
|
||||
* r12: 0 scratch
|
||||
* lr as-is
|
||||
* pc: return address (= lr)
|
||||
* psr: INITIAL_XPSR scratch
|
||||
*/
|
||||
asm ("mov r1, lr\n\t"
|
||||
"mov r2, r1\n\t"
|
||||
"mov r3, #128\n\t"
|
||||
"lsl r3, #17\n\t"
|
||||
"push {r1, r2, r3}\n\t"
|
||||
"mov r1, #0\n\t"
|
||||
"mov r2, r1\n\t"
|
||||
"mov r3, r1\n\t"
|
||||
"push {r1, r2, r3}\n\t"
|
||||
"push {r1, r2}"
|
||||
: /* no output*/
|
||||
: /* no input */
|
||||
: "r1", "r2", "r3", "memory");
|
||||
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm ("mov r1, r0\n\t"
|
||||
"ldr r2, =running\n\t"
|
||||
"ldr r0, [r2]\n\t"
|
||||
"add r0, #20\n\t"
|
||||
"stm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mov r6, sp\n\t"
|
||||
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"sub r0, #56"
|
||||
: "=r" (tp), "=r" (arg_yield)
|
||||
: "0" (yield)
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
if (arg_yield)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
|
||||
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. */
|
||||
"ldr r1, =running\n\t"
|
||||
/* Update running. */
|
||||
"str r0, [r1]\n\t"
|
||||
"cmp r0, #0\n\t"
|
||||
"bne 0f\n\t"
|
||||
|
||||
/* Spawn an IDLE thread. */
|
||||
"ldr r1, =__main_stack_end__\n\t"
|
||||
"mov sp, r1\n\t"
|
||||
"ldr r0, =idle\n\t" /* PC = idle */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"cpsie i\n\t"
|
||||
"bx r0\n"
|
||||
|
||||
/* Normal context switch */
|
||||
"0:\n\t"
|
||||
/**/
|
||||
"add r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
"mov r8, r1\n\t"
|
||||
"mov r9, r2\n\t"
|
||||
"mov r10, r3\n\t"
|
||||
"ldm r0!, {r1, r2}\n\t"
|
||||
"mov r11, r1\n\t"
|
||||
"mov sp, r2\n\t"
|
||||
"sub r0, #45\n\t"
|
||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
||||
"cmp r1, #247\n\t"
|
||||
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"cpsie i\n"
|
||||
/**/
|
||||
"1:\n\t"
|
||||
/*
|
||||
0: r0
|
||||
4: r1
|
||||
8: r2
|
||||
12: r3
|
||||
16: r12
|
||||
20: lr
|
||||
24: pc
|
||||
28: psr
|
||||
32: possibly exists for alignment
|
||||
[28 or 32] <-- pc
|
||||
*/
|
||||
"ldr r0, [sp, #28]\n\t"
|
||||
"lsl r1, r0, #23\n\t"
|
||||
"bcc 2f\n\t"
|
||||
/**/
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #32]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
"ldr r0, [sp, #20]\n\t"
|
||||
"mov lr, r0\n\t"
|
||||
"ldr r0, [sp, #16]\n\t"
|
||||
"mov r12, r0\n\t"
|
||||
"pop {r0, r1, r2, r3}\n\t"
|
||||
"add sp, #16\n\t"
|
||||
"pop {pc}\n"
|
||||
"2:\n\t"
|
||||
"ldr r2, [sp, #24]\n\t"
|
||||
"mov r1, #1\n\t"
|
||||
"orr r2, r1\n\t" /* Ensure Thumb-mode */
|
||||
"str r2, [sp, #28]\n\t"
|
||||
"msr APSR_nzcvq, r0\n\t"
|
||||
/**/
|
||||
"ldr r0, [sp, #20]\n\t"
|
||||
"mov lr, r0\n\t"
|
||||
"ldr r0, [sp, #16]\n\t"
|
||||
"mov r12, r0\n\t"
|
||||
"pop {r0, r1, r2, r3}\n\t"
|
||||
"add sp, #12\n\t"
|
||||
"pop {pc}"
|
||||
: "=r" (tp) /* Return value in R0 */
|
||||
: "0" (tp)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
return (uint32_t)tp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wakeup the thread TP. Called with schedule lock held.
|
||||
@@ -907,21 +495,21 @@ chx_wakeup (struct chx_pq *pq)
|
||||
tp = px->master;
|
||||
if (tp->state == THREAD_WAIT_POLL)
|
||||
{
|
||||
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = 1;
|
||||
tp->v = (uintptr_t)1;
|
||||
if (tp->parent == &q_timer.q)
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
if (!running || tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
chx_spin_unlock (&px->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = 1;
|
||||
tp = (struct chx_thread *)pq;
|
||||
tp->v = (uintptr_t)1;
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
if (!running || tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
|
||||
@@ -929,21 +517,18 @@ chx_wakeup (struct chx_pq *pq)
|
||||
}
|
||||
|
||||
|
||||
/* The RETVAL is saved into register R8. */
|
||||
/* The RETVAL is saved into ->v. */
|
||||
static void __attribute__((noreturn))
|
||||
chx_exit (void *retval)
|
||||
{
|
||||
register uint32_t r8 asm ("r8");
|
||||
struct chx_pq *p;
|
||||
|
||||
asm volatile ("mov %0, %1" : "=r" (r8) : "r" (retval));
|
||||
|
||||
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)
|
||||
if (p->v == (uint32_t)running)
|
||||
if (p->v == (uintptr_t)running)
|
||||
{ /* should be one at most. */
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (p);
|
||||
@@ -958,7 +543,7 @@ chx_exit (void *retval)
|
||||
running->state = THREAD_FINISHED;
|
||||
else
|
||||
running->state = THREAD_EXITED;
|
||||
asm volatile ("" : : "r" (r8) : "memory");
|
||||
running->v = (uintptr_t)retval;
|
||||
chx_sched (CHX_SLEEP);
|
||||
/* never comes here. */
|
||||
for (;;);
|
||||
@@ -1003,10 +588,6 @@ chx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
|
||||
#define CHOPSTX_PRIO_MASK ((1 << CHOPSTX_PRIO_BITS) - 1)
|
||||
|
||||
typedef void *(voidfunc) (void *);
|
||||
|
||||
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
|
||||
|
||||
/**
|
||||
* chopstx_create - Create a thread
|
||||
* @flags_and_prio: Flags and priority
|
||||
@@ -1019,32 +600,14 @@ extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
|
||||
*/
|
||||
chopstx_t
|
||||
chopstx_create (uint32_t flags_and_prio,
|
||||
uint32_t stack_addr, size_t stack_size,
|
||||
uintptr_t stack_addr, size_t stack_size,
|
||||
voidfunc thread_entry, void *arg)
|
||||
{
|
||||
struct chx_thread *tp;
|
||||
void *stack;
|
||||
struct chx_stack_regs *p;
|
||||
chopstx_prio_t prio = (flags_and_prio & CHOPSTX_PRIO_MASK);
|
||||
|
||||
if (CHOPSTX_THREAD_SIZE != sizeof(struct chx_thread))
|
||||
cause_link_time_error_unexpected_size_of_struct_chx_thread ();
|
||||
|
||||
if (stack_size < sizeof (struct chx_thread) + 8 * sizeof (uint32_t))
|
||||
chx_fatal (CHOPSTX_ERR_THREAD_CREATE);
|
||||
|
||||
stack = (void *)(stack_addr + stack_size - sizeof (struct chx_thread)
|
||||
- sizeof (struct chx_stack_regs));
|
||||
memset (stack, 0, sizeof (struct chx_stack_regs));
|
||||
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
|
||||
p = (struct chx_stack_regs *)stack;
|
||||
p->reg[REG_R0] = (uint32_t)arg;
|
||||
p->reg[REG_LR] = (uint32_t)chopstx_exit;
|
||||
p->reg[REG_PC] = (uint32_t)thread_entry;
|
||||
p->reg[REG_XPSR] = INITIAL_XPSR;
|
||||
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
tp->tc.reg[REG_SP] = (uint32_t)stack;
|
||||
tp = chopstx_create_arch (stack_addr, stack_size, thread_entry,
|
||||
arg);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
@@ -1232,7 +795,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
if (tp0->state == THREAD_WAIT_TIME
|
||||
|| tp0->state == THREAD_WAIT_POLL)
|
||||
{
|
||||
((struct chx_stack_regs *)tp0->tc.reg[REG_SP])->reg[REG_R0] = 1;
|
||||
tp0->v = (uintptr_t)1;
|
||||
if (tp0->parent == &q_timer.q)
|
||||
chx_timer_dequeue (tp0);
|
||||
|
||||
@@ -1497,12 +1060,6 @@ chopstx_cleanup_pop (int execute)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We put "naked" attribute to chopstx_exit function. Since it never
|
||||
* returns, function prologue is not needed.
|
||||
*/
|
||||
void chopstx_exit (void *retval) __attribute__ ((naked));
|
||||
|
||||
/**
|
||||
* chopstx_exit - Terminate the execution of running thread
|
||||
* @retval: Return value (to be caught by a joining thread)
|
||||
@@ -1559,6 +1116,8 @@ chopstx_join (chopstx_t thd, void **ret)
|
||||
* We don't offer deadlock detection. It's users' responsibility.
|
||||
*/
|
||||
|
||||
chopstx_testcancel ();
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
if (tp->flag_detached)
|
||||
{
|
||||
@@ -1574,7 +1133,7 @@ chopstx_join (chopstx_t thd, void **ret)
|
||||
chx_timer_dequeue (running);
|
||||
chx_spin_lock (&q_join.lock);
|
||||
ll_prio_enqueue ((struct chx_pq *)running, &q_join.q);
|
||||
running->v = (uint32_t)tp;
|
||||
running->v = (uintptr_t)tp;
|
||||
running->state = THREAD_WAIT_EXIT;
|
||||
tp->flag_join_req = 1;
|
||||
|
||||
@@ -1598,7 +1157,7 @@ chopstx_join (chopstx_t thd, void **ret)
|
||||
{
|
||||
tp->state = THREAD_FINISHED;
|
||||
if (ret)
|
||||
*ret = (void *)tp->tc.reg[REG_EXIT]; /* R8 */
|
||||
*ret = (void *)tp->v;
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -1631,7 +1190,7 @@ chx_join_hook (struct chx_px *px, struct chx_poll_head *pd)
|
||||
{ /* Not yet exited.
|
||||
* Register the proxy to wait for TP's exit.
|
||||
*/
|
||||
px->v = (uint32_t)tp;
|
||||
px->v = (uintptr_t)tp;
|
||||
chx_spin_lock (&q_join.lock);
|
||||
ll_prio_enqueue ((struct chx_pq *)px, &q_join.q);
|
||||
chx_spin_unlock (&q_join.lock);
|
||||
@@ -1661,7 +1220,7 @@ chopstx_cancel (chopstx_t thd)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cancellation points: cond_wait, usec_wait, and poll. */
|
||||
/* Cancellation points: cond_wait, usec_wait, join, and poll. */
|
||||
if (tp->state == THREAD_WAIT_CND)
|
||||
{
|
||||
struct chx_cond *cond = (struct chx_cond *)tp->parent;
|
||||
@@ -1672,6 +1231,12 @@ chopstx_cancel (chopstx_t thd)
|
||||
}
|
||||
else if (tp->state == THREAD_WAIT_TIME)
|
||||
chx_timer_dequeue (tp);
|
||||
else if (tp->state == THREAD_WAIT_EXIT)
|
||||
{
|
||||
chx_spin_lock (&q_join.lock);
|
||||
ll_dequeue ((struct chx_pq *)tp);
|
||||
chx_spin_unlock (&q_join.lock);
|
||||
}
|
||||
else if (tp->state == THREAD_WAIT_POLL)
|
||||
{
|
||||
if (tp->parent == &q_timer.q)
|
||||
@@ -1683,7 +1248,7 @@ chopstx_cancel (chopstx_t thd)
|
||||
return;
|
||||
}
|
||||
|
||||
((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = -1;
|
||||
tp->v = (uintptr_t)-1;
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
chx_sched (CHX_YIELD);
|
||||
@@ -1904,209 +1469,3 @@ chopstx_setpriority (chopstx_prio_t prio_new)
|
||||
|
||||
return prio_orig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lower layer architecture specific exception handling entries.
|
||||
*
|
||||
*/
|
||||
|
||||
void __attribute__ ((naked))
|
||||
preempt (void)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
register struct chx_thread *cur asm ("r1");
|
||||
|
||||
asm volatile (
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsid i\n\t"
|
||||
#else
|
||||
"msr BASEPRI, r0\n\t"
|
||||
#endif
|
||||
"ldr r2, =running\n\t"
|
||||
"ldr r0, [r2]\n\t"
|
||||
"mov r1, r0"
|
||||
: "=r" (tp), "=r" (cur)
|
||||
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
|
||||
: "r2");
|
||||
|
||||
if (!cur)
|
||||
/* It's idle thread. It's ok to clobber registers. */
|
||||
;
|
||||
else
|
||||
{
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
asm volatile (
|
||||
"add %0, #20\n\t"
|
||||
"stm %0!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||
"stm %0!, {r2, r3, r4, r5, r6}"
|
||||
: "=r" (cur)
|
||||
: "0" (cur)
|
||||
/*
|
||||
* Memory clobber constraint here is not accurate, but this
|
||||
* works. R7 keeps its value, but having "r7" here prevents
|
||||
* use of R7 before this asm statement.
|
||||
*/
|
||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||
|
||||
if (tp)
|
||||
{
|
||||
if (tp->flag_sched_rr)
|
||||
{
|
||||
if (tp->state == THREAD_RUNNING)
|
||||
{
|
||||
chx_timer_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
}
|
||||
/*
|
||||
* It may be THREAD_READY after chx_timer_expired.
|
||||
* Then, do nothing.
|
||||
*/
|
||||
}
|
||||
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"
|
||||
/* Now, r0 points to the thread to be switched. */
|
||||
/* Put it to *running. */
|
||||
"ldr r1, =running\n\t"
|
||||
/* Update running. */
|
||||
"str r0, [r1]\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cmp r0, #0\n\t"
|
||||
"beq 1f\n\t"
|
||||
#else
|
||||
"cbz r0, 1f\n\t"
|
||||
#endif
|
||||
/**/
|
||||
"add r0, #20\n\t"
|
||||
"ldm r0!, {r4, r5, r6, r7}\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"ldm r0!, {r1, r2, r3}\n\t"
|
||||
"mov r8, r1\n\t"
|
||||
"mov r9, r2\n\t"
|
||||
"mov r10, r3\n\t"
|
||||
"ldm r0!, {r1, r2}\n\t"
|
||||
"mov r11, r1\n\t"
|
||||
"msr PSP, r2\n\t"
|
||||
#else
|
||||
"ldr r8, [r0], #4\n\t"
|
||||
"ldr r9, [r0], #4\n\t"
|
||||
"ldr r10, [r0], #4\n\t"
|
||||
"ldr r11, [r0], #4\n\t"
|
||||
"ldr r1, [r0], #4\n\t"
|
||||
"msr PSP, r1\n\t"
|
||||
#endif
|
||||
"sub r0, #45\n\t"
|
||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
||||
"mov r0, #0\n\t"
|
||||
"cmp r1, #247\n\t"
|
||||
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsie i\n"
|
||||
#else
|
||||
"msr BASEPRI, r0\n"
|
||||
#endif
|
||||
/**/
|
||||
"0:\n\t"
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0\n"
|
||||
"1:\n\t"
|
||||
/* Spawn an IDLE thread. */
|
||||
"ldr r0, =__main_stack_end__-32\n\t"
|
||||
"msr PSP, r0\n\t"
|
||||
"mov r1, #0\n\t"
|
||||
"mov r2, #0\n\t"
|
||||
"mov r3, #0\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"stm r0!, {r1, r2, r3}\n\t"
|
||||
"ldr r1, =idle\n\t" /* PC = idle */
|
||||
"mov r2, #0x010\n\t"
|
||||
"lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */
|
||||
"stm r0!, {r1, r2}\n\t"
|
||||
/**/
|
||||
/* Unmask interrupts. */
|
||||
"mov r0, #0\n\t"
|
||||
#if defined(__ARM_ARCH_6M__)
|
||||
"cpsie i\n\t"
|
||||
#else
|
||||
"msr BASEPRI, r0\n"
|
||||
#endif
|
||||
/**/
|
||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||
"bx r0"
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH_7M__)
|
||||
/*
|
||||
* System call: switch to another thread.
|
||||
* There are two cases:
|
||||
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
|
||||
* something (mutex, cond, intr, etc.)
|
||||
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
|
||||
* it is needed to be enqueued to READY queue.
|
||||
*/
|
||||
void __attribute__ ((naked))
|
||||
svc (void)
|
||||
{
|
||||
register struct chx_thread *tp asm ("r0");
|
||||
register uint32_t orig_r0 asm ("r1");
|
||||
|
||||
asm ("ldr r1, =running\n\t"
|
||||
"ldr r0, [r1]\n\t"
|
||||
"add r1, r0, #20\n\t"
|
||||
/* Save registers onto CHX_THREAD struct. */
|
||||
"stm r1!, {r4, r5, r6, r7}\n\t"
|
||||
"mov r2, r8\n\t"
|
||||
"mov r3, r9\n\t"
|
||||
"mov r4, r10\n\t"
|
||||
"mov r5, r11\n\t"
|
||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
|
||||
"ldr r1, [r6]"
|
||||
: "=r" (tp), "=r" (orig_r0)
|
||||
: /* no input */
|
||||
: "r2", "r3", "r4", "r5", "r6", "memory");
|
||||
|
||||
if (orig_r0) /* yield */
|
||||
{
|
||||
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"
|
||||
: /* no output */ : "r" (tp) : "memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ struct chx_qh {
|
||||
struct chx_pq *next, *prev;
|
||||
};
|
||||
|
||||
typedef uint32_t chopstx_t;
|
||||
typedef uintptr_t chopstx_t;
|
||||
typedef uint8_t chopstx_prio_t;
|
||||
|
||||
extern chopstx_t chopstx_main;
|
||||
@@ -39,7 +39,7 @@ extern chopstx_t chopstx_main;
|
||||
/* NOTE: This signature is different to PTHREAD's one. */
|
||||
chopstx_t
|
||||
chopstx_create (uint32_t flags_and_prio,
|
||||
uint32_t stack_addr, size_t stack_size,
|
||||
uintptr_t stack_addr, size_t stack_size,
|
||||
void *(thread_entry) (void *), void *);
|
||||
#define CHOPSTX_PRIO_BITS 8
|
||||
#define CHOPSTX_DETACHED 0x10000
|
||||
|
||||
77
contrib/adc-gnu-linux.c
Normal file
77
contrib/adc-gnu-linux.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* adc-gnu-linux.c - ADC driver for GNU/Linux emulation.
|
||||
* This ADC driver just fills pseudo random values.
|
||||
* It's completely useless other than for NeuG.
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* receipents of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include "adc.h"
|
||||
|
||||
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
|
||||
|
||||
/*
|
||||
* Do calibration for ADC.
|
||||
*/
|
||||
int
|
||||
adc_init (void)
|
||||
{
|
||||
srandom (ADC_RANDOM_SEED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
adc_start (void)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t adc_buf[64];
|
||||
|
||||
void
|
||||
adc_start_conversion (int offset, int count)
|
||||
{
|
||||
while (count--)
|
||||
adc_buf[offset++] = random ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
adc_stop (void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return 0 on success.
|
||||
* Return 1 on error.
|
||||
*/
|
||||
int
|
||||
adc_wait_completion (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename chopstx.info
|
||||
@set VERSION 1.1
|
||||
@set VERSION 1.4
|
||||
@settitle Chopstx Reference Manual
|
||||
@c Unify some of the indices.
|
||||
@syncodeindex tp fn
|
||||
|
||||
18
entry.c
18
entry.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* entry.c - Entry routine when reset and interrupt vectors.
|
||||
*
|
||||
* Copyright (C) 2013, 2014, 2015, 2016
|
||||
* Copyright (C) 2013, 2014, 2015, 2016, 2017
|
||||
* Flying Stone Technology
|
||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
*
|
||||
@@ -32,6 +32,21 @@
|
||||
#include <chopstx.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"
|
||||
@@ -225,3 +240,4 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
||||
chx_handle_intr, chx_handle_intr, chx_handle_intr,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
36
example-cdc-gnu-linux/Makefile
Normal file
36
example-cdc-gnu-linux/Makefile
Normal file
@@ -0,0 +1,36 @@
|
||||
# Makefile for example application of Chopstx
|
||||
|
||||
PROJECT = sample
|
||||
|
||||
### This is for GNU/Linux
|
||||
|
||||
CHOPSTX = ..
|
||||
LDSCRIPT=
|
||||
CSRC = sample.c usb-cdc.c
|
||||
|
||||
CHIP=gnu-linux
|
||||
# USE_SYS = yes
|
||||
USE_SYS =
|
||||
USE_USB = yes
|
||||
EMULATION=yes
|
||||
|
||||
###################################
|
||||
CROSS =
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
MCU = none
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DGNU_LINUX_EMULATION
|
||||
OPT = -g # -O3 -Os
|
||||
LIBS = -lpthread
|
||||
|
||||
####################
|
||||
include ../rules.mk
|
||||
|
||||
board.h:
|
||||
@echo Please make a symbolic link \'board.h\' to a file in ../board;
|
||||
@exit 1
|
||||
|
||||
distclean: clean
|
||||
35
example-cdc-gnu-linux/README
Normal file
35
example-cdc-gnu-linux/README
Normal file
@@ -0,0 +1,35 @@
|
||||
(1) preparation as root
|
||||
|
||||
Don't run ModemManager
|
||||
|
||||
# systemctl stop ModemManager
|
||||
|
||||
Install USBIP host module
|
||||
# modprobe vhci_hcd
|
||||
|
||||
|
||||
(2) Run sample program of USBIP server
|
||||
|
||||
$ ./sample
|
||||
|
||||
|
||||
(3) Use the USB device as root
|
||||
|
||||
Attach the Chopstx application program (USBIP device) to USBIP host.
|
||||
|
||||
# usbip attach -r 127.0.0.1 -b 1-1
|
||||
|
||||
|
||||
(4) Connect CDC-ACM device
|
||||
|
||||
$ cu -l /dev/ttyACM0
|
||||
|
||||
Then, you see the message from Chopstx. As you type lines, it echos.
|
||||
|
||||
Type RET, ~ then . , you can terminate the session.
|
||||
|
||||
|
||||
(5) Detach the USBIP device as root
|
||||
|
||||
# usbip detach -p 0
|
||||
|
||||
1
example-cdc-gnu-linux/board.h
Symbolic link
1
example-cdc-gnu-linux/board.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../board/board-gnu-linux.h
|
||||
197
example-cdc-gnu-linux/sample.c
Normal file
197
example-cdc-gnu-linux/sample.c
Normal file
@@ -0,0 +1,197 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "usb_lld.h"
|
||||
#include "tty.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
set_led (int on)
|
||||
{
|
||||
#if 0
|
||||
/* For debugging, no output of LED. */
|
||||
#if 1
|
||||
if (on)
|
||||
write (1, "********\x08\x08\x08\x08\x08\x08\x08\x08", 16);
|
||||
else
|
||||
write (1, " \x08\x08\x08\x08\x08\x08\x08\x08", 16);
|
||||
#else
|
||||
if (on)
|
||||
puts ("!");
|
||||
else
|
||||
puts ("");
|
||||
#endif
|
||||
#else
|
||||
(void)on;
|
||||
#endif
|
||||
}
|
||||
|
||||
static chopstx_mutex_t mtx;
|
||||
static chopstx_cond_t cnd0;
|
||||
static chopstx_cond_t cnd1;
|
||||
|
||||
static uint8_t u, v;
|
||||
static uint8_t m; /* 0..100 */
|
||||
|
||||
static void *
|
||||
pwm (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd0, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
chopstx_usec_wait (m);
|
||||
set_led (0);
|
||||
chopstx_usec_wait (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
blk (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd1, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
chopstx_usec_wait (200*1000);
|
||||
v = 1;
|
||||
chopstx_usec_wait (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
|
||||
static char __process1_stack_base__[4096];
|
||||
static char __process2_stack_base__[4096];
|
||||
|
||||
#define STACK_ADDR_PWM ((uintptr_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_PWM (sizeof __process1_stack_base__)
|
||||
|
||||
#define STACK_ADDR_BLK ((uintptr_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BLK (sizeof __process2_stack_base__)
|
||||
|
||||
|
||||
static char hexchar (uint8_t x)
|
||||
{
|
||||
x &= 0x0f;
|
||||
if (x <= 0x09)
|
||||
return '0' + x;
|
||||
else if (x <= 0x0f)
|
||||
return 'a' + x - 10;
|
||||
else
|
||||
return '?';
|
||||
}
|
||||
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#define main emulated_main
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
struct tty *tty;
|
||||
uint8_t count;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
chopstx_mutex_init (&mtx);
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
chopstx_cond_signal (&cnd1);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
u = 1;
|
||||
|
||||
tty = tty_open ();
|
||||
tty_wait_configured (tty);
|
||||
|
||||
count = 0;
|
||||
m = 50;
|
||||
while (1)
|
||||
{
|
||||
char s[LINEBUFSIZE];
|
||||
|
||||
u = 1;
|
||||
tty_wait_connection (tty);
|
||||
|
||||
chopstx_usec_wait (50*1000);
|
||||
|
||||
puts("send ZLP");
|
||||
/* Send ZLP at the beginning. */
|
||||
tty_send (tty, s, 0);
|
||||
|
||||
memcpy (s, "xx: Hello, World with Chopstx!\r\n", 32);
|
||||
s[0] = hexchar (count >> 4);
|
||||
s[1] = hexchar (count & 0x0f);
|
||||
count++;
|
||||
|
||||
puts("send hello");
|
||||
if (tty_send (tty, s, 32) < 0)
|
||||
continue;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int size;
|
||||
uint32_t usec;
|
||||
|
||||
puts("recv msg");
|
||||
usec = 3000000; /* 3.0 seconds */
|
||||
size = tty_recv (tty, s + 4, &usec);
|
||||
if (size < 0)
|
||||
break;
|
||||
|
||||
if (size)
|
||||
{
|
||||
size--;
|
||||
|
||||
puts("send msg");
|
||||
s[0] = hexchar (size >> 4);
|
||||
s[1] = hexchar (size & 0x0f);
|
||||
s[2] = ':';
|
||||
s[3] = ' ';
|
||||
s[size + 4] = '\r';
|
||||
s[size + 5] = '\n';
|
||||
if (tty_send (tty, s, size + 6) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
u ^= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
example-cdc-gnu-linux/tty.h
Normal file
9
example-cdc-gnu-linux/tty.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#define LINEBUFSIZE 128
|
||||
|
||||
struct tty;
|
||||
|
||||
struct tty *tty_open (void);
|
||||
void tty_wait_configured (struct tty *tty);
|
||||
void tty_wait_connection (struct tty *tty);
|
||||
int tty_send (struct tty *tty, const char *buf, int count);
|
||||
int tty_recv (struct tty *tty, char *buf, uint32_t *timeout);
|
||||
953
example-cdc-gnu-linux/usb-cdc.c
Normal file
953
example-cdc-gnu-linux/usb-cdc.c
Normal file
@@ -0,0 +1,953 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <string.h>
|
||||
#include "usb_lld.h"
|
||||
#include "tty.h"
|
||||
|
||||
static chopstx_intr_t usb_intr;
|
||||
|
||||
struct line_coding
|
||||
{
|
||||
uint32_t bitrate;
|
||||
uint8_t format;
|
||||
uint8_t paritytype;
|
||||
uint8_t datatype;
|
||||
} __attribute__((packed));
|
||||
|
||||
static const struct line_coding line_coding0 = {
|
||||
115200, /* baud rate: 115200 */
|
||||
0x00, /* stop bits: 1 */
|
||||
0x00, /* parity: none */
|
||||
0x08 /* bits: 8 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Currently, we only support a single TTY.
|
||||
*
|
||||
* It is possible to extend to support multiple TTYs, for multiple
|
||||
* interfaces.
|
||||
*
|
||||
* In that case, add argument to TTY_OPEN function and
|
||||
* modify TTY_GET function to get the TTY structure. Functions which
|
||||
* directy accesses TTY0 (usb_device_reset and usb_set_configuration)
|
||||
* should be modified, too.
|
||||
*
|
||||
* Modification of TTY_MAIN thread will be also needed to echo back
|
||||
* input for each TTY, and the thread should run if one of TTY is
|
||||
* opened.
|
||||
*/
|
||||
|
||||
struct tty {
|
||||
chopstx_mutex_t mtx;
|
||||
chopstx_cond_t cnd;
|
||||
uint8_t inputline[LINEBUFSIZE]; /* Line editing is supported */
|
||||
uint8_t send_buf[LINEBUFSIZE]; /* Sending ring buffer for echo back */
|
||||
uint8_t send_buf0[64];
|
||||
uint8_t recv_buf0[64];
|
||||
uint32_t inputline_len : 8;
|
||||
uint32_t send_head : 8;
|
||||
uint32_t send_tail : 8;
|
||||
uint32_t flag_connected : 1;
|
||||
uint32_t flag_send_ready : 1;
|
||||
uint32_t flag_input_avail : 1;
|
||||
uint32_t : 2;
|
||||
uint32_t device_state : 3; /* USB device status */
|
||||
struct line_coding line_coding;
|
||||
};
|
||||
|
||||
static struct tty tty0;
|
||||
|
||||
/*
|
||||
* Locate TTY structure from interface number or endpoint number.
|
||||
* Currently, it always returns tty0, because we only have the one.
|
||||
*/
|
||||
static struct tty *
|
||||
tty_get (int interface, uint8_t ep_num)
|
||||
{
|
||||
struct tty *t = &tty0;
|
||||
|
||||
if (interface >= 0)
|
||||
{
|
||||
if (interface == 0)
|
||||
t = &tty0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ep_num == ENDP1 || ep_num == ENDP2 || ep_num == ENDP3)
|
||||
t = &tty0;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
||||
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||
#define USB_CDC_REQ_SEND_BREAK 0x23
|
||||
|
||||
/* USB Device Descriptor */
|
||||
static const uint8_t vcom_device_desc[18] = {
|
||||
18, /* bLength */
|
||||
DEVICE_DESCRIPTOR, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x02, /* bDeviceClass (CDC). */
|
||||
0x00, /* bDeviceSubClass. */
|
||||
0x00, /* bDeviceProtocol. */
|
||||
0x40, /* bMaxPacketSize. */
|
||||
0xFF, 0xFF, /* idVendor */
|
||||
0x01, 0x00, /* idProduct */
|
||||
0x00, 0x01, /* bcdDevice */
|
||||
1, /* iManufacturer. */
|
||||
2, /* iProduct. */
|
||||
3, /* iSerialNumber. */
|
||||
1 /* bNumConfigurations. */
|
||||
};
|
||||
|
||||
#define VCOM_FEATURE_BUS_POWERED 0x80
|
||||
|
||||
/* Configuration Descriptor tree for a CDC.*/
|
||||
static const uint8_t vcom_config_desc[67] = {
|
||||
9,
|
||||
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
|
||||
/* Configuration Descriptor.*/
|
||||
67, 0x00, /* wTotalLength. */
|
||||
0x02, /* bNumInterfaces. */
|
||||
0x01, /* bConfigurationValue. */
|
||||
0, /* iConfiguration. */
|
||||
VCOM_FEATURE_BUS_POWERED, /* bmAttributes. */
|
||||
50, /* bMaxPower (100mA). */
|
||||
/* Interface Descriptor.*/
|
||||
9,
|
||||
INTERFACE_DESCRIPTOR,
|
||||
0x00, /* bInterfaceNumber. */
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x01, /* bNumEndpoints. */
|
||||
0x02, /* bInterfaceClass (Communications Interface Class,
|
||||
CDC section 4.2). */
|
||||
0x02, /* bInterfaceSubClass (Abstract Control Model, CDC
|
||||
section 4.3). */
|
||||
0x01, /* bInterfaceProtocol (AT commands, CDC section
|
||||
4.4). */
|
||||
0, /* iInterface. */
|
||||
/* Header Functional Descriptor (CDC section 5.2.3).*/
|
||||
5, /* bLength. */
|
||||
0x24, /* bDescriptorType (CS_INTERFACE). */
|
||||
0x00, /* bDescriptorSubtype (Header Functional Descriptor). */
|
||||
0x10, 0x01, /* bcdCDC. */
|
||||
/* Call Management Functional Descriptor. */
|
||||
5, /* bFunctionLength. */
|
||||
0x24, /* bDescriptorType (CS_INTERFACE). */
|
||||
0x01, /* bDescriptorSubtype (Call Management Functional
|
||||
Descriptor). */
|
||||
0x03, /* bmCapabilities (D0+D1). */
|
||||
0x01, /* bDataInterface. */
|
||||
/* ACM Functional Descriptor.*/
|
||||
4, /* bFunctionLength. */
|
||||
0x24, /* bDescriptorType (CS_INTERFACE). */
|
||||
0x02, /* bDescriptorSubtype (Abstract Control Management
|
||||
Descriptor). */
|
||||
0x02, /* bmCapabilities. */
|
||||
/* Union Functional Descriptor.*/
|
||||
5, /* bFunctionLength. */
|
||||
0x24, /* bDescriptorType (CS_INTERFACE). */
|
||||
0x06, /* bDescriptorSubtype (Union Functional
|
||||
Descriptor). */
|
||||
0x00, /* bMasterInterface (Communication Class
|
||||
Interface). */
|
||||
0x01, /* bSlaveInterface0 (Data Class Interface). */
|
||||
/* Endpoint 2 Descriptor.*/
|
||||
7,
|
||||
ENDPOINT_DESCRIPTOR,
|
||||
ENDP2|0x80, /* bEndpointAddress. */
|
||||
0x03, /* bmAttributes (Interrupt). */
|
||||
0x08, 0x00, /* wMaxPacketSize. */
|
||||
0xFF, /* bInterval. */
|
||||
/* Interface Descriptor.*/
|
||||
9,
|
||||
INTERFACE_DESCRIPTOR, /* bDescriptorType: */
|
||||
0x01, /* bInterfaceNumber. */
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x02, /* bNumEndpoints. */
|
||||
0x0A, /* bInterfaceClass (Data Class Interface, CDC section 4.5). */
|
||||
0x00, /* bInterfaceSubClass (CDC section 4.6). */
|
||||
0x00, /* bInterfaceProtocol (CDC section 4.7). */
|
||||
0x00, /* iInterface. */
|
||||
/* Endpoint 3 Descriptor.*/
|
||||
7,
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
ENDP3, /* bEndpointAddress. */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval. */
|
||||
/* Endpoint 1 Descriptor.*/
|
||||
7,
|
||||
ENDPOINT_DESCRIPTOR, /* bDescriptorType: Endpoint */
|
||||
ENDP1|0x80, /* bEndpointAddress. */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00 /* bInterval. */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* U.S. English language identifier.
|
||||
*/
|
||||
static const uint8_t vcom_string0[4] = {
|
||||
4, /* bLength */
|
||||
STRING_DESCRIPTOR,
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
static const uint8_t vcom_string1[] = {
|
||||
23*2+2, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
/* Manufacturer: "Flying Stone Technology" */
|
||||
'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
|
||||
't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
|
||||
'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0,
|
||||
};
|
||||
|
||||
static const uint8_t vcom_string2[] = {
|
||||
14*2+2, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
/* Product name: "Chopstx Sample" */
|
||||
'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
|
||||
'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Serial Number string.
|
||||
*/
|
||||
static const uint8_t vcom_string3[28] = {
|
||||
28, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
|
||||
};
|
||||
|
||||
|
||||
#define NUM_INTERFACES 2
|
||||
|
||||
|
||||
static void
|
||||
usb_device_reset (struct usb_dev *dev)
|
||||
{
|
||||
usb_lld_reset (dev, VCOM_FEATURE_BUS_POWERED);
|
||||
|
||||
/* Initialize Endpoint 0 */
|
||||
usb_lld_setup_endp (dev, ENDP0, 1, 1);
|
||||
|
||||
chopstx_mutex_lock (&tty0.mtx);
|
||||
tty0.inputline_len = 0;
|
||||
tty0.send_head = tty0.send_tail = 0;
|
||||
tty0.flag_connected = 0;
|
||||
tty0.flag_send_ready = 1;
|
||||
tty0.flag_input_avail = 0;
|
||||
tty0.device_state = ATTACHED;
|
||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||
chopstx_mutex_unlock (&tty0.mtx);
|
||||
}
|
||||
|
||||
|
||||
#define CDC_CTRL_DTR 0x0001
|
||||
|
||||
static void
|
||||
usb_ctrl_write_finish (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
|
||||
&& USB_SETUP_SET (arg->type)
|
||||
&& arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
{
|
||||
struct tty *t = tty_get (arg->index, 0);
|
||||
|
||||
/* Open/close the connection. */
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
t->flag_connected = ((arg->value & CDC_CTRL_DTR) != 0);
|
||||
chopstx_cond_signal (&t->cnd);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* The transaction was already finished. So, it is no use to call
|
||||
* usb_lld_ctrl_error when the condition does not match.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
vcom_port_data_setup (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
|
||||
if (USB_SETUP_GET (arg->type))
|
||||
{
|
||||
struct tty *t = tty_get (arg->index, 0);
|
||||
|
||||
if (arg->request == USB_CDC_REQ_GET_LINE_CODING)
|
||||
return usb_lld_ctrl_send (dev, &t->line_coding,
|
||||
sizeof (struct line_coding));
|
||||
}
|
||||
else /* USB_SETUP_SET (req) */
|
||||
{
|
||||
if (arg->request == USB_CDC_REQ_SET_LINE_CODING
|
||||
&& arg->len == sizeof (struct line_coding))
|
||||
{
|
||||
struct tty *t = tty_get (arg->index, 0);
|
||||
|
||||
return usb_lld_ctrl_recv (dev, &t->line_coding,
|
||||
sizeof (struct line_coding));
|
||||
}
|
||||
else if (arg->request == USB_CDC_REQ_SET_CONTROL_LINE_STATE)
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
usb_setup (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0)
|
||||
return vcom_port_data_setup (dev);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_descriptor (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
uint8_t desc_type = (arg->value >> 8);
|
||||
uint8_t desc_index = (arg->value & 0xff);
|
||||
|
||||
if (rcp != DEVICE_RECIPIENT)
|
||||
return -1;
|
||||
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
return usb_lld_ctrl_send (dev,
|
||||
vcom_device_desc, sizeof (vcom_device_desc));
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
return usb_lld_ctrl_send (dev,
|
||||
vcom_config_desc, sizeof (vcom_config_desc));
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
const uint8_t *str;
|
||||
int size;
|
||||
|
||||
switch (desc_index)
|
||||
{
|
||||
case 0:
|
||||
str = vcom_string0;
|
||||
size = sizeof (vcom_string0);
|
||||
break;
|
||||
case 1:
|
||||
str = vcom_string1;
|
||||
size = sizeof (vcom_string1);
|
||||
break;
|
||||
case 2:
|
||||
str = vcom_string2;
|
||||
size = sizeof (vcom_string2);
|
||||
break;
|
||||
case 3:
|
||||
str = vcom_string3;
|
||||
size = sizeof (vcom_string3);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_send (dev, str, size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
vcom_setup_endpoints_for_interface (struct usb_dev *dev,
|
||||
uint16_t interface, int stop)
|
||||
{
|
||||
if (interface == 0)
|
||||
{
|
||||
if (!stop)
|
||||
usb_lld_setup_endp (dev, ENDP2, 0, 1);
|
||||
else
|
||||
usb_lld_stall_tx (ENDP2);
|
||||
}
|
||||
else if (interface == 1)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
usb_lld_setup_endp (dev, ENDP1, 0, 1);
|
||||
usb_lld_setup_endp (dev, ENDP3, 1, 0);
|
||||
/* Start with no data receiving (ENDP3 not enabled)*/
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_tx (ENDP1);
|
||||
usb_lld_stall_rx (ENDP3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_set_configuration (struct usb_dev *dev)
|
||||
{
|
||||
int i;
|
||||
uint8_t current_conf;
|
||||
|
||||
current_conf = usb_lld_current_configuration (dev);
|
||||
if (current_conf == 0)
|
||||
{
|
||||
if (dev->dev_req.value != 1)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 1);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
vcom_setup_endpoints_for_interface (dev, i, 0);
|
||||
chopstx_mutex_lock (&tty0.mtx);
|
||||
tty0.device_state = CONFIGURED;
|
||||
chopstx_cond_signal (&tty0.cnd);
|
||||
chopstx_mutex_unlock (&tty0.mtx);
|
||||
}
|
||||
else if (current_conf != dev->dev_req.value)
|
||||
{
|
||||
if (dev->dev_req.value != 0)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
vcom_setup_endpoints_for_interface (dev, i, 1);
|
||||
chopstx_mutex_lock (&tty0.mtx);
|
||||
tty0.device_state = ADDRESSED;
|
||||
chopstx_cond_signal (&tty0.cnd);
|
||||
chopstx_mutex_unlock (&tty0.mtx);
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
uint16_t alt = dev->dev_req.value;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
if (alt != 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
vcom_setup_endpoints_for_interface (dev, interface, 0);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint8_t zero = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
/* We don't have alternate interface, so, always return 0. */
|
||||
return usb_lld_ctrl_send (dev, &zero, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_status_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint16_t status_info = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Put a character into the ring buffer to be send back.
|
||||
*/
|
||||
static void
|
||||
put_char_to_ringbuffer (struct tty *t, int c)
|
||||
{
|
||||
uint32_t next = (t->send_tail + 1) % LINEBUFSIZE;
|
||||
|
||||
if (t->send_head == next)
|
||||
/* full */
|
||||
/* All that we can do is ignore this char. */
|
||||
return;
|
||||
|
||||
t->send_buf[t->send_tail] = c;
|
||||
t->send_tail = next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get characters from ring buffer into S.
|
||||
*/
|
||||
static int
|
||||
get_chars_from_ringbuffer (struct tty *t, uint8_t *s, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (t->send_head == t->send_tail)
|
||||
/* Empty */
|
||||
return i;
|
||||
|
||||
do
|
||||
{
|
||||
s[i++] = t->send_buf[t->send_head];
|
||||
t->send_head = (t->send_head + 1) % LINEBUFSIZE;
|
||||
}
|
||||
while (t->send_head != t->send_tail && i < len);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
tty_echo_char (struct tty *t, int c)
|
||||
{
|
||||
put_char_to_ringbuffer (t, c);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
struct tty *t = tty_get (-1, ep_num);
|
||||
|
||||
(void)len;
|
||||
if (ep_num == ENDP1)
|
||||
{
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
if (t->flag_send_ready == 0)
|
||||
{
|
||||
t->flag_send_ready = 1;
|
||||
chopstx_cond_signal (&t->cnd);
|
||||
}
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
else if (ep_num == ENDP2)
|
||||
{
|
||||
/* Nothing */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
tty_input_char (struct tty *t, int c)
|
||||
{
|
||||
unsigned int i;
|
||||
int r = 0;
|
||||
|
||||
/* Process DEL, C-U, C-R, and RET as editing command. */
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
switch (c)
|
||||
{
|
||||
case 0x0d: /* Control-M */
|
||||
t->inputline[t->inputline_len++] = '\n';
|
||||
tty_echo_char (t, 0x0d);
|
||||
tty_echo_char (t, 0x0a);
|
||||
t->flag_input_avail = 1;
|
||||
r = 1;
|
||||
chopstx_cond_signal (&t->cnd);
|
||||
break;
|
||||
case 0x12: /* Control-R */
|
||||
tty_echo_char (t, '^');
|
||||
tty_echo_char (t, 'R');
|
||||
tty_echo_char (t, 0x0d);
|
||||
tty_echo_char (t, 0x0a);
|
||||
for (i = 0; i < t->inputline_len; i++)
|
||||
tty_echo_char (t, t->inputline[i]);
|
||||
break;
|
||||
case 0x15: /* Control-U */
|
||||
for (i = 0; i < t->inputline_len; i++)
|
||||
{
|
||||
tty_echo_char (t, 0x08);
|
||||
tty_echo_char (t, 0x20);
|
||||
tty_echo_char (t, 0x08);
|
||||
}
|
||||
t->inputline_len = 0;
|
||||
break;
|
||||
case 0x7f: /* DEL */
|
||||
if (t->inputline_len > 0)
|
||||
{
|
||||
tty_echo_char (t, 0x08);
|
||||
tty_echo_char (t, 0x20);
|
||||
tty_echo_char (t, 0x08);
|
||||
t->inputline_len--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (t->inputline_len < sizeof (t->inputline) - 1)
|
||||
{
|
||||
tty_echo_char (t, c);
|
||||
t->inputline[t->inputline_len++] = c;
|
||||
}
|
||||
else
|
||||
/* Beep */
|
||||
tty_echo_char (t, 0x0a);
|
||||
break;
|
||||
}
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
struct tty *t = tty_get (-1, ep_num);
|
||||
if (ep_num == ENDP3)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (tty_input_char (t, t->recv_buf0[i]))
|
||||
break;
|
||||
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
if (t->flag_input_avail == 0)
|
||||
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
}
|
||||
|
||||
static void *tty_main (void *arg);
|
||||
|
||||
#include <signal.h>
|
||||
#define INTR_REQ_USB SIGUSR1
|
||||
#define PRIO_TTY 4
|
||||
|
||||
static char __process3_stack_base__[4096];
|
||||
#define STACK_ADDR_TTY ((uintptr_t)__process3_stack_base__)
|
||||
#define STACK_SIZE_TTY (sizeof __process3_stack_base__)
|
||||
|
||||
struct tty *
|
||||
tty_open (void)
|
||||
{
|
||||
chopstx_mutex_init (&tty0.mtx);
|
||||
chopstx_cond_init (&tty0.cnd);
|
||||
tty0.inputline_len = 0;
|
||||
tty0.send_head = tty0.send_tail = 0;
|
||||
tty0.flag_connected = 0;
|
||||
tty0.flag_send_ready = 1;
|
||||
tty0.flag_input_avail = 0;
|
||||
tty0.device_state = UNCONNECTED;
|
||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||
|
||||
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
|
||||
return &tty0;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
tty_main (void *arg)
|
||||
{
|
||||
struct tty *t = arg;
|
||||
struct usb_dev dev;
|
||||
int e;
|
||||
|
||||
#if defined(OLDER_SYS_H)
|
||||
/*
|
||||
* Historically (before sys < 3.0), NVIC priority setting for USB
|
||||
* interrupt was done in usb_lld_sys_init. Thus this code.
|
||||
*
|
||||
* When USB interrupt occurs between usb_lld_init (which assumes
|
||||
* ISR) and chopstx_claim_irq (which clears pending interrupt),
|
||||
* invocation of usb_lld_event_handler won't occur.
|
||||
*
|
||||
* Calling usb_lld_event_handler is no harm even if there were no
|
||||
* interrupts, thus, we call it unconditionally here, just in case
|
||||
* if there is a request.
|
||||
*
|
||||
* We can't call usb_lld_init after chopstx_claim_irq, as
|
||||
* usb_lld_init does its own setting for NVIC. Calling
|
||||
* chopstx_claim_irq after usb_lld_init overrides that.
|
||||
*
|
||||
*/
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
goto event_handle;
|
||||
#else
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, VCOM_FEATURE_BUS_POWERED);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_intr_wait (&usb_intr);
|
||||
if (usb_intr.ready)
|
||||
{
|
||||
uint8_t ep_num;
|
||||
#if defined(OLDER_SYS_H)
|
||||
event_handle:
|
||||
#endif
|
||||
/*
|
||||
* When interrupt is detected, call usb_lld_event_handler.
|
||||
* The event may be one of following:
|
||||
* (1) Transfer to endpoint (bulk or interrupt)
|
||||
* In this case EP_NUM is encoded in the variable E.
|
||||
* (2) "NONE" event: some trasfer was done, but all was
|
||||
* done by lower layer, no other work is needed in
|
||||
* upper layer.
|
||||
* (3) Device events: Reset or Suspend
|
||||
* (4) Device requests to the endpoint zero.
|
||||
*
|
||||
*/
|
||||
e = usb_lld_event_handler (&dev);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
|
||||
if (ep_num != 0)
|
||||
{
|
||||
if (USB_EVENT_TXRX (e))
|
||||
usb_tx_done (ep_num, USB_EVENT_LEN (e));
|
||||
else
|
||||
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
|
||||
}
|
||||
else
|
||||
switch (USB_EVENT_ID (e))
|
||||
{
|
||||
case USB_EVENT_DEVICE_RESET:
|
||||
usb_device_reset (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_DEVICE_ADDRESSED:
|
||||
/* The addres is assigned to the device. We don't
|
||||
* need to do anything for this actually, but in this
|
||||
* application, we maintain the USB status of the
|
||||
* device. Usually, just "continue" as EVENT_OK is
|
||||
* OK.
|
||||
*/
|
||||
chopstx_mutex_lock (&tty0.mtx);
|
||||
tty0.device_state = ADDRESSED;
|
||||
chopstx_cond_signal (&tty0.cnd);
|
||||
chopstx_mutex_unlock (&tty0.mtx);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_DESCRIPTOR:
|
||||
if (usb_get_descriptor (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_CONFIGURATION:
|
||||
if (usb_set_configuration (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_INTERFACE:
|
||||
if (usb_set_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_REQUEST:
|
||||
/* Device specific device request. */
|
||||
if (usb_setup (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_STATUS_INTERFACE:
|
||||
if (usb_get_status_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_INTERFACE:
|
||||
if (usb_get_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_FEATURE_DEVICE:
|
||||
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
||||
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
||||
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
||||
usb_lld_ctrl_ack (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_WRITE_FINISH:
|
||||
/* Control WRITE transfer finished. */
|
||||
usb_ctrl_write_finish (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_OK:
|
||||
case USB_EVENT_DEVICE_SUSPEND:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
if (t->device_state == CONFIGURED && t->flag_connected
|
||||
&& t->flag_send_ready)
|
||||
{
|
||||
uint8_t line[32];
|
||||
int len = get_chars_from_ringbuffer (t, line, sizeof (len));
|
||||
|
||||
if (len)
|
||||
{
|
||||
memcpy (t->send_buf0, line, len);
|
||||
usb_lld_tx_enable_buf (ENDP1, t->send_buf0, len);
|
||||
t->flag_send_ready = 0;
|
||||
}
|
||||
}
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tty_wait_configured (struct tty *t)
|
||||
{
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
while (t->device_state != CONFIGURED)
|
||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tty_wait_connection (struct tty *t)
|
||||
{
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
while (t->flag_connected == 0)
|
||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||
t->flag_send_ready = 1;
|
||||
t->flag_input_avail = 0;
|
||||
t->send_head = t->send_tail = 0;
|
||||
t->inputline_len = 0;
|
||||
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64); /* Accept input for line */
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
}
|
||||
|
||||
static int
|
||||
check_tx (struct tty *t)
|
||||
{
|
||||
if (t->flag_send_ready)
|
||||
/* TX done */
|
||||
return 1;
|
||||
if (t->flag_connected == 0)
|
||||
/* Disconnected */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tty_send (struct tty *t, const char *buf, int len)
|
||||
{
|
||||
int r;
|
||||
const char *p;
|
||||
int count;
|
||||
|
||||
p = buf;
|
||||
count = len >= 64 ? 64 : len;
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
while ((r = check_tx (t)) == 0)
|
||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||
if (r > 0)
|
||||
{
|
||||
usb_lld_tx_enable_buf (ENDP1, p, count);
|
||||
t->flag_send_ready = 0;
|
||||
}
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
|
||||
len -= count;
|
||||
p += count;
|
||||
if (len == 0 && count != 64)
|
||||
/*
|
||||
* The size of the last packet should be != 0
|
||||
* If 64, send ZLP (zelo length packet)
|
||||
*/
|
||||
break;
|
||||
count = len >= 64 ? 64 : len;
|
||||
}
|
||||
|
||||
/* Wait until all sent. */
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
while ((r = check_tx (t)) == 0)
|
||||
chopstx_cond_wait (&t->cnd, &t->mtx);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_rx (void *arg)
|
||||
{
|
||||
struct tty *t = arg;
|
||||
|
||||
if (t->flag_input_avail)
|
||||
/* RX */
|
||||
return 1;
|
||||
if (t->flag_connected == 0)
|
||||
/* Disconnected */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns -1 on connection close
|
||||
* 0 on timeout.
|
||||
* >0 length of the inputline (including final \n)
|
||||
*
|
||||
*/
|
||||
int
|
||||
tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
||||
{
|
||||
int r;
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
|
||||
poll_desc.type = CHOPSTX_POLL_COND;
|
||||
poll_desc.ready = 0;
|
||||
poll_desc.cond = &t->cnd;
|
||||
poll_desc.mutex = &t->mtx;
|
||||
poll_desc.check = check_rx;
|
||||
poll_desc.arg = t;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct chx_poll_head *pd_array[1] = {
|
||||
(struct chx_poll_head *)&poll_desc
|
||||
};
|
||||
chopstx_poll (timeout, 1, pd_array);
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
r = check_rx (t);
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
if (r || (timeout != NULL && *timeout == 0))
|
||||
break;
|
||||
}
|
||||
|
||||
chopstx_mutex_lock (&t->mtx);
|
||||
if (t->flag_connected == 0)
|
||||
r = -1;
|
||||
else if (t->flag_input_avail)
|
||||
{
|
||||
r = t->inputline_len;
|
||||
memcpy (buf, t->inputline, r);
|
||||
t->flag_input_avail = 0;
|
||||
usb_lld_rx_enable_buf (ENDP3, t->recv_buf0, 64);
|
||||
t->inputline_len = 0;
|
||||
}
|
||||
else
|
||||
r = 0;
|
||||
chopstx_mutex_unlock (&t->mtx);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -61,14 +61,14 @@ blk (void *arg)
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
|
||||
|
||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
|
||||
|
||||
|
||||
static char hexchar (uint8_t x)
|
||||
@@ -98,8 +98,8 @@ main (int argc, const char *argv[])
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
@@ -642,9 +642,9 @@ static void *tty_main (void *arg);
|
||||
#define INTR_REQ_USB 20
|
||||
#define PRIO_TTY 4
|
||||
|
||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
||||
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
|
||||
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
|
||||
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
|
||||
#define STACK_ADDR_TTY ((uint32_t)__process3_stack_base__)
|
||||
#define STACK_SIZE_TTY ((uint32_t)__process3_stack_size__)
|
||||
|
||||
struct tty *
|
||||
tty_open (void)
|
||||
@@ -659,7 +659,7 @@ tty_open (void)
|
||||
tty0.device_state = UNCONNECTED;
|
||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||
|
||||
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
|
||||
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
|
||||
return &tty0;
|
||||
}
|
||||
|
||||
|
||||
43
example-fraucheky/EXAMPLE-README
Normal file
43
example-fraucheky/EXAMPLE-README
Normal file
@@ -0,0 +1,43 @@
|
||||
(0) configure and make
|
||||
|
||||
This example assumes that you have fraucheky source code
|
||||
along with chopstx.
|
||||
|
||||
--- chopstx --- chostx --- example-fraucheky
|
||||
|
|
||||
\- fraucheky
|
||||
|
||||
|
||||
If you use vendor id and product id of 234b:0004 under
|
||||
the condition of FSIJ, you can configure this program as:
|
||||
|
||||
$ ./configure --vidpid=234b:0004
|
||||
|
||||
then, invoke make.
|
||||
|
||||
$ make
|
||||
|
||||
|
||||
(1) preparation as root
|
||||
|
||||
Install USBIP host module
|
||||
# modprobe vhci_hcd
|
||||
|
||||
|
||||
(2) Run sample program of USBIP server
|
||||
|
||||
$ ./sample-msc
|
||||
|
||||
|
||||
(3) Use the USB device as root
|
||||
|
||||
Attach the Chopstx application program (USBIP device) to USBIP host.
|
||||
|
||||
# usbip attach -r 127.0.0.1 -b 1-1
|
||||
|
||||
|
||||
(4) Use the USB Mass Storage Class device
|
||||
|
||||
You can mount the storage.
|
||||
|
||||
Unmounting the storage, the program will exit.
|
||||
62
example-fraucheky/INDEX.HTM
Normal file
62
example-fraucheky/INDEX.HTM
Normal file
@@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head><title>How to use this device</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>How to use this device</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>This is an example program for GNU/Linux to see how
|
||||
Chopstx works with USB emulation by USBIP.</p>
|
||||
<p>Now, you are accessing this file.
|
||||
It means that the device is running as USB memory
|
||||
(USB Mass Storage Class device).</p>
|
||||
|
||||
<h2>README, GNU GPL and Corresponding Source code</h2>
|
||||
<p>In this program, it contains copyrighted software that is licensed under
|
||||
the GPLv3. Please see README for the explanation of the software and see
|
||||
GNU GPLv3 for terms and conditions.</p>
|
||||
<p>You may obtain the complete Corresponding Source code from git repositories.
|
||||
This program uses Chopstx for RTOS, and Fraucheky for
|
||||
GPL container. Those code are availabe in the Chopstx repository.</p>
|
||||
<p>You can also download tarballs from the repository.</p>
|
||||
<ul>
|
||||
<li><a href="README">README</a></li>
|
||||
<li><a href="COPYING">GNU GPLv3</a></li>
|
||||
<li><a href="https://anonscm.debian.org/cgit/gnuk/chopstx/">Chopstx Repository</a></li>
|
||||
<li><a href="https://git.gniibe.org/gitweb/?p=chopstx/chopstx.git;a=snapshot;h=@REVISION_CHOPSTX@;sf=tgz">Chopstx tarball</a></li>
|
||||
<li><a href="https://git.gniibe.org/gitweb/?p=chopstx/fraucheky.git;a=snapshot;h=@REVISION_FRAUCHEKY@;sf=tgz">Fraucheky tarball</a></li>
|
||||
</ul>
|
||||
|
||||
<h3>Source code by physical media</h3>
|
||||
<p>For those who want source code by physical media, Flying Stone Technology sells a microSD card (with SD card adapter) which contains all repositories at git.gniibe.org.</p>
|
||||
<p>The price is JPY1000 for a single media including tax and shipment in Japan. Please use YUUBIN-FURIKAE account of Flying Stone Technology below. Note that the account name is in Japanese (which means: Flying Stone Technology).</p>
|
||||
<p>On the form of YUUBIN-FURIKAE, you specify your address and you can write some message. The media will be sent to your address written in the form.</p>
|
||||
<ul>
|
||||
<li>Account No: 00110-2-346446</li>
|
||||
<li>Account name: Tobiishi Gijutsu</li>
|
||||
</ul>
|
||||
|
||||
<p>If it is difficult for you to use YUUBIN-FURIKAE, please write to the following address.</p>
|
||||
<ul>
|
||||
<li>Niibe Yutaka</li>
|
||||
<li>Flying Stone Technology</li>
|
||||
<li>1-5-14 Iwagami, Maebashi</li>
|
||||
<li>Gunma, 371-0031 JAPAN</li>
|
||||
</ul>
|
||||
|
||||
<p>This source code offer will be valid for three years after the shipment of this device or at least until 2021-03-31.</p>
|
||||
|
||||
<h2>Links</h2>
|
||||
<ul>
|
||||
<li><a href="https://www.gniibe.org/category/fst-01.html">
|
||||
FST-01 support pages</a></li>
|
||||
<li><a href="https://lists.alioth.debian.org/mailman/listinfo/gnuk-users">
|
||||
Mailing list: Gnuk Users</a></li>
|
||||
<li><a href="https://www.gnu.org/gnu/manifesto.ja.html">
|
||||
GNU Manifesto (Japanese Translation)</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
45
example-fraucheky/Makefile
Normal file
45
example-fraucheky/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
# Makefile for NeuG
|
||||
|
||||
# Define project name here
|
||||
PROJECT = sample-msc
|
||||
|
||||
CHOPSTX = ..
|
||||
FRAUCHEKY = ../../fraucheky
|
||||
LDSCRIPT=
|
||||
|
||||
CSRC = main.c
|
||||
CHIP=gnu-linux
|
||||
USE_SYS =
|
||||
USE_USB = yes
|
||||
EMULATION=yes
|
||||
# USE_ADC = yes
|
||||
|
||||
include $(FRAUCHEKY)/src.mk
|
||||
|
||||
###################################
|
||||
CROSS =
|
||||
CC = $(CROSS)gcc
|
||||
LD = $(CROSS)gcc
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
|
||||
MCU = none
|
||||
CWARN = -Wall -Wextra -Wstrict-prototypes
|
||||
DEFS = -DGNU_LINUX_EMULATION
|
||||
OPT = -O3 -g
|
||||
LIBS = -lpthread
|
||||
|
||||
BFDNAME_OBJ=elf64-x86-64
|
||||
BFDARCH=i386:x86-64
|
||||
|
||||
#######################
|
||||
include $(CHOPSTX)/rules.mk
|
||||
|
||||
include $(FRAUCHEKY)/build.mk
|
||||
###################################
|
||||
|
||||
board.h:
|
||||
@echo Please run configure to have a symbolic link \'board.h\'
|
||||
@exit 1
|
||||
|
||||
distclean:: clean
|
||||
-rm -f config.h
|
||||
1
example-fraucheky/board.h
Symbolic link
1
example-fraucheky/board.h
Symbolic link
@@ -0,0 +1 @@
|
||||
../board/board-gnu-linux.h
|
||||
2
example-fraucheky/config.h.in
Normal file
2
example-fraucheky/config.h.in
Normal file
@@ -0,0 +1,2 @@
|
||||
@FRAUCHEKY_DEFINE@
|
||||
@FRAUCHEKY_MSC_DEFINE@
|
||||
137
example-fraucheky/configure
vendored
Executable file
137
example-fraucheky/configure
vendored
Executable file
@@ -0,0 +1,137 @@
|
||||
#! /bin/bash
|
||||
|
||||
# This is bash which supports ANSI-C Quoting
|
||||
nl=$'\n'
|
||||
|
||||
# Default settings
|
||||
help=no
|
||||
vidpid=none
|
||||
verbose=no
|
||||
debug=no
|
||||
with_fraucheky=yes
|
||||
with_index=./INDEX.HTM
|
||||
|
||||
if test -d ../.git; then
|
||||
REVISION=`git describe --dirty="-modified"`
|
||||
REVISION_CHOPSTX=`cd .. && git describe --dirty="-modified"`
|
||||
REVISION_FRAUCHEKY=`cd ../../fraucheky &&git describe --dirty="-modified"`
|
||||
else
|
||||
REVISION=`cat ../VERSION`
|
||||
REVISION_CHOPSTX=`cat ../VERSION`
|
||||
REVISION_FRAUCHEKY=`cat ../../fraucheky/VERSION`
|
||||
fi
|
||||
|
||||
# Process each option
|
||||
for option; do
|
||||
case $option in
|
||||
*=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;;
|
||||
*) optarg=yes ;;
|
||||
esac
|
||||
|
||||
case $option in
|
||||
-h | --help)
|
||||
help=yes ;;
|
||||
-v | --verbose)
|
||||
verbose=yes ;;
|
||||
--vidpid=*)
|
||||
vidpid=$optarg ;;
|
||||
*)
|
||||
echo "Unrecognized option \`$option'" >&2
|
||||
echo "Try \`$0 --help' for more information." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test "$help" = "yes"; then
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTION]...
|
||||
|
||||
Defaults for the options are specified in brackets.
|
||||
|
||||
Configuration:
|
||||
-h, --help display this help and exit [no]
|
||||
--vidpid=VID:PID specify vendor/product ID [<NONE>]
|
||||
--with-index=INDEX specify INDEX file [none]
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test "$vidpid" = "none"; then
|
||||
echo "Please specify Vendor ID and Product ID by --vidpid option." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VIDPID="$vidpid"
|
||||
VERSION="0100"
|
||||
PRODUCT="Fraucheky"
|
||||
VENDOR="Free Software Initiative of Japan"
|
||||
SERIALNO="FSIJ-`cat ../VERSION | sed -e 's%^[^/]*/%%'`-"
|
||||
|
||||
|
||||
../../fraucheky/configure "$vidpid" $with_index $REVISION $REVISION_CHOPSTX $REVISION_FRAUCHEKY
|
||||
|
||||
ENABLE_FRAUCHEKY=""
|
||||
FRAUCHEKY_DEFINE="#define FRAUCHEKY_SUPPORT 1"
|
||||
FRAUCHEKY_MSC_DEFINE="#define MSC_INTERFACE_NO 2"
|
||||
if ! test -f ../../fraucheky/build.mk; then
|
||||
echo "'fraucheky' not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output_vid_pid_version () {
|
||||
echo $VIDPID | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\):\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* idVendor */\\${nl} 0x\4, 0x\3, /* idProduct */%p"
|
||||
echo $VERSION | sed -n -e "s%^\([0-9a-f][0-9a-f]\)\([0-9a-f][0-9a-f]\)$% 0x\2, 0x\1, /* bcdDevice */%p"
|
||||
}
|
||||
|
||||
output_vendor_product_serial_strings () {
|
||||
prefix=$1
|
||||
|
||||
echo "static const uint8_t ${prefix}string_vendor[] = {"
|
||||
echo " ${#VENDOR}*2+2, /* bLength */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* Manufacturer: \"$VENDOR\" */"
|
||||
echo $VENDOR | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo "static const uint8_t ${prefix}string_product[] = {"
|
||||
echo " ${#PRODUCT}*2+2, /* bLength */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* Product name: \"$PRODUCT\" */"
|
||||
echo $PRODUCT | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo '};'
|
||||
|
||||
if test -n "$prefix"; then
|
||||
echo
|
||||
echo "static uint8_t ${prefix}string_serial[] = {"
|
||||
echo " ${#SERIALNO}*2+2+16, /* bLength */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* Serial number: \"$SERIALNO\" */"
|
||||
echo $SERIALNO | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
|
||||
echo " 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,"
|
||||
echo '};'
|
||||
echo
|
||||
echo "static const uint8_t ${prefix}revision_detail[] = {"
|
||||
echo " ${#REVISION}*2+2, /* bLength */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* revision detail: \"$REVISION\" */"
|
||||
echo $REVISION | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo '};'
|
||||
echo
|
||||
echo "static const uint8_t ${prefix}config_options[] = {"
|
||||
echo " ${#CONFIG}*2+2, /* bLength */"
|
||||
echo " STRING_DESCRIPTOR, /* bDescriptorType */"
|
||||
echo " /* configure options: \"$CONFIG\" */"
|
||||
echo $CONFIG | sed -e "s/\(........\)/\1\\${nl}/g" | sed -n -e "s/\(.\)/'\1', 0, /g" -e "s/^/ /" -e "/^ ./s/ $//p"
|
||||
echo '};'
|
||||
fi
|
||||
}
|
||||
|
||||
output_vid_pid_version > fraucheky-vid-pid-ver.c.inc
|
||||
output_vendor_product_serial_strings >fraucheky-usb-strings.c.inc
|
||||
|
||||
sed -e "s/@FRAUCHEKY_DEFINE@/$FRAUCHEKY_DEFINE/" \
|
||||
-e "s/@FRAUCHEKY_MSC_DEFINE@/$FRAUCHEKY_MSC_DEFINE/" \
|
||||
< config.h.in > config.h
|
||||
exit 0
|
||||
320
example-fraucheky/main.c
Normal file
320
example-fraucheky/main.c
Normal file
@@ -0,0 +1,320 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
#define NUM_INTERFACES 1
|
||||
#define FEATURE_BUS_POWERED 0x80
|
||||
|
||||
static chopstx_mutex_t usb_mtx;
|
||||
static chopstx_cond_t usb_cnd;
|
||||
static uint32_t bDeviceState = UNCONNECTED; /* USB device status */
|
||||
|
||||
extern void EP6_IN_Callback (uint16_t len);
|
||||
extern void EP6_OUT_Callback (uint16_t len);
|
||||
|
||||
#define MSC_MASS_STORAGE_RESET_COMMAND 0xFF
|
||||
extern int fraucheky_enabled (void);
|
||||
extern void fraucheky_main (void);
|
||||
|
||||
extern void fraucheky_setup_endpoints_for_interface (struct usb_dev *dev, int stop);
|
||||
extern int fraucheky_setup (struct usb_dev *dev);
|
||||
extern int fraucheky_get_descriptor (struct usb_dev *dev);
|
||||
|
||||
static void
|
||||
setup_endpoints_for_interface (struct usb_dev *dev, uint16_t interface, int stop)
|
||||
{
|
||||
if (interface == 0)
|
||||
fraucheky_setup_endpoints_for_interface (dev, stop);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_device_reset (struct usb_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
usb_lld_reset (dev, FEATURE_BUS_POWERED);
|
||||
|
||||
/* Initialize Endpoint 0. */
|
||||
usb_lld_setup_endp (dev, ENDP0, 1, 1);
|
||||
|
||||
/* Stop the interface */
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
setup_endpoints_for_interface (dev, i, 1);
|
||||
|
||||
/* Notify upper layer. */
|
||||
chopstx_mutex_lock (&usb_mtx);
|
||||
bDeviceState = ATTACHED;
|
||||
chopstx_cond_signal (&usb_cnd);
|
||||
chopstx_mutex_unlock (&usb_mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_ctrl_write_finish (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT) && arg->index == 0
|
||||
&& USB_SETUP_SET (arg->type))
|
||||
{
|
||||
if (arg->request == MSC_MASS_STORAGE_RESET_COMMAND)
|
||||
fraucheky_setup_endpoints_for_interface (dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_setup (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (type_rcp == (CLASS_REQUEST | INTERFACE_RECIPIENT)
|
||||
&& arg->index == 0)
|
||||
return fraucheky_setup (dev);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
usb_set_configuration (struct usb_dev *dev)
|
||||
{
|
||||
int i;
|
||||
uint8_t current_conf;
|
||||
|
||||
current_conf = usb_lld_current_configuration (dev);
|
||||
if (current_conf == 0)
|
||||
{
|
||||
if (dev->dev_req.value != 1)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 1);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
setup_endpoints_for_interface (dev, i, 0);
|
||||
chopstx_mutex_lock (&usb_mtx);
|
||||
bDeviceState = CONFIGURED;
|
||||
chopstx_mutex_unlock (&usb_mtx);
|
||||
}
|
||||
else if (current_conf != dev->dev_req.value)
|
||||
{
|
||||
if (dev->dev_req.value != 0)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
for (i = 0; i < NUM_INTERFACES; i++)
|
||||
setup_endpoints_for_interface (dev, i, 1);
|
||||
chopstx_mutex_lock (&usb_mtx);
|
||||
bDeviceState = ADDRESSED;
|
||||
chopstx_cond_signal (&usb_cnd);
|
||||
chopstx_mutex_unlock (&usb_mtx);
|
||||
}
|
||||
|
||||
/* Do nothing when current_conf == value */
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
uint16_t alt = dev->dev_req.value;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
if (alt != 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
setup_endpoints_for_interface (dev, interface, 0);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint8_t zero = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &zero, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_get_status_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint16_t status_info = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
|
||||
static void usb_tx_done (uint8_t ep_num, uint16_t len);
|
||||
static void usb_rx_ready (uint8_t ep_num, uint16_t len);
|
||||
|
||||
|
||||
#define INTR_REQ_USB SIGUSR1
|
||||
#define PRIO_USB 3
|
||||
|
||||
static void *
|
||||
usb_main (void *arg)
|
||||
{
|
||||
chopstx_intr_t interrupt;
|
||||
struct usb_dev dev;
|
||||
int e;
|
||||
|
||||
(void)arg;
|
||||
chopstx_claim_irq (&interrupt, INTR_REQ_USB);
|
||||
usb_lld_init (&dev, FEATURE_BUS_POWERED);
|
||||
goto event_handle; /* For old SYS < 3.0 */
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_intr_wait (&interrupt);
|
||||
|
||||
if (interrupt.ready)
|
||||
{
|
||||
uint8_t ep_num;
|
||||
|
||||
event_handle:
|
||||
e = usb_lld_event_handler (&dev);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
|
||||
if (ep_num != 0)
|
||||
{
|
||||
if (USB_EVENT_TXRX (e))
|
||||
usb_tx_done (ep_num, USB_EVENT_LEN (e));
|
||||
else
|
||||
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
|
||||
}
|
||||
else
|
||||
switch (USB_EVENT_ID (e))
|
||||
{
|
||||
case USB_EVENT_DEVICE_RESET:
|
||||
usb_device_reset (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_DEVICE_ADDRESSED:
|
||||
chopstx_mutex_lock (&usb_mtx);
|
||||
bDeviceState = ADDRESSED;
|
||||
chopstx_cond_signal (&usb_cnd);
|
||||
chopstx_mutex_unlock (&usb_mtx);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_DESCRIPTOR:
|
||||
if (fraucheky_get_descriptor (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_CONFIGURATION:
|
||||
if (usb_set_configuration (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_INTERFACE:
|
||||
if (usb_set_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_REQUEST:
|
||||
/* Device specific device request. */
|
||||
if (usb_setup (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_STATUS_INTERFACE:
|
||||
if (usb_get_status_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_INTERFACE:
|
||||
if (usb_get_interface (&dev) < 0)
|
||||
usb_lld_ctrl_error (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_FEATURE_DEVICE:
|
||||
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
||||
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
||||
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
||||
usb_lld_ctrl_ack (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_WRITE_FINISH:
|
||||
/* Control WRITE transfer finished. */
|
||||
usb_ctrl_write_finish (&dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_OK:
|
||||
case USB_EVENT_DEVICE_SUSPEND:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
if (ep_num == ENDP6)
|
||||
EP6_IN_Callback (len);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
if (ep_num == ENDP6)
|
||||
EP6_OUT_Callback (len);
|
||||
}
|
||||
|
||||
static char __process3_stack_base__[4096];
|
||||
|
||||
#define STACK_ADDR_USB ((uintptr_t)__process3_stack_base__)
|
||||
#define STACK_SIZE_USB (sizeof __process3_stack_base__)
|
||||
|
||||
#ifdef GNU_LINUX_EMULATION
|
||||
#define main emulated_main
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Entry point.
|
||||
*
|
||||
* NOTE: the main function is already a thread in the system on entry.
|
||||
*/
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
chopstx_t usb_thd;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
chopstx_mutex_init (&usb_mtx);
|
||||
chopstx_cond_init (&usb_cnd);
|
||||
|
||||
bDeviceState = UNCONNECTED;
|
||||
usb_thd = chopstx_create (PRIO_USB, STACK_ADDR_USB, STACK_SIZE_USB,
|
||||
usb_main, NULL);
|
||||
while (bDeviceState != CONFIGURED)
|
||||
chopstx_usec_wait (250*1000);
|
||||
fraucheky_main ();
|
||||
chopstx_cancel (usb_thd);
|
||||
chopstx_join (usb_thd, NULL);
|
||||
usb_lld_shutdown ();
|
||||
bDeviceState = UNCONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -75,14 +75,14 @@ blk (void *arg)
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
|
||||
|
||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
|
||||
|
||||
|
||||
static char hexchar (uint8_t x)
|
||||
@@ -114,8 +114,8 @@ main (int argc, const char *argv[])
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
@@ -629,9 +629,9 @@ static void *tty_main (void *arg);
|
||||
#define INTR_REQ_USB 24
|
||||
#define PRIO_TTY 4
|
||||
|
||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
||||
const uint32_t __stackaddr_tty = (uint32_t)&__process3_stack_base__;
|
||||
const size_t __stacksize_tty = (size_t)&__process3_stack_size__;
|
||||
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
|
||||
#define STACK_ADDR_TTY ((uint32_t)__process3_stack_base__)
|
||||
#define STACK_SIZE_TTY ((uint32_t)__process3_stack_size__)
|
||||
|
||||
struct tty *
|
||||
tty_open (void)
|
||||
@@ -646,7 +646,7 @@ tty_open (void)
|
||||
tty0.device_state = UNCONNECTED;
|
||||
memcpy (&tty0.line_coding, &line_coding0, sizeof (struct line_coding));
|
||||
|
||||
chopstx_create (PRIO_TTY, __stackaddr_tty, __stacksize_tty, tty_main, &tty0);
|
||||
chopstx_create (PRIO_TTY, STACK_ADDR_TTY, STACK_SIZE_TTY, tty_main, &tty0);
|
||||
return &tty0;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,14 +166,14 @@ button (void *arg)
|
||||
#define PRIO_LED 3
|
||||
#define PRIO_BUTTON 2
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
|
||||
|
||||
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
|
||||
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_BUTTON ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BUTTON ((uint32_t)__process2_stack_size__)
|
||||
|
||||
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
|
||||
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
|
||||
@@ -382,10 +382,10 @@ main (int argc, const char *argv[])
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
|
||||
__stacksize_led, led, NULL);
|
||||
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
|
||||
__stacksize_button, button, NULL);
|
||||
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
|
||||
STACK_SIZE_LED, led, NULL);
|
||||
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
|
||||
STACK_SIZE_BUTTON, button, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
@@ -166,14 +166,14 @@ button (void *arg)
|
||||
#define PRIO_LED 3
|
||||
#define PRIO_BUTTON 2
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t __stackaddr_led = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_led = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
|
||||
|
||||
const uint32_t __stackaddr_button = (uint32_t)&__process2_stack_base__;
|
||||
const size_t __stacksize_button = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_BUTTON ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BUTTON ((uint32_t)__process2_stack_size__)
|
||||
|
||||
#define DATA55(x0,x1,x2,x3,x4) (x0<<20)|(x1<<15)|(x2<<10)|(x3<< 5)|(x4<< 0)
|
||||
#define SIZE55(img) (sizeof (img) / sizeof (uint32_t))
|
||||
@@ -370,10 +370,10 @@ main (int argc, const char *argv[])
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
led_thd = chopstx_create (PRIO_LED, __stackaddr_led,
|
||||
__stacksize_led, led, NULL);
|
||||
button_thd = chopstx_create (PRIO_BUTTON, __stackaddr_button,
|
||||
__stacksize_button, button, NULL);
|
||||
led_thd = chopstx_create (PRIO_LED, STACK_ADDR_LED,
|
||||
STACK_SIZE_LED, led, NULL);
|
||||
button_thd = chopstx_create (PRIO_BUTTON, STACK_ADDR_BUTTON,
|
||||
STACK_SIZE_BUTTON, button, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
@@ -88,10 +88,10 @@ led_enable_column (uint8_t col)
|
||||
|
||||
#define PRIO_LED 3
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
|
||||
const uint32_t stackaddr_led = (uint32_t)&__process1_stack_base__;
|
||||
const size_t stacksize_led = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_LED ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_LED ((uint32_t)__process1_stack_size__)
|
||||
|
||||
static void *
|
||||
led (void *arg)
|
||||
@@ -119,10 +119,10 @@ led (void *arg)
|
||||
|
||||
|
||||
#define PRIO_SPK 4
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t stackaddr_spk = (uint32_t)&__process2_stack_base__;
|
||||
const size_t stacksize_spk = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_SPK ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_SPK ((uint32_t)__process2_stack_size__)
|
||||
|
||||
static chopstx_mutex_t spk_mtx;
|
||||
static chopstx_cond_t spk_cnd;
|
||||
@@ -193,10 +193,10 @@ spk (void *arg)
|
||||
|
||||
|
||||
#define PRIO_MUSIC 2
|
||||
extern uint8_t __process3_stack_base__, __process3_stack_size__;
|
||||
extern uint8_t __process3_stack_base__[], __process3_stack_size__[];
|
||||
|
||||
const uint32_t stackaddr_music = (uint32_t)&__process3_stack_base__;
|
||||
const size_t stacksize_music = (size_t)&__process3_stack_size__;
|
||||
#define STACK_ADDR_MUSIC ((uint32_t)__process3_stack_base__)
|
||||
#define STACK_SIZE_MUSIC ((uint32_t)__process3_stack_size__)
|
||||
|
||||
#define C 0
|
||||
#define D 1
|
||||
@@ -254,7 +254,7 @@ music (void *arg)
|
||||
chopstx_cond_init (&spk_cnd);
|
||||
chopstx_cond_init (&spk_cnd_no_tone);
|
||||
|
||||
chopstx_create (PRIO_SPK, stackaddr_spk, stacksize_spk, spk, NULL);
|
||||
chopstx_create (PRIO_SPK, STACK_ADDR_SPK, STACK_SIZE_SPK, spk, NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -350,8 +350,8 @@ main (int argc, const char *argv[])
|
||||
chopstx_mutex_init (&mtx);
|
||||
chopstx_cond_init (&cnd);
|
||||
|
||||
chopstx_create (PRIO_LED, stackaddr_led, stacksize_led, led, NULL);
|
||||
chopstx_create (PRIO_MUSIC, stackaddr_music, stacksize_music, music, NULL);
|
||||
chopstx_create (PRIO_LED, STACK_ADDR_LED, STACK_SIZE_LED, led, NULL);
|
||||
chopstx_create (PRIO_MUSIC, STACK_ADDR_MUSIC, STACK_SIZE_MUSIC, music, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
@@ -72,14 +72,14 @@ blk (void *arg)
|
||||
#define PRIO_BLK 2
|
||||
#endif
|
||||
|
||||
extern uint8_t __process1_stack_base__, __process1_stack_size__;
|
||||
extern uint8_t __process2_stack_base__, __process2_stack_size__;
|
||||
extern uint8_t __process1_stack_base__[], __process1_stack_size__[];
|
||||
extern uint8_t __process2_stack_base__[], __process2_stack_size__[];
|
||||
|
||||
const uint32_t __stackaddr_pwm = (uint32_t)&__process1_stack_base__;
|
||||
const size_t __stacksize_pwm = (size_t)&__process1_stack_size__;
|
||||
#define STACK_ADDR_PWM ((uint32_t)__process1_stack_base__)
|
||||
#define STACK_SIZE_PWM ((uint32_t)__process1_stack_size__)
|
||||
|
||||
const uint32_t __stackaddr_blk = (uint32_t)&__process2_stack_base__;
|
||||
const size_t __stacksize_blk = (size_t)&__process2_stack_size__;
|
||||
#define STACK_ADDR_BLK ((uint32_t)__process2_stack_base__)
|
||||
#define STACK_SIZE_BLK ((uint32_t)__process2_stack_size__)
|
||||
|
||||
|
||||
int
|
||||
@@ -94,8 +94,8 @@ main (int argc, const char *argv[])
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, __stackaddr_pwm, __stacksize_pwm, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, __stackaddr_blk, __stacksize_blk, blk, NULL);
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
|
||||
502
mcu/stm32f103.h
502
mcu/stm32f103.h
@@ -1,10 +1,8 @@
|
||||
#define PERIPH_BASE 0x40000000
|
||||
#define APB1PERIPH_BASE PERIPH_BASE
|
||||
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
|
||||
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
|
||||
|
||||
#define RCC_APB2RSTR_ADC1RST 0x00000200
|
||||
#define RCC_APB2RSTR_ADC2RST 0x00000400
|
||||
|
||||
struct RCC {
|
||||
volatile uint32_t CR;
|
||||
volatile uint32_t CFGR;
|
||||
@@ -26,6 +24,17 @@ static struct RCC *const RCC = (struct RCC *)RCC_BASE;
|
||||
|
||||
#define RCC_APB2ENR_ADC1EN 0x00000200
|
||||
#define RCC_APB2ENR_ADC2EN 0x00000400
|
||||
#define RCC_APB2ENR_TIM1EN 0x00000800
|
||||
#define RCC_APB1ENR_TIM2EN 0x00000001
|
||||
#define RCC_APB1ENR_TIM3EN 0x00000002
|
||||
#define RCC_APB1ENR_TIM4EN 0x00000004
|
||||
|
||||
#define RCC_APB2RSTR_ADC1RST 0x00000200
|
||||
#define RCC_APB2RSTR_ADC2RST 0x00000400
|
||||
#define RCC_APB2RSTR_TIM1RST 0x00000800
|
||||
#define RCC_APB1RSTR_TIM2RST 0x00000001
|
||||
#define RCC_APB1RSTR_TIM3RST 0x00000002
|
||||
#define RCC_APB1RSTR_TIM4RST 0x00000004
|
||||
|
||||
#define CRC_CR_RESET 0x00000001
|
||||
|
||||
@@ -202,3 +211,490 @@ struct SCB
|
||||
#define SCS_BASE 0xE000E000
|
||||
#define SCB_BASE (SCS_BASE + 0x0D00)
|
||||
static struct SCB *const SCB = (struct SCB *)SCB_BASE;
|
||||
|
||||
/* Timer */
|
||||
struct TIM
|
||||
{
|
||||
volatile uint16_t CR1; uint16_t RESERVED0;
|
||||
volatile uint16_t CR2; uint16_t RESERVED1;
|
||||
volatile uint16_t SMCR; uint16_t RESERVED2;
|
||||
volatile uint16_t DIER; uint16_t RESERVED3;
|
||||
volatile uint16_t SR; uint16_t RESERVED4;
|
||||
volatile uint16_t EGR; uint16_t RESERVED5;
|
||||
volatile uint16_t CCMR1; uint16_t RESERVED6;
|
||||
volatile uint16_t CCMR2; uint16_t RESERVED7;
|
||||
volatile uint16_t CCER; uint16_t RESERVED8;
|
||||
volatile uint16_t CNT; uint16_t RESERVED9;
|
||||
volatile uint16_t PSC; uint16_t RESERVED10;
|
||||
volatile uint16_t ARR; uint16_t RESERVED11;
|
||||
volatile uint16_t RCR; uint16_t RESERVED12;
|
||||
volatile uint16_t CCR1; uint16_t RESERVED13;
|
||||
volatile uint16_t CCR2; uint16_t RESERVED14;
|
||||
volatile uint16_t CCR3; uint16_t RESERVED15;
|
||||
volatile uint16_t CCR4; uint16_t RESERVED16;
|
||||
volatile uint16_t BDTR; uint16_t RESERVED17;
|
||||
volatile uint16_t DCR; uint16_t RESERVED18;
|
||||
volatile uint16_t DMAR; uint16_t RESERVED19;
|
||||
};
|
||||
|
||||
#define TIM2_BASE 0x40000000
|
||||
#define TIM3_BASE 0x40000400
|
||||
#define TIM4_BASE 0x40000800
|
||||
static struct TIM *const TIM2 = (struct TIM *)TIM2_BASE;
|
||||
static struct TIM *const TIM3 = (struct TIM *)TIM3_BASE;
|
||||
static struct TIM *const TIM4 = (struct TIM *)TIM4_BASE;
|
||||
|
||||
#define TIM_CR1_CEN 0x0001
|
||||
#define TIM_CR1_UDIS 0x0002
|
||||
#define TIM_CR1_URS 0x0004
|
||||
#define TIM_CR1_OPM 0x0008
|
||||
#define TIM_CR1_DIR 0x0010
|
||||
#define TIM_CR1_CMS 0x0060
|
||||
#define TIM_CR1_CMS_0 0x0020
|
||||
#define TIM_CR1_CMS_1 0x0040
|
||||
#define TIM_CR1_ARPE 0x0080
|
||||
#define TIM_CR1_CKD 0x0300
|
||||
#define TIM_CR1_CKD_0 0x0100
|
||||
#define TIM_CR1_CKD_1 0x0200
|
||||
|
||||
#define TIM_CR2_CCPC 0x0001
|
||||
#define TIM_CR2_CCUS 0x0004
|
||||
#define TIM_CR2_CCDS 0x0008
|
||||
#define TIM_CR2_MMS 0x0070
|
||||
#define TIM_CR2_MMS_0 0x0010
|
||||
#define TIM_CR2_MMS_1 0x0020
|
||||
#define TIM_CR2_MMS_2 0x0040
|
||||
#define TIM_CR2_TI1S 0x0080
|
||||
#define TIM_CR2_OIS1 0x0100
|
||||
#define TIM_CR2_OIS1N 0x0200
|
||||
#define TIM_CR2_OIS2 0x0400
|
||||
#define TIM_CR2_OIS2N 0x0800
|
||||
#define TIM_CR2_OIS3 0x1000
|
||||
#define TIM_CR2_OIS3N 0x2000
|
||||
#define TIM_CR2_OIS4 0x4000
|
||||
|
||||
#define TIM_SMCR_SMS 0x0007
|
||||
#define TIM_SMCR_SMS_0 0x0001
|
||||
#define TIM_SMCR_SMS_1 0x0002
|
||||
#define TIM_SMCR_SMS_2 0x0004
|
||||
#define TIM_SMCR_TS 0x0070
|
||||
#define TIM_SMCR_TS_0 0x0010
|
||||
#define TIM_SMCR_TS_1 0x0020
|
||||
#define TIM_SMCR_TS_2 0x0040
|
||||
#define TIM_SMCR_MSM 0x0080
|
||||
|
||||
#define TIM_SMCR_ETF 0x0F00
|
||||
#define TIM_SMCR_ETF_0 0x0100
|
||||
#define TIM_SMCR_ETF_1 0x0200
|
||||
#define TIM_SMCR_ETF_2 0x0400
|
||||
#define TIM_SMCR_ETF_3 0x0800
|
||||
|
||||
#define TIM_SMCR_ETPS 0x3000
|
||||
#define TIM_SMCR_ETPS_0 0x1000
|
||||
#define TIM_SMCR_ETPS_1 0x2000
|
||||
|
||||
#define TIM_SMCR_ECE 0x4000
|
||||
#define TIM_SMCR_ETP 0x8000
|
||||
|
||||
#define TIM_DIER_UIE 0x0001
|
||||
#define TIM_DIER_CC1IE 0x0002
|
||||
#define TIM_DIER_CC2IE 0x0004
|
||||
#define TIM_DIER_CC3IE 0x0008
|
||||
#define TIM_DIER_CC4IE 0x0010
|
||||
#define TIM_DIER_COMIE 0x0020
|
||||
#define TIM_DIER_TIE 0x0040
|
||||
#define TIM_DIER_BIE 0x0080
|
||||
#define TIM_DIER_UDE 0x0100
|
||||
#define TIM_DIER_CC1DE 0x0200
|
||||
#define TIM_DIER_CC2DE 0x0400
|
||||
#define TIM_DIER_CC3DE 0x0800
|
||||
#define TIM_DIER_CC4DE 0x1000
|
||||
#define TIM_DIER_COMDE 0x2000
|
||||
#define TIM_DIER_TDE 0x4000
|
||||
|
||||
#define TIM_SR_UIF 0x0001
|
||||
#define TIM_SR_CC1IF 0x0002
|
||||
#define TIM_SR_CC2IF 0x0004
|
||||
#define TIM_SR_CC3IF 0x0008
|
||||
#define TIM_SR_CC4IF 0x0010
|
||||
#define TIM_SR_COMIF 0x0020
|
||||
#define TIM_SR_TIF 0x0040
|
||||
#define TIM_SR_BIF 0x0080
|
||||
#define TIM_SR_CC1OF 0x0200
|
||||
#define TIM_SR_CC2OF 0x0400
|
||||
#define TIM_SR_CC3OF 0x0800
|
||||
#define TIM_SR_CC4OF 0x1000
|
||||
|
||||
#define TIM_EGR_UG 0x01
|
||||
#define TIM_EGR_CC1G 0x02
|
||||
#define TIM_EGR_CC2G 0x04
|
||||
#define TIM_EGR_CC3G 0x08
|
||||
#define TIM_EGR_CC4G 0x10
|
||||
#define TIM_EGR_COMG 0x20
|
||||
#define TIM_EGR_TG 0x40
|
||||
#define TIM_EGR_BG 0x80
|
||||
|
||||
#define TIM_CCMR1_CC1S 0x0003
|
||||
#define TIM_CCMR1_CC1S_0 0x0001
|
||||
#define TIM_CCMR1_CC1S_1 0x0002
|
||||
|
||||
#define TIM_CCMR1_OC1FE 0x0004
|
||||
#define TIM_CCMR1_OC1PE 0x0008
|
||||
|
||||
#define TIM_CCMR1_OC1M 0x0070
|
||||
#define TIM_CCMR1_OC1M_0 0x0010
|
||||
#define TIM_CCMR1_OC1M_1 0x0020
|
||||
#define TIM_CCMR1_OC1M_2 0x0040
|
||||
|
||||
#define TIM_CCMR1_OC1CE 0x0080
|
||||
|
||||
#define TIM_CCMR1_CC2S 0x0300
|
||||
#define TIM_CCMR1_CC2S_0 0x0100
|
||||
#define TIM_CCMR1_CC2S_1 0x0200
|
||||
|
||||
#define TIM_CCMR1_OC2FE 0x0400
|
||||
#define TIM_CCMR1_OC2PE 0x0800
|
||||
|
||||
#define TIM_CCMR1_OC2M 0x7000
|
||||
#define TIM_CCMR1_OC2M_0 0x1000
|
||||
#define TIM_CCMR1_OC2M_1 0x2000
|
||||
#define TIM_CCMR1_OC2M_2 0x4000
|
||||
|
||||
#define TIM_CCMR1_OC2CE 0x8000
|
||||
|
||||
|
||||
#define TIM_CCMR1_IC1PSC 0x000C
|
||||
#define TIM_CCMR1_IC1PSC_0 0x0004
|
||||
#define TIM_CCMR1_IC1PSC_1 0x0008
|
||||
|
||||
#define TIM_CCMR1_IC1F 0x00F0
|
||||
#define TIM_CCMR1_IC1F_0 0x0010
|
||||
#define TIM_CCMR1_IC1F_1 0x0020
|
||||
#define TIM_CCMR1_IC1F_2 0x0040
|
||||
#define TIM_CCMR1_IC1F_3 0x0080
|
||||
|
||||
#define TIM_CCMR1_IC2PSC 0x0C00
|
||||
#define TIM_CCMR1_IC2PSC_0 0x0400
|
||||
#define TIM_CCMR1_IC2PSC_1 0x0800
|
||||
|
||||
#define TIM_CCMR1_IC2F 0xF000
|
||||
#define TIM_CCMR1_IC2F_0 0x1000
|
||||
#define TIM_CCMR1_IC2F_1 0x2000
|
||||
#define TIM_CCMR1_IC2F_2 0x4000
|
||||
#define TIM_CCMR1_IC2F_3 0x8000
|
||||
|
||||
#define TIM_CCMR2_CC3S 0x0003
|
||||
#define TIM_CCMR2_CC3S_0 0x0001
|
||||
#define TIM_CCMR2_CC3S_1 0x0002
|
||||
|
||||
#define TIM_CCMR2_OC3FE 0x0004
|
||||
#define TIM_CCMR2_OC3PE 0x0008
|
||||
|
||||
#define TIM_CCMR2_OC3M 0x0070
|
||||
#define TIM_CCMR2_OC3M_0 0x0010
|
||||
#define TIM_CCMR2_OC3M_1 0x0020
|
||||
#define TIM_CCMR2_OC3M_2 0x0040
|
||||
|
||||
#define TIM_CCMR2_OC3CE 0x0080
|
||||
|
||||
#define TIM_CCMR2_CC4S 0x0300
|
||||
#define TIM_CCMR2_CC4S_0 0x0100
|
||||
#define TIM_CCMR2_CC4S_1 0x0200
|
||||
|
||||
#define TIM_CCMR2_OC4FE 0x0400
|
||||
#define TIM_CCMR2_OC4PE 0x0800
|
||||
|
||||
#define TIM_CCMR2_OC4M 0x7000
|
||||
#define TIM_CCMR2_OC4M_0 0x1000
|
||||
#define TIM_CCMR2_OC4M_1 0x2000
|
||||
#define TIM_CCMR2_OC4M_2 0x4000
|
||||
|
||||
#define TIM_CCMR2_OC4CE 0x8000
|
||||
|
||||
|
||||
#define TIM_CCMR2_IC3PSC 0x000C
|
||||
#define TIM_CCMR2_IC3PSC_0 0x0004
|
||||
#define TIM_CCMR2_IC3PSC_1 0x0008
|
||||
|
||||
#define TIM_CCMR2_IC3F 0x00F0
|
||||
#define TIM_CCMR2_IC3F_0 0x0010
|
||||
#define TIM_CCMR2_IC3F_1 0x0020
|
||||
#define TIM_CCMR2_IC3F_2 0x0040
|
||||
#define TIM_CCMR2_IC3F_3 0x0080
|
||||
|
||||
#define TIM_CCMR2_IC4PSC 0x0C00
|
||||
#define TIM_CCMR2_IC4PSC_0 0x0400
|
||||
#define TIM_CCMR2_IC4PSC_1 0x0800
|
||||
|
||||
#define TIM_CCMR2_IC4F 0xF000
|
||||
#define TIM_CCMR2_IC4F_0 0x1000
|
||||
#define TIM_CCMR2_IC4F_1 0x2000
|
||||
#define TIM_CCMR2_IC4F_2 0x4000
|
||||
#define TIM_CCMR2_IC4F_3 0x8000
|
||||
|
||||
#define TIM_CCER_CC1E 0x0001
|
||||
#define TIM_CCER_CC1P 0x0002
|
||||
#define TIM_CCER_CC1NE 0x0004
|
||||
#define TIM_CCER_CC1NP 0x0008
|
||||
#define TIM_CCER_CC2E 0x0010
|
||||
#define TIM_CCER_CC2P 0x0020
|
||||
#define TIM_CCER_CC2NE 0x0040
|
||||
#define TIM_CCER_CC2NP 0x0080
|
||||
#define TIM_CCER_CC3E 0x0100
|
||||
#define TIM_CCER_CC3P 0x0200
|
||||
#define TIM_CCER_CC3NE 0x0400
|
||||
#define TIM_CCER_CC3NP 0x0800
|
||||
#define TIM_CCER_CC4E 0x1000
|
||||
#define TIM_CCER_CC4P 0x2000
|
||||
|
||||
#define TIM_CNT_CNT 0xFFFF
|
||||
|
||||
#define TIM_PSC_PSC 0xFFFF
|
||||
|
||||
#define TIM_ARR_ARR 0xFFFF
|
||||
|
||||
#define TIM_RCR_REP 0xFF
|
||||
|
||||
#define TIM_CCR1_CCR1 0xFFFF
|
||||
#define TIM_CCR2_CCR2 0xFFFF
|
||||
#define TIM_CCR3_CCR3 0xFFFF
|
||||
#define TIM_CCR4_CCR4 0xFFFF
|
||||
|
||||
#define TIM_BDTR_DTG 0x00FF
|
||||
#define TIM_BDTR_DTG_0 0x0001
|
||||
#define TIM_BDTR_DTG_1 0x0002
|
||||
#define TIM_BDTR_DTG_2 0x0004
|
||||
#define TIM_BDTR_DTG_3 0x0008
|
||||
#define TIM_BDTR_DTG_4 0x0010
|
||||
#define TIM_BDTR_DTG_5 0x0020
|
||||
#define TIM_BDTR_DTG_6 0x0040
|
||||
#define TIM_BDTR_DTG_7 0x0080
|
||||
|
||||
#define TIM_BDTR_LOCK 0x0300
|
||||
#define TIM_BDTR_LOCK_0 0x0100
|
||||
#define TIM_BDTR_LOCK_1 0x0200
|
||||
|
||||
#define TIM_BDTR_OSSI 0x0400
|
||||
#define TIM_BDTR_OSSR 0x0800
|
||||
#define TIM_BDTR_BKE 0x1000
|
||||
#define TIM_BDTR_BKP 0x2000
|
||||
#define TIM_BDTR_AOE 0x4000
|
||||
#define TIM_BDTR_MOE 0x8000
|
||||
|
||||
#define TIM_DCR_DBA 0x001F
|
||||
#define TIM_DCR_DBA_0 0x0001
|
||||
#define TIM_DCR_DBA_1 0x0002
|
||||
#define TIM_DCR_DBA_2 0x0004
|
||||
#define TIM_DCR_DBA_3 0x0008
|
||||
#define TIM_DCR_DBA_4 0x0010
|
||||
|
||||
#define TIM_DCR_DBL 0x1F00
|
||||
#define TIM_DCR_DBL_0 0x0100
|
||||
#define TIM_DCR_DBL_1 0x0200
|
||||
#define TIM_DCR_DBL_2 0x0400
|
||||
#define TIM_DCR_DBL_3 0x0800
|
||||
#define TIM_DCR_DBL_4 0x1000
|
||||
|
||||
#define TIM_DMAR_DMAB 0xFFFF
|
||||
|
||||
struct EXTI
|
||||
{
|
||||
volatile uint32_t IMR;
|
||||
volatile uint32_t EMR;
|
||||
volatile uint32_t RTSR;
|
||||
volatile uint32_t FTSR;
|
||||
volatile uint32_t SWIER;
|
||||
volatile uint32_t PR;
|
||||
};
|
||||
|
||||
#define EXTI_BASE 0x40010400
|
||||
static struct EXTI *const EXTI = (struct EXTI *)EXTI_BASE;
|
||||
|
||||
#define EXTI_IMR_MR0 0x00000001
|
||||
#define EXTI_IMR_MR1 0x00000002
|
||||
#define EXTI_IMR_MR2 0x00000004
|
||||
#define EXTI_IMR_MR3 0x00000008
|
||||
#define EXTI_IMR_MR4 0x00000010
|
||||
#define EXTI_IMR_MR5 0x00000020
|
||||
#define EXTI_IMR_MR6 0x00000040
|
||||
#define EXTI_IMR_MR7 0x00000080
|
||||
#define EXTI_IMR_MR8 0x00000100
|
||||
#define EXTI_IMR_MR9 0x00000200
|
||||
#define EXTI_IMR_MR10 0x00000400
|
||||
#define EXTI_IMR_MR11 0x00000800
|
||||
#define EXTI_IMR_MR12 0x00001000
|
||||
#define EXTI_IMR_MR13 0x00002000
|
||||
#define EXTI_IMR_MR14 0x00004000
|
||||
#define EXTI_IMR_MR15 0x00008000
|
||||
#define EXTI_IMR_MR16 0x00010000
|
||||
#define EXTI_IMR_MR17 0x00020000
|
||||
#define EXTI_IMR_MR18 0x00040000
|
||||
#define EXTI_IMR_MR19 0x00080000
|
||||
|
||||
#define EXTI_EMR_MR0 0x00000001
|
||||
#define EXTI_EMR_MR1 0x00000002
|
||||
#define EXTI_EMR_MR2 0x00000004
|
||||
#define EXTI_EMR_MR3 0x00000008
|
||||
#define EXTI_EMR_MR4 0x00000010
|
||||
#define EXTI_EMR_MR5 0x00000020
|
||||
#define EXTI_EMR_MR6 0x00000040
|
||||
#define EXTI_EMR_MR7 0x00000080
|
||||
#define EXTI_EMR_MR8 0x00000100
|
||||
#define EXTI_EMR_MR9 0x00000200
|
||||
#define EXTI_EMR_MR10 0x00000400
|
||||
#define EXTI_EMR_MR11 0x00000800
|
||||
#define EXTI_EMR_MR12 0x00001000
|
||||
#define EXTI_EMR_MR13 0x00002000
|
||||
#define EXTI_EMR_MR14 0x00004000
|
||||
#define EXTI_EMR_MR15 0x00008000
|
||||
#define EXTI_EMR_MR16 0x00010000
|
||||
#define EXTI_EMR_MR17 0x00020000
|
||||
#define EXTI_EMR_MR18 0x00040000
|
||||
#define EXTI_EMR_MR19 0x00080000
|
||||
|
||||
#define EXTI_RTSR_TR0 0x00000001
|
||||
#define EXTI_RTSR_TR1 0x00000002
|
||||
#define EXTI_RTSR_TR2 0x00000004
|
||||
#define EXTI_RTSR_TR3 0x00000008
|
||||
#define EXTI_RTSR_TR4 0x00000010
|
||||
#define EXTI_RTSR_TR5 0x00000020
|
||||
#define EXTI_RTSR_TR6 0x00000040
|
||||
#define EXTI_RTSR_TR7 0x00000080
|
||||
#define EXTI_RTSR_TR8 0x00000100
|
||||
#define EXTI_RTSR_TR9 0x00000200
|
||||
#define EXTI_RTSR_TR10 0x00000400
|
||||
#define EXTI_RTSR_TR11 0x00000800
|
||||
#define EXTI_RTSR_TR12 0x00001000
|
||||
#define EXTI_RTSR_TR13 0x00002000
|
||||
#define EXTI_RTSR_TR14 0x00004000
|
||||
#define EXTI_RTSR_TR15 0x00008000
|
||||
#define EXTI_RTSR_TR16 0x00010000
|
||||
#define EXTI_RTSR_TR17 0x00020000
|
||||
#define EXTI_RTSR_TR18 0x00040000
|
||||
#define EXTI_RTSR_TR19 0x00080000
|
||||
|
||||
#define EXTI_FTSR_TR0 0x00000001
|
||||
#define EXTI_FTSR_TR1 0x00000002
|
||||
#define EXTI_FTSR_TR2 0x00000004
|
||||
#define EXTI_FTSR_TR3 0x00000008
|
||||
#define EXTI_FTSR_TR4 0x00000010
|
||||
#define EXTI_FTSR_TR5 0x00000020
|
||||
#define EXTI_FTSR_TR6 0x00000040
|
||||
#define EXTI_FTSR_TR7 0x00000080
|
||||
#define EXTI_FTSR_TR8 0x00000100
|
||||
#define EXTI_FTSR_TR9 0x00000200
|
||||
#define EXTI_FTSR_TR10 0x00000400
|
||||
#define EXTI_FTSR_TR11 0x00000800
|
||||
#define EXTI_FTSR_TR12 0x00001000
|
||||
#define EXTI_FTSR_TR13 0x00002000
|
||||
#define EXTI_FTSR_TR14 0x00004000
|
||||
#define EXTI_FTSR_TR15 0x00008000
|
||||
#define EXTI_FTSR_TR16 0x00010000
|
||||
#define EXTI_FTSR_TR17 0x00020000
|
||||
#define EXTI_FTSR_TR18 0x00040000
|
||||
#define EXTI_FTSR_TR19 0x00080000
|
||||
|
||||
#define EXTI_SWIER_SWIER0 0x00000001
|
||||
#define EXTI_SWIER_SWIER1 0x00000002
|
||||
#define EXTI_SWIER_SWIER2 0x00000004
|
||||
#define EXTI_SWIER_SWIER3 0x00000008
|
||||
#define EXTI_SWIER_SWIER4 0x00000010
|
||||
#define EXTI_SWIER_SWIER5 0x00000020
|
||||
#define EXTI_SWIER_SWIER6 0x00000040
|
||||
#define EXTI_SWIER_SWIER7 0x00000080
|
||||
#define EXTI_SWIER_SWIER8 0x00000100
|
||||
#define EXTI_SWIER_SWIER9 0x00000200
|
||||
#define EXTI_SWIER_SWIER10 0x00000400
|
||||
#define EXTI_SWIER_SWIER11 0x00000800
|
||||
#define EXTI_SWIER_SWIER12 0x00001000
|
||||
#define EXTI_SWIER_SWIER13 0x00002000
|
||||
#define EXTI_SWIER_SWIER14 0x00004000
|
||||
#define EXTI_SWIER_SWIER15 0x00008000
|
||||
#define EXTI_SWIER_SWIER16 0x00010000
|
||||
#define EXTI_SWIER_SWIER17 0x00020000
|
||||
#define EXTI_SWIER_SWIER18 0x00040000
|
||||
#define EXTI_SWIER_SWIER19 0x00080000
|
||||
|
||||
#define EXTI_PR_PR0 0x00000001
|
||||
#define EXTI_PR_PR1 0x00000002
|
||||
#define EXTI_PR_PR2 0x00000004
|
||||
#define EXTI_PR_PR3 0x00000008
|
||||
#define EXTI_PR_PR4 0x00000010
|
||||
#define EXTI_PR_PR5 0x00000020
|
||||
#define EXTI_PR_PR6 0x00000040
|
||||
#define EXTI_PR_PR7 0x00000080
|
||||
#define EXTI_PR_PR8 0x00000100
|
||||
#define EXTI_PR_PR9 0x00000200
|
||||
#define EXTI_PR_PR10 0x00000400
|
||||
#define EXTI_PR_PR11 0x00000800
|
||||
#define EXTI_PR_PR12 0x00001000
|
||||
#define EXTI_PR_PR13 0x00002000
|
||||
#define EXTI_PR_PR14 0x00004000
|
||||
#define EXTI_PR_PR15 0x00008000
|
||||
#define EXTI_PR_PR16 0x00010000
|
||||
#define EXTI_PR_PR17 0x00020000
|
||||
#define EXTI_PR_PR18 0x00040000
|
||||
#define EXTI_PR_PR19 0x00080000
|
||||
|
||||
#define EXTI0_IRQ 6
|
||||
#define EXTI1_IRQ 7
|
||||
#define EXTI2_IRQ 8
|
||||
#define EXTI9_5_IRQ 23
|
||||
#define TIM2_IRQ 28
|
||||
#define TIM3_IRQ 29
|
||||
#define TIM4_IRQ 30
|
||||
|
||||
struct AFIO
|
||||
{
|
||||
volatile uint32_t EVCR;
|
||||
volatile uint32_t MAPR;
|
||||
volatile uint32_t EXTICR[4];
|
||||
uint32_t RESERVED0;
|
||||
volatile uint32_t MAPR2;
|
||||
};
|
||||
|
||||
#define AFIO_BASE 0x40010000
|
||||
static struct AFIO *const AFIO = (struct AFIO *)AFIO_BASE;
|
||||
|
||||
#define AFIO_EXTICR1_EXTI0_PA 0x0000
|
||||
#define AFIO_EXTICR1_EXTI0_PB 0x0001
|
||||
#define AFIO_EXTICR1_EXTI0_PC 0x0002
|
||||
#define AFIO_EXTICR1_EXTI0_PD 0x0003
|
||||
|
||||
#define AFIO_EXTICR1_EXTI1_PA 0x0000
|
||||
#define AFIO_EXTICR1_EXTI1_PB 0x0010
|
||||
#define AFIO_EXTICR1_EXTI1_PC 0x0020
|
||||
#define AFIO_EXTICR1_EXTI1_PD 0x0030
|
||||
|
||||
#define AFIO_EXTICR1_EXTI2_PA 0x0000
|
||||
#define AFIO_EXTICR1_EXTI2_PB 0x0100
|
||||
#define AFIO_EXTICR1_EXTI2_PC 0x0200
|
||||
#define AFIO_EXTICR1_EXTI2_PD 0x0300
|
||||
|
||||
#define AFIO_EXTICR1_EXTI3_PA 0x0000
|
||||
#define AFIO_EXTICR1_EXTI3_PB 0x1000
|
||||
#define AFIO_EXTICR1_EXTI3_PC 0x2000
|
||||
#define AFIO_EXTICR1_EXTI3_PD 0x3000
|
||||
|
||||
#define AFIO_EXTICR2_EXTI4_PA 0x0000
|
||||
#define AFIO_EXTICR2_EXTI4_PB 0x0001
|
||||
#define AFIO_EXTICR2_EXTI4_PC 0x0002
|
||||
#define AFIO_EXTICR2_EXTI4_PD 0x0003
|
||||
|
||||
#define AFIO_EXTICR2_EXTI5_PA 0x0000
|
||||
#define AFIO_EXTICR2_EXTI5_PB 0x0010
|
||||
#define AFIO_EXTICR2_EXTI5_PC 0x0020
|
||||
#define AFIO_EXTICR2_EXTI5_PD 0x0030
|
||||
|
||||
#define AFIO_EXTICR2_EXTI6_PA 0x0000
|
||||
#define AFIO_EXTICR2_EXTI6_PB 0x0100
|
||||
#define AFIO_EXTICR2_EXTI6_PC 0x0200
|
||||
#define AFIO_EXTICR2_EXTI6_PD 0x0300
|
||||
|
||||
#define AFIO_EXTICR2_EXTI7_PA 0x0000
|
||||
#define AFIO_EXTICR2_EXTI7_PB 0x1000
|
||||
#define AFIO_EXTICR2_EXTI7_PC 0x2000
|
||||
#define AFIO_EXTICR2_EXTI7_PD 0x3000
|
||||
|
||||
#define AFIO_MAPR_TIM3_REMAP_PARTIALREMAP 0x00000800
|
||||
#define AFIO_MAPR_SWJ_CFG_DISABLE 0x04000000
|
||||
|
||||
@@ -213,7 +213,11 @@ static int
|
||||
flash_write (uint32_t dst_addr, const uint8_t *src, size_t len)
|
||||
{
|
||||
int status;
|
||||
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
|
||||
uint32_t flash_end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
|
||||
#else
|
||||
uint32_t flash_end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
|
||||
#endif
|
||||
|
||||
if (dst_addr < FLASH_START || dst_addr + len > flash_end)
|
||||
return 0;
|
||||
@@ -269,7 +273,11 @@ static void __attribute__((naked))
|
||||
flash_erase_all_and_exec (void (*entry)(void))
|
||||
{
|
||||
uint32_t addr = FLASH_START;
|
||||
#if defined(STM32F103_OVERRIDE_FLASH_SIZE_KB)
|
||||
uint32_t end = FLASH_START_ADDR + STM32F103_OVERRIDE_FLASH_SIZE_KB*1024;
|
||||
#else
|
||||
uint32_t end = FLASH_START_ADDR + (*FLASH_SIZE_REG)*1024;
|
||||
#endif
|
||||
uint32_t page_size = 1024;
|
||||
int r;
|
||||
|
||||
|
||||
@@ -272,43 +272,7 @@ kl27z_ep_clear_dtog (int rx, uint8_t n)
|
||||
kl27z_ep_clear_stall (n);
|
||||
}
|
||||
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
|
||||
|
||||
enum STANDARD_REQUESTS {
|
||||
GET_STATUS = 0,
|
||||
CLEAR_FEATURE,
|
||||
RESERVED1,
|
||||
SET_FEATURE,
|
||||
RESERVED2,
|
||||
SET_ADDRESS,
|
||||
GET_DESCRIPTOR,
|
||||
SET_DESCRIPTOR,
|
||||
GET_CONFIGURATION,
|
||||
SET_CONFIGURATION,
|
||||
GET_INTERFACE,
|
||||
SET_INTERFACE,
|
||||
SYNCH_FRAME,
|
||||
TOTAL_REQUEST /* Total number of Standard request */
|
||||
};
|
||||
|
||||
|
||||
enum FEATURE_SELECTOR {
|
||||
FEATURE_ENDPOINT_HALT=0,
|
||||
FEATURE_DEVICE_REMOTE_WAKEUP=1
|
||||
};
|
||||
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum {
|
||||
WAIT_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
PAUSE
|
||||
};
|
||||
#include "usb_lld_driver.h"
|
||||
|
||||
static int handle_transaction (struct usb_dev *dev, uint8_t stat);
|
||||
|
||||
@@ -445,7 +409,7 @@ handle_datastage_in (struct usb_dev *dev, uint8_t stat)
|
||||
{
|
||||
/* No more data to send, proceed to receive OUT acknowledge. */
|
||||
dev->state = WAIT_STATUS_OUT;
|
||||
kl27z_prepare_ep0_out (&dev->dev_req, 8, DATA1);
|
||||
kl27z_prepare_ep0_out (&dev->dev_req, 0, DATA1);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -470,12 +434,13 @@ std_none (struct usb_dev *dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint16_t status_info;
|
||||
|
||||
static int
|
||||
std_get_status (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
uint16_t status_info = 0;
|
||||
|
||||
if (arg->value != 0 || arg->len != 2 || (arg->index >> 8) != 0
|
||||
|| USB_SETUP_SET (arg->type))
|
||||
@@ -1000,8 +965,7 @@ usb_lld_ctrl_send (struct usb_dev *dev, const void *buf, size_t buflen)
|
||||
dev->state = IN_DATA;
|
||||
}
|
||||
|
||||
if (len)
|
||||
kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
|
||||
kl27z_prepare_ep0_in (data_p->addr, len, DATA1);
|
||||
|
||||
data_p->len -= len;
|
||||
data_p->addr += len;
|
||||
|
||||
@@ -31,44 +31,7 @@
|
||||
|
||||
#include "sys-stm32f103.h"
|
||||
#include "usb_lld.h"
|
||||
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
|
||||
|
||||
enum STANDARD_REQUESTS
|
||||
{
|
||||
GET_STATUS = 0,
|
||||
CLEAR_FEATURE,
|
||||
RESERVED1,
|
||||
SET_FEATURE,
|
||||
RESERVED2,
|
||||
SET_ADDRESS,
|
||||
GET_DESCRIPTOR,
|
||||
SET_DESCRIPTOR,
|
||||
GET_CONFIGURATION,
|
||||
SET_CONFIGURATION,
|
||||
GET_INTERFACE,
|
||||
SET_INTERFACE,
|
||||
SYNCH_FRAME,
|
||||
TOTAL_REQUEST /* Total number of Standard request */
|
||||
};
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
};
|
||||
|
||||
enum FEATURE_SELECTOR
|
||||
{
|
||||
FEATURE_ENDPOINT_HALT=0,
|
||||
FEATURE_DEVICE_REMOTE_WAKEUP=1
|
||||
};
|
||||
#include "usb_lld_driver.h"
|
||||
|
||||
#define REG_BASE (0x40005C00UL) /* USB_IP Peripheral Registers base address */
|
||||
#define PMA_ADDR (0x40006000UL) /* USB_IP Packet Memory Area base address */
|
||||
|
||||
2180
mcu/usb-usbip.c
Normal file
2180
mcu/usb-usbip.c
Normal file
File diff suppressed because it is too large
Load Diff
27
rules.mk
27
rules.mk
@@ -10,7 +10,11 @@ ifneq ($(USE_SYS),)
|
||||
CSRC += $(CHOPSTX)/mcu/sys-$(CHIP).c
|
||||
endif
|
||||
ifneq ($(USE_USB),)
|
||||
ifeq ($(EMULATION),)
|
||||
CSRC += $(CHOPSTX)/mcu/usb-$(CHIP).c
|
||||
else
|
||||
CSRC += $(CHOPSTX)/mcu/usb-usbip.c
|
||||
endif
|
||||
endif
|
||||
ifneq ($(USE_ADC),)
|
||||
CSRC += $(CHOPSTX)/contrib/adc-$(CHIP).c
|
||||
@@ -19,10 +23,14 @@ endif
|
||||
INCDIR += $(CHOPSTX)
|
||||
|
||||
BUILDDIR = build
|
||||
ifeq ($(EMULATION),)
|
||||
OUTFILES = $(BUILDDIR)/$(PROJECT).elf $(BUILDDIR)/$(PROJECT).bin
|
||||
ifneq ($(ENABLE_OUTPUT_HEX),)
|
||||
OUTFILES += $(BUILDDIR)/$(PROJECT).hex
|
||||
endif
|
||||
else
|
||||
OUTFILES = $(BUILDDIR)/$(PROJECT)
|
||||
endif
|
||||
|
||||
|
||||
OPT += -ffunction-sections -fdata-sections -fno-common
|
||||
@@ -34,14 +42,23 @@ LLIBDIR = $(patsubst %,-L%,$(LIBDIR))
|
||||
|
||||
VPATH = $(sort $(dir $(CSRC)))
|
||||
###
|
||||
ifeq ($(EMULATION),)
|
||||
MCFLAGS = -mcpu=$(MCU)
|
||||
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) \
|
||||
-Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections
|
||||
else
|
||||
MCFLAGS =
|
||||
LDFLAGS =
|
||||
DEFS += -D_GNU_SOURCE
|
||||
endif
|
||||
|
||||
CFLAGS = $(MCFLAGS) $(OPT) $(CWARN) -Wa,-alms=$(BUILDDIR)/$(notdir $(<:.c=.lst)) $(DEFS)
|
||||
LDFLAGS += $(LLIBDIR)
|
||||
|
||||
LDFLAGS = $(MCFLAGS) -nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(BUILDDIR)/$(PROJECT).map,--cref,--no-warn-mismatch,--gc-sections $(LLIBDIR)
|
||||
|
||||
ifeq ($(EMULATION),)
|
||||
CFLAGS += -mthumb -mno-thumb-interwork -DTHUMB
|
||||
LDFLAGS += -mthumb -mno-thumb-interwork
|
||||
endif
|
||||
|
||||
CFLAGS += -MD -MP -MF .dep/$(@F).d
|
||||
|
||||
@@ -56,6 +73,7 @@ $(OBJS) : $(BUILDDIR)/%.o : %.c Makefile
|
||||
@echo
|
||||
$(CC) -c $(CFLAGS) -I. $(IINCDIR) $< -o $@
|
||||
|
||||
ifeq ($(EMULATION),)
|
||||
%.elf: $(OBJS) $(OBJS_ADD) $(LDSCRIPT)
|
||||
@echo
|
||||
$(LD) $(OBJS) $(OBJS_ADD) $(LDFLAGS) $(LIBS) -o $@
|
||||
@@ -65,6 +83,11 @@ $(OBJS) : $(BUILDDIR)/%.o : %.c Makefile
|
||||
|
||||
%.hex: %.elf $(LDSCRIPT)
|
||||
$(OBJCOPY) -O ihex $< $@
|
||||
else
|
||||
$(BUILDDIR)/$(PROJECT): $(OBJS) $(OBJS_ADD)
|
||||
@echo
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(OBJS_ADD) $(LIBS)
|
||||
endif
|
||||
|
||||
clean:
|
||||
-rm -f -r .dep $(BUILDDIR)
|
||||
|
||||
@@ -134,12 +134,19 @@ uint8_t usb_lld_current_configuration (struct usb_dev *dev);
|
||||
void usb_lld_prepare_shutdown (void);
|
||||
void usb_lld_shutdown (void);
|
||||
|
||||
#ifdef MCU_KINETIS_L
|
||||
#if defined(MCU_KINETIS_L)
|
||||
void usb_lld_tx_enable_buf (int ep_num, const void *buf, size_t len);
|
||||
void usb_lld_rx_enable_buf (int ep_num, void *buf, size_t len);
|
||||
|
||||
void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
|
||||
void usb_lld_stall (int ep_num);
|
||||
#elif defined(GNU_LINUX_EMULATION)
|
||||
void usb_lld_tx_enable_buf (int ep_num, const void *buf, size_t len);
|
||||
void usb_lld_rx_enable_buf (int ep_num, void *buf, size_t len);
|
||||
|
||||
void usb_lld_setup_endp (struct usb_dev *dev, int ep_num, int rx_en, int tx_en);
|
||||
void usb_lld_stall_tx (int ep_num);
|
||||
void usb_lld_stall_rx (int ep_num);
|
||||
#else
|
||||
/* EP_TYPE[1:0] EndPoint TYPE */
|
||||
#define EP_BULK (0x0000) /* EndPoint BULK */
|
||||
|
||||
37
usb_lld_driver.h
Normal file
37
usb_lld_driver.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
|
||||
|
||||
enum STANDARD_REQUESTS
|
||||
{
|
||||
GET_STATUS = 0,
|
||||
CLEAR_FEATURE,
|
||||
RESERVED1,
|
||||
SET_FEATURE,
|
||||
RESERVED2,
|
||||
SET_ADDRESS,
|
||||
GET_DESCRIPTOR,
|
||||
SET_DESCRIPTOR,
|
||||
GET_CONFIGURATION,
|
||||
SET_CONFIGURATION,
|
||||
GET_INTERFACE,
|
||||
SET_INTERFACE,
|
||||
SYNCH_FRAME,
|
||||
TOTAL_REQUEST /* Total number of Standard request */
|
||||
};
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
};
|
||||
|
||||
enum FEATURE_SELECTOR
|
||||
{
|
||||
FEATURE_ENDPOINT_HALT=0,
|
||||
FEATURE_DEVICE_REMOTE_WAKEUP=1
|
||||
};
|
||||
Reference in New Issue
Block a user