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

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

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

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

  对于规范模式,要读满一行才会返回用户空间.例如我们在shell上输入指令的时候,要按下enter键指令才会进行处理.在 tty->read_flags数组中定义了一些满行的标志,如果read_buf中对应的数据在tty->read_flags中被置位. 就会认为这次读入已经到结尾了.在这里还要注意的是,不要将__DISABLED_CHAR即’/0’拷贝到用户空间.

  对于原始模式,只需要将read_buf中的数据读入到用户空间就可以返回了.在这里需要注意read_buf是一个环形缓存,需要copy两次.例如tail在head之前的情况.

  /* If there is enough space in the read buffer now, let the

  * low-level driver know. We use n_tty_chars_in_buffer() to

  * check the buffer, as it now knows about canonical mode.

  * Otherwise, if the driver is throttled and the line is

  * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,

  * we won't get any more characters.

  */

  if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {

  n_tty_set_room(tty);

  check_unthrottle(tty);

  }

  OK.到这里,read_buf中或多或少已经有数据被取出了.如果当前的数据量少于TTY_THRESHOLD_UNTHROTTLE.就可以调用check_unthrottle()将其它的写进程唤醒了

  if (b - buf >= minimum)

  break;

  if (time)

  timeout = time;

  }

  mutex_unlock(&tty->atomic_read_lock);

  remove_wait_queue(&tty->read_wait, &wait);

  if (!waitqueue_active(&tty->read_wait))

  tty->minimum_to_wake = minimum;

  __set_current_state(TASK_RUNNING);

  已经读完了数据,是该到清理的时候了.将进程移出等待队列,并当进程状态设为TASK_RUNNING

  size = b - buf;

  if (size) {

  retval = size;

  if (nr)

  clear_bit(TTY_PUSH, &tty->flags);

  } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))

  goto do_it_again;

  //更新剩余空间数

  n_tty_set_room(tty);

  return retval;

  }

  TTY_PUSH:是由底层驱动程序在读到一个EOF字符并将其放入缓存区造成的,表示用户要尽快将缓存区数据取走.

  如果本次操作没有读取任何数据,且被设置了TTY_PUSH,则跳转到do_it_again,继续执行.如果本次操作读取了数据,可以等到下一次read的时候再来取.

  最后,更新read_buf的剩余空间数.

  五:控制终端数据的来源

  从这个函数里面我们可以看到,数据是从read_buf中取出来的,但是谁将数据放入到read_buf中的呢?为了探究出它的根源.我们还得要从vty_init()说起.

  在之前分析过. vty_init()会调用一个表面字义看起来与键盘相关的一个子函数: kbd_init().跟踪这个函数:

  int __init kbd_init(void)

  {

  int i;

  int error;

  for (i = 0; i < MAX_NR_CONSOLES; i++) {

  kbd_table[i].ledflagstate = KBD_DEFLEDS;

  kbd_table[i].default_ledflagstate = KBD_DEFLEDS;

  kbd_table[i].ledmode = LED_SHOW_FLAGS;

  kbd_table[i].lockstate = KBD_DEFLOCK;

  kbd_table[i].slockstate = 0;

  kbd_table[i].modeflags = KBD_DEFMODE;

  kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;

  }

  error = input_register_handler(&kbd_handler);

  if (error)

  return error;

  tasklet_enable(&keyboard_tasklet);

  tasklet_schedule(&keyboard_tasklet);

  return 0;

  }

  暂时用不到的部份我们先不与分析。 在这里注册了一个input handler。结合前面我们分析的input子系统,在handler里会处理input device上报的事件。跟进这个handler看一下:

  kbd_handler定义如下:

  static struct input_handler kbd_handler = {

  .event     = kbd_event,

  .connect   = kbd_connect,

  .disconnect = kbd_disconnect,

  .start = kbd_start,

  .name    = &kbd&,

  .id_table   = kbd_ids,

  };

  Id_table是用来匹配input device的。跟进去看一下,看哪些device的事件,才会交给它处理:

  static const struct input_device_id kbd_ids[] = {

  {

  .flags = INPUT_DEVICE_ID_MATCH_EVBIT,

  .evbit = { BIT_MASK(EV_KEY) },

  },

  {

  .flags = INPUT_DEVICE_ID_MATCH_EVBIT,

  .evbit = { BIT_MASK(EV_SND) },

  },

  { },    /* Terminating entry */

  };

  从这个id_table中看来,只要是能支持EV_KEY或者是EV_SND的设备都会被这个hnadler匹配到。相应的。也就能够处理input device上报的事件了.

  根据之前的input子系统分析,在input device和handler 进行匹配的时候会调用handler->connect.即kbd_connect().代码如下:

  static int kbd_connect(struct input_handler *handler, struct input_dev *dev,

  const struct input_device_id *id)

  {

  struct input_handle *handle;

  int error;

  int i;

  for (i = KEY_RESERVED; i < BTN_MISC; i++)

  if (test_bit(i, dev->keybit))

  break;

  if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))

  return -ENODEV;

  handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);

  if (!handle)

  return -ENOMEM;

  handle->dev = dev;

  handle->handler = handler;

  handle->name = &kbd&;

  error = input_register_handle(handle);

  if (error)

  goto err_free_handle;

  error = input_open_device(handle);

  if (error)

  goto err_unregister_handle;

  return 0;

  err_unregister_handle:

  input_unregister_handle(handle);

  err_free_handle:

  kfree(handle);

  return error;

  }

  在这段代码里,它申请分初始化了一个hande结构,并将其注册。Open。这些都是我们之前分析过的东东。在注册handle的时候。又会调用到hande->start.函数如下:

  static void kbd_start(struct input_handle *handle)

  {

  unsigned char leds = ledstate;

  tasklet_disable(&keyboard_tasklet);

  if (leds != 0xff) {

  input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));

  input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));

  input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));

  input_inject_event(handle, EV_SYN, SYN_REPORT, 0);

  }

  tasklet_enable(&keyboard_tasklet);

  }

  这里就是对键盘上的LED进行操作。启用了tasklent。这些都不是我们所关心的重点。

  来看下它的事件处理过程:

  static void kbd_event(struct input_handle *handle, unsigned int event_type,

  unsigned int event_code, int value)

  {

  if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))

  kbd_rawcode(value);

  if (event_type == EV_KEY)

  kbd_keycode(event_code, value, HW_RAW(handle->dev));

  tasklet_schedule(&keyboard_tasklet);

  do_poke_blanked_console = 1;

  schedule_console_callback();

  }

  不管对应键盘的那一种模式。后面的数据流程都会转入到input_queue()进等处理。

  实际上。控制终端由vc_cons[ ]数组表示。数组中的每一个项都表示一个控制终端。由全局变量fg_console来指示当前所用的cosole/另外。对于键盘等输出设备也对应一个数组。即kbd_table[ ].用来表示当前终端的控制信息.

  其余的都不是我们想关心的。来跟踪一下这个函数的实现:

  static void put_queue(struct vc_data *vc, int ch)

关键词标签: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清除用户登录记录和命令历史方法