linux 0.11串口程式分析

來源:互聯網
上載者:User

0.11核心維護著3個終端,一個顯示器和鍵盤,另外兩個是串口1,2. 每個終端有維護著3個隊列讀寫和輔助緩衝隊列。對於每個緩衝隊列,讀操作從隊列左邊取字元,並將隊尾指標向右移動。寫操作從隊列右邊寫字元,並將隊頭指標向右移動。任何一個移動到隊列尾端則折回到左端從新開始。

主要的終端讀寫函數包括tty_read(),tty_write(),copy_to_cooked().

tty_read(),tty_write()在檔案系統操作字元裝置檔案時被調用。例如一個程式讀寫/dev/tty就會執行系統調用sys_read(fs/read_write.c),這個系統調用在判斷出讀的是一個字元裝置檔案後會調用rw_char函數(fs/char_dev.c),該函數會根據所讀裝置的子裝置號等資訊,由字元裝置讀寫函數表調用rw_tty,最終調用到終端的讀函數tty_read()。

copy_to_cooked()由鍵盤的中斷處理程序呼叫(do_tty_interruptt),用於根據終端termios結構設定的各種標誌對read_q隊列進行處理,傳化成規範模式字元序列並儲存在輔助隊列secondary中,供tty_read讀取。如果回顯標誌置位還會把字元隊列放入write_q,並調用終端處理函數(con_write)輸出到螢幕,如果是串口裝置則調用(rs_write)發送到串列終端。最後copy_to_cooked還會喚醒等待輔助隊列的進程。

 

//將3個終端定義成表格

struct tty_struct tty_table[] = { 
 {

//第一個是顯示器終端,初始化其tty_struct結構體
  {ICRNL,  /* change incoming CR to NL */
  OPOST|ONLCR, /* change outgoing NL to CRNL */
  0,
  ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
  0,  /* console termio */
  INIT_C_CC},
  0,   /* initial pgrp */
  0,   /* initial stopped */
  con_write,               //終端輸出函數
  {0,0,0,0,""},  /* console read-queue */
  {0,0,0,0,""},  /* console write-queue */
  {0,0,0,0,""}  /* console secondary queue */
 },{    //下邊初始串口1,2
  {0, /* no translation */
  0,  /* no translation */
  B2400 | CS8,
  0,
  0,
  INIT_C_CC},
  0,
  0,
  rs_write,    //串口輸出函數
  {0x3f8,0,0,0,""},  /* rs 1,串口讀寫隊列的data域對應著UART寄存器的起始地址 */
  {0x3f8,0,0,0,""},
  {0,0,0,0,""}
 },{
  {0, /* no translation */
  0,  /* no translation */
  B2400 | CS8,
  0,
  0,
  INIT_C_CC},
  0,
  0,
  rs_write,
  {0x2f8,0,0,0,""},  /* rs 2 */
  {0x2f8,0,0,0,""},
  {0,0,0,0,""}
 }
};

/*
 * these are the tables used by the machine code handlers.
 * you can implement pseudo-tty's or something by changing
 * them. Currently not done.
 */

//將3個終端中的讀寫隊列定義成表格
struct tty_queue * table_list[]={
 &tty_table[0].read_q, &tty_table[0].write_q,
 &tty_table[1].read_q, &tty_table[1].write_q,
 &tty_table[2].read_q, &tty_table[2].write_q
 };

void tty_init(void)
{
 rs_init(); //串口初始化,設定中斷,初始化傳輸速率和允許寫保持空以外的所有終端
 con_init();//顯示終端的初始化
}

void tty_intr(struct tty_struct * tty, int mask)
{
 int i;

 if (tty->pgrp <= 0)  //tty->pgrp為零時,表示為初始init進程該進程不控制終端
  return;
 for (i=0;i<NR_TASKS;i++)
  if (task[i] && task[i]->pgrp==tty->pgrp)
   task[i]->signal |= mask;
}

static void sleep_if_empty(struct tty_queue * queue)
{
 cli();

//如果當前進程沒有訊號要處理,並且隊列為空白,則將當前進程加入到等待該隊列的進程鏈表中
 while (!current->signal && EMPTY(*queue))
  interruptible_sleep_on(&queue->proc_list);
 sti();
}

static void sleep_if_full(struct tty_queue * queue)
{
 if (!FULL(*queue))
  return;
 cli();
 while (!current->signal && LEFT(*queue)<128)
  interruptible_sleep_on(&queue->proc_list);
 sti();
}

void wait_for_keypress(void)
{
 sleep_if_empty(&tty_table[0].secondary);
}

 

用到幾個宏:

#define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1)) //緩衝區剩餘空間大小
#define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)]) //取最近用的字元??
#define FULL(a) (!LEFT(a))   //緩衝區滿了
#define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1)) //緩衝區中字元個數
#define GETCH(queue,c) /
(void)({c=(queue).buf[(queue).tail];INC((queue).tail);}) //取緩衝區字元,從隊尾取,並將隊列尾指標+1
#define PUTCH(c,queue) /
(void)({(queue).buf[(queue).head]=(c);INC((queue).head);})//向緩衝區寫字元,從隊頭寫,並將隊列頭指標+1

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.