Compare commits
11 Commits
release/1.
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6b96fe434 | ||
|
|
c5a83cb9a5 | ||
|
|
8f20122e54 | ||
|
|
c31a91947d | ||
|
|
71cc5a8f32 | ||
|
|
73d6c13d15 | ||
|
|
d43fbb140a | ||
|
|
9b822282f0 | ||
|
|
91ddc8fd02 | ||
|
|
0698bc4c9e | ||
|
|
7dda49eb40 |
35
ChangeLog
35
ChangeLog
@@ -1,3 +1,33 @@
|
|||||||
|
2021-10-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.20.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.20.
|
||||||
|
|
||||||
|
2021-10-11 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
Backport from master.
|
||||||
|
* mcu/usb-usbip.c (URB_DATA_SIZE): Tweak the value.
|
||||||
|
|
||||||
|
2021-02-18 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* VERSION: 1.19.
|
||||||
|
* doc/chopstx.texi (VERSION): 1.19.
|
||||||
|
|
||||||
|
2021-02-17 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
Backport from master.
|
||||||
|
* contrib/ackbtn-gnu-linux.c: New.
|
||||||
|
* mcu/usb-usbip.c (usbip_run_server): Add start-up message.
|
||||||
|
* contrib/adc-gnu-linux.c (adc_start_conversion): Use getrandom.
|
||||||
|
|
||||||
|
2021-02-12 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
Backport from 2.1.
|
||||||
|
* chopstx-gnu-linux.c (chopstx_create_arch): Clear TP.
|
||||||
|
* example-cdc-gnu-linux/usb-cdc.c (tty_recv): Cancel the input.
|
||||||
|
* example-cdc-gnu-linux/sample.c (main): Handle timeout by canceling
|
||||||
|
input.
|
||||||
|
|
||||||
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
|
2019-12-30 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* VERSION: 1.18.
|
* VERSION: 1.18.
|
||||||
@@ -8,11 +38,6 @@
|
|||||||
* chopstx.c (chopstx_poll): Call CHECK for condition
|
* chopstx.c (chopstx_poll): Call CHECK for condition
|
||||||
valiable after woken up.
|
valiable after woken up.
|
||||||
|
|
||||||
2019-12-20 NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
|
|
||||||
* mcu/usb-st-common.c (usb_lld_ctrl_recv): Fix receiving
|
|
||||||
more than one packet.
|
|
||||||
|
|
||||||
2019-12-04 NIIBE Yutaka <gniibe@fsij.org>
|
2019-12-04 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* chopstx-gnu-linux.c (chx_thread_start): Fix return value.
|
* chopstx-gnu-linux.c (chx_thread_start): Fix return value.
|
||||||
|
|||||||
29
NEWS
29
NEWS
@@ -1,6 +1,35 @@
|
|||||||
NEWS - Noteworthy changes
|
NEWS - Noteworthy changes
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.20
|
||||||
|
|
||||||
|
Released 2021-10-12
|
||||||
|
|
||||||
|
** Fix of USB driver for GNU/Linux emulation
|
||||||
|
|
||||||
|
Fix the value of URB_DATA_SIZE, so that Gnuk can work with PC/SC.
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 1.19
|
||||||
|
|
||||||
|
Released 2021-02-18
|
||||||
|
|
||||||
|
** Acknowledge button support for GNU/Linux emulation
|
||||||
|
User is asked acknowledge by RET with standard input.
|
||||||
|
|
||||||
|
** USB driver for GNU/Linux emulation
|
||||||
|
It shows start-up message now.
|
||||||
|
|
||||||
|
** ADC driver for GNU/Linux emulation
|
||||||
|
It uses getrandom(2), output is not deterministic any more.
|
||||||
|
|
||||||
|
** Bug fix for GNU/Linux emulation
|
||||||
|
When creating a thread, allocated memory for struct chx_thread was not
|
||||||
|
initialized by chopstx_create_arch, assuming getcontext does it well.
|
||||||
|
To make sure (getcontext would not update the area for FPU registers,
|
||||||
|
when not used), it's now initialized by zeros.
|
||||||
|
|
||||||
|
|
||||||
* Major changes in Chopstx 1.18
|
* Major changes in Chopstx 1.18
|
||||||
|
|
||||||
Released 2019-12-30
|
Released 2019-12-30
|
||||||
|
|||||||
16
README
16
README
@@ -1,6 +1,6 @@
|
|||||||
Chopstx - Threads and only Threads
|
Chopstx - Threads and only Threads
|
||||||
Version 1.18
|
Version 1.20
|
||||||
2019-12-30
|
2021-10-12
|
||||||
Niibe Yutaka
|
Niibe Yutaka
|
||||||
Flying Stone Technology
|
Flying Stone Technology
|
||||||
|
|
||||||
@@ -60,14 +60,6 @@ For STM32 Primer2, see the directory: example-primer2.
|
|||||||
Future Works
|
Future Works
|
||||||
============
|
============
|
||||||
|
|
||||||
RISC-V port (for GD32VF103) is under development. Please have a look
|
RISC-V port (for GD32VF103) is available in 2.x. Please have a look
|
||||||
at the master branch.
|
at the master branch, and test it if possible.
|
||||||
|
|
||||||
Convenience function to determine the bottom of thread stack,
|
|
||||||
configuration of thread size by compiler's output would be next things
|
|
||||||
to be done.
|
|
||||||
|
|
||||||
Experimental SMP port for Cortex-A7 is under development. For SMP,
|
|
||||||
more careful considerations for shared access to objects of struct
|
|
||||||
chx_pq is needed. So, modifications required will not be small.
|
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
* chopstx-gnu-linux.c - Threads and only threads: Arch specific code
|
||||||
* for GNU/Linux emulation
|
* for GNU/Linux emulation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017, 2018, 2019 Flying Stone Technology
|
* Copyright (C) 2017, 2018, 2019, 2021 Flying Stone Technology
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Chopstx, a thread library for embedded.
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
@@ -349,6 +349,7 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
|||||||
* signal blocked. The sigmask will be cleared in chx_thread_start.
|
* signal blocked. The sigmask will be cleared in chx_thread_start.
|
||||||
*/
|
*/
|
||||||
chx_cpu_sched_lock ();
|
chx_cpu_sched_lock ();
|
||||||
|
memset (tp, 0, sizeof (struct chx_thread));
|
||||||
getcontext (&tp->tc);
|
getcontext (&tp->tc);
|
||||||
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
|
tp->tc.uc_stack.ss_sp = (void *)stack_addr;
|
||||||
tp->tc.uc_stack.ss_size = stack_size;
|
tp->tc.uc_stack.ss_size = stack_size;
|
||||||
|
|||||||
232
contrib/ackbtn-gnu-linux.c
Normal file
232
contrib/ackbtn-gnu-linux.c
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* ackbtn-gnu-linux.c - Acknowledge button support for GNU/Linux
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Free Software Initiative of Japan
|
||||||
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
*
|
||||||
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
|
*
|
||||||
|
* Chopstx is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Chopstx is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As additional permission under GNU GPL version 3 section 7, you may
|
||||||
|
* distribute non-source form of the Program without the copy of the
|
||||||
|
* GNU GPL normally required by section 4, provided you inform the
|
||||||
|
* recipients of GNU GPL by a written offer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <chopstx.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static pthread_t tid_main;
|
||||||
|
static pthread_t tid_ui;
|
||||||
|
|
||||||
|
static pthread_mutex_t mutex;
|
||||||
|
static pthread_cond_t cond;
|
||||||
|
static int enabled;
|
||||||
|
static int event_fd;
|
||||||
|
|
||||||
|
static void
|
||||||
|
ackbtn_intr (int signum, siginfo_t *siginfo, void *arg)
|
||||||
|
{
|
||||||
|
extern void chx_sigmask (ucontext_t *uc);
|
||||||
|
extern void chx_handle_intr (int signum);
|
||||||
|
|
||||||
|
ucontext_t *uc = arg;
|
||||||
|
(void)signum;
|
||||||
|
(void)siginfo;
|
||||||
|
chx_handle_intr (SIGUSR2);
|
||||||
|
chx_sigmask (uc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ACKBTN_ACKED (1 << 0)
|
||||||
|
#define ACKBTN_TIMEOUT (1 << 2)
|
||||||
|
|
||||||
|
static void *
|
||||||
|
user_interaction (void *arg)
|
||||||
|
{
|
||||||
|
struct pollfd pollfds[2];
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
pollfds[0].fd = 0; /* standard input */
|
||||||
|
pollfds[0].events = POLLIN;
|
||||||
|
|
||||||
|
pollfds[1].fd = event_fd;
|
||||||
|
pollfds[1].events = POLLIN;
|
||||||
|
|
||||||
|
fputs ("User interaction thread for AckBtn started.\n", stdout);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
unsigned int acked_or_timeout = 0;
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
while (!enabled)
|
||||||
|
pthread_cond_wait (&cond, &mutex);
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
|
||||||
|
/* Consume all input if any. */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
pollfds[0].revents = 0;
|
||||||
|
|
||||||
|
r = poll (pollfds, 1, 0);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror ("poll");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((pollfds[0].revents & POLLIN))
|
||||||
|
read (0, buf, sizeof buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs ("Type RET to acknowledge (or wait for timeout) > ", stdout);
|
||||||
|
fflush (stdout);
|
||||||
|
|
||||||
|
while (!acked_or_timeout)
|
||||||
|
{
|
||||||
|
pollfds[0].revents = 0;
|
||||||
|
pollfds[1].revents = 0;
|
||||||
|
|
||||||
|
if (poll (pollfds, 2, -1) < 0)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror ("poll");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pollfds[0].revents & POLLIN))
|
||||||
|
{
|
||||||
|
read (0, buf, sizeof buf);
|
||||||
|
acked_or_timeout |= ACKBTN_ACKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pollfds[1].revents & POLLIN))
|
||||||
|
acked_or_timeout |= ACKBTN_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
if ((acked_or_timeout & ACKBTN_ACKED))
|
||||||
|
{
|
||||||
|
if ((acked_or_timeout & ACKBTN_TIMEOUT))
|
||||||
|
/* No output of newline, as it follows timeout message. */
|
||||||
|
fputs ("Input ignored", stdout);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_kill (tid_main, SIGUSR2);
|
||||||
|
fputs ("Acknowledged\n", stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((acked_or_timeout & ACKBTN_TIMEOUT))
|
||||||
|
fputs ("\nTimeout\n", stdout);
|
||||||
|
|
||||||
|
while (enabled)
|
||||||
|
pthread_cond_wait (&cond, &mutex);
|
||||||
|
|
||||||
|
read (event_fd, buf, sizeof (uint64_t));
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_init (chopstx_intr_t *intr)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
sigset_t sigset;
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
|
event_fd = eventfd (0, EFD_CLOEXEC);
|
||||||
|
if (event_fd < 0)
|
||||||
|
{
|
||||||
|
perror ("eventfd");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_init (&mutex, NULL);
|
||||||
|
pthread_cond_init (&cond, NULL);
|
||||||
|
enabled = 0;
|
||||||
|
|
||||||
|
sigemptyset (&sigset);
|
||||||
|
sigaddset (&sigset, SIGUSR2);
|
||||||
|
sigaddset (&sigset, SIGALRM);
|
||||||
|
|
||||||
|
tid_main = pthread_self ();
|
||||||
|
|
||||||
|
/* Launch the thread for user interaction. */
|
||||||
|
pthread_sigmask (SIG_BLOCK, &sigset, NULL);
|
||||||
|
|
||||||
|
r = pthread_create (&tid_ui, NULL, user_interaction, NULL);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "ackbtn_init: %s\n", strerror (r));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
act.sa_sigaction = ackbtn_intr;
|
||||||
|
sigfillset (&act.sa_mask);
|
||||||
|
act.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||||
|
sigaction (SIGUSR2, &act, NULL);
|
||||||
|
|
||||||
|
pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
|
||||||
|
|
||||||
|
chopstx_claim_irq (intr, SIGUSR2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_enable (void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
enabled = 1;
|
||||||
|
pthread_cond_signal (&cond);
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ackbtn_disable (void)
|
||||||
|
{
|
||||||
|
const uint64_t l = 1;
|
||||||
|
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
enabled = 0;
|
||||||
|
write (event_fd, &l, sizeof (l));
|
||||||
|
pthread_cond_signal (&cond);
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* This ADC driver just fills pseudo random values.
|
* This ADC driver just fills pseudo random values.
|
||||||
* It's completely useless other than for NeuG.
|
* It's completely useless other than for NeuG.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Free Software Initiative of Japan
|
* Copyright (C) 2017, 2021 Free Software Initiative of Japan
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Chopstx, a thread library for embedded.
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#include <chopstx.h>
|
#include <chopstx.h>
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
|
|
||||||
#define ADC_RANDOM_SEED 0x01034649 /* "Hello, father!" in Japanese */
|
#include <sys/random.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do calibration for ADC.
|
* Do calibration for ADC.
|
||||||
@@ -41,7 +41,6 @@
|
|||||||
int
|
int
|
||||||
adc_init (void)
|
adc_init (void)
|
||||||
{
|
{
|
||||||
srandom (ADC_RANDOM_SEED);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +54,7 @@ uint32_t adc_buf[64];
|
|||||||
void
|
void
|
||||||
adc_start_conversion (int offset, int count)
|
adc_start_conversion (int offset, int count)
|
||||||
{
|
{
|
||||||
while (count--)
|
getrandom (adc_buf+offset, count, 0);
|
||||||
adc_buf[offset++] = random ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
\input texinfo @c -*-texinfo-*-
|
\input texinfo @c -*-texinfo-*-
|
||||||
@c %**start of header
|
@c %**start of header
|
||||||
@setfilename chopstx.info
|
@setfilename chopstx.info
|
||||||
@set VERSION 1.18
|
@set VERSION 1.20
|
||||||
@settitle Chopstx Reference Manual
|
@settitle Chopstx Reference Manual
|
||||||
@c Unify some of the indices.
|
@c Unify some of the indices.
|
||||||
@syncodeindex tp fn
|
@syncodeindex tp fn
|
||||||
|
|||||||
@@ -179,7 +179,14 @@ main (int argc, const char *argv[])
|
|||||||
if (size < 0)
|
if (size < 0)
|
||||||
goto connection_loop;
|
goto connection_loop;
|
||||||
|
|
||||||
if (size == 1)
|
if (size == 0)
|
||||||
|
/* Timeout */
|
||||||
|
{
|
||||||
|
if (tty_send (tty, "\r\n", 2) < 0)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (size == 1)
|
||||||
/* Do nothing but prompt again. */
|
/* Do nothing but prompt again. */
|
||||||
break;
|
break;
|
||||||
else if (size)
|
else if (size)
|
||||||
|
|||||||
@@ -904,8 +904,18 @@ tty_recv (struct tty *t, char *buf, uint32_t *timeout)
|
|||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
r = check_rx (t);
|
r = check_rx (t);
|
||||||
chopstx_mutex_unlock (&t->mtx);
|
chopstx_mutex_unlock (&t->mtx);
|
||||||
if (r || (timeout != NULL && *timeout == 0))
|
if (r)
|
||||||
break;
|
break;
|
||||||
|
else if (timeout != NULL && *timeout == 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Cancel the input. */
|
||||||
|
for (i = 0; i < t->inputline_len; i++)
|
||||||
|
tty_send (t, "\x08\x20\x08", 3);
|
||||||
|
t->inputline_len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chopstx_mutex_lock (&t->mtx);
|
chopstx_mutex_lock (&t->mtx);
|
||||||
|
|||||||
@@ -864,8 +864,6 @@ usb_lld_ctrl_recv (struct usb_dev *dev, void *p, size_t len)
|
|||||||
struct ctrl_data *data_p = &dev->ctrl_data;
|
struct ctrl_data *data_p = &dev->ctrl_data;
|
||||||
data_p->addr = p;
|
data_p->addr = p;
|
||||||
data_p->len = len;
|
data_p->len = len;
|
||||||
if (len > USB_MAX_PACKET_SIZE)
|
|
||||||
len = USB_MAX_PACKET_SIZE;
|
|
||||||
dev->state = OUT_DATA;
|
dev->state = OUT_DATA;
|
||||||
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
ep_set_rx_status (ENDP0, EP_RX_VALID);
|
||||||
return USB_EVENT_OK;
|
return USB_EVENT_OK;
|
||||||
|
|||||||
133
mcu/usb-usbip.c
133
mcu/usb-usbip.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* usb-usbip.c - USB Device Emulation (server side) by USBIP
|
* usb-usbip.c - USB Device Emulation (server side) by USBIP
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017, 2018 g10 Code GmbH
|
* Copyright (C) 2017, 2018, 2021 g10 Code GmbH
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||||
*
|
*
|
||||||
* This file is a part of Chopstx, a thread library for embedded.
|
* This file is a part of Chopstx, a thread library for embedded.
|
||||||
@@ -22,10 +22,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME:
|
* This driver is intended to emulate USB full-speed device, which
|
||||||
RESET handling
|
* maximum packet size is 64.
|
||||||
USB Shutdown
|
*
|
||||||
Use reply structure of its own
|
* "USBIP" is actually URB over network (instead of USB packet over
|
||||||
|
* network), and its (current) naive protocol may expose possible
|
||||||
|
* demarcation problem, which never occurs in real host-device; In
|
||||||
|
* real host-device relationship, it is host side, which does
|
||||||
|
* composition/decomposition of URB to/from packets. In an
|
||||||
|
* implmentation of USB device with USBIP, it needs to be device side,
|
||||||
|
* which does composition/decomposition of URB to/from packets.
|
||||||
|
*
|
||||||
|
* In this implementation of USB driver, URB_DATA_SIZE is defined as
|
||||||
|
* (65544+10), because (major) target device intended is CCID. In the
|
||||||
|
* CCID specification, you can find the value 65544+10.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* FIXME:
|
||||||
|
* RESET handling
|
||||||
|
* USB Shutdown
|
||||||
|
* Use reply structure of its own
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@@ -96,7 +112,7 @@ struct urb {
|
|||||||
struct urb *next;
|
struct urb *next;
|
||||||
struct urb *prev;
|
struct urb *prev;
|
||||||
|
|
||||||
uint16_t remain;
|
uint32_t remain;
|
||||||
char *data_p;
|
char *data_p;
|
||||||
|
|
||||||
pthread_t tid;
|
pthread_t tid;
|
||||||
@@ -236,7 +252,67 @@ attach_device (char busid[32], size_t *len_p)
|
|||||||
return (const char *)&usbip_usb_device;
|
return (const char *)&usbip_usb_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define URB_DATA_SIZE 65535
|
/*
|
||||||
|
* The number 65544 comes from ISO 7816-4, which defines data format
|
||||||
|
* of smartcard; CLS INS P1 P2 occupies four octets. Then, Lc-octet
|
||||||
|
* to represent size of command data block, then command data block.
|
||||||
|
* Lastly, Le-octet to represent size of response data block to be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* /----- for CLS INS P1 P2
|
||||||
|
* |
|
||||||
|
* | /-- for Lc
|
||||||
|
* | |
|
||||||
|
* | | /-- for data block
|
||||||
|
* | | |
|
||||||
|
* | | | /-- for Le
|
||||||
|
* | | | |
|
||||||
|
* v v v v
|
||||||
|
* 4 + 3 + 65535 + 2 = 65544
|
||||||
|
*
|
||||||
|
* The number 10 comes from the CCID protocol specification; It is the
|
||||||
|
* header size of CCID. Besides, we can find the number 65544 in the
|
||||||
|
* CCID protocol specification, too.
|
||||||
|
*
|
||||||
|
* And... we have "AND ONE MORE" three times.
|
||||||
|
*
|
||||||
|
* We accept that, as Buddha did.
|
||||||
|
*
|
||||||
|
* There are different interpretations for the historical fact and the
|
||||||
|
* idiom. Most likely, nowadays, here, third-time is considered a
|
||||||
|
* strikeout, perhaps, due to popularity of baseball.
|
||||||
|
*/
|
||||||
|
#define URB_DATA_SIZE (65544+10+1+1+1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The reasons why there are "+1" three times.
|
||||||
|
*
|
||||||
|
* Wrong (1): +1, because of confusion of data size maximum.
|
||||||
|
* Wrong (2): +1, because of confusion of the size for Le.
|
||||||
|
* Wrong (3): +1, because of keeping applying old patch.
|
||||||
|
*
|
||||||
|
* Something like this may occur, unfortunately, in our world.
|
||||||
|
*
|
||||||
|
* We need to consider the real case of the max buffer size for
|
||||||
|
* libusb_bulk_transfer with CCID (let us call this "CASE_MAX").
|
||||||
|
*
|
||||||
|
* (1) Although the data size maximum (for all cases) is 65536, it
|
||||||
|
* only occurs when Le size is zero. In the particular case of
|
||||||
|
* CASE_MAX, it is actually 65535. When just applying the max value
|
||||||
|
* 65536, +1 occurs.
|
||||||
|
*
|
||||||
|
* (2) Although maximum size to represent Le is 3, it only occurs when
|
||||||
|
* Lc size is zero. In the particular case of CASE_MAX, it is
|
||||||
|
* actually 2. When just applying the max value 3, +1 occurs.
|
||||||
|
*
|
||||||
|
* (3) Fedora keeps a old patch for Ominikey 3121. The patch was
|
||||||
|
* written when the value of CMD_BUF_SIZE in libccid was small for
|
||||||
|
* short extended APDU exchange. In the patch, it uses the value 11
|
||||||
|
* for the header size (instead of 10) of TPDU, for its special
|
||||||
|
* support. Historically, CMD_BUF_SIZE in libccid was updated
|
||||||
|
* to bigger value to handle extended APDU exchange. When just applying
|
||||||
|
* the old patch using 11, +1 occurs.
|
||||||
|
*/
|
||||||
|
|
||||||
struct usbip_msg_cmd {
|
struct usbip_msg_cmd {
|
||||||
uint32_t devid;
|
uint32_t devid;
|
||||||
@@ -299,12 +375,14 @@ static int write_data_transaction (struct usb_control *usbc_p,
|
|||||||
static int read_data_transaction (struct usb_control *usbc_p,
|
static int read_data_transaction (struct usb_control *usbc_p,
|
||||||
int ep_num, char *buf, uint16_t count);
|
int ep_num, char *buf, uint16_t count);
|
||||||
|
|
||||||
|
#define USB_MAX_PACKET_SIZE 64 /* For USB fullspeed device. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hc_handle_control_urb (struct urb *urb)
|
hc_handle_control_urb (struct urb *urb)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
uint16_t remain = urb->len;
|
uint32_t remain = urb->len;
|
||||||
uint64_t l;
|
uint64_t l;
|
||||||
|
|
||||||
if ((debug & DEBUG_USB))
|
if ((debug & DEBUG_USB))
|
||||||
@@ -325,10 +403,10 @@ hc_handle_control_urb (struct urb *urb)
|
|||||||
|
|
||||||
while (r == 0)
|
while (r == 0)
|
||||||
{
|
{
|
||||||
if (remain > 64)
|
if (remain > USB_MAX_PACKET_SIZE)
|
||||||
count = 64;
|
count = USB_MAX_PACKET_SIZE;
|
||||||
else
|
else
|
||||||
count = remain;
|
count = (uint16_t)remain;
|
||||||
|
|
||||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||||
r = control_write_data_transaction (urb->data_p, count);
|
r = control_write_data_transaction (urb->data_p, count);
|
||||||
@@ -337,7 +415,7 @@ hc_handle_control_urb (struct urb *urb)
|
|||||||
|
|
||||||
urb->data_p += count;
|
urb->data_p += count;
|
||||||
remain -= count;
|
remain -= count;
|
||||||
if (count < 64)
|
if (count < USB_MAX_PACKET_SIZE)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
@@ -353,10 +431,10 @@ hc_handle_control_urb (struct urb *urb)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (remain > 64)
|
if (remain > USB_MAX_PACKET_SIZE)
|
||||||
count = 64;
|
count = USB_MAX_PACKET_SIZE;
|
||||||
else
|
else
|
||||||
count = remain;
|
count = (uint16_t)remain;
|
||||||
|
|
||||||
read (usbc_ep0.eventfd, &l, sizeof (l));
|
read (usbc_ep0.eventfd, &l, sizeof (l));
|
||||||
r = control_read_data_transaction (urb->data_p, count);
|
r = control_read_data_transaction (urb->data_p, count);
|
||||||
@@ -368,7 +446,7 @@ hc_handle_control_urb (struct urb *urb)
|
|||||||
|
|
||||||
remain -= r;
|
remain -= r;
|
||||||
urb->data_p += r;
|
urb->data_p += r;
|
||||||
if (r < 64)
|
if (r < USB_MAX_PACKET_SIZE)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,10 +594,10 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
|||||||
if ((debug & DEBUG_USB))
|
if ((debug & DEBUG_USB))
|
||||||
puts ("hc_hdu 0");
|
puts ("hc_hdu 0");
|
||||||
|
|
||||||
if (urb->remain > 64)
|
if (urb->remain > USB_MAX_PACKET_SIZE)
|
||||||
count = 64;
|
count = USB_MAX_PACKET_SIZE;
|
||||||
else
|
else
|
||||||
count = urb->remain;
|
count = (uint16_t)urb->remain;
|
||||||
|
|
||||||
if (urb->dir == USBIP_DIR_OUT)
|
if (urb->dir == USBIP_DIR_OUT)
|
||||||
{ /* Output from host to device. */
|
{ /* Output from host to device. */
|
||||||
@@ -533,7 +611,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
|||||||
urb->data_p += count;
|
urb->data_p += count;
|
||||||
urb->remain -= count;
|
urb->remain -= count;
|
||||||
|
|
||||||
if (urb->remain == 0 || count < 64)
|
if (urb->remain == 0 || count < USB_MAX_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
size_t len = urb->len - urb->remain;
|
size_t len = urb->len - urb->remain;
|
||||||
|
|
||||||
@@ -565,7 +643,7 @@ hc_handle_data_urb (struct usb_control *usbc_p)
|
|||||||
|
|
||||||
urb->remain -= r;
|
urb->remain -= r;
|
||||||
urb->data_p += r;
|
urb->data_p += r;
|
||||||
if (urb->remain == 0 || r < 64)
|
if (urb->remain == 0 || r < USB_MAX_PACKET_SIZE)
|
||||||
{
|
{
|
||||||
size_t len = urb->len - urb->remain;
|
size_t len = urb->len - urb->remain;
|
||||||
|
|
||||||
@@ -596,7 +674,7 @@ issue_get_desc (void)
|
|||||||
{
|
{
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
|
|
||||||
urb = malloc (sizeof (struct urb) + 64);
|
urb = malloc (sizeof (struct urb) + USB_MAX_PACKET_SIZE);
|
||||||
|
|
||||||
urb->next = urb->prev = urb;
|
urb->next = urb->prev = urb;
|
||||||
|
|
||||||
@@ -606,14 +684,14 @@ issue_get_desc (void)
|
|||||||
urb->setup[3] = 1; /* Value H: desc_type */
|
urb->setup[3] = 1; /* Value H: desc_type */
|
||||||
urb->setup[4] = 0; /* Index */
|
urb->setup[4] = 0; /* Index */
|
||||||
urb->setup[5] = 0;
|
urb->setup[5] = 0;
|
||||||
urb->setup[6] = 64; /* Length */
|
urb->setup[6] = USB_MAX_PACKET_SIZE; /* Length */
|
||||||
urb->setup[7] = 0;
|
urb->setup[7] = 0;
|
||||||
urb->data_p = urb->data;
|
urb->data_p = urb->data;
|
||||||
urb->seq = 0;
|
urb->seq = 0;
|
||||||
urb->devid = 0;
|
urb->devid = 0;
|
||||||
urb->dir = USBIP_DIR_IN;
|
urb->dir = USBIP_DIR_IN;
|
||||||
urb->ep = 0;
|
urb->ep = 0;
|
||||||
urb->remain = urb->len = 64;
|
urb->remain = urb->len = USB_MAX_PACKET_SIZE;
|
||||||
hc_handle_control_urb (urb);
|
hc_handle_control_urb (urb);
|
||||||
return urb;
|
return urb;
|
||||||
}
|
}
|
||||||
@@ -729,7 +807,7 @@ usbip_handle_urb (uint32_t seq)
|
|||||||
|
|
||||||
leave:
|
leave:
|
||||||
msg.cmd = htonl (REP_URB_SUBMIT);
|
msg.cmd = htonl (REP_URB_SUBMIT);
|
||||||
msg.seq = htonl (urb->seq);
|
msg.seq = htonl (seq);
|
||||||
|
|
||||||
memset (&msg_rep, 0, sizeof (msg_rep));
|
memset (&msg_rep, 0, sizeof (msg_rep));
|
||||||
msg_rep.status = htonl (r);
|
msg_rep.status = htonl (r);
|
||||||
@@ -1080,6 +1158,11 @@ usbip_run_server (void *arg)
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fputs ("USBIP thread started.\n", stdout);
|
||||||
|
fputs ("You can use this by attaching following commands:\n", stdout);
|
||||||
|
fputs (" # modprobe vhci_hcd\n", stdout);
|
||||||
|
fputs (" # usbip attach -r 127.0.0.1 -b 1-1\n", stdout);
|
||||||
|
|
||||||
pollfds[1].fd = shutdown_notify_fd;
|
pollfds[1].fd = shutdown_notify_fd;
|
||||||
pollfds[1].events = POLLIN;
|
pollfds[1].events = POLLIN;
|
||||||
pollfds[1].revents = 0;
|
pollfds[1].revents = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user