/*
 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "console.h"
#include "fcntl.h"
#include "sys/ioctl.h"
#ifdef LOSCFG_FILE_MODE
#include "stdarg.h"
#endif
#include "unistd.h"
#include "securec.h"
#ifdef LOSCFG_SHELL_DMESG
#include "dmesg_pri.h"
#endif
#ifdef LOSCFG_SHELL
#include "shcmd.h"
#include "shell_pri.h"
#endif
#include "los_exc_pri.h"
#include "los_process_pri.h"
#include "los_sched_pri.h"
#include "user_copy.h"
#include "fs/driver.h"

#define EACH_CHAR 1
#define UART_IOC_MAGIC   'u'
#define UART_CFG_ATTR    _IOW(UART_IOC_MAGIC, 5, int)
#define UART_CFG_PRIVATE    _IOW(UART_IOC_MAGIC, 6, int)
/* 直接写在数据区的变量
#ifdef LOSCFG_QUICK_START
__attribute__ ((section(".data"))) UINT32 g_uart_fputc_en = 0;
#else
__attribute__ ((section(".data"))) UINT32 g_uart_fputc_en = 1;
#endif
*/
/* Inter-module variable */ //模块间变量
extern UINT32 g_uart_fputc_en;
STATIC UINT32 ConsoleSendTask(UINTPTR param);

STATIC UINT8 g_taskConsoleIDArray[LOSCFG_BASE_CORE_TSK_LIMIT];///< task 控制台ID池,同步task数量,理论上每个task都可以有一个自己的控制台
STATIC SPIN_LOCK_INIT(g_consoleSpin);///< 初始化控制台自旋锁
STATIC SPIN_LOCK_INIT(g_consoleWriteSpinLock);

#define SHELL_ENTRYID_INVALID     0xFFFFFFFF	///< 默认值,SHELL_ENTRYID 一般为 任务ID
#define SHELL_TASK_PRIORITY       9		///< shell 的优先级为 9
#define CONSOLE_CIRBUF_EVENT      0x02U	///< 控制台循环buffer事件	
#define CONSOLE_SEND_TASK_EXIT    0x04U	///< 控制台发送任务退出事件
#define CONSOLE_SEND_TASK_RUNNING 0x10U	///< 控制台发送任务正在执行事件

#define SHELL_ENTRY_NAME     "ShellEntry"
#define SHELL_ENTRY_NAME_LEN 10
CONSOLE_CB *g_console[CONSOLE_NUM];///< 控制台全局变量,控制台是共用的, 默认为 2个
#define MIN(a, b) ((a) < (b) ? (a) : (b))

/*
 * acquire uart driver function and filep of /dev/console,
 * then store uart driver function in *filepOps
 * and store filep of /dev/console in *privFilep.
 */
/*
* 获取/dev/console的uart驱动函数和filep，
* 然后将 uart 驱动函数存储在 *filepOps 中
* 并将 /dev/console 的文件存储在 *privFilep 中。
*/
INT32 GetFilepOps(const struct file *filep, struct file **privFilep, const struct file_operations_vfs **filepOps)
{
    INT32 ret;

    if ((filep == NULL) || (filep->f_vnode == NULL) || (filep->f_vnode->data == NULL)) {
        ret = EINVAL;
        goto ERROUT;
    }
	//通过 is_private 查找控制台设备的文件（现在是 *privFile）
    /* to find console device's filep(now it is *privFilep) throught i_private */
    struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
    *privFilep = (struct file *)drv->priv;// file 例如 g_serialFilep
    if (((*privFilep)->f_vnode == NULL) || ((*privFilep)->f_vnode->data == NULL)) {
        ret = EINVAL;
        goto ERROUT;
    }

    /* to find uart driver operation function throutht u.i_opss */

    drv = (struct drv_data *)(*privFilep)->f_vnode->data;

    *filepOps = (const struct file_operations_vfs *)drv->ops;//拿到串口驱动程序

    return ENOERR;
ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}
///获取控制台 模式值 
INT32 ConsoleTcGetAttr(INT32 fd, struct termios *termios)
{
    struct file *filep = NULL;
    CONSOLE_CB *consoleCB = NULL;

    INT32 ret = fs_getfilep(fd, &filep);
    if (ret < 0) {
        return -EPERM;
    }

    consoleCB = (CONSOLE_CB *)filep->f_priv;
    if (consoleCB == NULL) {
        return -EFAULT;
    }

    (VOID)memcpy_s(termios, sizeof(struct termios), &consoleCB->consoleTermios, sizeof(struct termios));
    return LOS_OK;
}
///设置控制台 模式值 
INT32 ConsoleTcSetAttr(INT32 fd, INT32 actions, const struct termios *termios)
{
    struct file *filep = NULL;
    CONSOLE_CB *consoleCB = NULL;

    (VOID)actions;

    INT32 ret = fs_getfilep(fd, &filep);
    if (ret < 0) {
        return -EPERM;
    }

    consoleCB = (CONSOLE_CB *)filep->f_priv;
    if (consoleCB == NULL) {
        return -EFAULT;
    }

    (VOID)memcpy_s(&consoleCB->consoleTermios, sizeof(struct termios), termios, sizeof(struct termios));
    return LOS_OK;
}

STATIC UINT32 ConsoleRefcountGet(const CONSOLE_CB *consoleCB)
{
    return consoleCB->refCount;
}
///设置控制台引用次数,也表示占用控制台的数量
STATIC VOID ConsoleRefcountSet(CONSOLE_CB *consoleCB, BOOL flag)
{
    (consoleCB->refCount) += flag ? 1 : -1;
}

///控制台是否被占用
BOOL IsConsoleOccupied(const CONSOLE_CB *consoleCB)
{
    return ConsoleRefcountGet(consoleCB);
}

STATIC INT32 ConsoleCtrlCaptureLine(CONSOLE_CB *consoleCB)
{
    struct termios consoleTermios = {0};
    UINT32 intSave;

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
    consoleTermios.c_lflag |= ICANON | ECHO;
    (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);

    return LOS_OK;
}
///< 铺捉到 ctrl + 字符, 例如 ctrl + c 
STATIC INT32 ConsoleCtrlCaptureChar(CONSOLE_CB *consoleCB)
{
    struct termios consoleTermios = {0};
    UINT32 intSave;

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
    consoleTermios.c_lflag &= ~(ICANON | ECHO);
    (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);

    return LOS_OK;
}
///< 铺捉到 ctrl + 右方向键(>)
STATIC INT32 ConsoleCtrlRightsCapture(CONSOLE_CB *consoleCB)
{
    (VOID)LOS_SemPend(consoleCB->consoleSem, LOS_WAIT_FOREVER);
    if ((ConsoleRefcountGet(consoleCB) == 0) &&
        (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) { //控制台没有任务使用且当前任务不是接收终端输入的shell entry 任务
        /* not 0:indicate that shellentry is in uart_read, suspend shellentry task directly 
		| 表示shellentry在uart_read中，直接挂起shellentry任务*/
        (VOID)LOS_TaskSuspend(consoleCB->shellEntryId);//挂起任务,意味着不接受输入
    }
    ConsoleRefcountSet(consoleCB, TRUE); //占用控制台
    return LOS_OK;
}

STATIC INT32 ConsoleCtrlRightsRelease(CONSOLE_CB *consoleCB)
{
    if (ConsoleRefcountGet(consoleCB) == 0) {
        PRINT_ERR("console is free\n");
        (VOID)LOS_SemPost(consoleCB->consoleSem);
        return LOS_NOK;
    } else {
        ConsoleRefcountSet(consoleCB, FALSE);//释放控制台
        if ((ConsoleRefcountGet(consoleCB) == 0) &&
            (OsCurrTaskGet()->taskID != consoleCB->shellEntryId)) {
            (VOID)LOS_TaskResume(consoleCB->shellEntryId);
        }
    }
    (VOID)LOS_SemPost(consoleCB->consoleSem);
    return LOS_OK;
}

STATIC CONSOLE_CB *OsGetConsoleByDevice(const CHAR *deviceName)
{
    INT32 ret;
    struct Vnode *vnode = NULL;

    VnodeHold();
    ret = VnodeLookup(deviceName, &vnode, 0);
    VnodeDrop();
    if (ret < 0) {
        set_errno(EACCES);
        return NULL;
    }

    if (g_console[CONSOLE_SERIAL - 1]->devVnode == vnode) {
        return g_console[CONSOLE_SERIAL - 1];
    } else if (g_console[CONSOLE_TELNET - 1]->devVnode == vnode) {
        return g_console[CONSOLE_TELNET - 1];
    } else {
        set_errno(ENOENT);
        return NULL;
    }
}
///获取控制台ID,(/dev/console1 = SERIAL, /dev/console2 = telnet)
STATIC INT32 OsGetConsoleID(const CHAR *deviceName)
{
    if ((deviceName != NULL) &&
        (strlen(deviceName) == strlen(SERIAL)) &&
        (!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
        return CONSOLE_SERIAL;//1 串口
    }
#ifdef LOSCFG_NET_TELNET
    else if ((deviceName != NULL) &&
             (strlen(deviceName) == strlen(TELNET)) &&
             (!strncmp(deviceName, TELNET, strlen(TELNET)))) {
        return CONSOLE_TELNET;//2 远程登录
    }
#endif
    return -1;
}
///通过路径找到控制台ID
STATIC INT32 OsConsoleFullpathToID(const CHAR *fullpath)
{
#define CONSOLE_SERIAL_1 "/dev/console1"
#define CONSOLE_TELNET_2 "/dev/console2"

    size_t len;

    if (fullpath == NULL) {
        return -1;
    }

    len = strlen(fullpath);
    if ((len == strlen(CONSOLE_SERIAL_1)) &&
        (!strncmp(fullpath, CONSOLE_SERIAL_1, strlen(CONSOLE_SERIAL_1)))) {
        return CONSOLE_SERIAL;
    }
#ifdef LOSCFG_NET_TELNET
    else if ((len == strlen(CONSOLE_TELNET_2)) &&
             (!strncmp(fullpath, CONSOLE_TELNET_2, strlen(CONSOLE_TELNET_2)))) {
        return CONSOLE_TELNET;
    }
#endif
    return -1;
}

STATIC BOOL ConsoleFifoEmpty(const CONSOLE_CB *console)
{
    return console->fifoOut == console->fifoIn;
}

STATIC VOID ConsoleFifoClearup(CONSOLE_CB *console)
{
    console->fifoOut = 0;
    console->fifoIn = 0;
    (VOID)memset_s(console->fifo, CONSOLE_FIFO_SIZE, 0, CONSOLE_FIFO_SIZE);
}
///控制台buf长度更新
STATIC VOID ConsoleFifoLenUpdate(CONSOLE_CB *console)
{
    console->currentLen = console->fifoIn - console->fifoOut;
}
///读取
STATIC INT32 ConsoleReadFifo(CHAR *buffer, CONSOLE_CB *console, size_t bufLen)
{
    INT32 ret;
    UINT32 readNum;

    readNum = MIN(bufLen, console->currentLen);
    ret = memcpy_s(buffer, bufLen, console->fifo + console->fifoOut, readNum);
    if (ret != EOK) {
        PRINTK("%s,%d memcpy_s failed\n", __FUNCTION__, __LINE__);
        return -1;
    }
    console->fifoOut += readNum;
    if (ConsoleFifoEmpty(console)) {
        ConsoleFifoClearup(console);
    }
    ConsoleFifoLenUpdate(console);
    return (INT32)readNum;
}
///打开串口或远程登录
INT32 FilepOpen(struct file *filep, const struct file_operations_vfs *fops)
{
    INT32 ret;
    if (fops->open == NULL) {
        return -EFAULT;
    }
	//使用 uart open函数打开filep（filep是对应 /dev/console 的 filep)
    /*
     * adopt uart open function to open filep (filep is
     * corresponding to filep of /dev/console)
     */
    ret = fops->open(filep);
    return (ret < 0) ? -EPERM : ret;
}

///向控制台buf中写入结束字符
STATIC INLINE VOID UserEndOfRead(CONSOLE_CB *consoleCB, struct file *filep,
                                 const struct file_operations_vfs *fops)
{
    CHAR ch;
    if (consoleCB->consoleTermios.c_lflag & ECHO) {
        ch = '\r';
        (VOID)fops->write(filep, &ch, 1);
    }
    consoleCB->fifo[consoleCB->fifoIn++] = '\n';
    consoleCB->fifo[consoleCB->fifoIn] = '\0';
    consoleCB->currentLen = consoleCB->fifoIn;
}
///根据VT终端标准 <ESC>[37m 为设置前景色
enum {
    STAT_NORMAL_KEY,///< 普通按键
    STAT_ESC_KEY,	///< 控制按键,只有 ESC 是
    STAT_MULTI_KEY	///< 多个按键,只有 [ 是
};
///用户shell检查上下左右键
STATIC INT32 UserShellCheckUDRL(const CHAR ch, INT32 *lastTokenType)
{
    INT32 ret = LOS_OK;
    if (ch == 0x1b) { /* 0x1b: ESC */
        *lastTokenType = STAT_ESC_KEY;// vt 的控制字符
        return ret;
    } else if (ch == 0x5b) { /* 0x5b: first Key combination */
        if (*lastTokenType == STAT_ESC_KEY) { //遇到 <ESC>[
            *lastTokenType = STAT_MULTI_KEY;
            return ret;
        }
    } else if (ch == 0x41) { /* up */
        if (*lastTokenType == STAT_MULTI_KEY) {
            *lastTokenType = STAT_NORMAL_KEY;
            return ret;
        }
    } else if (ch == 0x42) { /* down */
        if (*lastTokenType == STAT_MULTI_KEY) {
            *lastTokenType = STAT_NORMAL_KEY;
            return ret;
        }
    } else if (ch == 0x43) { /* right */
        if (*lastTokenType == STAT_MULTI_KEY) {
            *lastTokenType = STAT_NORMAL_KEY;
            return ret;
        }
    } else if (ch == 0x44) { /* left */
        if (*lastTokenType == STAT_MULTI_KEY) {
            *lastTokenType = STAT_NORMAL_KEY;
            return ret;
        }
    }
    return LOS_NOK;
}
///是否需要继续
STATIC INT32 IsNeedContinue(CONSOLE_CB *consoleCB, char ch, INT32 *lastTokenType)
{
    if (((ch == '\b') && (consoleCB->consoleTermios.c_lflag & ECHO) && (ConsoleFifoEmpty(consoleCB))) ||
        (UserShellCheckUDRL(ch, lastTokenType) == LOS_OK)) { /* parse the up/down/right/left key */
        return LOS_NOK;
    }

    return LOS_OK;
}
///输出到终端
STATIC VOID EchoToTerminal(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops, char ch)
{
    if (consoleCB->consoleTermios.c_lflag & ECHO) {
        if (ch == '\b') {//遇到回退字符
            (VOID)fops->write(filep, "\b \b", 3);//回退
        } else {
            (VOID)fops->write(filep, &ch, EACH_CHAR);//向终端写入字符
        }
    }
}
///存储读取的字符
STATIC VOID StoreReadChar(CONSOLE_CB *consoleCB, char ch, INT32 readcount)
{	//读取字符
    if ((readcount == EACH_CHAR) && (consoleCB->fifoIn <= (CONSOLE_FIFO_SIZE - 3))) {
        if (ch == '\b') {
            if (!ConsoleFifoEmpty(consoleCB)) {
                consoleCB->fifo[--consoleCB->fifoIn] = '\0';
            }
        } else {
            consoleCB->fifo[consoleCB->fifoIn] = (UINT8)ch;//将字符读入缓冲区
            consoleCB->fifoIn++;
        }
    }
}
///杀死进程组
VOID KillPgrp(UINT16 consoleId)
{
    if ((consoleId > CONSOLE_NUM) || (consoleId <= 0)) {
        return;
    }
    CONSOLE_CB *consoleCB = g_console[consoleId-1];
    /* the default of consoleCB->pgrpId is -1, may not be set yet, avoid killing all processes */
    if (consoleCB->pgrpId < 0) {
        return;
    }
    (VOID)OsKillLock(consoleCB->pgrpId, SIGINT);//发送信号 SIGINT对应 键盘中断（ctrl + c）信号
}
///使用参数buffer将控制台的buf接走
STATIC INT32 UserFilepRead(CONSOLE_CB *consoleCB, struct file *filep, const struct file_operations_vfs *fops,
                           CHAR *buffer, size_t bufLen)
{
    INT32 ret;
    INT32 needreturn = LOS_NOK;
    CHAR ch;
    INT32 lastTokenType = STAT_NORMAL_KEY;

    if (fops->read == NULL) {
        return -EFAULT;
    }
	
    /* Non-ICANON mode | 非规范模式 所有的输入即时有效，用户不需要另外输入行结束符，不能进行行编辑*/
    if ((consoleCB->consoleTermios.c_lflag & ICANON) == 0) {
        ret = fops->read(filep, buffer, bufLen);
        return (ret < 0) ? -EPERM : ret;
    }
	/** 
		在规范模式下，输入数据基于行进行处理。
		在用户输入一个行结束符（回车符、EOF等）之前，系统调用read()读不到用户输入的任何字符。
		除了EOF之外的行结束符（回车符等），与普通字符一样会被read()读到缓冲区中。
		在规范模式中，可以进行行编辑，而且一次调用read()最多只能读取一行数据。
		如果read()请求读取的数据字节少于当前行可读取的字节，则read()只读取被请求的字节数，剩下的字节下次再读。
	*/
    /* ICANON mode: store data to console buffer,  read data and stored data into console fifo */
    if (consoleCB->currentLen == 0) {//如果没有数据
        while (1) {//存储数据到控制台buf中
            ret = fops->read(filep, &ch, EACH_CHAR);//一个个字符读
            if (ret <= 0) {
                return ret;
            }

            if (IsNeedContinue(consoleCB, ch, &lastTokenType))//是否继续读
                continue;

            switch (ch) {
                case '\r':
                    ch = '\n';//回车换行
                case '\n':
                    EchoToTerminal(consoleCB, filep, fops, ch);//输出到终端
                    UserEndOfRead(consoleCB, filep, fops);//给控制台buf加上结束字符
                    ret = ConsoleReadFifo(buffer, consoleCB, bufLen);//读取控制台buf的信息到参数buffer中
                    needreturn = LOS_OK;//直接返回
                    break;
                case '\b':
                default:
                    EchoToTerminal(consoleCB, filep, fops, ch);//输出到终端
                    StoreReadChar(consoleCB, ch, ret);//将字符保存到控制台的buf中
                    break;
            }

            if (needreturn == LOS_OK)
                break;
        }
    } else {//如果数据准备好了,立即返回
        /* if data is already in console fifo, we returen them immediately */
        ret = ConsoleReadFifo(buffer, consoleCB, bufLen);//读取控制台buf的信息到参数buffer中
    }

    return ret;
}
///从串口或远程登录中读数据
INT32 FilepRead(struct file *filep, const struct file_operations_vfs *fops, CHAR *buffer, size_t bufLen)
{
    INT32 ret;
    if (fops->read == NULL) {
        return -EFAULT;
    }
    /*
     * adopt uart read function to read data from filep
     * and write data to buffer (filep is
     * corresponding to filep of /dev/console)
     *///采用uart read函数从文件中读取数据，将数据写入缓冲区（文件对应/dev/console的filep）
    ret = fops->read(filep, buffer, bufLen);
    return (ret < 0) ? -EPERM : ret;
}

///写数据到串口或远程登录
INT32 FilepWrite(struct file *filep, const struct file_operations_vfs *fops, const CHAR *buffer, size_t bufLen)
{
    INT32 ret;
    if (fops->write == NULL) {
        return -EFAULT;
    }

    ret = fops->write(filep, buffer, bufLen);
    return (ret < 0) ? -EPERM : ret;
}

///关闭串口或远程登录
INT32 FilepClose(struct file *filep, const struct file_operations_vfs *fops)
{
    INT32 ret;
    if ((fops == NULL) || (fops->close == NULL)) {
        return -EFAULT;
    }

    /*
     * adopt uart close function to open filep (filep is
     * corresponding to filep of /dev/console)
     */
    ret = fops->close(filep);
    return ret < 0 ? -EPERM : ret;
}

INT32 FilepIoctl(struct file *filep, const struct file_operations_vfs *fops, INT32 cmd, unsigned long arg)
{
    INT32 ret;
    if (fops->ioctl == NULL) {
        return -EFAULT;
    }

    ret = fops->ioctl(filep, cmd, arg);
    return (ret < 0) ? -EPERM : ret;
}

INT32 FilepPoll(struct file *filep, const struct file_operations_vfs *fops, poll_table *fds)
{
    INT32 ret;
    if (fops->poll == NULL) {
        return -EFAULT;
    }

    /*
     * adopt uart poll function to poll filep (filep is
     * corresponding to filep of /dev/serial)
     */
    ret = fops->poll(filep, fds);
    return (ret < 0) ? -EPERM : ret;
}

///对 file_operations_vfs->open 的实现函数,也就是说这是 打开控制台的实体函数.
STATIC INT32 ConsoleOpen(struct file *filep)
{
    INT32 ret;
    UINT32 consoleID;
    struct file *privFilep = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    consoleID = (UINT32)OsConsoleFullpathToID(filep->f_path);//先找到控制台ID返回 (1,2,-1)
    if (consoleID == (UINT32)-1) {
        ret = EPERM;
        goto ERROUT;
    }
    filep->f_priv = g_console[consoleID - 1]; //f_priv 每种文件系统对应结构体都同,所以是void的类型,如一张白纸,画什么模块自己定

    ret = GetFilepOps(filep, &privFilep, &fileOps);//获取文件系统的驱动程序
    if (ret != ENOERR) {
        ret = EINVAL;
        goto ERROUT;
    }
    ret = FilepOpen(privFilep, fileOps);//打开文件,其实调用的是 串口底层驱动程序  
    if (ret < 0) {
        ret = EPERM;
        goto ERROUT;
    }
    return ENOERR;

ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}
///关闭控制台
STATIC INT32 ConsoleClose(struct file *filep)
{
    INT32 ret;
    struct file *privFilep = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    ret = GetFilepOps(filep, &privFilep, &fileOps);
    if (ret != ENOERR) {
        ret = EINVAL;
        goto ERROUT;
    }
    ret = FilepClose(privFilep, fileOps);
    if (ret < 0) {
        ret = EPERM;
        goto ERROUT;
    }

    return ENOERR;

ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}

STATIC ssize_t DoRead(CONSOLE_CB *consoleCB, CHAR *buffer, size_t bufLen,
                      struct file *privFilep,
                      const struct file_operations_vfs *fileOps)
{
    INT32 ret;

#ifdef LOSCFG_SHELL
    if (OsCurrTaskGet()->taskID == consoleCB->shellEntryId) {//shell Entry 任务读取内容
        ret = FilepRead(privFilep, fileOps, buffer, bufLen);//直接从串口中读数据
    } else {//其他任务读取内容,需经过行规程处理
#endif
        (VOID)ConsoleCtrlRightsCapture(consoleCB);
        ret = UserFilepRead(consoleCB, privFilep, fileOps, buffer, bufLen);
        (VOID)ConsoleCtrlRightsRelease(consoleCB);
#ifdef LOSCFG_SHELL
    }
#endif

    return ret;
}
///任务从控制台读数据,例如 Shell Entry 任务会从此读数据
STATIC ssize_t ConsoleRead(struct file *filep, CHAR *buffer, size_t bufLen)
{
    INT32 ret;
    struct file *privFilep = NULL;
    CONSOLE_CB *consoleCB = NULL;
    CHAR *sbuffer = NULL;
    BOOL userBuf = FALSE;
    const struct file_operations_vfs *fileOps = NULL;

    if ((buffer == NULL) || (bufLen == 0)) {
        ret = EINVAL;
        goto ERROUT;
    }

    if (bufLen > CONSOLE_FIFO_SIZE) {
        bufLen = CONSOLE_FIFO_SIZE;
    }
	//检查buffer是否在用户区
    userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);
    ret = GetFilepOps(filep, &privFilep, &fileOps);
    if (ret != ENOERR) {
        ret = -EINVAL;
        goto ERROUT;
    }
    consoleCB = (CONSOLE_CB *)filep->f_priv;
    if (consoleCB == NULL) {
        consoleCB = OsGetConsoleByTaskID(OsCurrTaskGet()->taskID);
        if (consoleCB == NULL) {
            return -EFAULT;
        }
    }

    /*
     * shell task use FilepRead function to get data,
     * user task use UserFilepRead to get data
     */
    sbuffer = userBuf ? LOS_MemAlloc(m_aucSysMem0, bufLen) : buffer;
    if (sbuffer == NULL) {
        ret = -ENOMEM;
        goto ERROUT;
    }

    ret = DoRead(consoleCB, sbuffer, bufLen, privFilep, fileOps);//从 console buf中取数据
    if (ret < 0) {
        goto ERROUT;
    }

    if (userBuf) {
        if (LOS_ArchCopyToUser(buffer, sbuffer, bufLen) != 0) {
            ret = -EFAULT;
            goto ERROUT;
        }

        LOS_MemFree(m_aucSysMem0, sbuffer);
    }

    return ret;

ERROUT:
    if ((userBuf) && (sbuffer != NULL)) {
        LOS_MemFree(m_aucSysMem0, sbuffer);
    }
    set_errno(-ret);
    return VFS_ERROR;
}

STATIC ssize_t DoWrite(CirBufSendCB *cirBufSendCB, CHAR *buffer, size_t bufLen)
{
    INT32 cnt;
    size_t written = 0;
    UINT32 intSave;

#ifdef LOSCFG_SHELL_DMESG 
    (VOID)OsLogMemcpyRecord(buffer, bufLen); //同时写到内核缓冲区中,这也导致 OHOS# dmesg 会输出相同的内容
    if (OsCheckConsoleLock()) {
        return 0;
    }
#endif

    LOS_SpinLockSave(&g_consoleWriteSpinLock, &intSave);
    while (written < (INT32)bufLen) {
        /* Transform for CR/LR mode | 回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)*/
        if ((buffer[written] == '\n') || (buffer[written] == '\r')) {
            (VOID)LOS_CirBufWrite(&cirBufSendCB->cirBufCB, "\r", 1);
        }

        cnt = LOS_CirBufWrite(&cirBufSendCB->cirBufCB, &buffer[written], 1);
        if (cnt <= 0) {
            break;
        }
        written += cnt;
    }
    LOS_SpinUnlockRestore(&g_consoleWriteSpinLock, intSave);

    /* Log is cached but not printed when a system exception occurs */
    if (OsGetSystemStatus() == OS_SYSTEM_NORMAL) {
        (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);//发送数据事件
    }

    return written;
}
///用户任务写数据到控制台
STATIC ssize_t ConsoleWrite(struct file *filep, const CHAR *buffer, size_t bufLen)
{
    INT32 ret;
    CHAR *sbuffer = NULL;
    BOOL userBuf = FALSE;
    CirBufSendCB *cirBufSendCB = NULL;
    struct file *privFilep = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    if ((buffer == NULL) || (bufLen == 0)) {
        ret = EINVAL;
        goto ERROUT;
    }

    if (bufLen > CONSOLE_FIFO_SIZE) {
        bufLen = CONSOLE_FIFO_SIZE;
    }
	//检测buffer是否在用户空间
    userBuf = LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buffer, bufLen);

    ret = GetFilepOps(filep, &privFilep, &fileOps);
    if ((ret != ENOERR) || (fileOps->write == NULL) || (filep->f_priv == NULL)) {
        ret = EINVAL;
        goto ERROUT;
    }
    cirBufSendCB = ((CONSOLE_CB *)filep->f_priv)->cirBufSendCB;

    /*
     * adopt uart open function to read data from buffer | 用uart open函数从buffer中读取数据
     * and write data to filep (filep is | 向filep写入数据（filep对应/dev/console的filep）
     * corresponding to filep of /dev/console)
     */
    sbuffer = userBuf ? LOS_MemAlloc(m_aucSysMem0, bufLen) : (CHAR *)buffer;
    if (sbuffer == NULL) {
        ret = ENOMEM;
        goto ERROUT;
    }
	//将用户空间的数据拷贝进内核空间
    if (userBuf && (LOS_ArchCopyFromUser(sbuffer, buffer, bufLen) != 0)) {
        ret = EFAULT;
        goto ERROUT;
    }
    ret = DoWrite(cirBufSendCB, sbuffer, bufLen);//真正的写操作,向控制台任务发起写入事件

    if (userBuf) {
        LOS_MemFree(m_aucSysMem0, sbuffer);
    }

    return ret;

ERROUT:
    if (userBuf && sbuffer != NULL) {
        LOS_MemFree(m_aucSysMem0, sbuffer);
    }

    set_errno(ret);
    return VFS_ERROR;
}

STATIC INT32 ConsoleSetSW(CONSOLE_CB *consoleCB, unsigned long arg)
{
    struct termios kerTermios;
    UINT32 intSave;

    if (LOS_ArchCopyFromUser(&kerTermios, (struct termios *)arg, sizeof(struct termios)) != 0) {
        return -EFAULT;
    }

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &kerTermios);
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
    return LOS_OK;
}

#define DEFAULT_WINDOW_SIZE_COL 80
#define DEFAULT_WINDOW_SIZE_ROW 24
STATIC INT32 ConsoleGetWinSize(unsigned long arg)
{
    struct winsize kws = {
        .ws_col = DEFAULT_WINDOW_SIZE_COL,
        .ws_row = DEFAULT_WINDOW_SIZE_ROW
    };

    return (LOS_CopyFromKernel((VOID *)arg, sizeof(struct winsize), &kws, sizeof(struct winsize)) != 0) ?
        -EFAULT : LOS_OK;
}

STATIC INT32 ConsoleGetTermios(unsigned long arg)
{
    struct file *filep = NULL;
    CONSOLE_CB *consoleCB = NULL;

    INT32 ret = fs_getfilep(0, &filep);
    if (ret < 0) {
        return -EPERM;
    }

    consoleCB = (CONSOLE_CB *)filep->f_priv;
    if (consoleCB == NULL) {
        return -EFAULT;
    }

    return (LOS_ArchCopyToUser((VOID *)arg, &consoleCB->consoleTermios, sizeof(struct termios)) != 0) ?
        -EFAULT : LOS_OK;
}

INT32 ConsoleSetPgrp(CONSOLE_CB *consoleCB, unsigned long arg)
{
    if (LOS_ArchCopyFromUser(&consoleCB->pgrpId, (INT32 *)(UINTPTR)arg, sizeof(INT32)) != 0) {
        return -EFAULT;
    }
    return LOS_OK;
}

INT32 ConsoleGetPgrp(CONSOLE_CB *consoleCB, unsigned long arg)
{
    return (LOS_ArchCopyToUser((VOID *)arg, &consoleCB->pgrpId, sizeof(INT32)) != 0) ? -EFAULT : LOS_OK;
}

///< 对控制台i/o操作
STATIC INT32 ConsoleIoctl(struct file *filep, INT32 cmd, unsigned long arg)
{
    INT32 ret;
    struct file *privFilep = NULL;
    CONSOLE_CB *consoleCB = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    ret = GetFilepOps(filep, &privFilep, &fileOps);
    if (ret != ENOERR) {
        ret = EINVAL;
        goto ERROUT;
    }

    if (fileOps->ioctl == NULL) {
        ret = EFAULT;
        goto ERROUT;
    }

    consoleCB = (CONSOLE_CB *)filep->f_priv;
    if (consoleCB == NULL) {
        ret = EINVAL;
        goto ERROUT;
    }

    switch (cmd) {
        case CONSOLE_CONTROL_RIGHTS_CAPTURE:
            ret = ConsoleCtrlRightsCapture(consoleCB);
            break;
        case CONSOLE_CONTROL_RIGHTS_RELEASE:
            ret = ConsoleCtrlRightsRelease(consoleCB);
            break;
        case CONSOLE_CONTROL_CAPTURE_LINE:
            ret = ConsoleCtrlCaptureLine(consoleCB);
            break;
        case CONSOLE_CONTROL_CAPTURE_CHAR:
            ret = ConsoleCtrlCaptureChar(consoleCB);
            break;
        case CONSOLE_CONTROL_REG_USERTASK: //注册shell 客户端    http://weharmonyos.com/blog/72.html
            ret = ConsoleTaskReg(consoleCB->consoleID, arg);
            break;
        case TIOCGWINSZ:
            ret = ConsoleGetWinSize(arg);
            break;
        case TCSETSW:
            ret = ConsoleSetSW(consoleCB, arg);
            break;
        case TCGETS:
            ret = ConsoleGetTermios(arg);
            break;
        case TIOCGPGRP:
            ret = ConsoleGetPgrp(consoleCB, arg);
            break;
        case TIOCSPGRP:
            ret = ConsoleSetPgrp(consoleCB, arg);
            break;
        default:
            if ((cmd == UART_CFG_ATTR || cmd == UART_CFG_PRIVATE)
                && !LOS_IsUserAddress(arg)) {
                ret = EINVAL;
                goto ERROUT;
            }
            ret = fileOps->ioctl(privFilep, cmd, arg);
            break;
    }

    if (ret < 0) {
        ret = EPERM;
        goto ERROUT;
    }

    return ret;
ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}

STATIC INT32 ConsolePoll(struct file *filep, poll_table *fds)
{
    INT32 ret;
    struct file *privFilep = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    ret = GetFilepOps(filep, &privFilep, &fileOps);
    if (ret != ENOERR) {
        ret = EINVAL;
        goto ERROUT;
    }

    ret = FilepPoll(privFilep, fileOps, fds);
    if (ret < 0) {
        ret = EPERM;
        goto ERROUT;
    }
    return ret;

ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}

/*! console device driver function structure | 控制台设备驱动程序,对统一的vfs接口的实现 */
STATIC const struct file_operations_vfs g_consoleDevOps = {
    .open = ConsoleOpen,   /* open */
    .close = ConsoleClose, /* close */
    .read = ConsoleRead,   /* read */
    .write = ConsoleWrite, /* write */
    .seek = NULL,
    .ioctl = ConsoleIoctl,
    .mmap = NULL,
#ifndef CONFIG_DISABLE_POLL
    .poll = ConsolePoll,
#endif
};

/**
 * @brief termios 结构是在POSIX规范中定义的标准接口，它类似于系统V中的termio接口，
通过设置termios类型的数据结构中的值和使用一小组函数调用，你就可以对终端接口进行控制。
 * @param consoleCB 
 * @param deviceName 
 * @return STATIC 
 */
STATIC VOID OsConsoleTermiosInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
{
    struct termios consoleTermios = {0};
//c_cc[VINTR] 默认对应的控制符是^C，作用是清空输入和输出队列的数据并且向tty设备的前台进程组中的
//每一个程序发送一个SIGINT信号，对SIGINT信号没有定义处理程序的进程会马上退出。
    if ((deviceName != NULL) &&
        (strlen(deviceName) == strlen(SERIAL)) &&
        (!strncmp(deviceName, SERIAL, strlen(SERIAL)))) {
        consoleCB->isNonBlock = SetSerialBlock(consoleCB);

        /* set console to have a buffer for user */
        (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
        consoleTermios.c_lflag |= ICANON | ECHO;//控制模式标志 ICANON:使用标准输入模式 ECHO:显示输入字符
        consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */ //控制字符 
        (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
    }
#ifdef LOSCFG_NET_TELNET
    else if ((deviceName != NULL) &&
             (strlen(deviceName) == strlen(TELNET)) &&
             (!strncmp(deviceName, TELNET, strlen(TELNET)))) {
        consoleCB->isNonBlock = SetTelnetBlock(consoleCB);
        /* set console to have a buffer for user */
        (VOID)ConsoleTcGetAttr(consoleCB->fd, &consoleTermios);
        consoleTermios.c_lflag |= ICANON | ECHO;//控制模式标志 ICANON:使用标准输入模式 ECHO:显示输入字符
        consoleTermios.c_cc[VINTR] = 3; /* /003 for ^C */ //控制字符
        (VOID)ConsoleTcSetAttr(consoleCB->fd, 0, &consoleTermios);
    }
#endif
}
///控制台文件实例初始化
STATIC INT32 OsConsoleFileInit(CONSOLE_CB *consoleCB)
{
    INT32 ret;
    struct Vnode *vnode = NULL;
    struct file *filep = NULL;

    VnodeHold();
    ret = VnodeLookup(consoleCB->name, &vnode, 0);
    if (ret != LOS_OK) {
        ret = EACCES;
        goto ERROUT;
    }

    filep = files_allocate(vnode, O_RDWR, 0, consoleCB, FILE_START_FD);//分配FD给了控制台
    if (filep == NULL) {
        ret = EMFILE;
        goto ERROUT;
    }
    filep->ops = (struct file_operations_vfs *)((struct drv_data *)vnode->data)->ops;//关联驱动程序
    consoleCB->fd = filep->fd;

ERROUT:
    VnodeDrop();
    return ret;
}

/*
 * Initialized console control platform so that when we operate /dev/console
 * as if we are operating /dev/ttyS0 (uart0). | 初始化控制台以此来控制平台，以便在操作/dev/console时，就好像我们在操作/dev/ttyS0（uart0）
 */
STATIC INT32 OsConsoleDevInit(CONSOLE_CB *consoleCB, const CHAR *deviceName)
{
    INT32 ret;
    struct file *filep = NULL;
    struct Vnode *vnode = NULL;
    struct file_operations_vfs *devOps = NULL;

    /* allocate memory for filep,in order to unchange the value of filep */
    filep = (struct file *)LOS_MemAlloc(m_aucSysMem0, sizeof(struct file));
    if (filep == NULL) {
        ret = ENOMEM;
        goto ERROUT;
    }

    VnodeHold();
    ret = VnodeLookup(deviceName, &vnode, V_DUMMY);	//找到对应 vnode节点
    VnodeDrop(); // not correct, but can't fix perfectly here
    if (ret != LOS_OK) {
        ret = EACCES;
        PRINTK("!! can not find %s\n", consoleCB->name);
        goto ERROUT;
    }

    consoleCB->devVnode = vnode;//关联vnode节点

    /*
     * initialize the console filep which is associated with /dev/console,
     * assign the uart0 inode of /dev/ttyS0 to console inod of /dev/console,
     * then we can operate console's filep as if we operate uart0 filep of
     * /dev/ttyS0.
     */
     /*
     初始化与/dev/console关联的console filep，将/dev/ttyS0的uart0 inode赋给
     /dev/console的console inod，就可以像操作/dev/ttyS0的uart0 filep一样操作控制台的filep
     */
    (VOID)memset_s(filep, sizeof(struct file), 0, sizeof(struct file));
    filep->f_oflags = O_RDWR;	//读写模式
    filep->f_pos = 0;	//偏移位置,默认为0
    filep->f_vnode = vnode;	//节点关联
    filep->f_path = NULL;	//
    filep->f_priv = NULL;	//
    /*
     * Use filep to connect console and uart, we can find uart driver function throught filep.
     * now we can operate /dev/console to operate /dev/ttyS0 through filep.
     */
     //使用filep连接控制台和uart，通过它可以找到uart驱动函数, 可以通过filep操作/dev/console
    devOps = (struct file_operations_vfs *)((struct drv_data*)vnode->data)->ops;//获取默认驱动程序
    if (devOps != NULL && devOps->open != NULL) {
        (VOID)devOps->open(filep);
    } else {
        ret = ENOSYS;
        goto ERROUT;
    }

    ret = register_driver(consoleCB->name, &g_consoleDevOps, DEFFILEMODE, filep);//注册控制台设备驱动程序
    if (ret != LOS_OK) {
        goto ERROUT;
    }

    return LOS_OK;

ERROUT:
     if (filep) {
        (VOID)LOS_MemFree(m_aucSysMem0, filep);
    }

    set_errno(ret);
    return LOS_NOK;
}
/// 注销控制台设备
STATIC UINT32 OsConsoleDevDeinit(const CONSOLE_CB *consoleCB)
{
    return unregister_driver(consoleCB->name);//注销驱动
}

/// 创建一个控制台循环buf
STATIC CirBufSendCB *ConsoleCirBufCreate(VOID)
{
    UINT32 ret;
    CHAR *fifo = NULL;
    CirBufSendCB *cirBufSendCB = NULL;
    CirBuf *cirBufCB = NULL;

    cirBufSendCB = (CirBufSendCB *)LOS_MemAlloc(m_aucSysMem0, sizeof(CirBufSendCB));//分配一个循环buf发送控制块
    if (cirBufSendCB == NULL) {
        return NULL;
    }
    (VOID)memset_s(cirBufSendCB, sizeof(CirBufSendCB), 0, sizeof(CirBufSendCB));

    fifo = (CHAR *)LOS_MemAlloc(m_aucSysMem0, CONSOLE_CIRCBUF_SIZE);//分配FIFO buf 1K 
    if (fifo == NULL) {
        goto ERROR_WITH_SENDCB;
    }
    (VOID)memset_s(fifo, CONSOLE_CIRCBUF_SIZE, 0, CONSOLE_CIRCBUF_SIZE);

    cirBufCB = &cirBufSendCB->cirBufCB;
    ret = LOS_CirBufInit(cirBufCB, fifo, CONSOLE_CIRCBUF_SIZE);//环形BUF初始化
    if (ret != LOS_OK) {
        goto ERROR_WITH_FIFO;
    }

    (VOID)LOS_EventInit(&cirBufSendCB->sendEvent);//事件初始化
    return cirBufSendCB;

ERROR_WITH_FIFO:
    (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);
ERROR_WITH_SENDCB:
    (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);
    return NULL;
}
/// 删除循环buf
STATIC VOID ConsoleCirBufDelete(CirBufSendCB *cirBufSendCB)
{
    CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;

    (VOID)LOS_MemFree(m_aucSysMem0, cirBufCB->fifo);//释放内存 8K
    LOS_CirBufDeinit(cirBufCB);//清除初始化操作
    (VOID)LOS_EventDestroy(&cirBufSendCB->sendEvent);//销毁事件
    (VOID)LOS_MemFree(m_aucSysMem0, cirBufSendCB);//释放循环buf发送控制块
}
/// 控制台缓存初始化，创建一个 发送任务
STATIC UINT32 OsConsoleBufInit(CONSOLE_CB *consoleCB)
{
    UINT32 ret;
    TSK_INIT_PARAM_S initParam = {0};

    consoleCB->cirBufSendCB = ConsoleCirBufCreate();//创建控制台
    if (consoleCB->cirBufSendCB == NULL) {
        return LOS_NOK;
    }

    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ConsoleSendTask;//控制台发送任务入口函数
    initParam.usTaskPrio   = SHELL_TASK_PRIORITY;	//优先级9
    initParam.auwArgs[0]   = (UINTPTR)consoleCB;	//入口函数的参数
    initParam.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;	//16K
    initParam.pcName = (consoleCB->consoleID == CONSOLE_SERIAL) ? "SendToSer" : "SendToTelnet"; //控制台的两种方式
    initParam.uwResved     = LOS_TASK_STATUS_DETACHED; //使用任务分离模式

    ret = LOS_TaskCreate(&consoleCB->sendTaskID, &initParam);//创建task 并加入就绪队列，申请立即调度
    if (ret != LOS_OK) { //创建失败处理
        ConsoleCirBufDelete(consoleCB->cirBufSendCB);//释放循环buf
        consoleCB->cirBufSendCB = NULL;//置NULL
        return LOS_NOK;
    }//永久等待读取 CONSOLE_SEND_TASK_RUNNING 事件,CONSOLE_SEND_TASK_RUNNING 由 ConsoleSendTask 发出.
    (VOID)LOS_EventRead(&consoleCB->cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING,
                        LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
	// ... 读取到 CONSOLE_SEND_TASK_RUNNING 事件才会往下执行  
    return LOS_OK;
}
/// 控制台buf去初始化
STATIC VOID OsConsoleBufDeinit(CONSOLE_CB *consoleCB)
{
    CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;

    consoleCB->cirBufSendCB = NULL;
    (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_EXIT);//写任务退出事件 ConsoleSendTask将会收到事件，退出死循环
}
/// 控制台描述符初始化
STATIC CONSOLE_CB *OsConsoleCBInit(UINT32 consoleID)
{
    CONSOLE_CB *consoleCB = (CONSOLE_CB *)LOS_MemAlloc((VOID *)m_aucSysMem0, sizeof(CONSOLE_CB));//内核空间分配控制台描述符
    if (consoleCB == NULL) {
        return NULL;
    }
    (VOID)memset_s(consoleCB, sizeof(CONSOLE_CB), 0, sizeof(CONSOLE_CB));//清0

    consoleCB->consoleID = consoleID;//记录控制台ID
    consoleCB->pgrpId = -1;
    consoleCB->shellEntryId = SHELL_ENTRYID_INVALID; /* initialize shellEntryId to an invalid value *///将shellEntryId初始化为无效值
    consoleCB->name = LOS_MemAlloc((VOID *)m_aucSysMem0, CONSOLE_NAMELEN);//控制台名称 不能多于16个字符
    if (consoleCB->name == NULL) {
        PRINT_ERR("consoleCB->name malloc failed\n");
        (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);
        return NULL;
    }
    return consoleCB;
}
/// 释放控制台描述符初始化时所占用的内核空间
STATIC VOID OsConsoleCBDeinit(CONSOLE_CB *consoleCB)
{
    (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB->name);//释放控制台名称占用的内核内存
    consoleCB->name = NULL;
    (VOID)LOS_MemFree((VOID *)m_aucSysMem0, consoleCB);//释放控制台描述符所占用的内核内存
}
/// 创建一个控制台，这个函数的goto语句贼多
STATIC CONSOLE_CB *OsConsoleCreate(UINT32 consoleID, const CHAR *deviceName)
{
    INT32 ret;
    CONSOLE_CB *consoleCB = OsConsoleCBInit(consoleID);//初始化控制台
    if (consoleCB == NULL) {
        PRINT_ERR("console malloc error.\n");
        return NULL;
    }

    ret = snprintf_s(consoleCB->name, CONSOLE_NAMELEN, CONSOLE_NAMELEN - 1,
                     "%s%u", CONSOLE, consoleCB->consoleID);//通过printf方式得到name 例如: /dev/console1
    if (ret == -1) {
        PRINT_ERR("consoleCB->name snprintf_s failed\n");
        goto ERR_WITH_NAME;
    }

    ret = (INT32)OsConsoleBufInit(consoleCB);//控制台buf初始化,创建 ConsoleSendTask 任务
    if (ret != LOS_OK) {
        PRINT_ERR("console OsConsoleBufInit error. %d\n", ret);
        goto ERR_WITH_NAME;
    }

    ret = (INT32)LOS_SemCreate(1, &consoleCB->consoleSem);//创建控制台信号量
    if (ret != LOS_OK) {
        PRINT_ERR("create sem for uart failed\n");
        goto ERR_WITH_BUF;
    }

    ret = OsConsoleDevInit(consoleCB, deviceName);//控制台设备初始化,注意这步要在 OsConsoleFileInit 的前面.
    if (ret != LOS_OK) {//先注册驱动程序
        PRINT_ERR("console OsConsoleDevInit error. %d\n", ret);
        goto ERR_WITH_SEM;
    }

    ret = OsConsoleFileInit(consoleCB);	//为 /dev/console(n|1:2)分配fd(n)
    if (ret != LOS_OK) {
        PRINT_ERR("console OsConsoleFileInit error. %d\n", ret);
        goto ERR_WITH_DEV;
    }

    OsConsoleTermiosInit(consoleCB, deviceName);//控制台行规程初始化
    return consoleCB;

ERR_WITH_DEV:
    ret = (INT32)OsConsoleDevDeinit(consoleCB);//控制台设备注销
    if (ret != LOS_OK) {
        PRINT_ERR("OsConsoleDevDeinit failed!\n");
    }
ERR_WITH_SEM:
    (VOID)LOS_SemDelete(consoleCB->consoleSem);//控制台信号量删除
ERR_WITH_BUF:
    OsConsoleBufDeinit(consoleCB);//控制台buf取消初始化
ERR_WITH_NAME:
    OsConsoleCBDeinit(consoleCB);//控制块取消初始化
    return NULL;
}
/// 删除控制台
STATIC UINT32 OsConsoleDelete(CONSOLE_CB *consoleCB)
{
    UINT32 ret;

    (VOID)files_close(consoleCB->fd);//回收系统文件句柄
    ret = OsConsoleDevDeinit(consoleCB);//注销驱动程序
    if (ret != LOS_OK) {
        PRINT_ERR("OsConsoleDevDeinit failed!\n");
    }
    OsConsoleBufDeinit((CONSOLE_CB *)consoleCB);//回收环形缓存区
    (VOID)LOS_SemDelete(consoleCB->consoleSem);//删除信号量
    (VOID)LOS_MemFree(m_aucSysMem0, consoleCB->name);//回收控制台名称,此名称占用内核内存
    consoleCB->name = NULL;
    (VOID)LOS_MemFree(m_aucSysMem0, consoleCB);//回收控制块本身占用的内存

    return ret;
}
///初始化系统控制台并返回 stdinfd stdoutfd stderrfd ，和system_console_deinit成对出现，像控制台的构造函数
/* Initialized system console and return stdinfd stdoutfd stderrfd */
INT32 system_console_init(const CHAR *deviceName)//deviceName: /dev/serial /dev/telnet
{
#ifdef LOSCFG_SHELL
    UINT32 ret;
#endif
    INT32 consoleID;
    UINT32 intSave;
    CONSOLE_CB *consoleCB = NULL;

    consoleID = OsGetConsoleID(deviceName);//获取控制台ID 返回[ CONSOLE_SERIAL(1) | CONSOLE_TELNET(2) | -1 ]三种结果
    if (consoleID == -1) {
        PRINT_ERR("device is full.\n");
        return VFS_ERROR;
    }

    consoleCB = OsConsoleCreate((UINT32)consoleID, deviceName);//创建一个控制台
    if (consoleCB == NULL) {
        PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
        return VFS_ERROR;
    }

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    g_console[consoleID - 1] = consoleCB;//全局变量,  g_console最大值只有2 ,所有任务共用控制台.
    if (OsCurrTaskGet() != NULL) {//当前task
        g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = (UINT8)consoleID;//任务绑定控制台ID
    }
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);

#ifdef LOSCFG_SHELL //shell支持
    ret = OsShellInit(consoleID);//初始化shell
    if (ret != LOS_OK) {//初始化shell失败
        PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
        LOS_SpinLockSave(&g_consoleSpin, &intSave);
        (VOID)OsConsoleDelete(consoleCB);//删除控制台
        g_console[consoleID - 1] = NULL;
        if (OsCurrTaskGet() != NULL) {
            g_taskConsoleIDArray[OsCurrTaskGet()->taskID] = 0;//表示当前任务还没有控制台。
        }
        LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
        return VFS_ERROR;
    }
#endif

    return ENOERR;
}
///控制台结束前的处理 和 system_console_init成对出现,像控制台的析构函数
INT32 system_console_deinit(const CHAR *deviceName)
{
    UINT32 ret;
    CONSOLE_CB *consoleCB = NULL;
    UINT32 taskIdx;
    LosTaskCB *taskCB = NULL;
    UINT32 intSave;

    consoleCB = OsGetConsoleByDevice(deviceName);//通过设备名称获取控制台描述符
    if (consoleCB == NULL) {
        return VFS_ERROR;
    }

#ifdef LOSCFG_SHELL
    (VOID)OsShellDeinit((INT32)consoleCB->consoleID);//shell结束前的处理，shell的析构函数
#endif

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    /* Redirect all tasks to serial as telnet was unavailable after deinitializing */
	//在远程登陆去初始化后变成无效时，将所有任务的控制台重定向到串口方式。
    for (taskIdx = 0; taskIdx < g_taskMaxNum; taskIdx++) {//这里是对所有的任务控制台方式设为串口化
        taskCB = ((LosTaskCB *)g_taskCBArray) + taskIdx;
        if (OsTaskIsUnused(taskCB)) {//任务还没被使用过
            continue;//继续
        } else {
            g_taskConsoleIDArray[taskCB->taskID] = CONSOLE_SERIAL;//任务对于的控制台变成串口方式
        }
    }
    g_console[consoleCB->consoleID - 1] = NULL;
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);

    ret = OsConsoleDelete(consoleCB);//删除控制台
    if (ret != LOS_OK) {
        PRINT_ERR("%s, Failed to system_console_deinit\n", __FUNCTION__);
        return VFS_ERROR;
    }

    return ENOERR;
}
///控制台使能
BOOL ConsoleEnable(VOID)
{
    INT32 consoleID;

    if (OsCurrTaskGet() != NULL) {//有当前任务的情况下
        consoleID = g_taskConsoleIDArray[OsCurrTaskGet()->taskID];//获取当前任务的控制台ID
        if (g_uart_fputc_en == 0) {
            if ((g_console[CONSOLE_TELNET - 1] != NULL) && OsPreemptable()) {
                return TRUE;
            }
        }

        if (consoleID == 0) {
            return FALSE;
        } else if ((consoleID == CONSOLE_TELNET) || (consoleID == CONSOLE_SERIAL)) {
            return ((OsGetSystemStatus() == OS_SYSTEM_NORMAL) && !OsPreemptable()) ? FALSE : TRUE;
        }
#if defined (LOSCFG_DRIVERS_USB_SERIAL_GADGET) || defined (LOSCFG_DRIVERS_USB_ETH_SER_GADGET)
        else if ((SerialTypeGet() == SERIAL_TYPE_USBTTY_DEV) && (userial_mask_get() == 1)) {
            return TRUE;
        }
#endif
    }

    return FALSE;
}
///<  ShellEntry是否在运行,其为负责接受来自终端敲入的一个个字符
BOOL IsShellEntryRunning(UINT32 shellEntryId)
{
    LosTaskCB *taskCB = NULL;
    if (shellEntryId == SHELL_ENTRYID_INVALID) {
        return FALSE;
    }
    taskCB = OsGetTaskCB(shellEntryId);//获取任务
    return !OsTaskIsUnused(taskCB) && //确定名为"ShellEntry"的任务
           (strlen(taskCB->taskName) == SHELL_ENTRY_NAME_LEN &&
            strncmp(taskCB->taskName, SHELL_ENTRY_NAME, SHELL_ENTRY_NAME_LEN) == 0);
}
///任务注册控制台,每个shell任务都有属于自己的控制台
INT32 ConsoleTaskReg(INT32 consoleID, UINT32 taskID)
{
    UINT32 intSave;

    LOS_SpinLockSave(&g_consoleSpin, &intSave);
    if (!IsShellEntryRunning(g_console[consoleID - 1]->shellEntryId)) {//如果控制台还没有捆绑shell客户端任务 
        g_console[consoleID - 1]->shellEntryId = taskID;	//给控制台捆绑一个shell客户端任务,接受终端输入.
        LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
        (VOID)OsSetCurrProcessGroupID(OS_USER_ROOT_PROCESS_ID);
        return LOS_OK;
    }
    LOS_SpinUnlockRestore(&g_consoleSpin, intSave);
    return (g_console[consoleID - 1]->shellEntryId == taskID) ? LOS_OK : LOS_NOK;
}
///无锁方式设置串口
BOOL SetSerialNonBlock(const CONSOLE_CB *consoleCB)
{
    if (consoleCB == NULL) {
        PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
        return FALSE;
    }
    return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_NONBLOCK) == 0;
}

///锁方式设置串口
BOOL SetSerialBlock(const CONSOLE_CB *consoleCB)
{
    if (consoleCB == NULL) {
        PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
        return TRUE;
    }
    return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_SERIAL, CONSOLE_RD_BLOCK) != 0;
}

///无锁方式设置远程登录
BOOL SetTelnetNonBlock(const CONSOLE_CB *consoleCB)
{
    if (consoleCB == NULL) {
        PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
        return FALSE;
    }
    return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_TELNET, CONSOLE_RD_NONBLOCK) == 0;
}

///锁方式设置远程登录
BOOL SetTelnetBlock(const CONSOLE_CB *consoleCB)
{
    if (consoleCB == NULL) {
        PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
        return TRUE;
    }
    return ioctl(consoleCB->fd, CONSOLE_CMD_RD_BLOCK_TELNET, CONSOLE_RD_BLOCK) != 0;
}

BOOL is_nonblock(const CONSOLE_CB *consoleCB)
{
    if (consoleCB == NULL) {
        PRINT_ERR("%s: Input parameter is illegal\n", __FUNCTION__);
        return FALSE;
    }
    return consoleCB->isNonBlock;
}
///控制台更新文件句柄
INT32 ConsoleUpdateFd(VOID)
{
    INT32 consoleID;

    if (OsCurrTaskGet() != NULL) {
        consoleID = g_taskConsoleIDArray[(OsCurrTaskGet())->taskID];//获取当前任务的控制台 (1,2,-1)
    } else {
        return -1;
    }

    if (g_uart_fputc_en == 0) {
        if (g_console[CONSOLE_TELNET - 1] != NULL) {
            consoleID = CONSOLE_TELNET;
        }
    } else if (consoleID == 0) {
        if (g_console[CONSOLE_SERIAL - 1] != NULL) {
            consoleID = CONSOLE_SERIAL;
        } else if (g_console[CONSOLE_TELNET - 1] != NULL) {
            consoleID = CONSOLE_TELNET;
        } else {
            PRINTK("No console dev used.\n");
            return -1;
        }
    }

    return (g_console[consoleID - 1] != NULL) ? g_console[consoleID - 1]->fd : -1;
}

///获取参数控制台ID 获取对应的控制台控制块(描述符)
CONSOLE_CB *OsGetConsoleByID(INT32 consoleID)
{
    if (consoleID != CONSOLE_TELNET) {//只允许 1,2存在，> 3 时统统变成1
        consoleID = CONSOLE_SERIAL;
    }
    return g_console[consoleID - 1];
}
///获取参数任务的控制台控制块(描述符)
CONSOLE_CB *OsGetConsoleByTaskID(UINT32 taskID)
{
    INT32 consoleID = g_taskConsoleIDArray[taskID];

    return OsGetConsoleByID(consoleID);
}
///设置控制台ID
VOID OsSetConsoleID(UINT32 newTaskID, UINT32 curTaskID)
{
    if ((newTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT) || (curTaskID >= LOSCFG_BASE_CORE_TSK_LIMIT)) {
        return;
    }

    g_taskConsoleIDArray[newTaskID] = g_taskConsoleIDArray[curTaskID];
}
///将buf内容写到终端设备
STATIC ssize_t WriteToTerminal(const CONSOLE_CB *consoleCB, const CHAR *buffer, size_t bufLen)
{
    INT32 ret, fd;
    INT32 cnt = 0;
    struct file *privFilep = NULL;
    struct file *filep = NULL;
    const struct file_operations_vfs *fileOps = NULL;

    fd = consoleCB->fd;//获取文件描述符
    ret = fs_getfilep(fd, &filep);//获取文件指针
    if (ret < 0) {
        ret = -EPERM;
        goto ERROUT;
    }
    ret = GetFilepOps(filep, &privFilep, &fileOps);//获取终端设备私有操作方法
    if (ret != ENOERR) {
        ret = -EINVAL;
        goto ERROUT;
    }

    if ((fileOps == NULL) || (fileOps->write == NULL)) {
        ret = EFAULT;
        goto ERROUT;
    }
    (VOID)fileOps->write(privFilep, buffer, bufLen);//写入终端设备,在终端设备上呈现出来

    return cnt;

ERROUT:
    set_errno(ret);
    return VFS_ERROR;
}
///控制台发送任务
STATIC UINT32 ConsoleSendTask(UINTPTR param)
{
    CONSOLE_CB *consoleCB = (CONSOLE_CB *)param;
    CirBufSendCB *cirBufSendCB = consoleCB->cirBufSendCB;
    CirBuf *cirBufCB = &cirBufSendCB->cirBufCB;
    UINT32 ret, size;
    CHAR *buf = NULL;

    (VOID)LOS_EventWrite(&cirBufSendCB->sendEvent, CONSOLE_SEND_TASK_RUNNING);//发送一个控制台任务正在运行的事件

    while (1) {//读取 CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT 这两个事件
        ret = LOS_EventRead(&cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT | CONSOLE_SEND_TASK_EXIT,
                            LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);//读取循环buf或任务退出的事件
        if (ret == CONSOLE_CIRBUF_EVENT) {//控制台循环buf事件发生
            size =  LOS_CirBufUsedSize(cirBufCB);//循环buf使用大小
            if (size == 0) {
                continue;
            }
            buf = (CHAR *)LOS_MemAlloc(m_aucSysMem1, size + 1);//分配接收cirbuf的内存
            if (buf == NULL) {
                continue;
            }
            (VOID)memset_s(buf, size + 1, 0, size + 1);//清0

            (VOID)LOS_CirBufRead(cirBufCB, buf, size);//读取循环cirBufCB至  buf

            (VOID)WriteToTerminal(consoleCB, buf, size);//将buf数据写到控制台终端设备
            (VOID)LOS_MemFree(m_aucSysMem1, buf);//清除buf
        } else if (ret == CONSOLE_SEND_TASK_EXIT) {//收到任务退出的事件, 由 OsConsoleBufDeinit 发出事件.
            break;//退出循环
        }
    }

    ConsoleCirBufDelete(cirBufSendCB);//删除循环buf,归还内存
    return LOS_OK;
}

#ifdef LOSCFG_KERNEL_SMP
VOID OsWaitConsoleSendTaskPend(UINT32 taskID)//等待控制台发送任务结束
{
    UINT32 i;
    CONSOLE_CB *console = NULL;
    LosTaskCB *taskCB = NULL;
    INT32 waitTime = 3000; /* 3000: 3 seconds */

    for (i = 0; i < CONSOLE_NUM; i++) {//轮询控制台
        console = g_console[i];
        if (console == NULL) {
            continue;
        }

        if (OS_TID_CHECK_INVALID(console->sendTaskID)) {
            continue;
        }

        taskCB = OS_TCB_FROM_TID(console->sendTaskID);
        while ((waitTime > 0) && (taskCB->taskEvent == NULL) && (taskID != console->sendTaskID)) {
            LOS_Mdelay(1); /* 1: wait console task pend */ //等待控制台任务挂起/待办
            --waitTime;
        }
    }
}
///唤醒控制台发送任务
VOID OsWakeConsoleSendTask(VOID)
{
    UINT32 i;
    CONSOLE_CB *console = NULL;

    for (i = 0; i < CONSOLE_NUM; i++) {//循环控制台数量，只有2个
        console = g_console[i];
        if (console == NULL) {
            continue;
        }

        if (console->cirBufSendCB != NULL) {//循环缓存描述符
            (VOID)LOS_EventWrite(&console->cirBufSendCB->sendEvent, CONSOLE_CIRBUF_EVENT);//写循环缓存区buf事件
        }
    }
}
#endif

