Completes simulated uart implementation... does not work
This commit is contained in:
parent
9e6b07c1b5
commit
a982ff5795
@ -46,7 +46,7 @@ CSRCS += up_unblocktask.c up_blocktask.c up_releasepending.c
|
||||
CSRCS += up_reprioritizertr.c up_exit.c up_schedulesigaction.c up_spiflash.c
|
||||
CSRCS += up_allocateheap.c up_devconsole.c up_uartwait.c
|
||||
|
||||
HOSTSRCS = up_stdio.c up_hostusleep.c up_simuart.c
|
||||
HOSTSRCS = up_hostusleep.c up_simuart.c
|
||||
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CSRCS += up_tickless.c
|
||||
@ -100,9 +100,6 @@ OBJS = $(AOBJS) $(COBJS) $(HOSTOBJS)
|
||||
|
||||
ifeq ($(CONFIG_SIM_X11FB),y)
|
||||
STDLIBS += -lX11 -lXext
|
||||
ifeq ($(CONFIG_SIM_TOUCHSCREEN),y)
|
||||
STDLIBS += -lpthread
|
||||
endif
|
||||
endif
|
||||
|
||||
EXTRA_LIBS ?=
|
||||
@ -113,6 +110,7 @@ STDLIBS += -lz
|
||||
endif
|
||||
|
||||
STDLIBS += -lc
|
||||
STDLIBS += -lpthread
|
||||
|
||||
# Determine which objects are required in the link. The
|
||||
# up_head object normally draws in all that is needed, but
|
||||
@ -120,11 +118,11 @@ STDLIBS += -lc
|
||||
# are called only from the host OS-specific logic (HOSTOBJS)
|
||||
|
||||
LINKOBJS = up_head$(OBJEXT)
|
||||
REQUIREDOBJS = $(LINKOBJS)
|
||||
REQUIREDOBJS = $(LINKOBJS) up_uartwait$(OBJEXT)
|
||||
|
||||
ifeq ($(CONFIG_SIM_X11FB),y)
|
||||
ifeq ($(CONFIG_SIM_TOUCHSCREEN),y)
|
||||
REQUIREDOBJS += up_touchscreen.o
|
||||
REQUIREDOBJS += up_touchscreen$(OBJEXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1,36 +1,37 @@
|
||||
calloc NXcalloc
|
||||
close NXclose
|
||||
closedir NXclosedir
|
||||
dup NXdup
|
||||
free NXfree
|
||||
fclose NXfclose
|
||||
fopen NXfopen
|
||||
fputc NXfputc
|
||||
fread NXfread
|
||||
fwrite NXfwrite
|
||||
fsync NXfsync
|
||||
gettimeofday NXgettimeofday
|
||||
ioctl NXioctl
|
||||
lseek NXlseek
|
||||
malloc NXmalloc
|
||||
malloc_init NXmalloc_init
|
||||
mkdir NXmkdir
|
||||
mount NXmount
|
||||
open NXopen
|
||||
opendir NXopendir
|
||||
read NXread
|
||||
realloc NXrealloc
|
||||
rewinddir NXrewinddir
|
||||
rmdir NXrmdir
|
||||
seekdir NXseekdir
|
||||
select NXselect
|
||||
sleep NXsleep
|
||||
socket NXsocket
|
||||
stat NXstat
|
||||
statfs NXstatfs
|
||||
system NXsystem
|
||||
umount NXumount
|
||||
unlink NXunlink
|
||||
usleep NXusleep
|
||||
write NXwrite
|
||||
zmalloc NXzmalloc
|
||||
calloc NXcalloc
|
||||
close NXclose
|
||||
closedir NXclosedir
|
||||
dup NXdup
|
||||
free NXfree
|
||||
fclose NXfclose
|
||||
fopen NXfopen
|
||||
fputc NXfputc
|
||||
fread NXfread
|
||||
fwrite NXfwrite
|
||||
fsync NXfsync
|
||||
gettimeofday NXgettimeofday
|
||||
ioctl NXioctl
|
||||
lseek NXlseek
|
||||
malloc NXmalloc
|
||||
malloc_init NXmalloc_init
|
||||
mkdir NXmkdir
|
||||
mount NXmount
|
||||
open NXopen
|
||||
opendir NXopendir
|
||||
pthread_create NXpthread_create
|
||||
read NXread
|
||||
realloc NXrealloc
|
||||
rewinddir NXrewinddir
|
||||
rmdir NXrmdir
|
||||
seekdir NXseekdir
|
||||
select NXselect
|
||||
sleep NXsleep
|
||||
socket NXsocket
|
||||
stat NXstat
|
||||
statfs NXstatfs
|
||||
system NXsystem
|
||||
umount NXumount
|
||||
unlink NXunlink
|
||||
usleep NXusleep
|
||||
write NXwrite
|
||||
zmalloc NXzmalloc
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**************************************************************************
|
||||
* sim.h
|
||||
* arch/sim/src/sim.h
|
||||
*
|
||||
* Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
@ -77,12 +77,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Simulated console UART input buffer size */
|
||||
|
||||
#ifndef CONFIG_SIM_UART_BUFSIZE
|
||||
# define CONFIG_SIM_UART_BUFSIZE 256
|
||||
#endif
|
||||
|
||||
/* Determine which device to use as the system logging device */
|
||||
|
||||
#ifndef CONFIG_SYSLOG
|
||||
@ -150,12 +144,6 @@ extern volatile int g_eventloop;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* up_simuart.c ***********************************************************/
|
||||
|
||||
extern char g_uartbuffer[CONFIG_SIM_UART_BUFSIZE];
|
||||
extern volatile int g_uarthead;
|
||||
extern volatile int g_uarttail;
|
||||
|
||||
/**************************************************************************
|
||||
* Public Function Prototypes
|
||||
**************************************************************************/
|
||||
@ -178,30 +166,27 @@ void up_registerblockdevice(void);
|
||||
|
||||
/* up_simuart.c ***********************************************************/
|
||||
|
||||
void *up_simuart(void *arg);
|
||||
void simuart_start(void);
|
||||
int simuart_putc(int ch);
|
||||
int simuart_getc(void);
|
||||
|
||||
/* up_uartwait.c **********************************************************/
|
||||
|
||||
void uart_wait_initialize(void);
|
||||
void up_simuart_post(void);
|
||||
void up_simuart_wait(void);
|
||||
void simuart_initialize(void);
|
||||
void simuart_post(void);
|
||||
void simuart_wait(void);
|
||||
|
||||
/* up_deviceimage.c *******************************************************/
|
||||
|
||||
char *up_deviceimage(void);
|
||||
|
||||
/* up_stdio.c *************************************************************/
|
||||
|
||||
size_t up_hostread(void *buffer, size_t len);
|
||||
size_t up_hostwrite(const void *buffer, size_t len);
|
||||
|
||||
/* up_netdev.c ************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
unsigned long up_getwalltime( void );
|
||||
#endif
|
||||
|
||||
/* up_x11framebuffer.c ******************************************************/
|
||||
/* up_x11framebuffer.c ****************************************************/
|
||||
|
||||
#ifdef CONFIG_SIM_X11FB
|
||||
int up_x11initialize(unsigned short width, unsigned short height,
|
||||
@ -214,13 +199,13 @@ int up_x11cmap(unsigned short first, unsigned short len,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* up_eventloop.c ***********************************************************/
|
||||
/* up_eventloop.c *********************************************************/
|
||||
|
||||
#if defined(CONFIG_SIM_X11FB) && defined(CONFIG_SIM_TOUCHSCREEN)
|
||||
void up_x11events(void);
|
||||
#endif
|
||||
|
||||
/* up_eventloop.c ***********************************************************/
|
||||
/* up_eventloop.c *********************************************************/
|
||||
|
||||
#if defined(CONFIG_SIM_X11FB) && defined(CONFIG_SIM_TOUCHSCREEN)
|
||||
int up_buttonevent(int x, int y, int buttons);
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
|
||||
@ -78,16 +79,60 @@ static const struct file_operations devconsole_fops =
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devconsole_read
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t devconsole_read(struct file *filep, char *buffer, size_t len)
|
||||
{
|
||||
return up_hostread(buffer, len);
|
||||
size_t remaining = len;
|
||||
int ch;
|
||||
|
||||
/* Loop until all requested bytes have been read. No error checking */
|
||||
|
||||
for (remaining = len; remaining > 0; remaining--)
|
||||
{
|
||||
ch = simuart_getc();
|
||||
if (ch < 0)
|
||||
{
|
||||
set_errno(EIO);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
*buffer++ = ch;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devconsole_write
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t devconsole_write(struct file *filep, const char *buffer, size_t len)
|
||||
{
|
||||
return up_hostwrite(buffer, len);
|
||||
int remaining;
|
||||
int ret = OK;
|
||||
|
||||
for (remaining = len; remaining > 0 && ret >= 0; remaining--)
|
||||
{
|
||||
unsigned char ch = *buffer++;
|
||||
ret = simuart_putc((int)ch);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
set_errno(EIO);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devconsole_poll
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
bool setup)
|
||||
@ -100,7 +145,23 @@ static int devconsole_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_devconsole
|
||||
****************************************************************************/
|
||||
|
||||
void up_devconsole(void)
|
||||
{
|
||||
(void)register_driver("/dev/console", &devconsole_fops, 0666, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_putc
|
||||
****************************************************************************/
|
||||
|
||||
int up_putc(int ch)
|
||||
{
|
||||
/* Just map to the host simuart_putc routine */
|
||||
|
||||
return simuart_putc(ch);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/up_initialize.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2013 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2011-2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -122,9 +122,8 @@ void up_initialize(void)
|
||||
syslog("SIM: Initializing");
|
||||
#endif
|
||||
|
||||
/* Register devices */
|
||||
|
||||
#if CONFIG_NFILE_DESCRIPTORS > 0
|
||||
/* Register devices */
|
||||
|
||||
#if defined(CONFIG_DEV_NULL)
|
||||
devnull_register(); /* Standard /dev/null */
|
||||
@ -136,9 +135,13 @@ void up_initialize(void)
|
||||
|
||||
#endif /* CONFIG_NFILE_DESCRIPTORS */
|
||||
|
||||
#if defined(USE_DEVCONSOLE)
|
||||
/* Start the sumulated UART device */
|
||||
|
||||
simuart_start();
|
||||
|
||||
/* Register a console (or not) */
|
||||
|
||||
#if defined(USE_DEVCONSOLE)
|
||||
up_devconsole(); /* Our private /dev/console */
|
||||
#elif defined(CONFIG_RAMLOG_CONSOLE)
|
||||
ramlog_consoleinit();
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/up_hostusleep.c
|
||||
* arch/sim/src/up_simuart.c
|
||||
*
|
||||
* Copyright (C) 2008 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -39,24 +39,26 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "sim.h"
|
||||
#include "host.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Simulated console UART input buffer size */
|
||||
/* Must match the defintion in sim.h */
|
||||
|
||||
#define SIMUART_BUFSIZE 256
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
char g_uartbuffer[CONFIG_SIM_UART_BUFSIZE];
|
||||
volatile int g_uarthead;
|
||||
volatile int g_uarttail;
|
||||
static char g_uartbuffer[SIMUART_BUFSIZE];
|
||||
static volatile int g_uarthead;
|
||||
static volatile int g_uarttail;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -82,23 +84,14 @@ static void setrawmode(void)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
* Name: simuart_thread
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_simuart
|
||||
****************************************************************************/
|
||||
|
||||
void *up_simuart(void *arg)
|
||||
static void *simuart_thread(void *arg)
|
||||
{
|
||||
unsigned char ch;
|
||||
ssize_t nread;
|
||||
|
||||
/* This thread runs in the host domain */
|
||||
/* Initialize the NuttX domain semaphore */
|
||||
|
||||
uart_wait_initialize();
|
||||
|
||||
/* Put stdin into raw mode */
|
||||
|
||||
setrawmode();
|
||||
@ -109,7 +102,7 @@ void *up_simuart(void *arg)
|
||||
{
|
||||
/* Read one character from stdin */
|
||||
|
||||
nread = read(0, ch, 1);
|
||||
nread = read(0, &ch, 1);
|
||||
|
||||
/* Check for failures (but don't do anything) */
|
||||
|
||||
@ -118,7 +111,7 @@ void *up_simuart(void *arg)
|
||||
/* Get the index to the next slot in the UART buffer */
|
||||
|
||||
int next = g_uarthead + 1;
|
||||
if (next >= CONFIG_SIM_UART_BUFSIZE)
|
||||
if (next >= SIMUART_BUFSIZE)
|
||||
{
|
||||
next = 0;
|
||||
}
|
||||
@ -139,7 +132,7 @@ void *up_simuart(void *arg)
|
||||
* input.
|
||||
*/
|
||||
|
||||
up_simuart_post();
|
||||
simuart_post();
|
||||
}
|
||||
|
||||
/* Update the head index */
|
||||
@ -151,3 +144,102 @@ void *up_simuart(void *arg)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: simuart_putraw
|
||||
****************************************************************************/
|
||||
|
||||
int simuart_putraw(int ch)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
|
||||
nwritten = write(1, &ch, 1);
|
||||
if (nwritten != 1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: simuart_start
|
||||
****************************************************************************/
|
||||
|
||||
void simuart_start(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/* This thread runs in the host domain */
|
||||
/* Perform the NuttX domain initialization */
|
||||
|
||||
simuart_initialize();
|
||||
|
||||
/* Start the simulated UART thread -- all default settings; no error
|
||||
* checking.
|
||||
*/
|
||||
|
||||
(void)pthread_create(&tid, NULL, simuart_thread, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: simuart_putc
|
||||
****************************************************************************/
|
||||
|
||||
int simuart_putc(int ch)
|
||||
{
|
||||
int ret = ch;
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
ret = simuart_putraw('\r');
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
ret = simuart_putraw(ch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: simuart_getc
|
||||
****************************************************************************/
|
||||
|
||||
int simuart_getc(void)
|
||||
{
|
||||
int index;
|
||||
int ch;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Wait for a byte to become available */
|
||||
|
||||
simuart_wait();
|
||||
|
||||
/* The UART buffer show be non-empty... check anyway */
|
||||
|
||||
if (g_uarthead == g_uarttail)
|
||||
{
|
||||
/* Take the next byte from the tail of the buffer */
|
||||
|
||||
index = g_uarttail;
|
||||
ch = (int)g_uartbuffer[index];
|
||||
|
||||
/* Increment the tai index (with wrapping) */
|
||||
|
||||
if (++index >= SIMUART_BUFSIZE)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
g_uarttail = index;
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/up_stdio.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
size_t up_hostread(void *buffer, size_t len)
|
||||
{
|
||||
/* Just map to the host fread() */
|
||||
|
||||
return fread(buffer, 1, len, stdin);
|
||||
}
|
||||
|
||||
size_t up_hostwrite(const void *buffer, size_t len)
|
||||
{
|
||||
/* Just map to the host fwrite() */
|
||||
|
||||
return fwrite(buffer, 1, len, stdout);
|
||||
}
|
||||
|
||||
int up_putc(int ch)
|
||||
{
|
||||
/* Just map to the host fputc routine */
|
||||
|
||||
return fputc(ch, stdout);
|
||||
}
|
||||
|
@ -64,31 +64,30 @@ static sem_t g_uartavail;
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: uart_wait_initialize
|
||||
* Name: simuart_initialize
|
||||
****************************************************************************/
|
||||
|
||||
void uart_wait_initialize(void)
|
||||
void simuart_initialize(void)
|
||||
{
|
||||
sem_init(&g_uartavail, 0, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_simuart_post
|
||||
* Name: simuart_post
|
||||
****************************************************************************/
|
||||
|
||||
void up_simuart_post(void)
|
||||
void simuart_post(void)
|
||||
{
|
||||
sem_post(&g_uartavail);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_simuart_wait
|
||||
* Name: simuart_wait
|
||||
****************************************************************************/
|
||||
|
||||
void up_simuart_wait(void)
|
||||
void simuart_wait(void)
|
||||
{
|
||||
while (g_uarthead == g_uarttail)
|
||||
{
|
||||
(void)sem_wait(&g_uartavail);
|
||||
}
|
||||
/* Should only fail if interrupted by a signal */
|
||||
|
||||
while (sem_wait(&g_uartavail) < 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user