123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-11-13 Shell init ver.
- */
- #define DBG_TAG "lwp.tty"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #define TTY_CONF_INCLUDE_CCHARS
- #include "tty_config.h"
- #include "tty_internal.h"
- #include "terminal.h"
- /* configure option: timeout of tty drain wait */
- static int tty_drainwait = 5 * 60;
- #define TTY_NAME_PREFIX "tty"
- static char *alloc_device_name(const char *name)
- {
- char *tty_dev_name;
- long name_buf_len = (sizeof(TTY_NAME_PREFIX) - 1) /* raw prefix */
- + rt_strlen(name) /* custom name */
- + 1; /* tailing \0 */
- tty_dev_name = rt_malloc(name_buf_len);
- if (tty_dev_name)
- sprintf(tty_dev_name, "%s%s", TTY_NAME_PREFIX, name);
- return tty_dev_name;
- }
- /* character device for tty */
- #ifdef RT_USING_DEVICE_OPS
- const static struct rt_device_ops tty_dev_ops = {
- /* IO directly through device is not allowed */
- };
- #else
- #error Must enable RT_USING_DEVICE_OPS in Kconfig
- #endif
- static int tty_fops_open(struct dfs_file *file)
- {
- int rc;
- lwp_tty_t tp;
- rt_device_t device;
- int devtype = 0; /* unused */
- if (file->vnode && file->vnode->data)
- {
- if (file->vnode->ref_count != 1)
- {
- rc = 0;
- }
- else
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- rc = bsd_ttydev_methods.d_open(tp, file->flags, devtype,
- rt_thread_self());
- }
- }
- else
- {
- rc = -EINVAL;
- }
- return rc;
- }
- static int tty_fops_close(struct dfs_file *file)
- {
- int rc;
- lwp_tty_t tp;
- rt_device_t device;
- int fflags = FFLAGS(file->flags);
- int devtype = 0; /* unused */
- if (file->vnode && file->vnode->data)
- {
- if (file->vnode->ref_count != 1)
- {
- rc = 0;
- }
- else
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- rc = bsd_ttydev_methods.d_close(tp, fflags, devtype, rt_thread_self());
- }
- }
- else
- {
- rc = -EINVAL;
- }
- return rc;
- }
- static int tty_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
- {
- int rc;
- lwp_tty_t tp;
- rt_device_t device;
- if (file->vnode && file->vnode->data)
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- rc = lwp_tty_ioctl_adapter(tp, cmd, file->flags, arg, rt_thread_self());
- }
- else
- {
- rc = -EINVAL;
- }
- return rc;
- }
- static ssize_t tty_fops_read(struct dfs_file *file, void *buf, size_t count,
- off_t *pos)
- {
- ssize_t rc = 0;
- int error;
- struct uio uio;
- struct iovec iov;
- rt_device_t device;
- struct lwp_tty *tp;
- int ioflags;
- int oflags = file->flags;
- if (file->vnode && file->vnode->data)
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- /* setup ioflags */
- ioflags = 0;
- if (oflags & O_NONBLOCK)
- ioflags |= IO_NDELAY;
- /* setup uio parameters */
- iov.iov_base = (void *)buf;
- iov.iov_len = count;
- uio.uio_offset = file->fpos;
- uio.uio_resid = count;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_rw = UIO_READ;
- rc = count;
- error = bsd_ttydev_methods.d_read(tp, &uio, ioflags);
- rc -= uio.uio_resid;
- if (error)
- {
- LOG_D("%s: failed to write %d bytes of data. error code %d",
- __func__, uio.uio_resid, error);
- rc = error;
- }
- /* reset file context */
- file->fpos = uio.uio_offset;
- }
- if (rc)
- LOG_D("%s(len=%d, buf=%c \"%d\")", __func__, rc, *((char *)buf),
- *((char *)buf));
- return rc;
- }
- static ssize_t tty_fops_write(struct dfs_file *file, const void *buf,
- size_t count, off_t *pos)
- {
- ssize_t rc = 0;
- int error;
- struct uio uio;
- struct iovec iov;
- rt_device_t device;
- struct lwp_tty *tp;
- int ioflags;
- int oflags = file->flags;
- if (file->vnode && file->vnode->data)
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- /* setup ioflags */
- ioflags = 0;
- if (oflags & O_NONBLOCK)
- ioflags |= IO_NDELAY;
- /* setup uio parameters */
- iov.iov_base = (void *)buf;
- iov.iov_len = count;
- uio.uio_offset = file->fpos;
- uio.uio_resid = count;
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_rw = UIO_WRITE;
- rc = count;
- error = bsd_ttydev_methods.d_write(tp, &uio, ioflags);
- if (error)
- {
- rc = error;
- LOG_D("%s: failed to write %d bytes of data. error code %d",
- __func__, uio.uio_resid, error);
- }
- else
- {
- rc -= uio.uio_resid;
- }
- /* reset file context */
- file->fpos = uio.uio_offset;
- }
- return rc;
- }
- static int tty_fops_flush(struct dfs_file *file)
- {
- return -EINVAL;
- }
- static off_t tty_fops_lseek(struct dfs_file *file, off_t offset, int wherece)
- {
- return -EINVAL;
- }
- static int tty_fops_truncate(struct dfs_file *file, off_t offset)
- {
- /**
- * regarding to POSIX.1, TRUNC is not supported for tty device.
- * return 0 always to make filesystem happy
- */
- return 0;
- }
- static int tty_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
- {
- int rc;
- rt_device_t device;
- struct lwp_tty *tp;
- if (file->vnode && file->vnode->data)
- {
- device = (rt_device_t)file->vnode->data;
- tp = rt_container_of(device, struct lwp_tty, parent);
- rc = bsd_ttydev_methods.d_poll(tp, req, rt_thread_self());
- }
- else
- {
- rc = -1;
- }
- return rc;
- }
- static int tty_fops_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
- {
- return -EINVAL;
- }
- static int tty_fops_lock(struct dfs_file *file, struct file_lock *flock)
- {
- return -EINVAL;
- }
- static int tty_fops_flock(struct dfs_file *file, int operation, struct file_lock *flock)
- {
- return -EINVAL;
- }
- static struct dfs_file_ops tty_file_ops = {
- .open = tty_fops_open,
- .close = tty_fops_close,
- .ioctl = tty_fops_ioctl,
- .read = tty_fops_read,
- .write = tty_fops_write,
- .flush = tty_fops_flush,
- .lseek = tty_fops_lseek,
- .truncate = tty_fops_truncate,
- .poll = tty_fops_poll,
- .mmap = tty_fops_mmap,
- .lock = tty_fops_lock,
- .flock = tty_fops_flock,
- };
- rt_inline void device_setup(lwp_tty_t terminal)
- {
- terminal->parent.type = RT_Device_Class_Char;
- #ifdef RT_USING_DEVICE_OPS
- terminal->parent.ops = &tty_dev_ops;
- #else
- #error Must enable RT_USING_DEVICE_OPS in Kconfig
- #endif
- }
- /* register TTY device */
- rt_err_t lwp_tty_register(lwp_tty_t terminal, const char *name)
- {
- rt_err_t rc = -RT_ENOMEM;
- const char *tty_name;
- char *alloc_name;
- if (terminal->t_devsw->tsw_flags & TF_NOPREFIX)
- {
- alloc_name = RT_NULL;
- tty_name = name;
- }
- else
- {
- alloc_name = alloc_device_name(name);
- tty_name = alloc_name;
- }
- if (tty_name)
- {
- device_setup(terminal);
- rc = rt_device_register(&terminal->parent, tty_name, 0);
- if (rc == RT_EOK)
- {
- terminal->parent.fops = &tty_file_ops;
- LOG_D("%s() /dev/%s device registered", __func__, tty_name);
- }
- rt_free(alloc_name);
- }
- return rc;
- }
- static void tty_init_termios(lwp_tty_t tp)
- {
- struct termios *t = &tp->t_termios_init_in;
- t->c_cflag = TTYDEF_CFLAG;
- t->c_iflag = TTYDEF_IFLAG;
- t->c_lflag = TTYDEF_LFLAG;
- t->c_oflag = TTYDEF_OFLAG;
- t->__c_ispeed = TTYDEF_SPEED;
- t->__c_ospeed = TTYDEF_SPEED;
- memcpy(&t->c_cc, tty_ctrl_charset,
- sizeof(tty_ctrl_charset) / sizeof(tty_ctrl_charset[0]));
- #ifdef USING_BSD_INIT_LOCK_DEVICE
- tp->t_termios_init_out = *t;
- #endif /* USING_BSD_INIT_LOCK_DEVICE */
- }
- lwp_tty_t lwp_tty_create_ext(lwp_ttydevsw_t handle, void *softc,
- rt_mutex_t custom_mtx)
- {
- lwp_tty_t tp;
- tp = rt_calloc(1, sizeof(struct lwp_tty)
- #ifdef USING_BSD_SIGINFO
- + LWP_TTY_PRBUF_SIZE
- #endif
- );
- if (!tp)
- return tp;
- bsd_devsw_init(handle);
- #ifdef USING_BSD_SIGINFO
- tp->t_prbufsz = LWP_TTY_PRBUF_SIZE;
- #endif
- tp->t_devsw = handle;
- tp->t_devswsoftc = softc;
- tp->t_flags = handle->tsw_flags;
- tp->t_drainwait = tty_drainwait;
- tty_init_termios(tp);
- cv_init(&tp->t_inwait, "ttyin");
- cv_init(&tp->t_outwait, "ttyout");
- cv_init(&tp->t_outserwait, "ttyosr");
- cv_init(&tp->t_bgwait, "ttybg");
- cv_init(&tp->t_dcdwait, "ttydcd");
- rt_wqueue_init(&tp->t_inpoll);
- rt_wqueue_init(&tp->t_outpoll);
- /* Allow drivers to use a custom mutex to lock the TTY. */
- if (custom_mtx != NULL)
- {
- tp->t_mtx = custom_mtx;
- }
- else
- {
- tp->t_mtx = &tp->t_mtxobj;
- rt_mutex_init(&tp->t_mtxobj, "ttydev", RT_IPC_FLAG_PRIO);
- }
- #ifdef USING_BSD_POLL
- knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
- knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
- #endif
- return tp;
- }
- lwp_tty_t lwp_tty_create(lwp_ttydevsw_t handle, void *softc)
- {
- return lwp_tty_create_ext(handle, softc, NULL);
- }
- void lwp_tty_delete(lwp_tty_t tp)
- {
- /*
- * ttyydev_leave() usually frees the i/o queues earlier, but it is
- * not always called between queue allocation and here. The queues
- * may be allocated by ioctls on a pty control device without the
- * corresponding pty slave device ever being open, or after it is
- * closed.
- */
- ttyinq_free(&tp->t_inq);
- ttyoutq_free(&tp->t_outq);
- rt_wqueue_wakeup_all(&tp->t_inpoll, (void *)POLLHUP);
- rt_wqueue_wakeup_all(&tp->t_outpoll, (void *)POLLHUP);
- #ifdef USING_BSD_POLL
- knlist_destroy(&tp->t_inpoll.si_note);
- knlist_destroy(&tp->t_outpoll.si_note);
- #endif
- cv_destroy(&tp->t_inwait);
- cv_destroy(&tp->t_outwait);
- cv_destroy(&tp->t_bgwait);
- cv_destroy(&tp->t_dcdwait);
- cv_destroy(&tp->t_outserwait);
- if (tp->t_mtx == &tp->t_mtxobj)
- rt_mutex_detach(&tp->t_mtxobj);
- ttydevsw_free(tp);
- rt_device_unregister(&tp->parent);
- rt_free(tp);
- }
- /*
- * Report on state of foreground process group.
- */
- void tty_info(struct lwp_tty *tp)
- {
- /* TODO */
- return;
- }
|