⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 C
字号:
/* Copyright (C) 2005  Thomas Petazzoni, David Decotigny   This program is free software; you can redistribute it and/or   modify it under the terms of the GNU General Public License   as published by the Free Software Foundation; either version 2   of the License, or (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,   USA.*/#include <sos/types.h>#include <sos/assert.h>#include <sos/errno.h>#include <sos/fs.h>#include <sos/ksynch.h>#include <sos/kwaitq.h>#include <sos/uaccess.h>#include <sos/kmalloc.h>#include <sos/list.h>#include <sos/chardev.h>#include <drivers/devices.h>#include "tty.h"#define TTY_BUFFER_LEN 64#define TTY_NAME_LEN   16struct tty_device {  sos_ui32_t        instance;  unsigned int      open_count;  char              buffer[TTY_BUFFER_LEN];  unsigned int      buffer_read;  unsigned int      buffer_write;  struct sos_ksema  sem;  struct sos_kwaitq wq;  sos_ret_t         (*write)(char c);  unsigned int      param;  struct tty_device *next, *prev;};static struct tty_device *tty_device_list;static struct tty_device *tty_device_find (sos_ui32_t instance){  struct tty_device *t;  int n;  list_foreach (tty_device_list, t, n)    {      if (t->instance == instance)	return t;    }  return NULL;}static sos_ret_t tty_read(struct sos_fs_opened_file *this,			  sos_uaddr_t dest_buf, sos_size_t *len){  sos_size_t count = 0;  struct tty_device *t;  sos_ret_t ret;  t = (struct tty_device *) this->custom_data;  if (*len == 0)    return SOS_OK;  while (1)    {      char c;      /* Take the semaphore */      sos_ksema_down (& t->sem, NULL);      /* No keys available in the ring buffer, wait until the	 add_chars callback wakes us up */      if (t->buffer_read == t->buffer_write)	{	  sos_ksema_up (& t->sem);	  sos_kwaitq_wait (& t->wq, NULL);	  /* Go back to begining of loop: maybe someone else stole the	     semaphore */	  continue;	}      c = t->buffer[t->buffer_read];      /* Copy the received character from the ring buffer to the	 destination buffer */      ret = sos_memcpy_to_user (dest_buf,				(sos_vaddr_t) & t->buffer[t->buffer_read],				sizeof (char));      if (sizeof(char) != ret)	{	  *len = count;	  sos_ksema_up (& t->sem);	  return ret;	}      dest_buf++;      /* Update the ring buffer read pointer */      t->buffer_read++;      if (t->buffer_read == TTY_BUFFER_LEN)	t->buffer_read = 0;      count++;      if (t->param & SOS_IOCTLPARAM_TTY_ECHO)	t->write (c);      sos_ksema_up (& t->sem);      /* Did we read enough bytes ? */      if (count == *len	  || (c == '\n' && t->param & SOS_IOCTLPARAM_TTY_CANON))	break;    }  *len = count;  return SOS_OK;}static sos_ret_t tty_write(struct sos_fs_opened_file *this,			   sos_uaddr_t src_buf, sos_size_t *len){  struct tty_device *t;  char c;  int i;  sos_ret_t ret;  t = (struct tty_device *) this->custom_data;  for (i = 0; i < *len; i++)    {      ret = sos_memcpy_from_user ((sos_vaddr_t) & c, src_buf, sizeof(char));      if (sizeof(char) != ret)	{	  *len = i;	  return ret;	}      sos_ksema_down (& t->sem, NULL);      t->write (c);      sos_ksema_up (& t->sem);      src_buf++;    }  return SOS_OK;}static sos_ret_t tty_ioctl(struct sos_fs_opened_file *this, int req_id,			   sos_ui32_t req_arg){  struct tty_device *t;  if (req_arg != SOS_IOCTLPARAM_TTY_ECHO      && req_arg != SOS_IOCTLPARAM_TTY_CANON)    return -SOS_EINVAL;  t = (struct tty_device *) this->custom_data;  sos_ksema_down (& t->sem, NULL);  switch (req_id)    {    case SOS_IOCTL_TTY_SETPARAM:      t->param |= req_arg;      break;    case SOS_IOCTL_TTY_RESETPARAM:      t->param &= ~req_arg;      break;    default:      sos_ksema_up (& t->sem);      return -SOS_EINVAL;    }  sos_ksema_up (& t->sem);  return SOS_OK;}static sos_ret_t tty_open(struct sos_fs_node        * fsnode,			  struct sos_fs_opened_file * of,			  void * chardev_class_custom_data){  struct tty_device *t;  t = tty_device_find (fsnode->dev_id.device_instance);  if (t == NULL)    return -SOS_ENOENT;  sos_ksema_down (& t->sem, NULL);  of->custom_data = t;  t->open_count ++;  sos_ksema_up (& t->sem);  return SOS_OK;}static sos_ret_t tty_close(struct sos_fs_opened_file *of,			   void *custom_data){  struct tty_device *t;  t = (struct tty_device *) of->custom_data;  sos_ksema_down (& t->sem, NULL);  t->open_count --;  sos_ksema_up (& t->sem);  return SOS_OK;}void tty_add_chars (struct tty_device *t, const char *s){  sos_ksema_down (& t->sem, NULL);  while (*s)    {      /* Add all characters to the ring buffer */      t->buffer[t->buffer_write] = *s;      t->buffer_write++;      if (t->buffer_write == TTY_BUFFER_LEN)	t->buffer_write = 0;      s++;    }  sos_ksema_up (& t->sem);  /* Wake up a possibly waiting thread */  sos_kwaitq_wakeup (& t->wq, SOS_KWQ_WAKEUP_ALL, SOS_OK);}struct sos_chardev_ops tty_ops = {  .read    = tty_read,  .write   = tty_write,  .open    = tty_open,  .close   = tty_close,  .ioctl   = tty_ioctl};sos_ret_t tty_create (sos_ui32_t device_instance,		      sos_ret_t (*write_func) (char c),		      struct tty_device **tty_out){  struct tty_device *tty;  if (tty_device_find (device_instance) != NULL)    return -SOS_EBUSY;  tty = (struct tty_device *) sos_kmalloc (sizeof(struct tty_device), 0);  if (tty == NULL)    return -SOS_ENOMEM;  memset (tty->buffer, 0, sizeof(tty->buffer));  tty->open_count   = 0;  tty->instance     = device_instance;  tty->write        = write_func;  tty->buffer_read  = 0;  tty->buffer_write = 0;  tty->param        = SOS_IOCTLPARAM_TTY_CANON;  sos_kwaitq_init(& tty->wq, "tty", SOS_KWQ_ORDER_FIFO);  sos_ksema_init(& tty->sem, "tty", 1, SOS_KWQ_ORDER_FIFO);  list_add_tail (tty_device_list, tty);  *tty_out = tty;  return SOS_OK;}sos_ret_t tty_remove (struct tty_device *tty){  if (tty == NULL)    return -SOS_EINVAL;  if (SOS_OK != sos_ksema_trydown (& tty->sem))    return -SOS_EBUSY;  if (tty->open_count != 0)    return -SOS_EBUSY;  sos_kwaitq_dispose (& tty->wq);  list_delete (tty_device_list, tty);  sos_kfree ((sos_vaddr_t) tty);  return SOS_OK;}sos_ret_t tty_subsystem_setup (void){  list_init (tty_device_list);  return sos_chardev_register_class (SOS_CHARDEV_TTY_MAJOR,				     & tty_ops, NULL);}sos_ret_t tty_subsystem_cleanup (void){  return sos_chardev_unregister_class (SOS_CHARDEV_TTY_MAJOR);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -