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

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

linux設(shè)備驅(qū)動(dòng)之控制臺(tái)驅(qū)動(dòng)(2)

時(shí)間:2015/6/28來源:IT貓撲網(wǎng)作者:網(wǎng)管聯(lián)盟我要評(píng)論(0)

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

  對(duì)于原始模式,只需要將read_buf中的數(shù)據(jù)讀入到用戶空間就可以返回了.在這里需要注意read_buf是一個(gè)環(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ù),是該到清理的時(shí)候了.將進(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ū)動(dòng)程序在讀到一個(gè)EOF字符并將其放入緩存區(qū)造成的,表示用戶要盡快將緩存區(qū)數(shù)據(jù)取走.

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

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

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

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

  在之前分析過. vty_init()會(huì)調(diào)用一個(gè)表面字義看起來與鍵盤相關(guān)的一個(gè)子函數(shù): kbd_init().跟蹤這個(gè)函數(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;

  }

  暫時(shí)用不到的部份我們先不與分析。 在這里注冊(cè)了一個(gè)input handler。結(jié)合前面我們分析的input子系統(tǒng),在handler里會(huì)處理input device上報(bào)的事件。跟進(jìn)這個(gè)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的事件,才會(huì)交給它處理:

  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 */

  };

  從這個(gè)id_table中看來,只要是能支持EV_KEY或者是EV_SND的設(shè)備都會(huì)被這個(gè)hnadler匹配到。相應(yīng)的。也就能夠處理input device上報(bào)的事件了.

  根據(jù)之前的input子系統(tǒng)分析,在input device和handler 進(jìn)行匹配的時(shí)候會(huì)調(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;

  }

  在這段代碼里,它申請(qǐng)分初始化了一個(gè)hande結(jié)構(gòu),并將其注冊(cè)。Open。這些都是我們之前分析過的東東。在注冊(cè)handle的時(shí)候。又會(huì)調(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);

  }

  這里就是對(duì)鍵盤上的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();

  }

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

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

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

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

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

相關(guān)閱讀

文章評(píng)論
發(fā)表評(píng)論

熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程使用screen管理你的遠(yuǎn)程會(huì)話使用screen管理你的遠(yuǎn)程會(huì)話GNU/Linux安裝vmwareGNU/Linux安裝vmware如何登錄linux vps圖形界面 Linux遠(yuǎn)程桌面連如何登錄linux vps圖形界面 Linux遠(yuǎn)程桌面連

相關(guān)下載

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