IT貓撲網(wǎng):您身邊最放心的安全下載站! 最新更新|軟件分類|軟件專題|手機(jī)版|論壇轉(zhuǎn)貼|軟件發(fā)布

您當(dāng)前所在位置: 首頁操作系統(tǒng)LINUX → linux設(shè)備驅(qū)動之控制臺驅(qū)動(2)

linux設(shè)備驅(qū)動之控制臺驅(qū)動(2)

時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(1)

  對于規(guī)范模式,要讀滿一行才會返回用戶空間.例如我們在shell上輸入指令的時候,要按下enter鍵指令才會進(jìn)行處理.在 tty->read_flags數(shù)組中定義了一些滿行的標(biāo)志,如果read_buf中對應(yīng)的數(shù)據(jù)在tty->read_flags中被置位. 就會認(rèn)為這次讀入已經(jīng)到結(jié)尾了.在這里還要注意的是,不要將__DISABLED_CHAR即’/0’拷貝到用戶空間.

  對于原始模式,只需要將read_buf中的數(shù)據(jù)讀入到用戶空間就可以返回了.在這里需要注意read_buf是一個環(huán)形緩存,需要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中或多或少已經(jīng)有數(shù)據(jù)被取出了.如果當(dāng)前的數(shù)據(jù)量少于TTY_THRESHOLD_UNTHROTTLE.就可以調(diào)用check_unthrottle()將其它的寫進(jìn)程喚醒了

  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);

  已經(jīng)讀完了數(shù)據(jù),是該到清理的時候了.將進(jìn)程移出等待隊(duì)列,并當(dāng)進(jìn)程狀態(tài)設(shè)為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;

  //更新剩余空間數(shù)

  n_tty_set_room(tty);

  return retval;

  }

  TTY_PUSH:是由底層驅(qū)動程序在讀到一個EOF字符并將其放入緩存區(qū)造成的,表示用戶要盡快將緩存區(qū)數(shù)據(jù)取走.

  如果本次操作沒有讀取任何數(shù)據(jù),且被設(shè)置了TTY_PUSH,則跳轉(zhuǎn)到do_it_again,繼續(xù)執(zhí)行.如果本次操作讀取了數(shù)據(jù),可以等到下一次read的時候再來取.

  最后,更新read_buf的剩余空間數(shù).

  五:控制終端數(shù)據(jù)的來源

  從這個函數(shù)里面我們可以看到,數(shù)據(jù)是從read_buf中取出來的,但是誰將數(shù)據(jù)放入到read_buf中的呢?為了探究出它的根源.我們還得要從vty_init()說起.

  在之前分析過. vty_init()會調(diào)用一個表面字義看起來與鍵盤相關(guān)的一個子函數(shù): kbd_init().跟蹤這個函數(shù):

  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。結(jié)合前面我們分析的input子系統(tǒng),在handler里會處理input device上報(bào)的事件。跟進(jìn)這個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的。跟進(jìn)去看一下,看哪些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的設(shè)備都會被這個hnadler匹配到。相應(yīng)的。也就能夠處理input device上報(bào)的事件了.

  根據(jù)之前的input子系統(tǒng)分析,在input device和handler 進(jìn)行匹配的時候會調(diào)用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結(jié)構(gòu),并將其注冊。Open。這些都是我們之前分析過的東東。在注冊handle的時候。又會調(diào)用到hande->start.函數(shù)如下:

  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進(jìn)行操作。啟用了tasklent。這些都不是我們所關(guān)心的重點(diǎn)。

  來看下它的事件處理過程:

  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();

  }

  不管對應(yīng)鍵盤的那一種模式。后面的數(shù)據(jù)流程都會轉(zhuǎn)入到input_queue()進(jìn)等處理。

  實(shí)際上。控制終端由vc_cons[ ]數(shù)組表示。數(shù)組中的每一個項(xiàng)都表示一個控制終端。由全局變量fg_console來指示當(dāng)前所用的cosole/另外。對于鍵盤等輸出設(shè)備也對應(yīng)一個數(shù)組。即kbd_table[ ].用來表示當(dāng)前終端的控制信息.

  其余的都不是我們想關(guān)心的。來跟蹤一下這個函數(shù)的實(shí)現(xiàn):

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

關(guān)鍵詞標(biāo)簽:linux

相關(guān)閱讀

文章評論
發(fā)表評論

熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP Linux操作系統(tǒng)修改IP

相關(guān)下載

    人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址 dmidecode命令查看內(nèi)存型號 linux tc實(shí)現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機(jī)、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負(fù)載