326 lines
7.5 KiB
C
326 lines
7.5 KiB
C
/*
|
|
* Copyright (c) 2006-2021, 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>
|
|
|
|
static struct tty_struct console_driver;
|
|
|
|
static void console_rx_notify(struct rt_device *dev)
|
|
{
|
|
struct tty_struct *console = NULL;
|
|
int len = 0;
|
|
int lens = 0;
|
|
char ch = 0;
|
|
char buf[1024] = {0};
|
|
|
|
console = (struct tty_struct *)dev;
|
|
RT_ASSERT(console != RT_NULL);
|
|
|
|
while (1)
|
|
{
|
|
len = rt_device_read(console->driver, -1, &ch, 1);
|
|
if (len == 0)
|
|
{
|
|
break;
|
|
}
|
|
lens += len;
|
|
buf[lens-1] = ch;
|
|
if (lens > 1024)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (console->ldisc->ops->receive_buf)
|
|
{
|
|
console->ldisc->ops->receive_buf((struct tty_struct *)console, buf, lens);
|
|
}
|
|
}
|
|
|
|
struct tty_struct *console_tty_get(void)
|
|
{
|
|
return &console_driver;
|
|
}
|
|
|
|
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->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
|
rt_device_close(console->driver);
|
|
}
|
|
|
|
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->driver, RT_DEVICE_CTRL_CONSOLE_OFLAG, &oflags);
|
|
|
|
ret = rt_device_open(console->driver, 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->driver, RT_DEVICE_CTRL_NOTIFY_SET, &rx_notify);
|
|
return RT_EOK;
|
|
}
|
|
|
|
struct rt_device *console_get_iodev(void)
|
|
{
|
|
rt_base_t level = 0;
|
|
struct rt_device *iodev = RT_NULL;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
iodev = console_driver.driver;
|
|
rt_hw_interrupt_enable(level);
|
|
return iodev;
|
|
}
|
|
|
|
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_driver;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
RT_ASSERT(console->init_flag >= TTY_INIT_FLAG_REGED);
|
|
|
|
io_before = console->driver;
|
|
|
|
if (iodev == io_before)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if (console->init_flag >= TTY_INIT_FLAG_INITED)
|
|
{
|
|
/* close old device */
|
|
iodev_close(console);
|
|
}
|
|
|
|
console->driver = 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_hw_interrupt_enable(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_hw_interrupt_disable();
|
|
|
|
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_hw_interrupt_enable(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_size_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_size_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->driver, -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->driver, 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_base_t level = 0;
|
|
rt_err_t ret = RT_EOK;
|
|
struct rt_device *device = RT_NULL;
|
|
struct tty_struct *console = &console_driver;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
RT_ASSERT(console->init_flag == TTY_INIT_FLAG_NONE);
|
|
RT_ASSERT(iodev != RT_NULL);
|
|
|
|
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");
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef RT_USING_POSIX_DEVIO
|
|
/* set fops */
|
|
console_set_fops(&con_fops);
|
|
device->fops = &con_fops;
|
|
#endif
|
|
console->type = TTY_DRIVER_TYPE_CONSOLE;
|
|
console->subtype = SERIAL_TYPE_NORMAL;
|
|
console->driver = iodev;
|
|
console->head = rt_calloc(1, sizeof(struct tty_node));
|
|
if (!console->head)
|
|
{
|
|
return -RT_ENOMEM;
|
|
}
|
|
tty_initstack(console->head);
|
|
|
|
rt_mutex_init(&console->lock, "ttylock", RT_IPC_FLAG_PRIO);
|
|
console->pgrp = -1;
|
|
console->session = -1;
|
|
console->foreground = RT_NULL;
|
|
rt_wqueue_init(&console->wait_queue);
|
|
|
|
tty_ldisc_init(console);
|
|
|
|
extern struct termios tty_std_termios;
|
|
console->init_termios = tty_std_termios;
|
|
console->init_termios.c_cflag =
|
|
B9600 | CS8 | CREAD | HUPCL; /* is normally B9600 default... */
|
|
console->init_termios.__c_ispeed = 9600;
|
|
console->init_termios.__c_ospeed = 9600;
|
|
|
|
console_ldata_init(console);
|
|
console->init_flag = TTY_INIT_FLAG_REGED;
|
|
exit:
|
|
rt_hw_interrupt_enable(level);
|
|
return ret;
|
|
}
|