mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 00:45:22 +08:00
sync smart & dfs (#8672)
Signed-off-by: xqyjlj <xqyjlj@126.com> Signed-off-by: Shell <smokewood@qq.com> Co-authored-by: xqyjlj <xqyjlj@126.com>
This commit is contained in:
@@ -81,7 +81,7 @@ CONFIG_RT_USING_CONSOLE=y
|
||||
CONFIG_RT_CONSOLEBUF_SIZE=256
|
||||
CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
|
||||
CONFIG_RT_VER_NUM=0x50100
|
||||
# CONFIG_RT_USING_STDC_ATOMIC is not set
|
||||
CONFIG_RT_USING_STDC_ATOMIC=y
|
||||
CONFIG_RT_BACKTRACE_LEVEL_MAX_NR=32
|
||||
CONFIG_RT_USING_CACHE=y
|
||||
CONFIG_RT_USING_HW_ATOMIC=y
|
||||
@@ -203,7 +203,7 @@ CONFIG_RT_USING_SOFT_RTC=y
|
||||
CONFIG_RT_USING_SDIO=y
|
||||
CONFIG_RT_SDIO_STACK_SIZE=4096
|
||||
CONFIG_RT_SDIO_THREAD_PRIORITY=15
|
||||
CONFIG_RT_MMCSD_STACK_SIZE=4096
|
||||
CONFIG_RT_MMCSD_STACK_SIZE=16384
|
||||
CONFIG_RT_MMCSD_THREAD_PREORITY=22
|
||||
CONFIG_RT_MMCSD_MAX_PARTITION=16
|
||||
# CONFIG_RT_SDIO_DEBUG is not set
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define RT_CONSOLEBUF_SIZE 256
|
||||
#define RT_CONSOLE_DEVICE_NAME "uart0"
|
||||
#define RT_VER_NUM 0x50100
|
||||
#define RT_USING_STDC_ATOMIC
|
||||
#define RT_BACKTRACE_LEVEL_MAX_NR 32
|
||||
#define RT_USING_CACHE
|
||||
#define RT_USING_HW_ATOMIC
|
||||
@@ -138,7 +139,7 @@
|
||||
#define RT_USING_SDIO
|
||||
#define RT_SDIO_STACK_SIZE 4096
|
||||
#define RT_SDIO_THREAD_PRIORITY 15
|
||||
#define RT_MMCSD_STACK_SIZE 4096
|
||||
#define RT_MMCSD_STACK_SIZE 16384
|
||||
#define RT_MMCSD_THREAD_PREORITY 22
|
||||
#define RT_MMCSD_MAX_PARTITION 16
|
||||
#define RT_USING_SPI
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_SMART)
|
||||
#include <console.h>
|
||||
#endif
|
||||
|
||||
#include <virtio_console.h>
|
||||
|
||||
static int console_init()
|
||||
@@ -36,8 +32,6 @@ static int console_init()
|
||||
}
|
||||
INIT_ENV_EXPORT(console_init);
|
||||
|
||||
#ifdef FINSH_USING_MSH
|
||||
|
||||
static int console(int argc, char **argv)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
@@ -48,23 +42,6 @@ static int console(int argc, char **argv)
|
||||
{
|
||||
rt_kprintf("console change to %s\n", argv[2]);
|
||||
rt_console_set_device(argv[2]);
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
{
|
||||
rt_device_t dev = rt_device_find(argv[2]);
|
||||
|
||||
if (dev != RT_NULL)
|
||||
{
|
||||
#ifdef RT_USING_SMART
|
||||
console_set_iodev(dev);
|
||||
#else
|
||||
rt_kprintf("TODO not supported\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
finsh_set_device(argv[2]);
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -81,5 +58,3 @@ static int console(int argc, char **argv)
|
||||
return result;
|
||||
}
|
||||
MSH_CMD_EXPORT(console, set console name);
|
||||
|
||||
#endif /* FINSH_USING_MSH */
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* 2020/10/7 bernard the first version
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
int main(void)
|
||||
|
||||
@@ -45,6 +45,7 @@ endif
|
||||
|
||||
config RT_USING_DFS_V2
|
||||
bool "DFS v2.0"
|
||||
select RT_USING_DEVICE_OPS
|
||||
endchoice
|
||||
|
||||
if RT_USING_DFS_V1
|
||||
@@ -170,6 +171,13 @@ endif
|
||||
depends on RT_USING_DFS_ROMFS
|
||||
default n
|
||||
|
||||
if RT_USING_SMART
|
||||
config RT_USING_DFS_PTYFS
|
||||
bool "Using Pseudo-Teletype Filesystem (UNIX98 PTY)"
|
||||
depends on RT_USING_DFS_DEVFS
|
||||
default y
|
||||
endif
|
||||
|
||||
config RT_USING_DFS_CROMFS
|
||||
bool "Enable ReadOnly compressed file system on flash"
|
||||
default n
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,9 @@
|
||||
#ifndef __DEVICE_FS_H__
|
||||
#define __DEVICE_FS_H__
|
||||
|
||||
int dfs_devfs_init(void);
|
||||
const struct dfs_file_ops *dfs_devfs_fops(void);
|
||||
mode_t dfs_devfs_device_to_mode(struct rt_device *device);
|
||||
void dfs_devfs_device_add(rt_device_t device);
|
||||
int dfs_devfs_update(void);
|
||||
|
||||
#endif
|
||||
|
||||
678
components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c
Normal file
678
components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -145,7 +145,7 @@ static struct dfs_vnode *dfs_mqueue_create_vnode(struct dfs_dentry *dentry, int
|
||||
}
|
||||
mq_file->msg_size = 8192;
|
||||
mq_file->max_msgs = 10;
|
||||
strncpy(mq_file->name, dentry->pathname + 1, RT_NAME_MAX);
|
||||
strncpy(mq_file->name, dentry->pathname + 1, RT_NAME_MAX - 1);
|
||||
dfs_mqueue_insert_after(&(mq_file->list));
|
||||
}
|
||||
|
||||
|
||||
5
components/dfs/dfs_v2/filesystems/ptyfs/README.md
Normal file
5
components/dfs/dfs_v2/filesystems/ptyfs/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# The Pseudo Terminal Filesystem
|
||||
|
||||
The device register on ptyfs is also registered in device frameworks with `rt_device_register()`.
|
||||
|
||||
It's possible to mount a new ptyfs instance on another path. Each instance is isolated to each other. And they don't share the id system. But generally speaking, you have to mount the ptyfs on `/dev` root, since all the file nodes in ptyfs are devices.
|
||||
11
components/dfs/dfs_v2/filesystems/ptyfs/SConscript
Normal file
11
components/dfs/dfs_v2/filesystems/ptyfs/SConscript
Normal file
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PTYFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
658
components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.c
Normal file
658
components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.c
Normal file
File diff suppressed because it is too large
Load Diff
22
components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.h
Normal file
22
components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-02 Shell init ver.
|
||||
*/
|
||||
#ifndef __FS_PTYFS_H__
|
||||
#define __FS_PTYFS_H__
|
||||
#include <rtthread.h>
|
||||
|
||||
typedef rt_base_t ptsno_t;
|
||||
|
||||
ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts);
|
||||
|
||||
rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno);
|
||||
|
||||
const char *ptyfs_get_rootpath(rt_device_t ptmx);
|
||||
|
||||
#endif /* __FS_PTYFS_H__ */
|
||||
@@ -29,6 +29,9 @@ rt_weak const struct romfs_dirent _root_dirent[] =
|
||||
{
|
||||
{ROMFS_DIRENT_DIR, "dev", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "mnt", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "proc", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "etc", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "bin", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "dummy", (rt_uint8_t *)_dummy, sizeof(_dummy) / sizeof(_dummy[0])},
|
||||
{ROMFS_DIRENT_FILE, "dummy.txt", _dummy_txt, sizeof(_dummy_txt)},
|
||||
};
|
||||
|
||||
@@ -202,6 +202,7 @@ int dfs_tmpfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
RT_UNUSED(superblock);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
@@ -317,26 +318,21 @@ static ssize_t dfs_tmpfs_read(struct dfs_file *file, void *buf, size_t count, of
|
||||
return length;
|
||||
}
|
||||
|
||||
static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
static ssize_t _dfs_tmpfs_write(struct tmpfs_file *d_file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
|
||||
|
||||
if (count + *pos > file->vnode->size)
|
||||
if (count + *pos > d_file->size)
|
||||
{
|
||||
rt_uint8_t *ptr;
|
||||
ptr = rt_realloc(d_file->data, *pos + count);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
rt_set_errno(-ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
@@ -347,7 +343,6 @@ static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t co
|
||||
/* update d_file and file size */
|
||||
d_file->data = ptr;
|
||||
d_file->size = *pos + count;
|
||||
file->vnode->size = d_file->size;
|
||||
LOG_D("tmpfile ptr:%x, size:%d", ptr, d_file->size);
|
||||
}
|
||||
|
||||
@@ -356,6 +351,21 @@ static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t co
|
||||
|
||||
/* update file current position */
|
||||
*pos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
|
||||
|
||||
count = _dfs_tmpfs_write(d_file, buf, count, pos);
|
||||
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
|
||||
return count;
|
||||
@@ -504,6 +514,7 @@ static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != RT_NULL);
|
||||
RT_UNUSED(superblock);
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
@@ -797,6 +808,8 @@ static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page)
|
||||
|
||||
ssize_t dfs_tmp_page_write(struct dfs_page *page)
|
||||
{
|
||||
off_t pos;
|
||||
size_t count = 0;
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
if (page->aspace->vnode->type == FT_DIRECTORY)
|
||||
@@ -806,13 +819,16 @@ ssize_t dfs_tmp_page_write(struct dfs_page *page)
|
||||
|
||||
d_file = (struct tmpfs_file *)(page->aspace->vnode->data);
|
||||
RT_ASSERT(d_file != RT_NULL);
|
||||
|
||||
rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
|
||||
if (page->len > 0)
|
||||
memcpy(d_file->data + page->fpos, page->page, page->len);
|
||||
|
||||
{
|
||||
pos = page->fpos;
|
||||
count = _dfs_tmpfs_write(d_file, page->page, page->len, &pos);
|
||||
}
|
||||
rt_mutex_release(&page->aspace->vnode->lock);
|
||||
|
||||
return F_OK;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#include <rtatomic.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifndef ATTR_MODE_SET
|
||||
#define ATTR_MODE_SET (1 << 6)
|
||||
#endif
|
||||
|
||||
#ifndef ATTR_ATIME_SET
|
||||
#define ATTR_ATIME_SET (1 << 7)
|
||||
#endif
|
||||
@@ -33,6 +37,14 @@
|
||||
#define ATTR_MTIME_SET (1 << 8)
|
||||
#endif
|
||||
|
||||
#ifndef ATTR_UID_SET
|
||||
#define ATTR_UID_SET (1 << 9)
|
||||
#endif
|
||||
|
||||
#ifndef ATTR_GID_SET
|
||||
#define ATTR_GID_SET (1 << 10)
|
||||
#endif
|
||||
|
||||
#ifndef AT_SYMLINK_NOFOLLOW
|
||||
#define AT_SYMLINK_NOFOLLOW 0x100
|
||||
#endif
|
||||
|
||||
@@ -175,20 +175,25 @@ int dfs_file_isdir(const char *path);
|
||||
int dfs_file_access(const char *path, mode_t mode);
|
||||
int dfs_file_chdir(const char *path);
|
||||
char *dfs_file_getcwd(char *buf, size_t size);
|
||||
char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode);
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
int dfs_file_mmap2(struct dfs_file *file, struct dfs_mmap2_args *mmap2);
|
||||
|
||||
int dfs_file_mmap(struct dfs_file *file, struct dfs_mmap2_args *mmap2);
|
||||
#endif
|
||||
|
||||
char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode);
|
||||
|
||||
/* 0x5254 is just a magic number to make these relatively unique ("RT") */
|
||||
#define RT_FIOFTRUNCATE 0x52540000U
|
||||
#define RT_FIOGETADDR 0x52540001U
|
||||
#define RT_FIOMMAP2 0x52540002U
|
||||
|
||||
/* dfs_file_realpath mode */
|
||||
#define DFS_REALPATH_EXCEPT_LAST 0
|
||||
#define DFS_REALPATH_EXCEPT_NONE 1
|
||||
#define DFS_REALPATH_ONLY_LAST 3
|
||||
|
||||
char *dfs_file_realpath(struct dfs_mnt **mnt, const char *fullpath, int mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,9 @@ struct dfs_partition
|
||||
struct dfs_attr
|
||||
{
|
||||
unsigned int ia_valid;
|
||||
mode_t st_mode;
|
||||
uid_t st_uid;
|
||||
gid_t st_gid;
|
||||
mode_t st_mode;
|
||||
struct timespec ia_atime;
|
||||
struct timespec ia_mtime;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
struct rt_varea;
|
||||
struct rt_aspace;
|
||||
struct dfs_vnode;
|
||||
struct dfs_dentry;
|
||||
struct dfs_aspace;
|
||||
@@ -30,7 +32,8 @@ struct dfs_aspace;
|
||||
struct dfs_mmap
|
||||
{
|
||||
rt_list_t mmap_node;
|
||||
struct rt_varea *varea;
|
||||
struct rt_aspace *aspace;
|
||||
void *vaddr;
|
||||
};
|
||||
|
||||
struct dfs_page
|
||||
|
||||
@@ -557,6 +557,111 @@ exit:
|
||||
return newfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The fd in the current process dup to designate fd table.
|
||||
*
|
||||
* @param oldfd is the fd in current process.
|
||||
*
|
||||
* @param fdtab is the fd table to dup, if empty, use global (_fdtab).
|
||||
*
|
||||
* @return -1 on failed or the allocated file descriptor.
|
||||
*/
|
||||
int dfs_dup_to(int oldfd, struct dfs_fdtable *fdtab)
|
||||
{
|
||||
int newfd = -1;
|
||||
struct dfs_fdtable *fdt = NULL;
|
||||
|
||||
if (dfs_file_lock() != RT_EOK)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
if (fdtab == NULL)
|
||||
{
|
||||
fdtab = &_fdtab;
|
||||
}
|
||||
|
||||
/* check old fd */
|
||||
fdt = dfs_fdtable_get();
|
||||
if ((oldfd < 0) || (oldfd >= fdt->maxfd))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
if (!fdt->fds[oldfd])
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
/* get a new fd*/
|
||||
newfd = _fdt_slot_alloc(fdtab, DFS_STDIO_OFFSET);
|
||||
if (newfd >= 0)
|
||||
{
|
||||
fdtab->fds[newfd] = fdt->fds[oldfd];
|
||||
|
||||
/* inc ref_count */
|
||||
rt_atomic_add(&(fdtab->fds[newfd]->ref_count), 1);
|
||||
}
|
||||
exit:
|
||||
dfs_file_unlock();
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The fd in the designate fd table dup to current process.
|
||||
*
|
||||
* @param oldfd is the fd in the designate fd table.
|
||||
*
|
||||
* @param fdtab is the fd table for oldfd, if empty, use global (_fdtab).
|
||||
*
|
||||
* @return -1 on failed or the allocated file descriptor.
|
||||
*/
|
||||
int dfs_dup_from(int oldfd, struct dfs_fdtable *fdtab)
|
||||
{
|
||||
int newfd = -1;
|
||||
struct dfs_file *file;
|
||||
|
||||
if (dfs_file_lock() != RT_EOK)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
if (fdtab == NULL)
|
||||
{
|
||||
fdtab = &_fdtab;
|
||||
}
|
||||
|
||||
/* check old fd */
|
||||
if ((oldfd < 0) || (oldfd >= fdtab->maxfd))
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
if (!fdtab->fds[oldfd])
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
/* get a new fd*/
|
||||
newfd = fd_new();
|
||||
file = fd_get(newfd);
|
||||
if (newfd >= 0 && file)
|
||||
{
|
||||
file->mode = fdtab->fds[oldfd]->mode;
|
||||
file->flags = fdtab->fds[oldfd]->flags;
|
||||
file->fops = fdtab->fds[oldfd]->fops;
|
||||
file->dentry = dfs_dentry_ref(fdtab->fds[oldfd]->dentry);
|
||||
file->vnode = fdtab->fds[oldfd]->vnode;
|
||||
file->mmap_context = RT_NULL;
|
||||
file->data = fdtab->fds[oldfd]->data;
|
||||
}
|
||||
|
||||
dfs_file_close(fdtab->fds[oldfd]);
|
||||
|
||||
exit:
|
||||
fdt_fd_release(fdtab, oldfd);
|
||||
dfs_file_unlock();
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
sysret_t sys_dup(int oldfd)
|
||||
#else
|
||||
@@ -856,7 +961,11 @@ int dfs_fd_dump(int argc, char** argv)
|
||||
{
|
||||
int index;
|
||||
|
||||
dfs_file_lock();
|
||||
if (dfs_file_lock() != RT_EOK)
|
||||
{
|
||||
return -RT_ENOSYS;
|
||||
}
|
||||
|
||||
for (index = 0; index < _fdtab.maxfd; index++)
|
||||
{
|
||||
struct dfs_file *file = _fdtab.fds[index];
|
||||
|
||||
@@ -29,22 +29,86 @@
|
||||
|
||||
#define MAX_RW_COUNT 0xfffc0000
|
||||
|
||||
rt_inline int _find_path_node(const char *path)
|
||||
rt_inline int _first_path_len(const char *path)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (path[i] != '\0')
|
||||
if (path[i] == '/')
|
||||
{
|
||||
if ('/' == path[i++])
|
||||
i++;
|
||||
while (path[i] != '\0' && path[i] != '/')
|
||||
{
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* return path-note length */
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _get_parent_path(const char *fullpath, char *path)
|
||||
{
|
||||
int len = 0;
|
||||
char *str = 0;
|
||||
|
||||
str = strrchr(fullpath, '/');
|
||||
if (str)
|
||||
{
|
||||
len = str - fullpath;
|
||||
if (len > 0)
|
||||
{
|
||||
rt_memcpy(path, fullpath, len);
|
||||
path[len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _try_readlink(const char *path, struct dfs_mnt *mnt, char *link)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dfs_dentry *dentry = dfs_dentry_lookup(mnt, path, 0);
|
||||
|
||||
if (dentry && dentry->vnode->type == FT_SYMLINK)
|
||||
{
|
||||
if (mnt->fs_ops->readlink)
|
||||
{
|
||||
if (dfs_is_mounted(mnt) == 0)
|
||||
{
|
||||
ret = mnt->fs_ops->readlink(dentry, link, DFS_PATH_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
dfs_dentry_unref(dentry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _insert_link_path(const char *link_fn, int link_len, char *tmp_path, int *index)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (link_fn[0] != '/')
|
||||
{
|
||||
if (link_len + 1 <= *index)
|
||||
{
|
||||
*index -= link_len;
|
||||
rt_memcpy(tmp_path + *index, link_fn, link_len);
|
||||
*index -= 1;
|
||||
tmp_path[*index] = '/';
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else if (link_len <= *index)
|
||||
{
|
||||
*index -= link_len;
|
||||
rt_memcpy(tmp_path + *index, link_fn, link_len);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* rw_verify_area doesn't like huge counts. We limit
|
||||
* them to something that fits in "int" so that others
|
||||
@@ -149,166 +213,97 @@ static void dfs_file_unref(struct dfs_file *file)
|
||||
}
|
||||
}
|
||||
|
||||
struct dfs_dentry* dfs_file_follow_link(struct dfs_dentry *dentry)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dfs_dentry *tmp = dfs_dentry_ref(dentry);
|
||||
|
||||
if (dentry && dentry->vnode && dentry->vnode->type == FT_SYMLINK)
|
||||
{
|
||||
char *buf = NULL;
|
||||
|
||||
buf = (char *)rt_malloc(DFS_PATH_MAX);
|
||||
if (buf)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (dfs_is_mounted(tmp->mnt) == 0)
|
||||
{
|
||||
ret = tmp->mnt->fs_ops->readlink(tmp, buf, DFS_PATH_MAX);
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
struct dfs_mnt *mnt = NULL;
|
||||
|
||||
if (buf[0] != '/')
|
||||
{
|
||||
char *dir = dfs_dentry_pathname(tmp);
|
||||
|
||||
/* is the relative directory */
|
||||
if (dir)
|
||||
{
|
||||
char *fullpath = dfs_normalize_path(dir, buf);
|
||||
if (fullpath)
|
||||
{
|
||||
strncpy(buf, fullpath, DFS_PATH_MAX);
|
||||
|
||||
rt_free(fullpath);
|
||||
}
|
||||
rt_free(dir);
|
||||
}
|
||||
}
|
||||
|
||||
mnt = dfs_mnt_lookup(buf);
|
||||
if (mnt)
|
||||
{
|
||||
struct dfs_dentry *de = dfs_dentry_lookup(mnt, buf, 0);
|
||||
|
||||
/* release the old dentry */
|
||||
dfs_dentry_unref(tmp);
|
||||
tmp = de;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (tmp && tmp->vnode->type == FT_SYMLINK);
|
||||
}
|
||||
|
||||
rt_free(buf);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function is creat a nolink path.
|
||||
*
|
||||
* @param mnt
|
||||
* @param fullpath
|
||||
* @param mode 0 middle path nolink; 1 all path nolink.
|
||||
* @param mode
|
||||
*
|
||||
* @return new path.
|
||||
*/
|
||||
char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode)
|
||||
char *dfs_file_realpath(struct dfs_mnt **mnt, const char *fullpath, int mode)
|
||||
{
|
||||
int index = 0;
|
||||
char *path = RT_NULL;
|
||||
char *link_fn;
|
||||
struct dfs_dentry *dentry = RT_NULL;
|
||||
|
||||
path = (char *)rt_malloc((DFS_PATH_MAX * 2) + 2); // path + \0 + link_fn + \0
|
||||
if (!path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
link_fn = path + DFS_PATH_MAX + 1;
|
||||
int path_len = 0, index = 0;
|
||||
char *path = RT_NULL, *link_fn, *tmp_path;
|
||||
struct dfs_mnt *tmp_mnt;
|
||||
|
||||
if (*mnt && fullpath)
|
||||
{
|
||||
int i = 0;
|
||||
char *fp = fullpath;
|
||||
int len, link_len;
|
||||
|
||||
while ((i = _find_path_node(fp)) > 0)
|
||||
path = (char *)rt_malloc((DFS_PATH_MAX * 3) + 3); // path + \0 + link_fn + \0 + tmp_path + \0
|
||||
if (!path)
|
||||
{
|
||||
if (i + index > DFS_PATH_MAX)
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
link_fn = path + DFS_PATH_MAX + 1;
|
||||
tmp_path = link_fn + (DFS_PATH_MAX + 1);
|
||||
|
||||
len = rt_strlen(fullpath);
|
||||
if (len > DFS_PATH_MAX)
|
||||
{
|
||||
goto _ERR_RET;
|
||||
}
|
||||
|
||||
index = (DFS_PATH_MAX - len);
|
||||
rt_strcpy(tmp_path + index, fullpath);
|
||||
|
||||
if (mode == DFS_REALPATH_ONLY_LAST)
|
||||
{
|
||||
path_len = _get_parent_path(fullpath, path);
|
||||
index += path_len;
|
||||
}
|
||||
|
||||
while ((len = _first_path_len(tmp_path + index)) > 0)
|
||||
{
|
||||
if (len + path_len > DFS_PATH_MAX)
|
||||
{
|
||||
goto _ERR_RET;
|
||||
}
|
||||
|
||||
rt_memcpy(path + index, fp, i);
|
||||
path[index + i] = '\0';
|
||||
rt_memcpy(path + path_len, tmp_path + index, len);
|
||||
path[path_len + len] = '\0';
|
||||
index += len;
|
||||
|
||||
tmp_mnt = dfs_mnt_lookup(path);
|
||||
if (tmp_mnt == RT_NULL)
|
||||
{
|
||||
goto _ERR_RET;
|
||||
}
|
||||
|
||||
*mnt = tmp_mnt;
|
||||
|
||||
/* the last should by mode process. */
|
||||
if ((fp[i] == '\0') && (!mode))
|
||||
if ((tmp_path[index] == '\0') && (mode == DFS_REALPATH_EXCEPT_LAST))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fp += i;
|
||||
|
||||
dentry = dfs_dentry_lookup(*mnt, path, 0);
|
||||
if (dentry && dentry->vnode->type == FT_SYMLINK)
|
||||
link_len = _try_readlink(path, *mnt, link_fn);
|
||||
if (link_len > 0)
|
||||
{
|
||||
int ret = -1;
|
||||
int ret = _insert_link_path(link_fn, link_len, tmp_path, &index);
|
||||
|
||||
if ((*mnt)->fs_ops->readlink)
|
||||
if (ret == 1)
|
||||
{
|
||||
if (dfs_is_mounted((*mnt)) == 0)
|
||||
{
|
||||
ret = (*mnt)->fs_ops->readlink(dentry, link_fn, DFS_PATH_MAX);
|
||||
}
|
||||
/* link_fn[0] == '/' */
|
||||
path_len = 0;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
int len = rt_strlen(link_fn);
|
||||
|
||||
if (link_fn[0] != '/')
|
||||
{
|
||||
path[index] = '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (len + index + 1 >= DFS_PATH_MAX)
|
||||
{
|
||||
goto _ERR_RET;
|
||||
}
|
||||
|
||||
rt_memcpy(path + index, link_fn, len);
|
||||
index += len;
|
||||
path[index] = '\0';
|
||||
*mnt = dfs_mnt_lookup(path);
|
||||
}
|
||||
else
|
||||
else if (ret < 0)
|
||||
{
|
||||
goto _ERR_RET;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index += i;
|
||||
path_len += len;
|
||||
}
|
||||
dfs_dentry_unref(dentry);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return path;
|
||||
|
||||
_ERR_RET:
|
||||
rt_free(path);
|
||||
path = RT_NULL;
|
||||
@@ -349,7 +344,7 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -370,9 +365,12 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
|
||||
else
|
||||
{
|
||||
struct dfs_dentry *target_dentry = RT_NULL;
|
||||
|
||||
/* follow symbol link */
|
||||
target_dentry = dfs_file_follow_link(dentry);
|
||||
char *path = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_ONLY_LAST);
|
||||
if (path)
|
||||
{
|
||||
target_dentry = dfs_dentry_lookup(mnt, path, oflags);
|
||||
rt_free(path);
|
||||
}
|
||||
dfs_dentry_unref(dentry);
|
||||
dentry = target_dentry;
|
||||
}
|
||||
@@ -507,7 +505,7 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG_E("open %s failed in file system: %s", path, dentry->mnt->fs_ops->name);
|
||||
LOG_I("open %s failed in file system: %s", path, dentry->mnt->fs_ops->name);
|
||||
DLOG(msg, mnt->fs_ops->name, "dfs_file", DLOG_MSG_RET, "open failed.");
|
||||
dfs_file_unref(file);
|
||||
}
|
||||
@@ -791,7 +789,7 @@ int dfs_file_stat(const char *path, struct stat *buf)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 1);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_NONE);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -845,7 +843,7 @@ int dfs_file_lstat(const char *path, struct stat *buf)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -924,7 +922,7 @@ int dfs_file_setattr(const char *path, struct dfs_attr *attr)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -1097,7 +1095,7 @@ int dfs_file_unlink(const char *path)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -1199,7 +1197,7 @@ int dfs_file_link(const char *oldname, const char *newname)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *tmp = dfs_nolink_path(&mnt, old_fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, old_fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(old_fullpath);
|
||||
@@ -1210,7 +1208,7 @@ int dfs_file_link(const char *oldname, const char *newname)
|
||||
new_fullpath = dfs_normalize_path(NULL, newname);
|
||||
if (new_fullpath)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, new_fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, new_fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(new_fullpath);
|
||||
@@ -1310,7 +1308,7 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
mnt = dfs_mnt_lookup(parent);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, parent, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, parent, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(parent);
|
||||
@@ -1318,7 +1316,7 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
}
|
||||
|
||||
DLOG(msg, "dfs_file", "dentry", DLOG_MSG, "dfs_dentry_lookup(mnt, %s)", fullpath);
|
||||
dentry = dfs_dentry_lookup(mnt, parent, 0);
|
||||
dentry = dfs_dentry_lookup(mnt, parent, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (dentry)
|
||||
{
|
||||
if (dentry->mnt->fs_ops->symlink)
|
||||
@@ -1326,17 +1324,6 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
char *path = dfs_normalize_path(parent, target);
|
||||
if (path)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, path, 0);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(path);
|
||||
path = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = path;
|
||||
}
|
||||
|
||||
ret = rt_strncmp(parent, path, strlen(parent));
|
||||
if (ret == 0)
|
||||
{
|
||||
@@ -1346,6 +1333,10 @@ int dfs_file_symlink(const char *target, const char *linkpath)
|
||||
tmp ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = path;
|
||||
}
|
||||
|
||||
if (dfs_is_mounted(mnt) == 0)
|
||||
{
|
||||
@@ -1401,7 +1392,7 @@ int dfs_file_readlink(const char *path, char *buf, int bufsize)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -1466,7 +1457,7 @@ int dfs_file_rename(const char *old_file, const char *new_file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *tmp = dfs_nolink_path(&mnt, old_fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, old_fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(old_fullpath);
|
||||
@@ -1477,7 +1468,7 @@ int dfs_file_rename(const char *old_file, const char *new_file)
|
||||
new_fullpath = dfs_normalize_path(NULL, new_file);
|
||||
if (new_fullpath)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, new_fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, new_fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(new_fullpath);
|
||||
@@ -1652,7 +1643,7 @@ int dfs_file_isdir(const char *path)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 1);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_NONE);
|
||||
if (tmp)
|
||||
{
|
||||
rt_free(fullpath);
|
||||
@@ -1853,7 +1844,7 @@ void ls(const char *pathname)
|
||||
mnt = dfs_mnt_lookup(fullpath);
|
||||
if (mnt)
|
||||
{
|
||||
char *tmp = dfs_nolink_path(&mnt, fullpath, 0);
|
||||
char *tmp = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST);
|
||||
if (tmp)
|
||||
{
|
||||
char *index;
|
||||
|
||||
@@ -269,7 +269,6 @@ static void dfs_pcache_thread(void *parameter)
|
||||
{
|
||||
page->len = page->size;
|
||||
}
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
if (aspace->ops->write)
|
||||
{
|
||||
aspace->ops->write(page);
|
||||
@@ -676,9 +675,14 @@ static int dfs_page_unmap(struct dfs_page *page)
|
||||
|
||||
if (map)
|
||||
{
|
||||
void *vaddr = dfs_aspace_vaddr(map->varea, page->fpos);
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, vaddr, ARCH_PAGE_SIZE);
|
||||
rt_varea_unmap_page(map->varea, vaddr);
|
||||
rt_varea_t varea;
|
||||
void *vaddr;
|
||||
|
||||
varea = rt_aspace_query(map->aspace, map->vaddr);
|
||||
RT_ASSERT(varea);
|
||||
vaddr = dfs_aspace_vaddr(varea, page->fpos);
|
||||
|
||||
rt_varea_unmap_page(varea, vaddr);
|
||||
|
||||
rt_free(map);
|
||||
}
|
||||
@@ -741,7 +745,6 @@ static void dfs_page_release(struct dfs_page *page)
|
||||
{
|
||||
page->len = page->size;
|
||||
}
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
if (aspace->ops->write)
|
||||
{
|
||||
aspace->ops->write(page);
|
||||
@@ -995,7 +998,6 @@ static struct dfs_page *dfs_aspace_load_page(struct dfs_file *file, off_t pos)
|
||||
page->size = ARCH_PAGE_SIZE;
|
||||
page->fpos = pos / ARCH_PAGE_SIZE * ARCH_PAGE_SIZE;
|
||||
aspace->ops->read(file, page);
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
page->ref_count ++;
|
||||
|
||||
dfs_page_insert(page);
|
||||
@@ -1105,7 +1107,6 @@ int dfs_aspace_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
len = count > len ? len : count;
|
||||
if (len)
|
||||
{
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
rt_memcpy(ptr, page->page + *pos - page->fpos, len);
|
||||
ptr += len;
|
||||
*pos += len;
|
||||
@@ -1158,7 +1159,6 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t
|
||||
len = page->fpos + ARCH_PAGE_SIZE - *pos;
|
||||
len = count > len ? len : count;
|
||||
rt_memcpy(page->page + *pos - page->fpos, ptr, len);
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
ptr += len;
|
||||
*pos += len;
|
||||
count -= len;
|
||||
@@ -1225,7 +1225,7 @@ int dfs_aspace_flush(struct dfs_aspace *aspace)
|
||||
{
|
||||
page->len = page->size;
|
||||
}
|
||||
//rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, page->page, page->size);
|
||||
|
||||
if (aspace->ops->write)
|
||||
{
|
||||
aspace->ops->write(page);
|
||||
@@ -1277,6 +1277,7 @@ void *dfs_aspace_mmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr
|
||||
void *ret = RT_NULL;
|
||||
struct dfs_page *page;
|
||||
struct dfs_aspace *aspace = file->vnode->aspace;
|
||||
rt_aspace_t target_aspace = varea->aspace;
|
||||
|
||||
page = dfs_page_lookup(file, dfs_aspace_fpos(varea, vaddr));
|
||||
if (page)
|
||||
@@ -1284,7 +1285,8 @@ void *dfs_aspace_mmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr
|
||||
struct dfs_mmap *map = (struct dfs_mmap *)rt_calloc(1, sizeof(struct dfs_mmap));
|
||||
if (map)
|
||||
{
|
||||
void *pg_paddr = rt_kmem_v2p(page->page);
|
||||
void *pg_vaddr = page->page;
|
||||
void *pg_paddr = rt_kmem_v2p(pg_vaddr);
|
||||
int err = rt_varea_map_range(varea, vaddr, pg_paddr, page->size);
|
||||
if (err == RT_EOK)
|
||||
{
|
||||
@@ -1301,10 +1303,12 @@ void *dfs_aspace_mmap(struct dfs_file *file, struct rt_varea *varea, void *vaddr
|
||||
* fetching of the next instruction can see the coherent data with the data cache,
|
||||
* TLB, MMU, main memory, and all the other observers in the computer system.
|
||||
*/
|
||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, vaddr, ARCH_PAGE_SIZE);
|
||||
rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, vaddr, ARCH_PAGE_SIZE);
|
||||
|
||||
ret = page->page;
|
||||
map->varea = varea;
|
||||
ret = pg_vaddr;
|
||||
map->aspace = target_aspace;
|
||||
map->vaddr = vaddr;
|
||||
dfs_aspace_lock(aspace);
|
||||
rt_list_insert_after(&page->mmap_head, &map->mmap_node);
|
||||
dfs_page_release(page);
|
||||
@@ -1329,6 +1333,8 @@ int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
|
||||
{
|
||||
struct dfs_vnode *vnode = file->vnode;
|
||||
struct dfs_aspace *aspace = vnode->aspace;
|
||||
void *unmap_start = varea->start;
|
||||
void *unmap_end = (char *)unmap_start + varea->size;
|
||||
|
||||
if (aspace)
|
||||
{
|
||||
@@ -1347,20 +1353,32 @@ int dfs_aspace_unmap(struct dfs_file *file, struct rt_varea *varea)
|
||||
{
|
||||
rt_list_t *node, *tmp;
|
||||
struct dfs_mmap *map;
|
||||
rt_varea_t map_varea = RT_NULL;
|
||||
|
||||
node = page->mmap_head.next;
|
||||
|
||||
while (node != &page->mmap_head)
|
||||
{
|
||||
rt_aspace_t map_aspace;
|
||||
map = rt_list_entry(node, struct dfs_mmap, mmap_node);
|
||||
tmp = node;
|
||||
node = node->next;
|
||||
|
||||
if (map && varea == map->varea)
|
||||
if (map && varea->aspace == map->aspace
|
||||
&& map->vaddr >= unmap_start && map->vaddr < unmap_end)
|
||||
{
|
||||
void *vaddr = dfs_aspace_vaddr(map->varea, page->fpos);
|
||||
void *vaddr = map->vaddr;
|
||||
map_aspace = map->aspace;
|
||||
|
||||
rt_varea_unmap_page(map->varea, vaddr);
|
||||
if (!map_varea || map_varea->aspace != map_aspace ||
|
||||
vaddr < map_varea->start ||
|
||||
vaddr >= map_varea->start + map_varea->size)
|
||||
{
|
||||
/* lock the tree so we don't access uncompleted data */
|
||||
map_varea = rt_aspace_query(map_aspace, vaddr);
|
||||
}
|
||||
|
||||
rt_varea_unmap_page(map_varea, vaddr);
|
||||
|
||||
if (varea->attr == MMU_MAP_U_RWCB && page->fpos < page->aspace->vnode->size)
|
||||
{
|
||||
@@ -1405,7 +1423,7 @@ int dfs_aspace_page_unmap(struct dfs_file *file, struct rt_varea *varea, void *v
|
||||
tmp = node;
|
||||
node = node->next;
|
||||
|
||||
if (map && varea == map->varea)
|
||||
if (map && varea->aspace == map->aspace && vaddr == map->vaddr)
|
||||
{
|
||||
if (varea->attr == MMU_MAP_U_RWCB)
|
||||
{
|
||||
|
||||
@@ -57,17 +57,6 @@ menuconfig RT_USING_SERIAL
|
||||
default 64
|
||||
endif
|
||||
|
||||
config RT_USING_TTY
|
||||
bool "Using TTY SYSTEM"
|
||||
depends on RT_USING_SMART
|
||||
default y
|
||||
|
||||
if RT_USING_TTY
|
||||
config RT_TTY_DEBUG
|
||||
bool "Using TTY DEBUG"
|
||||
default n
|
||||
endif
|
||||
|
||||
config RT_USING_CAN
|
||||
bool "Using CAN device drivers"
|
||||
default n
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
#include <rtdevice.h> /* for wqueue_init */
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#ifdef RT_USING_DFS_V2
|
||||
#include <devfs.h>
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
|
||||
#ifdef RT_USING_DEVICE
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
@@ -78,6 +82,10 @@ rt_err_t rt_device_register(rt_device_t dev,
|
||||
rt_wqueue_init(&(dev->wait_queue));
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
|
||||
#ifdef RT_USING_DFS_V2
|
||||
dfs_devfs_device_add(dev);
|
||||
#endif /* RT_USING_DFS_V2 */
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
RTM_EXPORT(rt_device_register);
|
||||
|
||||
@@ -107,7 +107,7 @@ struct rt_pic_irq
|
||||
rt_uint32_t mode;
|
||||
|
||||
rt_uint32_t priority;
|
||||
RT_DECLARE_BITMAP(affinity, RT_CPUS_NR);
|
||||
RT_BITMAP_DECLARE(affinity, RT_CPUS_NR);
|
||||
|
||||
rt_list_t list;
|
||||
rt_list_t children_nodes;
|
||||
|
||||
@@ -179,4 +179,5 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
rt_uint32_t flag,
|
||||
void *data);
|
||||
|
||||
rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial);
|
||||
#endif
|
||||
|
||||
@@ -191,4 +191,5 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
rt_uint32_t flag,
|
||||
void *data);
|
||||
|
||||
rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial);
|
||||
#endif
|
||||
|
||||
@@ -33,5 +33,6 @@ void rt_completion_init(struct rt_completion *completion);
|
||||
rt_err_t rt_completion_wait(struct rt_completion *completion,
|
||||
rt_int32_t timeout);
|
||||
void rt_completion_done(struct rt_completion *completion);
|
||||
rt_err_t rt_completion_wakeup(struct rt_completion *completion);
|
||||
|
||||
#endif
|
||||
|
||||
38
components/drivers/include/ipc/condvar.h
Normal file
38
components/drivers/include/ipc/condvar.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-20 Shell Add cond var API in kernel
|
||||
*/
|
||||
|
||||
#ifndef __LWP_TERMINAL_CONDVAR_H__
|
||||
#define __LWP_TERMINAL_CONDVAR_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
typedef struct rt_condvar
|
||||
{
|
||||
#ifdef USING_RT_OBJECT
|
||||
struct rt_object parent;
|
||||
#endif
|
||||
rt_atomic_t waiters_cnt;
|
||||
rt_atomic_t waiting_mtx;
|
||||
struct rt_wqueue event;
|
||||
} *rt_condvar_t;
|
||||
|
||||
void rt_condvar_init(rt_condvar_t cv, char *name);
|
||||
int rt_condvar_timedwait(rt_condvar_t cv, rt_mutex_t mtx, int suspend_flag,
|
||||
rt_tick_t timeout);
|
||||
int rt_condvar_signal(rt_condvar_t cv);
|
||||
int rt_condvar_broadcast(rt_condvar_t cv);
|
||||
|
||||
rt_inline void rt_condvar_detach(rt_condvar_t cv)
|
||||
{
|
||||
RT_UNUSED(cv);
|
||||
return ;
|
||||
}
|
||||
|
||||
#endif /* __LWP_TERMINAL_CONDVAR_H__ */
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <rtdef.h>
|
||||
#include <rtconfig.h>
|
||||
#include "condvar.h"
|
||||
|
||||
/**
|
||||
* Pipe Device
|
||||
@@ -34,6 +35,7 @@ struct rt_pipe_device
|
||||
int writer;
|
||||
int reader;
|
||||
|
||||
struct rt_condvar waitfor_parter;
|
||||
struct rt_mutex lock;
|
||||
};
|
||||
typedef struct rt_pipe_device rt_pipe_t;
|
||||
|
||||
@@ -49,6 +49,7 @@ int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int timeout);
|
||||
int rt_wqueue_wait_killable(rt_wqueue_t *queue, int condition, int timeout);
|
||||
int rt_wqueue_wait_interruptible(rt_wqueue_t *queue, int condition, int timeout);
|
||||
void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key);
|
||||
void rt_wqueue_wakeup_all(rt_wqueue_t *queue, void *key);
|
||||
|
||||
#define DEFINE_WAIT_FUNC(name, function) \
|
||||
struct rt_wqueue_node name = { \
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ipc/completion.h"
|
||||
#include "ipc/dataqueue.h"
|
||||
#include "ipc/workqueue.h"
|
||||
#include "ipc/condvar.h"
|
||||
#include "ipc/waitqueue.h"
|
||||
#include "ipc/pipe.h"
|
||||
#include "ipc/poll.h"
|
||||
|
||||
@@ -134,7 +134,7 @@ RTM_EXPORT(rt_completion_wait);
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*/
|
||||
void rt_completion_done(struct rt_completion *completion)
|
||||
static int _completion_done(struct rt_completion *completion)
|
||||
{
|
||||
rt_base_t level;
|
||||
rt_err_t error;
|
||||
@@ -145,7 +145,7 @@ void rt_completion_done(struct rt_completion *completion)
|
||||
if (RT_COMPLETION_FLAG(completion) == RT_COMPLETED)
|
||||
{
|
||||
rt_spin_unlock_irqrestore(&_completion_lock, level);
|
||||
return;
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
suspend_thread = RT_COMPLETION_THREAD(completion);
|
||||
@@ -160,10 +160,38 @@ void rt_completion_done(struct rt_completion *completion)
|
||||
LOG_D("%s: failed to resume thread", __func__);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no thread waiting */
|
||||
error = -RT_EEMPTY;
|
||||
}
|
||||
|
||||
completion->susp_thread_n_flag = RT_COMPLETION_NEW_STAT(RT_NULL, RT_COMPLETED);
|
||||
|
||||
rt_spin_unlock_irqrestore(&_completion_lock, level);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function indicates a completion has done.
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*/
|
||||
void rt_completion_done(struct rt_completion *completion)
|
||||
{
|
||||
_completion_done(completion);
|
||||
}
|
||||
RTM_EXPORT(rt_completion_done);
|
||||
|
||||
/**
|
||||
* @brief This function indicates a completion has done and wakeup the thread
|
||||
*
|
||||
* @param completion is a pointer to a completion object.
|
||||
*/
|
||||
rt_err_t rt_completion_wakeup(struct rt_completion *completion)
|
||||
{
|
||||
return _completion_done(completion);
|
||||
}
|
||||
RTM_EXPORT(rt_completion_wakeup);
|
||||
|
||||
|
||||
173
components/drivers/ipc/condvar.c
Normal file
173
components/drivers/ipc/condvar.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-20 Shell Support of condition variable
|
||||
*/
|
||||
#define DBG_TAG "ipc.condvar"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <rtdevice.h>
|
||||
#include <rtatomic.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
static struct rt_spinlock _local_cv_queue_lock = RT_SPINLOCK_INIT;
|
||||
|
||||
#define CV_ASSERT_LOCKED(cv) \
|
||||
RT_ASSERT(!(cv)->waiting_mtx || \
|
||||
rt_mutex_get_owner((rt_mutex_t)(cv)->waiting_mtx) == \
|
||||
rt_thread_self())
|
||||
|
||||
void rt_condvar_init(rt_condvar_t cv, char *name)
|
||||
{
|
||||
#ifdef USING_RT_OBJECT
|
||||
/* TODO: support rt object */
|
||||
rt_object_init();
|
||||
#endif
|
||||
|
||||
rt_wqueue_init(&cv->event);
|
||||
rt_atomic_store(&cv->waiters_cnt, 0);
|
||||
rt_atomic_store(&cv->waiting_mtx, 0);
|
||||
}
|
||||
|
||||
static int _waitq_inqueue(rt_wqueue_t *queue, struct rt_wqueue_node *node,
|
||||
rt_tick_t timeout, int suspend_flag)
|
||||
{
|
||||
rt_thread_t tcb = node->polling_thread;
|
||||
rt_timer_t timer = &(tcb->thread_timer);
|
||||
rt_err_t ret;
|
||||
|
||||
if (queue->flag != RT_WQ_FLAG_WAKEUP)
|
||||
{
|
||||
ret = rt_thread_suspend_with_flag(tcb, suspend_flag);
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
rt_wqueue_add(queue, node);
|
||||
if (timeout != RT_WAITING_FOREVER)
|
||||
{
|
||||
rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &timeout);
|
||||
|
||||
rt_timer_start(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = RT_EOK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define INIT_WAITQ_NODE(node) \
|
||||
{ \
|
||||
.polling_thread = rt_thread_self(), .key = 0, \
|
||||
.wakeup = __wqueue_default_wake, .wqueue = &cv->event, \
|
||||
.list = RT_LIST_OBJECT_INIT(node.list) \
|
||||
}
|
||||
|
||||
int rt_condvar_timedwait(rt_condvar_t cv, rt_mutex_t mtx, int suspend_flag,
|
||||
rt_tick_t timeout)
|
||||
{
|
||||
rt_err_t acq_mtx_succ, rc;
|
||||
rt_atomic_t waiting_mtx;
|
||||
struct rt_wqueue_node node = INIT_WAITQ_NODE(node);
|
||||
|
||||
/* not allowed in IRQ & critical section */
|
||||
RT_DEBUG_SCHEDULER_AVAILABLE(1);
|
||||
CV_ASSERT_LOCKED(cv);
|
||||
|
||||
/**
|
||||
* for the worst case, this is racy with the following works to reset field
|
||||
* before mutex is taken. The spinlock then comes to rescue.
|
||||
*/
|
||||
rt_spin_lock(&_local_cv_queue_lock);
|
||||
waiting_mtx = rt_atomic_load(&cv->waiting_mtx);
|
||||
if (!waiting_mtx)
|
||||
acq_mtx_succ = rt_atomic_compare_exchange_strong(
|
||||
&cv->waiting_mtx, &waiting_mtx, (size_t)mtx);
|
||||
else
|
||||
acq_mtx_succ = 0;
|
||||
|
||||
rt_spin_unlock(&_local_cv_queue_lock);
|
||||
|
||||
if (acq_mtx_succ == 1 || waiting_mtx == (size_t)mtx)
|
||||
{
|
||||
rt_atomic_add(&cv->waiters_cnt, 1);
|
||||
|
||||
rt_enter_critical();
|
||||
|
||||
if (suspend_flag == RT_INTERRUPTIBLE)
|
||||
rc = _waitq_inqueue(&cv->event, &node, timeout, RT_INTERRUPTIBLE);
|
||||
else /* UNINTERRUPTIBLE is forbidden, since it's not safe for user space */
|
||||
rc = _waitq_inqueue(&cv->event, &node, timeout, RT_KILLABLE);
|
||||
|
||||
acq_mtx_succ = rt_mutex_release(mtx);
|
||||
RT_ASSERT(acq_mtx_succ == 0);
|
||||
rt_exit_critical();
|
||||
|
||||
if (rc == RT_EOK)
|
||||
{
|
||||
rt_schedule();
|
||||
|
||||
rc = rt_get_errno();
|
||||
rc = rc > 0 ? -rc : rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("%s() failed to suspend", __func__);
|
||||
}
|
||||
|
||||
rt_wqueue_remove(&node);
|
||||
|
||||
rt_spin_lock(&_local_cv_queue_lock);
|
||||
if (rt_atomic_add(&cv->waiters_cnt, -1) == 1)
|
||||
{
|
||||
waiting_mtx = (size_t)mtx;
|
||||
acq_mtx_succ = rt_atomic_compare_exchange_strong(&cv->waiting_mtx,
|
||||
&waiting_mtx, 0);
|
||||
RT_ASSERT(acq_mtx_succ == 1);
|
||||
}
|
||||
rt_spin_unlock(&_local_cv_queue_lock);
|
||||
|
||||
acq_mtx_succ = rt_mutex_take(mtx, RT_WAITING_FOREVER);
|
||||
RT_ASSERT(acq_mtx_succ == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("%s: conflict waiting mutex", __func__);
|
||||
rc = -EBUSY;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Keep in mind that we always operating when cv.waiting_mtx is taken */
|
||||
|
||||
int rt_condvar_signal(rt_condvar_t cv)
|
||||
{
|
||||
CV_ASSERT_LOCKED(cv);
|
||||
|
||||
/* to avoid spurious wakeups */
|
||||
if (rt_atomic_load(&cv->waiters_cnt) > 0)
|
||||
rt_wqueue_wakeup(&cv->event, 0);
|
||||
|
||||
cv->event.flag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_condvar_broadcast(rt_condvar_t cv)
|
||||
{
|
||||
CV_ASSERT_LOCKED(cv);
|
||||
|
||||
/* to avoid spurious wakeups */
|
||||
if (rt_atomic_load(&cv->waiters_cnt) > 0)
|
||||
rt_wqueue_wakeup_all(&cv->event, 0);
|
||||
|
||||
cv->event.flag = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -9,11 +9,13 @@
|
||||
* 2017-11-08 JasonJiaJie fix memory leak issue when close a pipe.
|
||||
* 2023-06-28 shell return POLLHUP when writer closed its channel on poll()
|
||||
* fix flag test on pipe_fops_open()
|
||||
* 2023-12-02 shell Make read pipe operation interruptable.
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtdevice.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/errno.h>
|
||||
#include <ipc/condvar.h>
|
||||
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
|
||||
#include <unistd.h>
|
||||
@@ -69,12 +71,12 @@ static int pipe_fops_open(struct dfs_file *fd)
|
||||
|
||||
if ((fd->flags & O_ACCMODE) == O_RDONLY)
|
||||
{
|
||||
pipe->reader = 1;
|
||||
pipe->reader += 1;
|
||||
}
|
||||
|
||||
if ((fd->flags & O_ACCMODE) == O_WRONLY)
|
||||
{
|
||||
pipe->writer = 1;
|
||||
pipe->writer += 1;
|
||||
}
|
||||
if (fd->vnode->ref_count == 1)
|
||||
{
|
||||
@@ -86,6 +88,21 @@ static int pipe_fops_open(struct dfs_file *fd)
|
||||
}
|
||||
}
|
||||
|
||||
if ((fd->flags & O_ACCMODE) == O_RDONLY && !pipe->writer)
|
||||
{
|
||||
/* wait for partner */
|
||||
rc = rt_condvar_timedwait(&pipe->waitfor_parter, &pipe->lock,
|
||||
RT_INTERRUPTIBLE, RT_WAITING_FOREVER);
|
||||
if (rc != 0)
|
||||
{
|
||||
pipe->reader--;
|
||||
}
|
||||
}
|
||||
else if ((fd->flags & O_ACCMODE) == O_WRONLY)
|
||||
{
|
||||
rt_condvar_broadcast(&pipe->waitfor_parter);
|
||||
}
|
||||
|
||||
__exit:
|
||||
rt_mutex_release(&pipe->lock);
|
||||
|
||||
@@ -117,12 +134,12 @@ static int pipe_fops_close(struct dfs_file *fd)
|
||||
|
||||
if ((fd->flags & O_RDONLY) == O_RDONLY)
|
||||
{
|
||||
pipe->reader = 0;
|
||||
pipe->reader -= 1;
|
||||
}
|
||||
|
||||
if ((fd->flags & O_WRONLY) == O_WRONLY)
|
||||
{
|
||||
pipe->writer = 0;
|
||||
pipe->writer -= 1;
|
||||
while (!rt_list_isempty(&pipe->reader_queue.waiting_list))
|
||||
{
|
||||
rt_wqueue_wakeup(&pipe->reader_queue, (void*)POLLIN);
|
||||
@@ -234,7 +251,8 @@ static ssize_t pipe_fops_read(struct dfs_file *fd, void *buf, size_t count)
|
||||
|
||||
rt_mutex_release(&pipe->lock);
|
||||
rt_wqueue_wakeup(&pipe->writer_queue, (void*)POLLOUT);
|
||||
rt_wqueue_wait(&pipe->reader_queue, 0, -1);
|
||||
if (rt_wqueue_wait_interruptible(&pipe->reader_queue, 0, -1) == -RT_EINTR)
|
||||
return -EINTR;
|
||||
rt_mutex_take(&pipe->lock, RT_WAITING_FOREVER);
|
||||
}
|
||||
}
|
||||
@@ -309,7 +327,8 @@ static ssize_t pipe_fops_write(struct dfs_file *fd, const void *buf, size_t coun
|
||||
rt_mutex_release(&pipe->lock);
|
||||
rt_wqueue_wakeup(&pipe->reader_queue, (void*)POLLIN);
|
||||
/* pipe full, waiting on suspended write list */
|
||||
rt_wqueue_wait(&pipe->writer_queue, 0, -1);
|
||||
if (rt_wqueue_wait_interruptible(&pipe->writer_queue, 0, -1) == -RT_EINTR)
|
||||
return -EINTR;
|
||||
rt_mutex_take(&pipe->lock, -1);
|
||||
}
|
||||
rt_mutex_release(&pipe->lock);
|
||||
@@ -611,6 +630,8 @@ rt_pipe_t *rt_pipe_create(const char *name, int bufsz)
|
||||
rt_mutex_init(&pipe->lock, name, RT_IPC_FLAG_FIFO);
|
||||
rt_wqueue_init(&pipe->reader_queue);
|
||||
rt_wqueue_init(&pipe->writer_queue);
|
||||
rt_condvar_init(&pipe->waitfor_parter, "piwfp");
|
||||
|
||||
pipe->writer = 0;
|
||||
pipe->reader = 0;
|
||||
|
||||
@@ -674,6 +695,7 @@ int rt_pipe_delete(const char *name)
|
||||
|
||||
pipe = (rt_pipe_t *)device;
|
||||
|
||||
rt_condvar_detach(&pipe->waitfor_parter);
|
||||
rt_mutex_detach(&pipe->lock);
|
||||
#if defined(RT_USING_POSIX_DEVIO) && defined(RT_USING_POSIX_PIPE)
|
||||
resource_id_put(&id_mgr, pipe->pipeno);
|
||||
@@ -736,11 +758,6 @@ int pipe(int fildes[2])
|
||||
pipe->is_named = RT_FALSE; /* unamed pipe */
|
||||
pipe->pipeno = pipeno;
|
||||
rt_snprintf(dev_name, sizeof(dev_name), "/dev/%s", dname);
|
||||
fildes[0] = open(dev_name, O_RDONLY, 0);
|
||||
if (fildes[0] < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fildes[1] = open(dev_name, O_WRONLY, 0);
|
||||
if (fildes[1] < 0)
|
||||
@@ -749,6 +766,12 @@ int pipe(int fildes[2])
|
||||
return -1;
|
||||
}
|
||||
|
||||
fildes[0] = open(dev_name, O_RDONLY, 0);
|
||||
if (fildes[0] < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
* to blocked thread.
|
||||
* 2022-01-24 THEWON let rt_wqueue_wait return thread->error when using signal
|
||||
* 2023-09-15 xqyjlj perf rt_hw_interrupt_disable/enable
|
||||
* 2023-11-21 Shell Support wakeup_all
|
||||
*/
|
||||
#define DBG_TAG "ipc.waitqueue"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rthw.h>
|
||||
@@ -64,7 +68,8 @@ int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will wake up a pending thread on the specified waiting queue that meets the conditions.
|
||||
* @brief This function will wake up a pending thread on the specified
|
||||
* waiting queue that meets the conditions.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
@@ -94,17 +99,89 @@ void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key)
|
||||
entry = rt_list_entry(node, struct rt_wqueue_node, list);
|
||||
if (entry->wakeup(entry, key) == 0)
|
||||
{
|
||||
rt_thread_resume(entry->polling_thread);
|
||||
need_schedule = 1;
|
||||
/**
|
||||
* even though another thread may interrupt the thread and
|
||||
* wakeup it meanwhile, we can asuume that condition is ready
|
||||
*/
|
||||
entry->polling_thread->error = RT_EOK;
|
||||
if (!rt_thread_resume(entry->polling_thread))
|
||||
{
|
||||
need_schedule = 1;
|
||||
|
||||
rt_list_remove(&(entry->list));
|
||||
break;
|
||||
rt_list_remove(&(entry->list));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||
if (need_schedule)
|
||||
rt_schedule();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function will wake up all pending thread on the specified
|
||||
* waiting queue that meets the conditions.
|
||||
*
|
||||
* @param queue is a pointer to the wait queue.
|
||||
*
|
||||
* @param key is the wakeup conditions, but it is not effective now, because
|
||||
* default wakeup function always return 0.
|
||||
* If user wants to use it, user should define their own wakeup
|
||||
* function.
|
||||
*/
|
||||
void rt_wqueue_wakeup_all(rt_wqueue_t *queue, void *key)
|
||||
{
|
||||
rt_base_t level;
|
||||
int need_schedule = 0;
|
||||
|
||||
rt_list_t *queue_list;
|
||||
struct rt_list_node *node;
|
||||
struct rt_wqueue_node *entry;
|
||||
|
||||
queue_list = &(queue->waiting_list);
|
||||
|
||||
level = rt_spin_lock_irqsave(&(queue->spinlock));
|
||||
/* set wakeup flag in the queue */
|
||||
queue->flag = RT_WQ_FLAG_WAKEUP;
|
||||
|
||||
if (!(rt_list_isempty(queue_list)))
|
||||
{
|
||||
for (node = queue_list->next; node != queue_list; )
|
||||
{
|
||||
entry = rt_list_entry(node, struct rt_wqueue_node, list);
|
||||
if (entry->wakeup(entry, key) == 0)
|
||||
{
|
||||
/**
|
||||
* even though another thread may interrupt the thread and
|
||||
* wakeup it meanwhile, we can asuume that condition is ready
|
||||
*/
|
||||
entry->polling_thread->error = RT_EOK;
|
||||
if (!rt_thread_resume(entry->polling_thread))
|
||||
{
|
||||
need_schedule = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wakeup happened too soon that waker hadn't slept */
|
||||
LOG_D("%s: Thread resume failed", __func__);
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
rt_spin_unlock_irqrestore(&(queue->spinlock), level);
|
||||
if (need_schedule)
|
||||
rt_schedule();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +261,7 @@ __exit_wakeup:
|
||||
|
||||
rt_wqueue_remove(&__wait);
|
||||
|
||||
return tid->error;
|
||||
return tid->error > 0 ? -tid->error : tid->error;
|
||||
}
|
||||
|
||||
int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int msec)
|
||||
|
||||
@@ -136,6 +136,7 @@ rt_inline void rt_ktime_hrtimer_keep_errno(rt_ktime_hrtimer_t timer, rt_err_t er
|
||||
RT_ASSERT(timer != RT_NULL);
|
||||
|
||||
timer->error = err;
|
||||
rt_set_errno(-err);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1109,17 +1109,20 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
|
||||
|
||||
if (tag && id >= 0)
|
||||
{
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
if (!rt_list_isempty(&_aliases_nodes))
|
||||
{
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info->id == id)
|
||||
{
|
||||
np = info->np;
|
||||
break;
|
||||
if (info->id == id)
|
||||
{
|
||||
np = info->np;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1130,18 +1133,20 @@ struct rt_ofw_node *rt_ofw_get_alias_node(const char *tag, int id)
|
||||
int ofw_alias_node_id(struct rt_ofw_node *np)
|
||||
{
|
||||
int id;
|
||||
struct alias_info *info;
|
||||
struct alias_info *info = RT_NULL;
|
||||
|
||||
if (np)
|
||||
{
|
||||
id = -1;
|
||||
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
if (!rt_list_isempty(&_aliases_nodes))
|
||||
{
|
||||
if (info->np == np)
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
{
|
||||
id = info->id;
|
||||
break;
|
||||
if (info->np == np)
|
||||
{
|
||||
id = info->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1161,18 +1166,20 @@ int rt_ofw_get_alias_id(struct rt_ofw_node *np, const char *tag)
|
||||
if (np && tag)
|
||||
{
|
||||
id = -1;
|
||||
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
if (!rt_list_isempty(&_aliases_nodes))
|
||||
{
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info->np == np)
|
||||
{
|
||||
id = info->id;
|
||||
break;
|
||||
if (info->np == np)
|
||||
{
|
||||
id = info->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1192,17 +1199,19 @@ int rt_ofw_get_alias_last_id(const char *tag)
|
||||
if (tag)
|
||||
{
|
||||
id = -1;
|
||||
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
if (!rt_list_isempty(&_aliases_nodes))
|
||||
{
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
rt_list_for_each_entry(info, &_aliases_nodes, list)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (rt_strncmp(info->tag, tag, info->tag_len))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info->id > id)
|
||||
{
|
||||
id = info->id;
|
||||
if (info->id > id)
|
||||
{
|
||||
id = info->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1465,7 +1474,7 @@ static const char *ofw_get_prop_fuzzy_name(const struct rt_ofw_node *np, const c
|
||||
char *sf, split_field[64];
|
||||
rt_size_t len = 0, max_ak = 0;
|
||||
const char *str, *result = RT_NULL;
|
||||
RT_DECLARE_BITMAP(ak, sizeof(split_field));
|
||||
RT_BITMAP_DECLARE(ak, sizeof(split_field));
|
||||
struct rt_ofw_prop *prop;
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,6 +8,9 @@ src = []
|
||||
if not GetDepend(['RT_USING_SERIAL']):
|
||||
Return('group')
|
||||
|
||||
if GetDepend(['RT_USING_SMART']):
|
||||
src += Glob('serial_tty.c')
|
||||
|
||||
if GetDepend(['RT_USING_SERIAL_V2']):
|
||||
src += ['serial_v2.c']
|
||||
else:
|
||||
|
||||
@@ -909,7 +909,7 @@ static rt_ssize_t rt_serial_write(struct rt_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(RT_USING_POSIX_TERMIOS) && !defined(RT_USING_TTY)
|
||||
#if defined(RT_USING_POSIX_TERMIOS) && !defined(RT_USING_SMART)
|
||||
struct speed_baudrate_item
|
||||
{
|
||||
speed_t speed;
|
||||
@@ -1058,7 +1058,7 @@ static rt_err_t rt_serial_control(struct rt_device *dev,
|
||||
}
|
||||
break;
|
||||
#ifdef RT_USING_POSIX_STDIO
|
||||
#if defined(RT_USING_POSIX_TERMIOS) && !defined(RT_USING_TTY)
|
||||
#if defined(RT_USING_POSIX_TERMIOS) && !defined(RT_USING_SMART)
|
||||
case TCGETA:
|
||||
{
|
||||
struct termios *tio = (struct termios*)args;
|
||||
@@ -1315,9 +1315,21 @@ rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,
|
||||
device->fops = &_serial_fops;
|
||||
#endif
|
||||
|
||||
#if defined(RT_USING_SMART)
|
||||
rt_hw_serial_register_tty(serial);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(RT_USING_SMART) && defined(LWP_DEBUG)
|
||||
static volatile int _early_input = 0;
|
||||
int lwp_startup_debug_request(void)
|
||||
{
|
||||
return _early_input;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ISR for serial interrupt */
|
||||
void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
{
|
||||
@@ -1360,8 +1372,17 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
rt_spin_unlock_irqrestore(&(serial->spinlock), level);
|
||||
}
|
||||
|
||||
/* invoke callback */
|
||||
if (serial->parent.rx_indicate != RT_NULL)
|
||||
/**
|
||||
* Invoke callback.
|
||||
* First try notify if any, and if notify is existed, rx_indicate()
|
||||
* is not callback. This seperate the priority and makes the reuse
|
||||
* of same serial device reasonable for RT console.
|
||||
*/
|
||||
if (serial->rx_notify.notify)
|
||||
{
|
||||
serial->rx_notify.notify(serial->rx_notify.dev);
|
||||
}
|
||||
else if (serial->parent.rx_indicate != RT_NULL)
|
||||
{
|
||||
rt_size_t rx_length;
|
||||
|
||||
@@ -1376,10 +1397,9 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
|
||||
serial->parent.rx_indicate(&serial->parent, rx_length);
|
||||
}
|
||||
}
|
||||
if (serial->rx_notify.notify)
|
||||
{
|
||||
serial->rx_notify.notify(serial->rx_notify.dev);
|
||||
}
|
||||
#if defined(RT_USING_SMART) && defined(LWP_DEBUG)
|
||||
_early_input = 1;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case RT_SERIAL_EVENT_TX_DONE:
|
||||
|
||||
321
components/drivers/serial/serial_tty.c
Normal file
321
components/drivers/serial/serial_tty.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-11-21 Shell init ver.
|
||||
*/
|
||||
|
||||
#define DBG_TAG "drivers.serial"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <terminal/terminal.h>
|
||||
|
||||
#define TTY_NAME_PREFIX "S" /* (S)erial */
|
||||
#define LWP_TTY_WORKQUEUE_PRIORITY 3
|
||||
|
||||
struct serial_tty_context
|
||||
{
|
||||
struct rt_serial_device *parent;
|
||||
struct rt_device_notify backup_notify;
|
||||
struct rt_work work;
|
||||
};
|
||||
|
||||
static struct rt_workqueue *_ttyworkq; /* system work queue */
|
||||
|
||||
static rt_atomic_t _device_id_counter = 0;
|
||||
|
||||
static long get_dec_digits(rt_ubase_t val)
|
||||
{
|
||||
long result = 1;
|
||||
while (1)
|
||||
{
|
||||
if (val < 10)
|
||||
return result;
|
||||
if (val < 100)
|
||||
return result + 1;
|
||||
if (val < 1000)
|
||||
return result + 2;
|
||||
if (val < 10000)
|
||||
return result + 3;
|
||||
val /= 10000U;
|
||||
result += 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *alloc_device_name(void)
|
||||
{
|
||||
char *tty_dev_name;
|
||||
unsigned int devid = rt_atomic_add(&_device_id_counter, 1);
|
||||
long digits_len = (sizeof(TTY_NAME_PREFIX) - 1) /* raw prefix */
|
||||
+ get_dec_digits(devid) + 1; /* tailing \0 */
|
||||
|
||||
tty_dev_name = rt_malloc(digits_len);
|
||||
if (tty_dev_name)
|
||||
rt_sprintf(tty_dev_name, "%s%u", TTY_NAME_PREFIX, devid);
|
||||
return tty_dev_name;
|
||||
}
|
||||
|
||||
static void _tty_rx_notify(struct rt_device *device)
|
||||
{
|
||||
lwp_tty_t tp;
|
||||
struct serial_tty_context *softc;
|
||||
|
||||
tp = rt_container_of(device, struct lwp_tty, parent);
|
||||
RT_ASSERT(tp);
|
||||
|
||||
softc = tty_softc(tp);
|
||||
|
||||
if (_ttyworkq)
|
||||
rt_workqueue_submit_work(_ttyworkq, &softc->work, 0);
|
||||
}
|
||||
|
||||
static void _tty_rx_worker(struct rt_work *work, void *data)
|
||||
{
|
||||
char input;
|
||||
rt_ssize_t readbytes;
|
||||
lwp_tty_t tp = data;
|
||||
struct serial_tty_context *softc;
|
||||
struct rt_serial_device *serial;
|
||||
|
||||
tty_lock(tp);
|
||||
|
||||
while (1)
|
||||
{
|
||||
softc = tty_softc(tp);
|
||||
serial = softc->parent;
|
||||
readbytes = rt_device_read(&serial->parent, -1, &input, 1);
|
||||
if (readbytes != 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ttydisc_rint(tp, input, 0);
|
||||
}
|
||||
|
||||
ttydisc_rint_done(tp);
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
rt_inline void _setup_serial(struct rt_serial_device *serial, lwp_tty_t tp,
|
||||
struct serial_tty_context *softc)
|
||||
{
|
||||
struct rt_device_notify notify;
|
||||
|
||||
softc->backup_notify = serial->rx_notify;
|
||||
notify.dev = &tp->parent;
|
||||
notify.notify = _tty_rx_notify;
|
||||
|
||||
rt_device_init(&serial->parent);
|
||||
|
||||
rt_work_init(&softc->work, _tty_rx_worker, tp);
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_NOTIFY_SET, ¬ify);
|
||||
}
|
||||
|
||||
rt_inline void _restore_serial(struct rt_serial_device *serial, lwp_tty_t tp,
|
||||
struct serial_tty_context *softc)
|
||||
{
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_NOTIFY_SET, &softc->backup_notify);
|
||||
}
|
||||
|
||||
static int _serial_isbusy(struct rt_serial_device *serial)
|
||||
{
|
||||
rt_thread_t user_thread = rt_console_current_user();
|
||||
rt_thread_t self_thread = rt_thread_self();
|
||||
|
||||
return rt_console_get_device() == &serial->parent &&
|
||||
(user_thread != RT_NULL && user_thread != self_thread);
|
||||
}
|
||||
|
||||
static void serial_tty_outwakeup(struct lwp_tty *tp)
|
||||
{
|
||||
char out_char;
|
||||
int len;
|
||||
struct serial_tty_context *context = tty_softc(tp);
|
||||
struct rt_serial_device *device;
|
||||
|
||||
if (!context || !context->parent)
|
||||
{
|
||||
LOG_E("%s: Data corruption", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
device = context->parent;
|
||||
|
||||
if (_serial_isbusy(device))
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
while ((len = ttydisc_getc(tp, &out_char, sizeof(out_char))) != 0)
|
||||
{
|
||||
device->ops->putc(device, out_char);
|
||||
|
||||
/* discard remaining if emergency output is happened */
|
||||
if (_serial_isbusy(device))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int serial_tty_open(struct lwp_tty *tp)
|
||||
{
|
||||
struct serial_tty_context *softc;
|
||||
struct rt_serial_device *serial;
|
||||
rt_err_t error;
|
||||
int oflags;
|
||||
|
||||
softc = tty_softc(tp);
|
||||
serial = softc->parent;
|
||||
|
||||
LOG_D("%s", __func__);
|
||||
|
||||
rt_device_control(&serial->parent, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
|
||||
|
||||
error = rt_device_open(&serial->parent, oflags);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
/**
|
||||
* to avoid driver accesssing null data,
|
||||
* these are setup only after tty is registered
|
||||
*/
|
||||
_setup_serial(serial, tp, softc);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void serial_tty_close(struct lwp_tty *tp)
|
||||
{
|
||||
struct serial_tty_context *softc;
|
||||
struct rt_serial_device *serial;
|
||||
softc = tty_softc(tp);
|
||||
serial = softc->parent;
|
||||
|
||||
LOG_D("%s", __func__);
|
||||
|
||||
_restore_serial(serial, tp, softc);
|
||||
rt_device_close(&serial->parent);
|
||||
}
|
||||
|
||||
static int serial_tty_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data,
|
||||
struct rt_thread *td)
|
||||
{
|
||||
int error;
|
||||
switch (cmd)
|
||||
{
|
||||
default:
|
||||
/**
|
||||
* Note: for the most case, we don't let serial layer handle ioctl,
|
||||
* for that they can't act properly regarding to the process
|
||||
* management system, since it is unawared of that. So a ENOSYS is
|
||||
* returned and caused the TTY layer to handle ioctl itself.
|
||||
*/
|
||||
error = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct lwp_ttydevsw serial_ttydevsw = {
|
||||
.tsw_open = serial_tty_open,
|
||||
.tsw_close = serial_tty_close,
|
||||
.tsw_ioctl = serial_tty_ioctl,
|
||||
.tsw_outwakeup = serial_tty_outwakeup,
|
||||
};
|
||||
|
||||
rt_err_t rt_hw_serial_register_tty(struct rt_serial_device *serial)
|
||||
{
|
||||
rt_err_t rc;
|
||||
lwp_tty_t tty;
|
||||
char *dev_name;
|
||||
struct serial_tty_context *softc;
|
||||
|
||||
if (serial->rx_notify.dev)
|
||||
{
|
||||
return -RT_EBUSY;
|
||||
}
|
||||
|
||||
softc = rt_malloc(sizeof(struct serial_tty_context));
|
||||
if (softc)
|
||||
{
|
||||
dev_name = alloc_device_name();
|
||||
if (dev_name)
|
||||
{
|
||||
softc->parent = serial;
|
||||
tty = lwp_tty_create(&serial_ttydevsw, softc);
|
||||
if (tty)
|
||||
{
|
||||
rc = lwp_tty_register(tty, dev_name);
|
||||
|
||||
if (rc != RT_EOK)
|
||||
{
|
||||
rt_free(tty);
|
||||
rt_free(softc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_free(softc);
|
||||
rc = -RT_ENOMEM;
|
||||
}
|
||||
|
||||
rt_free(dev_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_free(softc);
|
||||
rc = -RT_ENOMEM;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = -RT_ENOMEM;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
rt_err_t rt_hw_serial_unregister_tty(struct rt_serial_device *serial)
|
||||
{
|
||||
rt_device_t tty_dev;
|
||||
lwp_tty_t tp;
|
||||
struct serial_tty_context *softc;
|
||||
|
||||
tty_dev = serial->rx_notify.dev;
|
||||
tp = rt_container_of(tty_dev, struct lwp_tty, parent);
|
||||
|
||||
/* restore serial setting */
|
||||
softc = tty_softc(tp);
|
||||
serial->rx_notify = softc->backup_notify;
|
||||
|
||||
tty_rel_gone(tp);
|
||||
|
||||
/* device unregister? */
|
||||
rt_device_destroy(&tp->parent);
|
||||
/* resource free? */
|
||||
lwp_tty_delete(tp);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int _tty_workqueue_init(void)
|
||||
{
|
||||
if (_ttyworkq != RT_NULL)
|
||||
return RT_EOK;
|
||||
|
||||
_ttyworkq = rt_workqueue_create("ttyworkq", RT_SYSTEM_WORKQUEUE_STACKSIZE,
|
||||
LWP_TTY_WORKQUEUE_PRIORITY);
|
||||
RT_ASSERT(_ttyworkq != RT_NULL);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_PREV_EXPORT(_tty_workqueue_init);
|
||||
@@ -1,10 +0,0 @@
|
||||
from building import *
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
src = Glob('*.c')
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + "/include"]
|
||||
|
||||
group = DefineGroup('tty', src, depend = ['RT_USING_SMART', 'RT_USING_TTY'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
@@ -1,346 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <tty.h>
|
||||
|
||||
#define DBG_TAG "CONSOLE"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <ipc/waitqueue.h>
|
||||
#include <ipc/ringbuffer.h>
|
||||
|
||||
static struct tty_struct console_dev;
|
||||
static struct rt_ringbuffer console_rx_ringbuffer;
|
||||
static struct rt_wqueue console_rx_wqueue;
|
||||
static rt_thread_t console_rx_thread;
|
||||
static const size_t rb_bufsz = 0x1000;
|
||||
|
||||
static void console_rx_work(void *parameter)
|
||||
{
|
||||
int len;
|
||||
char ch;
|
||||
int lens;
|
||||
static char buf[0x1000];
|
||||
|
||||
struct tty_struct *console;
|
||||
console = &console_dev;
|
||||
|
||||
while (1)
|
||||
{
|
||||
rt_wqueue_wait(&console_rx_wqueue, 0, RT_WAITING_FOREVER);
|
||||
lens = 0;
|
||||
|
||||
while (lens < sizeof(buf))
|
||||
{
|
||||
len = rt_ringbuffer_get(&console_rx_ringbuffer, (void *)&ch, sizeof(ch));
|
||||
if (len == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lens += len;
|
||||
buf[lens-1] = ch;
|
||||
}
|
||||
|
||||
if (lens && console->ldisc->ops->receive_buf)
|
||||
{
|
||||
console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rx_thread_init(void)
|
||||
{
|
||||
void *rb_buffer;
|
||||
rt_thread_t thread;
|
||||
|
||||
rb_buffer = rt_malloc(rb_bufsz);
|
||||
rt_ringbuffer_init(&console_rx_ringbuffer, rb_buffer, rb_bufsz);
|
||||
rt_wqueue_init(&console_rx_wqueue);
|
||||
|
||||
thread = rt_thread_create("console_rx", console_rx_work, &console_dev, rb_bufsz, 10, 10);
|
||||
if (thread != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(thread);
|
||||
console_rx_thread = thread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(rx_thread_init);
|
||||
|
||||
static void console_rx_notify(struct rt_device *dev)
|
||||
{
|
||||
struct tty_struct *console = NULL;
|
||||
int len = 0;
|
||||
int lens = 0;
|
||||
char ch = 0;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
len = rt_device_read(console->io_dev, -1, &ch, 1);
|
||||
if (len == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lens += len;
|
||||
rt_ringbuffer_put(&console_rx_ringbuffer, (void *)&ch, sizeof(ch));
|
||||
if (lens > rb_bufsz)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (console_rx_thread)
|
||||
rt_wqueue_wakeup(&console_rx_wqueue, 0);
|
||||
}
|
||||
|
||||
struct tty_struct *console_tty_get(void)
|
||||
{
|
||||
return &console_dev;
|
||||
}
|
||||
|
||||
static void iodev_close(struct tty_struct *console)
|
||||
{
|
||||
struct rt_device_notify rx_notify;
|
||||
|
||||
rx_notify.notify = RT_NULL;
|
||||
rx_notify.dev = RT_NULL;
|
||||
|
||||
/* clear notify */
|
||||
rt_device_control(console->io_dev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
||||
rt_device_close(console->io_dev);
|
||||
}
|
||||
|
||||
static rt_err_t iodev_open(struct tty_struct *console)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device_notify rx_notify;
|
||||
rt_uint16_t oflags = 0;
|
||||
|
||||
rt_device_control(console->io_dev, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
|
||||
|
||||
ret = rt_device_open(console->io_dev, oflags);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rx_notify.notify = console_rx_notify;
|
||||
rx_notify.dev = (struct rt_device *)console;
|
||||
rt_device_control(console->io_dev, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
struct rt_device *console_get_iodev(void)
|
||||
{
|
||||
return console_dev.io_dev;
|
||||
}
|
||||
|
||||
struct rt_device *console_set_iodev(struct rt_device *iodev)
|
||||
{
|
||||
rt_base_t level = 0;
|
||||
struct rt_device *io_before = RT_NULL;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(iodev != RT_NULL);
|
||||
|
||||
console = &console_dev;
|
||||
|
||||
level = rt_spin_lock_irqsave(&console->spinlock);
|
||||
|
||||
RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED);
|
||||
|
||||
io_before = console->io_dev;
|
||||
if (iodev == io_before)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (console->init_flag >= TTY_INIT_FLAG_INITED)
|
||||
{
|
||||
/* close old device */
|
||||
iodev_close(console);
|
||||
}
|
||||
|
||||
console->io_dev = iodev;
|
||||
if (console->init_flag >= TTY_INIT_FLAG_INITED)
|
||||
{
|
||||
rt_err_t ret;
|
||||
/* open new device */
|
||||
ret = iodev_open(console);
|
||||
RT_ASSERT(ret == RT_EOK);
|
||||
}
|
||||
|
||||
exit:
|
||||
rt_spin_unlock_irqrestore(&console->spinlock, level);
|
||||
return io_before;
|
||||
}
|
||||
|
||||
/* RT-Thread Device Interface */
|
||||
/*
|
||||
* This function initializes console device.
|
||||
*/
|
||||
static rt_err_t rt_console_init(struct rt_device *dev)
|
||||
{
|
||||
rt_base_t level = 0;
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
|
||||
level = rt_spin_lock_irqsave(&console->spinlock);
|
||||
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_REGED);
|
||||
|
||||
result = iodev_open(console);
|
||||
if (result != RT_EOK)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
console->init_flag = TTY_INIT_FLAG_INITED;
|
||||
exit:
|
||||
rt_spin_unlock_irqrestore(&console->spinlock, level);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_close(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_console_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_ssize_t rt_console_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
|
||||
len = rt_device_write((struct rt_device *)console->io_dev, -1, buffer, size);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_err_t rt_console_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
struct tty_struct *console = RT_NULL;
|
||||
|
||||
console = (struct tty_struct *)dev;
|
||||
RT_ASSERT(console != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_INITED);
|
||||
|
||||
len = rt_device_control((struct rt_device *)console->io_dev, cmd, args);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops console_ops =
|
||||
{
|
||||
rt_console_init,
|
||||
rt_console_open,
|
||||
rt_console_close,
|
||||
rt_console_read,
|
||||
rt_console_write,
|
||||
rt_console_control,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* console register
|
||||
*/
|
||||
static struct dfs_file_ops con_fops;
|
||||
rt_err_t console_register(const char *name, struct rt_device *iodev)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
struct tty_struct *console = &console_dev;
|
||||
|
||||
RT_ASSERT(iodev != RT_NULL);
|
||||
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE);
|
||||
|
||||
tty_init(console, TTY_DRIVER_TYPE_CONSOLE, SERIAL_TYPE_NORMAL, iodev);
|
||||
console_ldata_init(console);
|
||||
|
||||
device = &(console->parent);
|
||||
device->type = RT_Device_Class_Char;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &console_ops;
|
||||
#else
|
||||
device->init = rt_console_init;
|
||||
device->open = rt_console_open;
|
||||
device->close = rt_console_close;
|
||||
device->read = rt_console_read;
|
||||
device->write = rt_console_write;
|
||||
device->control = rt_console_control;
|
||||
#endif
|
||||
|
||||
/* register a character device */
|
||||
ret = rt_device_register(device, name, 0);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("console driver register fail\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&con_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
device->fops = &con_fops;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __CONSOLE_
|
||||
#define __CONSOLE_
|
||||
#include <rtthread.h>
|
||||
#include "tty.h"
|
||||
|
||||
struct tty_struct *console_tty_get(void);
|
||||
struct rt_device *console_get_iodev(void);
|
||||
struct rt_device *console_set_iodev(struct rt_device *iodev);
|
||||
rt_err_t console_register(const char *name, struct rt_device *iodev);
|
||||
#endif
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __TTY_H__
|
||||
#define __TTY_H__
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <tty_ldisc.h>
|
||||
#ifdef RT_USING_SMART
|
||||
#include <lwp.h>
|
||||
#endif
|
||||
#if defined(RT_USING_POSIX_TERMIOS)
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#ifndef ENOIOCTLCMD
|
||||
#define ENOIOCTLCMD (515) /* No ioctl command */
|
||||
#endif
|
||||
|
||||
#define current lwp_self()
|
||||
#define __DISABLED_CHAR '\0'
|
||||
|
||||
struct tty_node
|
||||
{
|
||||
struct rt_lwp *lwp;
|
||||
struct tty_node *next;
|
||||
};
|
||||
|
||||
void tty_initstack(struct tty_node *node);
|
||||
int tty_push(struct tty_node **head, struct rt_lwp *lwp);
|
||||
struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp);
|
||||
/*
|
||||
* When a break, frame error, or parity error happens, these codes are
|
||||
* stuffed into the flags buffer.
|
||||
*/
|
||||
#define TTY_NORMAL 0
|
||||
#define TTY_BREAK 1
|
||||
#define TTY_FRAME 2
|
||||
#define TTY_PARITY 3
|
||||
#define TTY_OVERRUN 4
|
||||
|
||||
#define INTR_CHAR(tty) ((tty)->init_termios.c_cc[VINTR])
|
||||
#define QUIT_CHAR(tty) ((tty)->init_termios.c_cc[VQUIT])
|
||||
#define ERASE_CHAR(tty) ((tty)->init_termios.c_cc[VERASE])
|
||||
#define KILL_CHAR(tty) ((tty)->init_termios.c_cc[VKILL])
|
||||
#define EOF_CHAR(tty) ((tty)->init_termios.c_cc[VEOF])
|
||||
#define TIME_CHAR(tty) ((tty)->init_termios.c_cc[VTIME])
|
||||
#define MIN_CHAR(tty) ((tty)->init_termios.c_cc[VMIN])
|
||||
#define SWTC_CHAR(tty) ((tty)->init_termios.c_cc[VSWTC])
|
||||
#define START_CHAR(tty) ((tty)->init_termios.c_cc[VSTART])
|
||||
#define STOP_CHAR(tty) ((tty)->init_termios.c_cc[VSTOP])
|
||||
#define SUSP_CHAR(tty) ((tty)->init_termios.c_cc[VSUSP])
|
||||
#define EOL_CHAR(tty) ((tty)->init_termios.c_cc[VEOL])
|
||||
#define REPRINT_CHAR(tty) ((tty)->init_termios.c_cc[VREPRINT])
|
||||
#define DISCARD_CHAR(tty) ((tty)->init_termios.c_cc[VDISCARD])
|
||||
#define WERASE_CHAR(tty) ((tty)->init_termios.c_cc[VWERASE])
|
||||
#define LNEXT_CHAR(tty) ((tty)->init_termios.c_cc[VLNEXT])
|
||||
#define EOL2_CHAR(tty) ((tty)->init_termios.c_cc[VEOL2])
|
||||
|
||||
#define _I_FLAG(tty,f) ((tty)->init_termios.c_iflag & (f))
|
||||
#define _O_FLAG(tty,f) ((tty)->init_termios.c_oflag & (f))
|
||||
#define _C_FLAG(tty,f) ((tty)->init_termios.c_cflag & (f))
|
||||
#define _L_FLAG(tty,f) ((tty)->init_termios.c_lflag & (f))
|
||||
|
||||
#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK)
|
||||
#define I_BRKINT(tty) _I_FLAG((tty),BRKINT)
|
||||
#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR)
|
||||
#define I_PARMRK(tty) _I_FLAG((tty),PARMRK)
|
||||
#define I_INPCK(tty) _I_FLAG((tty),INPCK)
|
||||
#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP)
|
||||
#define I_INLCR(tty) _I_FLAG((tty),INLCR)
|
||||
#define I_IGNCR(tty) _I_FLAG((tty),IGNCR)
|
||||
#define I_ICRNL(tty) _I_FLAG((tty),ICRNL)
|
||||
#define I_IUCLC(tty) _I_FLAG((tty),IUCLC)
|
||||
#define I_IXON(tty) _I_FLAG((tty),IXON)
|
||||
#define I_IXANY(tty) _I_FLAG((tty),IXANY)
|
||||
#define I_IXOFF(tty) _I_FLAG((tty),IXOFF)
|
||||
#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL)
|
||||
#define I_IUTF8(tty) _I_FLAG((tty), IUTF8)
|
||||
|
||||
#define O_OPOST(tty) _O_FLAG((tty),OPOST)
|
||||
#define O_OLCUC(tty) _O_FLAG((tty),OLCUC)
|
||||
#define O_ONLCR(tty) _O_FLAG((tty),ONLCR)
|
||||
#define O_OCRNL(tty) _O_FLAG((tty),OCRNL)
|
||||
#define O_ONOCR(tty) _O_FLAG((tty),ONOCR)
|
||||
#define O_ONLRET(tty) _O_FLAG((tty),ONLRET)
|
||||
#define O_OFILL(tty) _O_FLAG((tty),OFILL)
|
||||
#define O_OFDEL(tty) _O_FLAG((tty),OFDEL)
|
||||
#define O_NLDLY(tty) _O_FLAG((tty),NLDLY)
|
||||
#define O_CRDLY(tty) _O_FLAG((tty),CRDLY)
|
||||
#define O_TABDLY(tty) _O_FLAG((tty),TABDLY)
|
||||
#define O_BSDLY(tty) _O_FLAG((tty),BSDLY)
|
||||
#define O_VTDLY(tty) _O_FLAG((tty),VTDLY)
|
||||
#define O_FFDLY(tty) _O_FLAG((tty),FFDLY)
|
||||
|
||||
#define C_BAUD(tty) _C_FLAG((tty),CBAUD)
|
||||
#define C_CSIZE(tty) _C_FLAG((tty),CSIZE)
|
||||
#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB)
|
||||
#define C_CREAD(tty) _C_FLAG((tty),CREAD)
|
||||
#define C_PARENB(tty) _C_FLAG((tty),PARENB)
|
||||
#define C_PARODD(tty) _C_FLAG((tty),PARODD)
|
||||
#define C_HUPCL(tty) _C_FLAG((tty),HUPCL)
|
||||
#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL)
|
||||
#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD)
|
||||
#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS)
|
||||
|
||||
#define L_ISIG(tty) _L_FLAG((tty),ISIG)
|
||||
#define L_ICANON(tty) _L_FLAG((tty),ICANON)
|
||||
#define L_XCASE(tty) _L_FLAG((tty),XCASE)
|
||||
#define L_ECHO(tty) _L_FLAG((tty),ECHO)
|
||||
#define L_ECHOE(tty) _L_FLAG((tty),ECHOE)
|
||||
#define L_ECHOK(tty) _L_FLAG((tty),ECHOK)
|
||||
#define L_ECHONL(tty) _L_FLAG((tty),ECHONL)
|
||||
#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH)
|
||||
#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP)
|
||||
#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL)
|
||||
#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT)
|
||||
#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE)
|
||||
#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO)
|
||||
#define L_PENDIN(tty) _L_FLAG((tty),PENDIN)
|
||||
#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
|
||||
#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC)
|
||||
|
||||
/*
|
||||
* Where all of the state associated with a tty is kept while the tty
|
||||
* is open. Since the termios state should be kept even if the tty
|
||||
* has been closed --- for things like the baud rate, etc --- it is
|
||||
* not stored here, but rather a pointer to the real state is stored
|
||||
* here. Possible the winsize structure should have the same
|
||||
* treatment, but (1) the default 80x24 is usually right and (2) it's
|
||||
* most often used by a windowing system, which will set the correct
|
||||
* size each time the window is created or resized anyway.
|
||||
* - TYT, 9/14/92
|
||||
*/
|
||||
struct tty_struct
|
||||
{
|
||||
struct rt_device parent;
|
||||
int type;
|
||||
int subtype;
|
||||
int init_flag;
|
||||
int index; //for pty
|
||||
int pts_lock; //for pty
|
||||
|
||||
struct tty_struct *other_struct; //for pty
|
||||
|
||||
struct termios init_termios;
|
||||
struct winsize winsize;
|
||||
struct rt_mutex lock;
|
||||
pid_t pgrp;
|
||||
pid_t session;
|
||||
struct rt_lwp *foreground;
|
||||
struct tty_node *head;
|
||||
|
||||
struct tty_ldisc *ldisc;
|
||||
void *disc_data;
|
||||
struct rt_device *io_dev;
|
||||
|
||||
struct rt_wqueue wait_queue;
|
||||
|
||||
#define RT_TTY_BUF 1024
|
||||
rt_list_t tty_drivers;
|
||||
struct rt_spinlock spinlock;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TTY_INIT_FLAG_NONE = 0,
|
||||
TTY_INIT_FLAG_ALLOCED,
|
||||
TTY_INIT_FLAG_REGED,
|
||||
TTY_INIT_FLAG_INITED,
|
||||
};
|
||||
|
||||
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
|
||||
#define TTY_DRIVER_TYPE_CONSOLE 0x0002
|
||||
#define TTY_DRIVER_TYPE_SERIAL 0x0003
|
||||
#define TTY_DRIVER_TYPE_PTY 0x0004
|
||||
#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
|
||||
#define TTY_DRIVER_TYPE_SYSCONS 0x0006
|
||||
|
||||
/* tty magic number */
|
||||
#define TTY_MAGIC 0x5401
|
||||
|
||||
/*
|
||||
* These bits are used in the flags field of the tty structure.
|
||||
*
|
||||
* So that interrupts won't be able to mess up the queues,
|
||||
* copy_to_cooked must be atomic with respect to itself, as must
|
||||
* tty->write. Thus, you must use the inline functions set_bit() and
|
||||
* clear_bit() to make things atomic.
|
||||
*/
|
||||
#define TTY_THROTTLED 0
|
||||
#define TTY_IO_ERROR 1
|
||||
#define TTY_OTHER_CLOSED 2
|
||||
#define TTY_EXCLUSIVE 3
|
||||
#define TTY_DEBUG 4
|
||||
#define TTY_DO_WRITE_WAKEUP 5
|
||||
#define TTY_PUSH 6
|
||||
#define TTY_CLOSING 7
|
||||
#define TTY_DONT_FLIP 8
|
||||
#define TTY_HW_COOK_OUT 14
|
||||
#define TTY_HW_COOK_IN 15
|
||||
#define TTY_PTY_LOCK 16
|
||||
#define TTY_NO_WRITE_SPLIT 17
|
||||
|
||||
#define NR_LDISCS 30
|
||||
|
||||
/* line disciplines */
|
||||
#define N_TTY 0
|
||||
#define N_SLIP 1
|
||||
#define N_MOUSE 2
|
||||
#define N_PPP 3
|
||||
#define N_STRIP 4
|
||||
#define N_AX25 5
|
||||
#define N_X25 6 /* X.25 async */
|
||||
#define N_6PACK 7
|
||||
#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
|
||||
#define N_R3964 9 /* Reserved for Simatic R3964 module */
|
||||
#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */
|
||||
#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */
|
||||
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data */
|
||||
/* cards about SMS messages */
|
||||
#define N_HDLC 13 /* synchronous HDLC */
|
||||
#define N_SYNC_PPP 14 /* synchronous PPP */
|
||||
#define N_HCI 15 /* Bluetooth HCI UART */
|
||||
#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */
|
||||
#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */
|
||||
#define N_PPS 18 /* Pulse per Second */
|
||||
#define N_V253 19 /* Codec control over voice modem */
|
||||
#define N_CAIF 20 /* CAIF protocol for talking to modems */
|
||||
#define N_GSM0710 21 /* GSM 0710 Mux */
|
||||
#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */
|
||||
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
|
||||
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
|
||||
#define N_NCI 25 /* NFC NCI UART */
|
||||
|
||||
/* Used for packet mode */
|
||||
#define TIOCPKT_DATA 0
|
||||
#define TIOCPKT_FLUSHREAD 1
|
||||
#define TIOCPKT_FLUSHWRITE 2
|
||||
#define TIOCPKT_STOP 4
|
||||
#define TIOCPKT_START 8
|
||||
#define TIOCPKT_NOSTOP 16
|
||||
#define TIOCPKT_DOSTOP 32
|
||||
|
||||
/* pty subtypes */
|
||||
#define PTY_TYPE_MASTER 0x0001
|
||||
#define PTY_TYPE_SLAVE 0x0002
|
||||
|
||||
/* serial subtype definitions */
|
||||
#define SERIAL_TYPE_NORMAL 1
|
||||
|
||||
#define max(a, b) ({\
|
||||
typeof(a) _a = a;\
|
||||
typeof(b) _b = b;\
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
#define min(a, b) ({\
|
||||
typeof(a) _a = a;\
|
||||
typeof(b) _b = b;\
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
void mutex_lock(rt_mutex_t mutex);
|
||||
void mutex_unlock(rt_mutex_t mutex);
|
||||
int __tty_check_change(struct tty_struct *tty, int sig);
|
||||
int tty_check_change(struct tty_struct *tty);
|
||||
|
||||
rt_inline struct rt_wqueue *wait_queue_get(struct rt_lwp *lwp, struct tty_struct *tty)
|
||||
{
|
||||
if (lwp == RT_NULL)
|
||||
{
|
||||
return &tty->wait_queue;
|
||||
}
|
||||
return &lwp->wait_queue;
|
||||
}
|
||||
|
||||
rt_inline struct rt_wqueue *wait_queue_current_get(struct rt_lwp *lwp, struct tty_struct *tty)
|
||||
{
|
||||
return wait_queue_get(lwp, tty);
|
||||
}
|
||||
|
||||
rt_inline void tty_wakeup_check(struct tty_struct *tty)
|
||||
{
|
||||
struct rt_wqueue *wq = NULL;
|
||||
|
||||
wq = wait_queue_current_get(tty->foreground, tty);
|
||||
rt_wqueue_wakeup(wq, (void*)POLLIN);
|
||||
}
|
||||
|
||||
int tty_init(struct tty_struct *tty, int type, int subtype, struct rt_device *iodev);
|
||||
const struct dfs_file_ops *tty_get_fops(void);
|
||||
|
||||
int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *arg);
|
||||
|
||||
void console_ldata_init(struct tty_struct *tty);
|
||||
int n_tty_receive_buf(struct tty_struct *tty, char *cp, int count);
|
||||
|
||||
#endif /*__TTY_H__*/
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#ifndef __TTY_LDISC_
|
||||
#define __TTY_LDISC_
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <tty.h>
|
||||
#if defined(RT_USING_POSIX_TERMIOS)
|
||||
#include <termios.h>
|
||||
#endif
|
||||
struct tty_struct;
|
||||
|
||||
struct tty_ldisc_ops
|
||||
{
|
||||
char *name;
|
||||
int num;
|
||||
|
||||
int (*open) (struct dfs_file *fd);
|
||||
int (*close) (struct tty_struct *tty);
|
||||
int (*ioctl) (struct dfs_file *fd, int cmd, void *args);
|
||||
int (*read) (struct dfs_file *fd, void *buf, size_t count);
|
||||
int (*write) (struct dfs_file *fd, const void *buf, size_t count);
|
||||
int (*flush) (struct dfs_file *fd);
|
||||
int (*lseek) (struct dfs_file *fd, off_t offset);
|
||||
int (*getdents) (struct dfs_file *fd, struct dirent *dirp, uint32_t count);
|
||||
|
||||
int (*poll) (struct dfs_file *fd, struct rt_pollreq *req);
|
||||
void (*set_termios) (struct tty_struct *tty, struct termios *old);
|
||||
int (*receive_buf) (struct tty_struct *tty,char *cp, int count);
|
||||
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct tty_ldisc
|
||||
{
|
||||
struct tty_ldisc_ops *ops;
|
||||
struct tty_struct *tty;
|
||||
};
|
||||
|
||||
#define TTY_LDISC_MAGIC 0x5403
|
||||
|
||||
int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
|
||||
void tty_ldisc_kill(struct tty_struct *tty);
|
||||
void tty_ldisc_init(struct tty_struct *tty);
|
||||
void tty_ldisc_release(struct tty_struct *tty);
|
||||
void n_tty_init(void);
|
||||
|
||||
#endif // __TTY_LDISC_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2021.12.07 linzhenxing first version
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
#include <tty.h>
|
||||
#include <tty_ldisc.h>
|
||||
|
||||
#define DBG_TAG "PTY"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
#define PTY_PTS_SIZE 10
|
||||
static struct tty_struct ptm_dev;
|
||||
static struct tty_struct pts_devs[PTY_PTS_SIZE];
|
||||
static int pts_index = 0;
|
||||
|
||||
static int pts_register(struct tty_struct *ptmx, struct tty_struct *pts, int pts_index);
|
||||
|
||||
/* check free pts device */
|
||||
static struct tty_struct *find_freepts(void)
|
||||
{
|
||||
for(int i = 0; i < PTY_PTS_SIZE; i++)
|
||||
{
|
||||
if (pts_devs[i].init_flag == TTY_INIT_FLAG_NONE)
|
||||
{
|
||||
pts_devs[i].init_flag = TTY_INIT_FLAG_ALLOCED;
|
||||
return &pts_devs[i];
|
||||
}
|
||||
}
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
/* Set the lock flag on a pty */
|
||||
static int pty_set_lock(struct tty_struct *tty, int *arg)
|
||||
{
|
||||
int val = *arg;
|
||||
|
||||
if (val)
|
||||
{
|
||||
tty->pts_lock = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
tty->pts_lock = val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pty_get_lock(struct tty_struct *tty, int *arg)
|
||||
{
|
||||
*arg = tty->pts_lock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pty_get_index(struct tty_struct *tty, int *arg)
|
||||
{
|
||||
*arg = tty->index;
|
||||
return 0;
|
||||
}
|
||||
/* RT-Thread Device Interface */
|
||||
/*
|
||||
* This function initializes console device.
|
||||
*/
|
||||
static rt_err_t pty_device_init(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
tty = (struct tty_struct *)dev;
|
||||
|
||||
RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_REGED);
|
||||
tty->init_flag = TTY_INIT_FLAG_INITED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t pty_device_open(struct rt_device *dev, rt_uint16_t oflag)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_err_t pty_device_close(struct rt_device *dev)
|
||||
{
|
||||
rt_err_t result = RT_EOK;
|
||||
struct tty_struct *tty = (struct tty_struct*)dev;
|
||||
//struct tty_struct *to = RT_NULL;
|
||||
|
||||
if (tty->subtype == PTY_TYPE_MASTER)
|
||||
{
|
||||
// to = tty->other_struct;
|
||||
// to->init_flag = TTY_INIT_FLAG_NONE;
|
||||
// to->other_struct = RT_NULL;
|
||||
// to->foreground = RT_NULL;
|
||||
// to->index = -1;
|
||||
// tty_ldisc_kill(to);
|
||||
// tty->other_struct = RT_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// to = tty->other_struct;
|
||||
// to->other_struct = RT_NULL;
|
||||
// tty->init_flag = TTY_INIT_FLAG_NONE;
|
||||
// tty->other_struct = RT_NULL;
|
||||
// tty->foreground = RT_NULL;
|
||||
// tty->index = -1;
|
||||
// tty->other_struct = RT_NULL;
|
||||
// tty_ldisc_kill(tty);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static rt_ssize_t pty_device_read(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_ssize_t pty_device_write(struct rt_device *dev,
|
||||
rt_off_t pos,
|
||||
const void *buffer,
|
||||
rt_size_t size)
|
||||
{
|
||||
rt_size_t len = 0;
|
||||
rt_base_t level = 0;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
struct tty_struct *to = RT_NULL;
|
||||
|
||||
tty = (struct tty_struct *)dev;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
|
||||
to = tty->other_struct;
|
||||
|
||||
level = rt_spin_lock_irqsave(&tty->spinlock);
|
||||
if (to->ldisc->ops->receive_buf)
|
||||
{
|
||||
len = to->ldisc->ops->receive_buf(to, (char *)buffer, size);
|
||||
}
|
||||
rt_spin_unlock_irqrestore(&tty->spinlock, level);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static rt_err_t pty_device_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
struct tty_struct *tty = (struct tty_struct *)dev;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
|
||||
return pty_set_lock(tty, (int *)args);
|
||||
case TIOCGPTLCK: /* Get PT Lock status */
|
||||
return pty_get_lock(tty, (int *)args);
|
||||
case TIOCGPTN: /* Get PT Number */
|
||||
return pty_get_index(tty, (int *)args);
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static int ptmx_open(struct dfs_file *fd)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tty_struct *tty = RT_NULL;
|
||||
struct tty_struct *pts = RT_NULL;
|
||||
struct tty_ldisc *ld = RT_NULL;
|
||||
|
||||
tty = (struct tty_struct *)fd->vnode->data;
|
||||
RT_ASSERT(tty != RT_NULL);
|
||||
|
||||
pts = find_freepts();
|
||||
if (pts == RT_NULL)
|
||||
{
|
||||
LOG_E("No free PTS device found.\n");
|
||||
return -1;
|
||||
}
|
||||
ret = pts_register(tty, pts, pts_index);
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG_E("pts register fail\n");
|
||||
rt_free(pts);
|
||||
return -1;
|
||||
}
|
||||
pts_index++;
|
||||
tty->other_struct = pts;
|
||||
|
||||
ld = tty->ldisc;
|
||||
if (ld->ops->open)
|
||||
{
|
||||
ret = ld->ops->open(fd);
|
||||
}
|
||||
|
||||
rt_device_t device = (rt_device_t)fd->vnode->data;
|
||||
if(fd->vnode->ref_count == 1)
|
||||
{
|
||||
ret = rt_device_open(device, fd->flags);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops pty_device_ops =
|
||||
{
|
||||
pty_device_init,
|
||||
pty_device_open,
|
||||
pty_device_close,
|
||||
pty_device_read,
|
||||
pty_device_write,
|
||||
pty_device_control,
|
||||
};
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
static struct dfs_file_ops pts_fops;
|
||||
static struct dfs_file_ops ptmx_fops;
|
||||
static int pts_register(struct tty_struct *ptmx, struct tty_struct *pts, int pts_index)
|
||||
{
|
||||
char name[20];
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
|
||||
RT_ASSERT(ptmx!=RT_NULL);
|
||||
|
||||
if (pts->init_flag != TTY_INIT_FLAG_ALLOCED)
|
||||
{
|
||||
LOG_E("pts%d has been registered\n", pts_index);
|
||||
ret = (-RT_EBUSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
tty_init(pts, TTY_DRIVER_TYPE_PTY, PTY_TYPE_SLAVE, NULL);
|
||||
pts->index = pts_index;
|
||||
pts->pts_lock = 1;
|
||||
pts->other_struct = ptmx;
|
||||
|
||||
device = &pts->parent;
|
||||
device->type = RT_Device_Class_Char;
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &pty_device_ops;
|
||||
#else
|
||||
device->init = pty_device_init;
|
||||
device->open = pty_device_open;
|
||||
device->close = pty_device_close;
|
||||
device->read = pty_device_read;
|
||||
device->write = pty_device_write;
|
||||
device->control = pty_device_control;
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
rt_snprintf(name, sizeof(name), "pts%d", pts_index);
|
||||
ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("pts%d register failed\n", pts_index);
|
||||
ret = -RT_EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&pts_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
device->fops = &pts_fops;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ptmx_register(void)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
struct rt_device *device = RT_NULL;
|
||||
struct tty_struct *ptmx = &ptm_dev;
|
||||
|
||||
RT_ASSERT(ptmx->init_flag == TTY_INIT_FLAG_NONE);
|
||||
|
||||
tty_init(ptmx, TTY_DRIVER_TYPE_PTY, PTY_TYPE_MASTER, NULL);
|
||||
|
||||
device = &(ptmx->parent);
|
||||
device->type = RT_Device_Class_Char;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
device->ops = &pty_device_ops;
|
||||
#else
|
||||
device->init = pty_device_init;
|
||||
device->open = pty_device_open;
|
||||
device->close = pty_device_close;
|
||||
device->read = pty_device_read;
|
||||
device->write = pty_device_write;
|
||||
device->control = pty_device_control;
|
||||
#endif /* RT_USING_DEVICE_OPS */
|
||||
|
||||
ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("ptmx register fail\n");
|
||||
ret = -RT_EIO;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
memcpy(&ptmx_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
|
||||
ptmx_fops.open = ptmx_open;
|
||||
device->fops = &ptmx_fops;
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(ptmx_register);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,122 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <rtthread.h>
|
||||
#include <tty.h>
|
||||
#if defined(RT_USING_POSIX_DEVIO)
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "TTY_IOCTL"
|
||||
#ifdef RT_TTY_DEBUG
|
||||
#define DBG_LVL DBG_LOG
|
||||
#else
|
||||
#define DBG_LVL DBG_INFO
|
||||
#endif /* RT_TTY_DEBUG */
|
||||
#include <rtdbg.h>
|
||||
|
||||
/*
|
||||
* Internal flag options for termios setting behavior
|
||||
*/
|
||||
#define TERMIOS_FLUSH 1
|
||||
#define TERMIOS_WAIT 2
|
||||
#define TERMIOS_TERMIO 4
|
||||
#define TERMIOS_OLD 8
|
||||
|
||||
/**
|
||||
* set_termios - set termios values for a tty
|
||||
* @tty: terminal device
|
||||
* @arg: user data
|
||||
* @opt: option information
|
||||
*
|
||||
* Helper function to prepare termios data and run necessary other
|
||||
* functions before using tty_set_termios to do the actual changes.
|
||||
*
|
||||
* Locking:
|
||||
* Called functions take ldisc and termios_rwsem locks
|
||||
*/
|
||||
|
||||
static int set_termios(struct tty_struct *tty, void *arg, int opt)
|
||||
{
|
||||
struct termios old_termios;
|
||||
struct tty_ldisc *ld = RT_NULL;
|
||||
struct termios *new_termios = (struct termios *)arg;
|
||||
rt_base_t level = 0;
|
||||
int retval = tty_check_change(tty);
|
||||
|
||||
if (retval)
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
memcpy(&old_termios, &(tty->init_termios), sizeof(struct termios));
|
||||
level = rt_spin_lock_irqsave(&tty->spinlock);
|
||||
tty->init_termios = *new_termios;
|
||||
rt_spin_unlock_irqrestore(&tty->spinlock, level);
|
||||
ld = tty->ldisc;
|
||||
if (ld != NULL)
|
||||
{
|
||||
if (ld->ops->set_termios)
|
||||
{
|
||||
ld->ops->set_termios(tty, &old_termios);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n_tty_ioctl_extend(struct tty_struct *tty, int cmd, void *args)
|
||||
{
|
||||
int ret = 0;
|
||||
void *p = (void *)args;
|
||||
struct tty_struct *real_tty = RT_NULL;
|
||||
|
||||
if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
|
||||
{
|
||||
real_tty = tty->other_struct;
|
||||
}
|
||||
else
|
||||
{
|
||||
real_tty = tty;
|
||||
}
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case TCGETS:
|
||||
case TCGETA:
|
||||
{
|
||||
struct termios *tio = (struct termios *)p;
|
||||
if (tio == RT_NULL)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
memcpy(tio, &real_tty->init_termios, sizeof(real_tty->init_termios));
|
||||
return ret;
|
||||
}
|
||||
case TCSETSF:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
|
||||
}
|
||||
case TCSETSW:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
|
||||
}
|
||||
case TCSETS:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_OLD);
|
||||
}
|
||||
case TCSETAF:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
|
||||
}
|
||||
case TCSETAW:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
|
||||
}
|
||||
case TCSETA:
|
||||
{
|
||||
return set_termios(real_tty, p, TERMIOS_TERMIO);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user