跳到主要內容

輸入/輸出系統-TTY

TTY任務


在 TTY 任務中執行一個迴圈,此迴圈將輪詢每一個 TTY,處理它的事件,包括從鍵盤緩衝區讀取資料、顯示字元等內容。

  1. 並非每輪詢到某個 TTY 時,箭頭所對應的全部事件都會發生,只有當某個 TTY 對應的控制台是現在控制台時,它才可以讀取鍵盤緩衝區(虛線)
  2. TTY 可以對輸入的資料作更多的處理,但在這裡,我們只把它簡化為「顯示」一項。
  3. 雖然圖中鍵盤和顯示器的畫在 TTY 的外面,但應把鍵盤和顯示器算做每一個 TTY 的一部分,它們是公用的。
執行的過程如上,則輪詢到每個 TTY 不外乎作兩件事:
  1. 處理輸入:查看是不是現在 TTY,如果是則從鍵盤緩衝區讀取資料
  2. 處理輸出:如果有要顯示的內容則要顯示它
TTY 任務程式碼示意
與先前程式實現的區別在於:

  1. 每個 TTY 都應該有自己的讀和寫的動作。所以在 keyboard_read() 內部,函數需要了解自己是被哪一個 TTY 使用。我們透過為函數傳入一個參數來作到這一點,此參數指向當前 TTY 的指針。
  2. 為了讓輸入和輸出分離,被 keyboard_read() 使用的 in_process() 不應該在直接回顯字元,而應該將回顯的任務交給 TTY 來完成,這樣,我們就需要為每個 TTY 建立一塊緩衝區,用以放置將被回顯的字元。
  3. 每個 TTY 回顯字元時操作的 CONSOLE 是不同的,故每個 TTY 都應該有一個成員來記載其對應的 CONSOLE 資訊。

TTY 結構

#define TTY_IN_BYTES 256  /* tty input queue size */

struct s_console;

/* TTY */
typedef struct s_tty
{
    u32    in_buf[TTY_IN_BYTES];  /* TTY 輸入緩衝區 */
    u32*   p_inbuf_head;          /* 指向緩衝區中下一個空閒位置 */
    u32*   p_inbuf_tail;          /* 指向鍵盤任務應處理的鍵值 */
    int    inbuf_count;           /* 緩衝區中已經填充了多少 */


    struct s_console * p_console;
} TTY;

CONSOLE 結構

typedef struct s_console
{
    unsigned int current_start_addr; /* 當前顯示到了什麼位置 */
    unsigned int original_addr;      /* 當前控制台對應顯示卡記憶體位置 */
    unsigned int v_mem_limit;        /* 當前控制台占的顯示卡記憶體大小 */
    unsigned int cursor;             /* 當前光標位置 */
} CONSOLE;
TTY 任務程式碼示意

程式碼

include/console.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         console.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_CONSOLE_H_
#define _ORANGES_CONSOLE_H_


/* CONSOLE */
typedef struct s_console
{
 unsigned int current_start_addr; /* 當前顯示到了什麼位置   */
 unsigned int original_addr;  /* 當前控制台對應顯存位置 */
 unsigned int v_mem_limit;  /* 當前控制台占的顯存大小 */
 unsigned int cursor;   /* 當前光標位置 */
}CONSOLE;

#define SCR_UP 1 /* scroll forward */
#define SCR_DN -1 /* scroll backward */

#define SCREEN_SIZE  (80 * 25)
#define SCREEN_WIDTH  80

#define DEFAULT_CHAR_COLOR 0x07 /* 0000 0111 黑底白字 */


#endif /* _ORANGES_CONSOLE_H_ */

include/const.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_CONST_H_
#define _ORANGES_CONST_H_


/* EXTERN */
#define EXTERN extern /* EXTERN is defined as extern except in global.c */

/* 函數類型 */
#define PUBLIC  /* PUBLIC is the opposite of PRIVATE */
#define PRIVATE static /* PRIVATE x limits the scope of x */

/* Color */
/*
 * e.g. MAKE_COLOR(BLUE, RED)
 *      MAKE_COLOR(BLACK, RED) | BRIGHT
 *      MAKE_COLOR(BLACK, RED) | BRIGHT | FLASH
 */
#define BLACK   0x0     /* 0000 */
#define WHITE   0x7     /* 0111 */
#define RED     0x4     /* 0100 */
#define GREEN   0x2     /* 0010 */
#define BLUE    0x1     /* 0001 */
#define FLASH   0x80    /* 1000 0000 */
#define BRIGHT  0x08    /* 0000 1000 */
#define MAKE_COLOR(x,y) (x | y) /* MAKE_COLOR(Background,Foreground) */

/* GDT 和 IDT 中描述符的個數 */
#define GDT_SIZE 128
#define IDT_SIZE 256

/* 權限 */
#define PRIVILEGE_KRNL 0
#define PRIVILEGE_TASK 1
#define PRIVILEGE_USER 3
/* RPL */
#define RPL_KRNL SA_RPL0
#define RPL_TASK SA_RPL1
#define RPL_USER SA_RPL3

/* TTY */
#define NR_CONSOLES 3 /* consoles */

/* 8259A interrupt controller ports. */
#define INT_M_CTL 0x20 /* I/O port for interrupt controller         <Master> */
#define INT_M_CTLMASK 0x21 /* setting bits in this port disables ints   <Master> */
#define INT_S_CTL 0xA0 /* I/O port for second interrupt controller  <Slave>  */
#define INT_S_CTLMASK 0xA1 /* setting bits in this port disables ints   <Slave>  */

/* 8253/8254 PIT (Programmable Interval Timer) */
#define TIMER0         0x40 /* I/O port for timer channel 0 */
#define TIMER_MODE     0x43 /* I/O port for timer mode control */
#define RATE_GENERATOR 0x34 /* 00-11-010-0 :
        * Counter0 - LSB then MSB - rate generator - binary
        */
#define TIMER_FREQ     1193182L/* clock frequency for timer in PC and AT */
#define HZ             100  /* clock freq (software settable on IBM-PC) */

/* AT keyboard */
/* 8042 ports */
#define KB_DATA  0x60 /* I/O port for keyboard data
     Read : Read Output Buffer
     Write: Write Input Buffer(8042 Data&8048 Command) */
#define KB_CMD  0x64 /* I/O port for keyboard command
     Read : Read Status Register
     Write: Write Input Buffer(8042 Command) */
#define LED_CODE 0xED
#define KB_ACK  0xFA

/* VGA */
#define CRTC_ADDR_REG 0x3D4 /* CRT Controller Registers - Addr Register */
#define CRTC_DATA_REG 0x3D5 /* CRT Controller Registers - Data Register */
#define START_ADDR_H 0xC /* reg index of video mem start addr (MSB) */
#define START_ADDR_L 0xD /* reg index of video mem start addr (LSB) */
#define CURSOR_H 0xE /* reg index of cursor position (MSB) */
#define CURSOR_L 0xF /* reg index of cursor position (LSB) */
#define V_MEM_BASE 0xB8000 /* base of color video memory */
#define V_MEM_SIZE 0x8000 /* 32K: B8000H -> BFFFFH */

/* Hardware interrupts */
#define NR_IRQ  16 /* Number of IRQs */
#define CLOCK_IRQ 0
#define KEYBOARD_IRQ 1
#define CASCADE_IRQ 2 /* cascade enable for 2nd AT controller */
#define ETHER_IRQ 3 /* default ethernet interrupt vector */
#define SECONDARY_IRQ 3 /* RS232 interrupt vector for port 2 */
#define RS232_IRQ 4 /* RS232 interrupt vector for port 1 */
#define XT_WINI_IRQ 5 /* xt winchester */
#define FLOPPY_IRQ 6 /* floppy disk */
#define PRINTER_IRQ 7
#define AT_WINI_IRQ 14 /* at winchester */

/* system call */
#define NR_SYS_CALL     1

#endif /* _ORANGES_CONST_H_ */

include/global.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            global.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* EXTERN is defined as extern except in global.c */
#ifdef GLOBAL_VARIABLES_HERE
#undef EXTERN
#define EXTERN
#endif

EXTERN int  ticks;

EXTERN int  disp_pos;
EXTERN u8  gdt_ptr[6]; // 0~15:Limit  16~47:Base
EXTERN DESCRIPTOR gdt[GDT_SIZE];
EXTERN u8  idt_ptr[6]; // 0~15:Limit  16~47:Base
EXTERN GATE  idt[IDT_SIZE];

EXTERN u32  k_reenter;

EXTERN TSS  tss;
EXTERN PROCESS* p_proc_ready;

EXTERN int  nr_current_console;

extern PROCESS  proc_table[];
extern char  task_stack[];
extern  TASK            task_table[];
extern irq_handler irq_table[];
extern TTY  tty_table[];
extern  CONSOLE         console_table[];


include/proto.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/* klib.asm */
PUBLIC void out_byte(u16 port, u8 value);
PUBLIC u8 in_byte(u16 port);
PUBLIC void disp_str(char * info);
PUBLIC void disp_color_str(char * info, int color);

/* protect.c */
PUBLIC void init_prot();
PUBLIC u32 seg2phys(u16 seg);

/* klib.c */
PUBLIC void delay(int time);

/* kernel.asm */
void restart();

/* main.c */
void TestA();
void TestB();
void TestC();

/* i8259.c */
PUBLIC void put_irq_handler(int irq, irq_handler handler);
PUBLIC void spurious_irq(int irq);

/* clock.c */
PUBLIC void clock_handler(int irq);
PUBLIC void init_clock();

/* keyboard.c */
PUBLIC void init_keyboard();

/* tty.c */
PUBLIC void task_tty();
PUBLIC void in_process(TTY* p_tty, u32 key);

/* console.c */
PUBLIC void out_char(CONSOLE* p_con, char ch);
PUBLIC void scroll_screen(CONSOLE* p_con, int direction);

/* 以下是系統調用相關 */

/* proc.c */
PUBLIC  int     sys_get_ticks();        /* sys_call */

/* syscall.asm */
PUBLIC  void    sys_call();             /* int_handler */
PUBLIC  int     get_ticks();

include/tty.h

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    tty.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#ifndef _ORANGES_TTY_H_
#define _ORANGES_TTY_H_


#define TTY_IN_BYTES 256 /* tty input queue size */

struct s_console;

/* TTY */
typedef struct s_tty
{
 u32 in_buf[TTY_IN_BYTES]; /* TTY 輸入緩衝區 */
 u32* p_inbuf_head;  /* 指向緩衝區中下一個空閒位置 */
 u32* p_inbuf_tail;  /* 指向鍵盤任務應處理的鍵值 */
 int inbuf_count;  /* 緩衝區中已經填充了多少 */

 struct s_console * p_console;
}TTY;


#endif /* _ORANGES_TTY_H_ */

kernel/console.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         console.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*
 迴車鍵: 把光標移到第一列
 換行鍵: 把光標前進到下一行
*/


#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

PRIVATE void set_cursor(unsigned int position);
PRIVATE void set_video_start_addr(u32 addr);
PRIVATE void flush(CONSOLE* p_con);

/*======================================================================*
      init_screen
 *======================================================================*/
PUBLIC void init_screen(TTY* p_tty)
{
 int nr_tty = p_tty - tty_table;
 p_tty->p_console = console_table + nr_tty;

 int v_mem_size = V_MEM_SIZE >> 1; /* 顯存總大小 (in WORD) */

 int con_v_mem_size                   = v_mem_size / NR_CONSOLES;
 p_tty->p_console->original_addr      = nr_tty * con_v_mem_size;
 p_tty->p_console->v_mem_limit        = con_v_mem_size;
 p_tty->p_console->current_start_addr = p_tty->p_console->original_addr;

 /* 默認光標位置在最開始處 */
 p_tty->p_console->cursor = p_tty->p_console->original_addr;

 if (nr_tty == 0) {
  /* 第一個控制台沿用原來的光標位置 */
  p_tty->p_console->cursor = disp_pos / 2;
  disp_pos = 0;
 }
 else {
  out_char(p_tty->p_console, nr_tty + '0');
  out_char(p_tty->p_console, '#');
 }

 set_cursor(p_tty->p_console->cursor);
}


/*======================================================================*
      is_current_console
*======================================================================*/
PUBLIC int is_current_console(CONSOLE* p_con)
{
 return (p_con == &console_table[nr_current_console]);
}


/*======================================================================*
      out_char
 *======================================================================*/
PUBLIC void out_char(CONSOLE* p_con, char ch)
{
 u8* p_vmem = (u8*)(V_MEM_BASE + p_con->cursor * 2);

 switch(ch) {
 case '\n':
  if (p_con->cursor < p_con->original_addr +
      p_con->v_mem_limit - SCREEN_WIDTH) {
   p_con->cursor = p_con->original_addr + SCREEN_WIDTH *
    ((p_con->cursor - p_con->original_addr) /
     SCREEN_WIDTH + 1);
  }
  break;
 case '\b':
  if (p_con->cursor > p_con->original_addr) {
   p_con->cursor--;
   *(p_vmem-2) = ' ';
   *(p_vmem-1) = DEFAULT_CHAR_COLOR;
  }
  break;
 default:
  if (p_con->cursor <
      p_con->original_addr + p_con->v_mem_limit - 1) {
   *p_vmem++ = ch;
   *p_vmem++ = DEFAULT_CHAR_COLOR;
   p_con->cursor++;
  }
  break;
 }

 while (p_con->cursor >= p_con->current_start_addr + SCREEN_SIZE) {
  scroll_screen(p_con, SCR_DN);
 }

 flush(p_con);
}

/*======================================================================*
                           flush
*======================================================================*/
PRIVATE void flush(CONSOLE* p_con)
{
        set_cursor(p_con->cursor);
        set_video_start_addr(p_con->current_start_addr);
}

/*======================================================================*
       set_cursor
 *======================================================================*/
PRIVATE void set_cursor(unsigned int position)
{
 disable_int();
 out_byte(CRTC_ADDR_REG, CURSOR_H);
 out_byte(CRTC_DATA_REG, (position >> 8) & 0xFF);
 out_byte(CRTC_ADDR_REG, CURSOR_L);
 out_byte(CRTC_DATA_REG, position & 0xFF);
 enable_int();
}

/*======================================================================*
     set_video_start_addr
 *======================================================================*/
PRIVATE void set_video_start_addr(u32 addr)
{
 disable_int();
 out_byte(CRTC_ADDR_REG, START_ADDR_H);
 out_byte(CRTC_DATA_REG, (addr >> 8) & 0xFF);
 out_byte(CRTC_ADDR_REG, START_ADDR_L);
 out_byte(CRTC_DATA_REG, addr & 0xFF);
 enable_int();
}



/*======================================================================*
      select_console
 *======================================================================*/
PUBLIC void select_console(int nr_console) /* 0 ~ (NR_CONSOLES - 1) */
{
 if ((nr_console < 0) || (nr_console >= NR_CONSOLES)) {
  return;
 }

 nr_current_console = nr_console;

 set_cursor(console_table[nr_console].cursor);
 set_video_start_addr(console_table[nr_console].current_start_addr);
}

/*======================================================================*
      scroll_screen
 *----------------------------------------------------------------------*
 滾屏.
 *----------------------------------------------------------------------*
 direction:
 SCR_UP : 向上滾屏
 SCR_DN : 向下滾屏
 其它 : 不做處理
 *======================================================================*/
PUBLIC void scroll_screen(CONSOLE* p_con, int direction)
{
 if (direction == SCR_UP) {
  if (p_con->current_start_addr > p_con->original_addr) {
   p_con->current_start_addr -= SCREEN_WIDTH;
  }
 }
 else if (direction == SCR_DN) {
  if (p_con->current_start_addr + SCREEN_SIZE <
      p_con->original_addr + p_con->v_mem_limit) {
   p_con->current_start_addr += SCREEN_WIDTH;
  }
 }
 else{
 }

 set_video_start_addr(p_con->current_start_addr);
 set_cursor(p_con->cursor);
}

kernel/global.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            global.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#define GLOBAL_VARIABLES_HERE

#include "type.h"
#include "const.h"
#include "protect.h"
#include "tty.h"
#include "console.h"
#include "proc.h"
#include "global.h"
#include "proto.h"


PUBLIC PROCESS  proc_table[NR_TASKS];

PUBLIC char  task_stack[STACK_SIZE_TOTAL];

PUBLIC TASK task_table[NR_TASKS] = {{task_tty, STACK_SIZE_TTY, "tty"},
     {TestA, STACK_SIZE_TESTA, "TestA"},
     {TestB, STACK_SIZE_TESTB, "TestB"},
     {TestC, STACK_SIZE_TESTC, "TestC"}};

PUBLIC TTY  tty_table[NR_CONSOLES];
PUBLIC CONSOLE  console_table[NR_CONSOLES];

PUBLIC irq_handler irq_table[NR_IRQ];

PUBLIC system_call sys_call_table[NR_SYS_CALL] = {sys_get_ticks};

kernel/keyboard.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                            keyboard.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "proto.h"
#include "keyboard.h"
#include "keymap.h"

PRIVATE KB_INPUT kb_in;

PRIVATE int code_with_E0;
PRIVATE int shift_l; /* l shift state */
PRIVATE int shift_r; /* r shift state */
PRIVATE int alt_l;  /* l alt state  */
PRIVATE int alt_r;  /* r left state  */
PRIVATE int ctrl_l;  /* l ctrl state  */
PRIVATE int ctrl_r;  /* l ctrl state  */
PRIVATE int caps_lock; /* Caps Lock  */
PRIVATE int num_lock; /* Num Lock  */
PRIVATE int scroll_lock; /* Scroll Lock  */
PRIVATE int column;

PRIVATE int caps_lock; /* Caps Lock  */
PRIVATE int num_lock; /* Num Lock  */
PRIVATE int scroll_lock; /* Scroll Lock  */

PRIVATE u8 get_byte_from_kbuf();
PRIVATE void    set_leds();
PRIVATE void    kb_wait();
PRIVATE void    kb_ack();

/*======================================================================*
                            keyboard_handler
 *======================================================================*/
PUBLIC void keyboard_handler(int irq)
{
 u8 scan_code = in_byte(KB_DATA);

 if (kb_in.count < KB_IN_BYTES) {
  *(kb_in.p_head) = scan_code;
  kb_in.p_head++;
  if (kb_in.p_head == kb_in.buf + KB_IN_BYTES) {
   kb_in.p_head = kb_in.buf;
  }
  kb_in.count++;
 }
}


/*======================================================================*
                           init_keyboard
*======================================================================*/
PUBLIC void init_keyboard()
{
 kb_in.count = 0;
 kb_in.p_head = kb_in.p_tail = kb_in.buf;

 shift_l = shift_r = 0;
 alt_l = alt_r   = 0;
 ctrl_l = ctrl_r  = 0;

 caps_lock   = 0;
 num_lock    = 1;
 scroll_lock = 0;

 set_leds();

        put_irq_handler(KEYBOARD_IRQ, keyboard_handler);/*設定鍵盤中斷處理程序*/
        enable_irq(KEYBOARD_IRQ);                       /*開鍵盤中斷*/
}


/*======================================================================*
                           keyboard_read
*======================================================================*/
PUBLIC void keyboard_read(TTY* p_tty)
{
 u8 scan_code;
 char output[2];
 int make; /* 1: make;  0: break. */

 u32 key = 0;/* 用一個整型來表示一個鍵。比如,如果 Home 被按下,
    * 則 key 值將為定義在 keyboard.h 中的 'HOME'。
    */
 u32* keyrow; /* 指向 keymap[] 的某一行 */

 if(kb_in.count > 0){
  code_with_E0 = 0;

  scan_code = get_byte_from_kbuf();

  /* 下面開始解析掃描碼 */
  if (scan_code == 0xE1) {
   int i;
   u8 pausebrk_scode[] = {0xE1, 0x1D, 0x45,
            0xE1, 0x9D, 0xC5};
   int is_pausebreak = 1;
   for(i=1;i<6;i++){
    if (get_byte_from_kbuf() != pausebrk_scode[i]) {
     is_pausebreak = 0;
     break;
    }
   }
   if (is_pausebreak) {
    key = PAUSEBREAK;
   }
  }
  else if (scan_code == 0xE0) {
   scan_code = get_byte_from_kbuf();

   /* PrintScreen 被按下 */
   if (scan_code == 0x2A) {
    if (get_byte_from_kbuf() == 0xE0) {
     if (get_byte_from_kbuf() == 0x37) {
      key = PRINTSCREEN;
      make = 1;
     }
    }
   }
   /* PrintScreen 被釋放 */
   if (scan_code == 0xB7) {
    if (get_byte_from_kbuf() == 0xE0) {
     if (get_byte_from_kbuf() == 0xAA) {
      key = PRINTSCREEN;
      make = 0;
     }
    }
   }
   /* 不是PrintScreen, 此時scan_code為0xE0緊跟的那個值. */
   if (key == 0) {
    code_with_E0 = 1;
   }
  }
  if ((key != PAUSEBREAK) && (key != PRINTSCREEN)) {
   /* 首先判斷Make Code 還是 Break Code */
   make = (scan_code & FLAG_BREAK ? 0 : 1);

   /* 先定位到 keymap 中的行 */
   keyrow = &keymap[(scan_code & 0x7F) * MAP_COLS];

   column = 0;

   int caps = shift_l || shift_r;
   if (caps_lock) {
    if ((keyrow[0] >= 'a') && (keyrow[0] <= 'z')){
     caps = !caps;
    }
   }
   if (caps) {
    column = 1;
   }

   if (code_with_E0) {
    column = 2;
   }

   key = keyrow[column];

   switch(key) {
   case SHIFT_L:
    shift_l = make;
    break;
   case SHIFT_R:
    shift_r = make;
    break;
   case CTRL_L:
    ctrl_l = make;
    break;
   case CTRL_R:
    ctrl_r = make;
    break;
   case ALT_L:
    alt_l = make;
    break;
   case ALT_R:
    alt_l = make;
    break;
   case CAPS_LOCK:
    if (make) {
     caps_lock   = !caps_lock;
     set_leds();
    }
    break;
   case NUM_LOCK:
    if (make) {
     num_lock    = !num_lock;
     set_leds();
    }
    break;
   case SCROLL_LOCK:
    if (make) {
     scroll_lock = !scroll_lock;
     set_leds();
    }
    break;
   default:
    break;
   }

   if (make) { /* 忽略 Break Code */
    int pad = 0;

    /* 首先處理小鍵盤 */
    if ((key >= PAD_SLASH) && (key <= PAD_9)) {
     pad = 1;
     switch(key) {
     case PAD_SLASH:
      key = '/';
      break;
     case PAD_STAR:
      key = '*';
      break;
     case PAD_MINUS:
      key = '-';
      break;
     case PAD_PLUS:
      key = '+';
      break;
     case PAD_ENTER:
      key = ENTER;
      break;
     default:
      if (num_lock &&
          (key >= PAD_0) &&
          (key <= PAD_9)) {
       key = key - PAD_0 + '0';
      }
      else if (num_lock &&
        (key == PAD_DOT)) {
       key = '.';
      }
      else{
       switch(key) {
       case PAD_HOME:
        key = HOME;
        break;
       case PAD_END:
        key = END;
        break;
       case PAD_PAGEUP:
        key = PAGEUP;
        break;
       case PAD_PAGEDOWN:
        key = PAGEDOWN;
        break;
       case PAD_INS:
        key = INSERT;
        break;
       case PAD_UP:
        key = UP;
        break;
       case PAD_DOWN:
        key = DOWN;
        break;
       case PAD_LEFT:
        key = LEFT;
        break;
       case PAD_RIGHT:
        key = RIGHT;
        break;
       case PAD_DOT:
        key = DELETE;
        break;
       default:
        break;
       }
      }
      break;
     }
    }

    key |= shift_l ? FLAG_SHIFT_L : 0;
    key |= shift_r ? FLAG_SHIFT_R : 0;
    key |= ctrl_l ? FLAG_CTRL_L : 0;
    key |= ctrl_r ? FLAG_CTRL_R : 0;
    key |= alt_l ? FLAG_ALT_L : 0;
    key |= alt_r ? FLAG_ALT_R : 0;
    key |= pad      ? FLAG_PAD      : 0;

    in_process(p_tty, key);
   }
  }
 }
}

/*======================================================================*
       get_byte_from_kbuf
 *======================================================================*/
PRIVATE u8 get_byte_from_kbuf()       /* 從鍵盤緩衝區中讀取下一個字節 */
{
        u8 scan_code;

        while (kb_in.count <= 0) {}   /* 等待下一個字節到來 */

        disable_int();
        scan_code = *(kb_in.p_tail);
        kb_in.p_tail++;
        if (kb_in.p_tail == kb_in.buf + KB_IN_BYTES) {
                kb_in.p_tail = kb_in.buf;
        }
        kb_in.count--;
        enable_int();

 return scan_code;
}

/*======================================================================*
     kb_wait
 *======================================================================*/
PRIVATE void kb_wait() /* 等待 8042 的輸入緩衝區空 */
{
 u8 kb_stat;

 do {
  kb_stat = in_byte(KB_CMD);
 } while (kb_stat & 0x02);
}


/*======================================================================*
     kb_ack
 *======================================================================*/
PRIVATE void kb_ack()
{
 u8 kb_read;

 do {
  kb_read = in_byte(KB_DATA);
 } while (kb_read =! KB_ACK);
}

/*======================================================================*
     set_leds
 *======================================================================*/
PRIVATE void set_leds()
{
 u8 leds = (caps_lock << 2) | (num_lock << 1) | scroll_lock;

 kb_wait();
 out_byte(KB_DATA, LED_CODE);
 kb_ack();

 kb_wait();
 out_byte(KB_DATA, leds);
 kb_ack();
}

kernel/clock.c, kernel/i8259.c, kernel/main.c, kernel/proc.c, kernel/protect.c, kernel/start.c, lib/klib.c (新增)

#include "tty.h"
#include "console.h"

kernel/tty.c

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               tty.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "string.h"
#include "proc.h"
#include "tty.h"
#include "console.h"
#include "global.h"
#include "keyboard.h"
#include "proto.h"

#define TTY_FIRST (tty_table)
#define TTY_END  (tty_table + NR_CONSOLES)

PRIVATE void init_tty(TTY* p_tty);
PRIVATE void tty_do_read(TTY* p_tty);
PRIVATE void tty_do_write(TTY* p_tty);
PRIVATE void put_key(TTY* p_tty, u32 key);

/*======================================================================*
                           task_tty
 *======================================================================*/
PUBLIC void task_tty()
{
 TTY* p_tty;

 init_keyboard();

 for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
  init_tty(p_tty);
 }
 select_console(0);
 while (1) {
  for (p_tty=TTY_FIRST;p_tty<TTY_END;p_tty++) {
   tty_do_read(p_tty);
   tty_do_write(p_tty);
  }
 }
}

/*======================================================================*
      init_tty
 *======================================================================*/
PRIVATE void init_tty(TTY* p_tty)
{
 p_tty->inbuf_count = 0;
 p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;

 init_screen(p_tty);
}

/*======================================================================*
    in_process
 *======================================================================*/
PUBLIC void in_process(TTY* p_tty, u32 key)
{
        char output[2] = {'\0', '\0'};

        if (!(key & FLAG_EXT)) {
  put_key(p_tty, key);
        }
        else {
                int raw_code = key & MASK_RAW;
                switch(raw_code) {
                case ENTER:
   put_key(p_tty, '\n');
   break;
                case BACKSPACE:
   put_key(p_tty, '\b');
   break;
                case UP:
                        if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
    scroll_screen(p_tty->p_console, SCR_DN);
                        }
   break;
  case DOWN:
   if ((key & FLAG_SHIFT_L) || (key & FLAG_SHIFT_R)) {
    scroll_screen(p_tty->p_console, SCR_UP);
   }
   break;
  case F1:
  case F2:
  case F3:
  case F4:
  case F5:
  case F6:
  case F7:
  case F8:
  case F9:
  case F10:
  case F11:
  case F12:
   /* Alt + F1~F12 */
   if ((key & FLAG_ALT_L) || (key & FLAG_ALT_R)) {
    select_console(raw_code - F1);
   }
   break;
                default:
                        break;
                }
        }
}

/*======================================================================*
         put_key
*======================================================================*/
PRIVATE void put_key(TTY* p_tty, u32 key)
{
 if (p_tty->inbuf_count < TTY_IN_BYTES) {
  *(p_tty->p_inbuf_head) = key;
  p_tty->p_inbuf_head++;
  if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES) {
   p_tty->p_inbuf_head = p_tty->in_buf;
  }
  p_tty->inbuf_count++;
 }
}


/*======================================================================*
         tty_do_read
 *======================================================================*/
PRIVATE void tty_do_read(TTY* p_tty)
{
 if (is_current_console(p_tty->p_console)) {
  keyboard_read(p_tty);
 }
}


/*======================================================================*
         tty_do_write
 *======================================================================*/
PRIVATE void tty_do_write(TTY* p_tty)
{
 if (p_tty->inbuf_count) {
  char ch = *(p_tty->p_inbuf_tail);
  p_tty->p_inbuf_tail++;
  if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES) {
   p_tty->p_inbuf_tail = p_tty->in_buf;
  }
  p_tty->inbuf_count--;

  out_char(p_tty->p_console, ch);
 }
}


Makefile

#########################
# Makefile for Orange'S #
#########################

# Entry point of Orange'S
# It must have the same value with 'KernelEntryPointPhyAddr' in load.inc!
ENTRYPOINT = 0x30400

# Offset of entry point in kernel file
# It depends on ENTRYPOINT
ENTRYOFFSET =   0x400

# Programs, flags, etc.
ASM  = nasm
DASM  = ndisasm
CC  = gcc
LD  = ld
ASMBFLAGS = -I boot/include/
ASMKFLAGS = -I include/ -f elf
CFLAGS  = -I include/ -m32 -c -fno-builtin -fno-stack-protector
LDFLAGS  = -s  -melf_i386 -Ttext $(ENTRYPOINT)
DASMFLAGS = -u -o $(ENTRYPOINT) -e $(ENTRYOFFSET)

# This Program
ORANGESBOOT = boot/boot.bin boot/loader.bin
ORANGESKERNEL = kernel.bin
OBJS  = kernel/kernel.o kernel/syscall.o kernel/start.o kernel/main.o\
     kernel/clock.o kernel/keyboard.o kernel/tty.o kernel/console.o\
     kernel/i8259.o kernel/global.o kernel/protect.o kernel/proc.o\
     lib/kliba.o lib/klib.o lib/string.o
DASMOUTPUT = kernel.bin.asm

# All Phony Targets
.PHONY : everything final image clean realclean disasm all buildimg

# Default starting position
nop :
 @echo "why not \`make image' huh? :)"

everything : $(ORANGESBOOT) $(ORANGESKERNEL)

all : realclean everything

image : realclean everything clean buildimg

clean :
 rm -f $(OBJS)

realclean :
 rm -f $(OBJS) $(ORANGESBOOT) $(ORANGESKERNEL)

disasm :
 $(DASM) $(DASMFLAGS) $(ORANGESKERNEL) > $(DASMOUTPUT)

# We assume that "a.img" exists in current folder
buildimg :
 mkdir tmp
 sleep 1
 sudo mount -o loop a.img tmp
 sleep 1
 sudo cp -fv boot/loader.bin tmp
 sudo cp -fv kernel.bin tmp
 sleep 1
 sudo umount tmp
 sleep 1
 rmdir tmp

boot/boot.bin : boot/boot.asm boot/include/load.inc boot/include/fat12hdr.inc
 $(ASM) $(ASMBFLAGS) -o $@ $<

boot/loader.bin : boot/loader.asm boot/include/load.inc boot/include/fat12hdr.inc boot/include/pm.inc
 $(ASM) $(ASMBFLAGS) -o $@ $<

$(ORANGESKERNEL) : $(OBJS)
 $(LD) $(LDFLAGS) -o $(ORANGESKERNEL) $(OBJS)

kernel/kernel.o : kernel/kernel.asm include/sconst.inc
 $(ASM) $(ASMKFLAGS) -o $@ $<

kernel/syscall.o : kernel/syscall.asm include/sconst.inc
 $(ASM) $(ASMKFLAGS) -o $@ $<

kernel/start.o: kernel/start.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/main.o: kernel/main.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/clock.o: kernel/clock.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/i8259.o: kernel/i8259.c include/type.h include/const.h include/protect.h include/proto.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/global.o: kernel/global.c include/type.h include/const.h include/protect.h include/proc.h \
   include/global.h include/proto.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/protect.o: kernel/protect.c include/type.h include/const.h include/protect.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

kernel/proc.o: kernel/proc.c
 $(CC) $(CFLAGS) -o $@ $<

kernel/keyboard.o: kernel/keyboard.c
 $(CC) $(CFLAGS) -o $@ $<
 
kernel/tty.o: kernel/tty.c

kernel/console.o: kernel/console.c
 $(CC) $(CFLAGS) -o $@ $<

lib/klib.o: lib/klib.c include/type.h include/const.h include/protect.h include/string.h include/proc.h include/proto.h \
   include/global.h
 $(CC) $(CFLAGS) -o $@ $<

lib/kliba.o : lib/kliba.asm
 $(ASM) $(ASMKFLAGS) -o $@ $<

lib/string.o : lib/string.asm
 $(ASM) $(ASMKFLAGS) -o $@ $<
執行結果

目錄結構

.
├── a.img
├── boot
│   ├── boot.asm
│   ├── include
│   │   ├── fat12hdr.inc
│   │   ├── load.inc
│   │   └── pm.inc
│   └── loader.asm
├── include
│   ├── console.h
│   ├── const.h
│   ├── global.h
│   ├── keyboard.h
│   ├── keymap.h
│   ├── proc.h
│   ├── protect.h
│   ├── proto.h
│   ├── sconst.inc
│   ├── string.h
│   ├── tty.h
│   └── type.h
├── kernel
│   ├── clock.c
│   ├── console.c
│   ├── global.c
│   ├── i8259.c
│   ├── kernel.asm
│   ├── keyboard.c
│   ├── main.c
│   ├── proc.c
│   ├── protect.c
│   ├── start.c
│   ├── syscall.asm
│   └── tty.c
├── lib
│   ├── kliba.asm
│   ├── klib.c
│   └── string.asm
└── Makefile

留言

這個網誌中的熱門文章

用 C# 批次控制 Word 合併列印

前由 我有全區的電話資料,問題在於我要依不同里別來製作出電話簿。結果如下圖: 單純採用合併列印無法達成我的需求。解決方法係用「功能變數」儲存上一個里別,與現在里別進行比較:若不同,則換頁。不過,這樣功能變數還蠻長的。最後,我還是採用 C# 來解決。 解決方案 用 C# 控制 WORD 中合併列印的「資料來源 Data Source」,給予不同里別的「sqlstatement」。迴圈處理不同的里別即可。但可預見其處理過程會很慢,不過還好,我可以不用在意它,有跑出結果即可。 程式碼 IList<string> areas = new List<string>() { "後壁", "侯伯", "嘉苳", "土溝", "嘉田", "嘉民", "菁豊", "崁頂", "後廍", "墨林", "菁寮", "新嘉", "頂長", "平安", "仕安", "竹新", "新東", "長安", "頂安", "福安", "烏樹" }; string root = @"D:\"; // 根目錄 string data = root + @"\data.docm"; // 資料檔(即資料來源) string template = root + @"\template.docx"; // 已設定好格式與合併欄位的 Word 檔 string output = @"d:\Final"; // 輸出之資料夾 object oMissing = System.Reflection.Missing.Va...

VLC c# 順利編譯

原文網址: http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 原文作者: haibindev 原文標題:c#万能视频播放器 本文的重點在於修正 class VlcPlayer,使其能順利在 VC# Express 2010 .Net Framework 4 下順利編譯。 修正重點在於 CallingConvention = CallingConvention. StdCall 改成 CallingConvention = CallingConvention. Cdecl using System; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace VlcDotNet { class VlcPlayer { private IntPtr libvlc_instance_; private IntPtr libvlc_media_player_; private double duration_; public VlcPlayer(string pluginPath) { string plugin_arg = "--plugin-path=" + pluginPath; string[] arguments = { "-I", "dummy", "--ignore-config", "--no-video-title", plugin_arg }; libvlc_instance_ = LibVlcAPI.libvlc_new(arguments); libvlc_media_player_ = LibVlcAPI.libvlc_media_player_new(libvlc_instance_); } public ...

[Symfony+Doctrine] 透過非 Id 來使用 Pessimistic Lock

根據 文件 ,Doctrine 有 Pessimistic Lock,又分為兩種: LockMode::PESSIMISTIC_WRITE:對應至 MySQL 的 Select FOR UPDATE LockMode::PESSIMISTIC_READ:對應至 MySQL 的 Select LOCK IN SHARE MODE 差別在於 LOCK IN SHARE MODE 會將在 row 的資料鎖定(row-level lock),在非同一交易(Transaction)下,不給寫入,其他交易可以讀取, 且可以繼續 Select LOCK IN SHARE MODE 。而 FOR UPDATE 不僅鎖定該資料,在非同一交易下,不給寫入,其它交易可以讀取, 但不能 Select LOCK IN SHARE MODE 。MySQL 文件有更詳細的比較與情境使用的說明,參考 網址 。 現在問題是,我們要完全採用 ORM 來處理資料。Doctrine 的文件提到 EntityManager::find 可以採用 Pessimistic Lock, 但 find 是透過 id 來處理 。而其他 find 系列函數(包括:findAll, findBy, findOneBy)皆不支援 LockMode。 因此,勢必要有方法來「透過非 id 來使用 Pessimistic Lock」。透過查看原始碼,簡單的方法是有的,解法之範例如下: 19 public function depositAction() 20 { 21 22 $em = $this->getDoctrine()->getManager(); 23 24 $em->transactional(function ($em) { 25 $entityName = 'AcmeTrainingBundle:Account'; 26 $lockMode = LockMode::PESSIMISTIC_READ; 27 $orderBy = null; 28 $...