IT猫扑网:您身边最放心的安全下载站! 最新更新| 软件分类| 专题汇总| 手机版

您当前所在位置:IT猫扑网 > 操作系统 > LINUX > linux设备驱动之控制台驱动(1)

linux设备驱动之控制台驱动(1)

时间:2015-06-28 00:00 来源:IT猫扑网|http://www.itmop.com/ 作者:网管联盟 我要评论(0)

  一:前言

  我们在之前分析过input子系统和tty设备驱动架构.今天需要将两者结合起来.看看linux中的控制台是怎么样实现的.

  二:控制台驱动的初始化

  之前在分析tty驱动架构的时候曾分析到.主设备为4,次设备为0的设备节点,即/dev/tty0为当前的控制终端.

  有tty_init()中,有以下代码段:

  static int __init tty_init(void)

  {

  ……

  ……

  #ifdef CONFIG_VT

  cdev_init(&vc0_cdev, &console_fops);

  if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||

  register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, &/dev/vc/0&) < 0)

  panic(&Couldn't register /dev/tty0 drivern&);

  device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), &tty0&);

  vty_init();

  #endif

  return 0;

  }

  CONFIG_VT:是指配置虚拟终端.即我们所说的控制台.在此可以看到TTY_MAJOR(4),0对应的设备节点操作集为console_fops.

  继续跟进vty_init()

  int __init vty_init(void)

  {

  vcs_init();

  console_driver = alloc_tty_driver(MAX_NR_CONSOLES);

  if (!console_driver)

  panic(&Couldn't allocate console drivern&);

  console_driver->owner = THIS_MODULE;

  console_driver->name = &tty&;

  console_driver->name_base = 1;

  console_driver->major = TTY_MAJOR;

  console_driver->minor_start = 1;

  console_driver->type = TTY_DRIVER_TYPE_CONSOLE;

  console_driver->init_termios = tty_std_termios;

  console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;

  tty_set_operations(console_driver, &con_ops);

  if (tty_register_driver(console_driver))

  panic(&Couldn't register console drivern&);

  kbd_init();

  console_map_init();

  #ifdef CONFIG_PROM_CONSOLE

  prom_con_init();

  #endif

  #ifdef CONFIG_MDA_CONSOLE

  mda_console_init();

  #endif

  return 0;

  }

  经过我们之前的tty驱动架构分析,这段代码看起来就比较简单了,它就是注册了一个tty驱动.这个驱动对应的操作集是位于con_ops里面的.

  仔细看.在之后还会调用kbd_init().顾名思义,这个是一个有关键盘的初始化.控制终端跟键盘有什么关系呢?在之前分析tty的时候,曾提到过,. 对于控制台而言,它的输入设备是键盘鼠标,它的输出设备是当前显示器.这两者是怎么关联起来的呢?不着急.请看下面的分析.

  三:控制台的open操作

  在前面分析了,对应console的操作集为con_ops.定义如下:

  static const struct file_operations console_fops = {

  .llseek    = no_llseek,

  .read = tty_read,

  .write      = redirected_tty_write,

  .poll     = tty_poll,

  .ioctl    = tty_ioctl,

  .compat_ioctl    = tty_compat_ioctl,

  .open      = tty_open,

  .release    = tty_release,

  .fasync   = tty_fasync,

  };

  里面的函数指针值我们都不陌生了,在之前分析的tty驱动中已经分析过了.

  结合前面的tty驱动分析.我们知道在open的时候,会调用ldisc的open和tty_driver.open.

  对于ldisc默认是tty_ldiscs[0].我们来看下它的具体赋值.

  console_init():

  void __init console_init(void)

  {

  initcall_t *call;

  /* Setup the default TTY line discipline. */

  (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

  /*

  * set up the console device so that later boot sequences can

  * inform about problems etc..

  */

  call = __con_initcall_start;

  while (call < __con_initcall_end) {

  (*call)();

  call++;

  }

  }

  在这里,通过tty_register_ldisc.将tty_ldisc_N_TTY注册为了第N_TTY项.即第1项. tty_ldisc_N_TTY定义如下:

  struct tty_ldisc tty_ldisc_N_TTY = {

  .magic     = TTY_LDISC_MAGIC,

  .name      = &n_tty&,

  .open      = n_tty_open,

  .close     = n_tty_close,

  .flush_buffer    = n_tty_flush_buffer,

  .chars_in_buffer = n_tty_chars_in_buffer,

  .read      = read_chan,

  .write     = write_chan,

  .ioctl     = n_tty_ioctl,

  .set_termios     = n_tty_set_termios,

  .poll      = normal_poll,

  .receive_buf     = n_tty_receive_buf,

  .write_wakeup    = n_tty_write_wakeup

  }

  对应的open操作为n_tty_open:

  static int n_tty_open(struct tty_struct *tty)

  {

  if (!tty)

  return -EINVAL;

  /* This one is ugly. Currently a malloc failure here can panic */

  if (!tty->read_buf) {

  tty->read_buf = alloc_buf();

  if (!tty->read_buf)

  return -ENOMEM;

  }

  memset(tty->read_buf, 0, N_TTY_BUF_SIZE);

  reset_._flags(tty);

  tty->column = 0;

  n_tty_set_termios(tty, NULL);

  tty->minimum_to_wake = 1;

  tty->closing = 0;

  return 0;

  }

  它为tty->read_buf分配内存.这个buffer空间大小为N_TTY_BUF_SIZE.read_buf实际上就是从按键的缓存区.然后调用reset_flags()来初始化tty中的一些字段:

  static void reset_buffer_flags(struct tty_struct *tty)

  {

  unsigned long flags;

  spin_lock_irqsave(&tty->read_lock, flags);

  tty->read_head = tty->read_tail = tty->read_cnt = 0;

  spin_unlock_irqrestore(&tty->read_lock, flags);

  tty->canon_head = tty->canon_data = tty->erasing = 0;

  memset(&tty->read_flags, 0, sizeof tty->read_flags);

  n_tty_set_room(tty);

  check_unthrottle(tty);

  }

  这里比较简,不再详细分析.在这里要注意几个tty成员的含义:

  Tty->read_head, tty->read_tail , tty->read_cnt分别代表read_buf中数据的写入位置,读取位置和数据总数.read_buf是一个环形缓存区.

  n_tty_set_room()是设备read_buf中的可用缓存区

  check_unthrottle():是用来判断是否需要打开&阀门&,允许输入数据流入

  对于console tty_driver对应的open函数如下示:

  static int con_open(struct tty_struct *tty, struct file *filp)

  {

  unsigned int currcons = tty->index;

  int ret = 0;

  acquire_console_sem();

  if (tty->driver_data == NULL) {

  ret = vc_allocate(currcons);

  if (ret == 0) {

  struct vc_data *vc = vc_cons[currcons].d;

  tty->driver_data = vc;

  vc->vc_tty = t

关键词标签:linux

相关阅读 安装红帽子RedHat Linux9.0操作系统教程 Tomcat9.0如何安装_Tomcat9.0环境变量配置方法 多种操作系统NTP客户端配置 Linux操作系统修改IP Linux实现SCSI硬盘热插拔及在线识别 Linux下用CDMA modem拨号上网

文章评论
发表评论

热门文章 安装红帽子RedHat Linux9.0操作系统教程 安装红帽子RedHat Linux9.0操作系统教程 Linux服务器:设计高性能网站架构-LLMP Linux服务器:设计高性能网站架构-LLMP 使用Clonezilla迁移到虚拟Linux环境 使用Clonezilla迁移到虚拟Linux环境 Linux上的MRTG流量监控中心 Linux上的MRTG流量监控中心 Linux 双网卡绑定一个IP原理及实现 Linux 双网卡绑定一个IP原理及实现 linux和windows等系统远程控制ubuntu桌面 linux和windows等系统远程控制ubuntu桌面

相关下载

人气排行 Linux下获取CPUID、硬盘序列号与MAC地址 dmidecode命令查看内存型号 linux tc实现ip流量限制 安装红帽子RedHat Linux9.0操作系统教程 linux下解压rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 关机、重启、注销 命令 查看linux服务器硬盘IO读写负载 linux命令行浏览器的使用方法 Linux NFS服务固定端口及防火墙配置 U盘安装Ubuntu 10.04 Linux清除用户登录记录和命令历史方法