<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 18.2.?tty_driver 函數指針 最終, tiny_tty 驅動聲明了 4 個函數指針. ### 18.2.1.?open 和 close open 函數被 tty 核心調用, 當一個用戶對這個 tty 驅動被分配的設備節點調用 open 時. tty 核心使用一個指向分配給這個設備的 tty_struct 結構的指針調用它, 還用一個文件指針. 這個 open 成員必須被一個 tty 驅動為它能正確工作而設置; 否則, -ENODEV 被返回給用戶當調用 open 時. 當調用這個 open 函數, tty 驅動被期望或者保存一些傳遞給它的 tty_struct 變量中的數據, 或者保存一個可以基于端口次編號來引用的靜態數組中的數據. 這是有必要的, 所以 tty 驅動知道哪個設備在被引用當以后的 close, write, 和其他函數被調用時. tiny_tty 驅動保存一個指針在 tty 結構中, 如同下面代碼所見到: ~~~ static int tiny_open(struct tty_struct *tty, struct file *file) { struct tiny_serial *tiny; struct timer_list *timer; int index; /* initialize the pointer in case something fails */ tty->driver_data = NULL; /* get the serial object associated with this tty pointer */ index = tty->index; tiny = tiny_table[index]; if (tiny == NULL) { /* first time accessing this device, let's create it */ tiny = kmalloc(sizeof(*tiny), GFP_KERNEL); if (!tiny) return -ENOMEM; init_MUTEX(&tiny->sem); tiny->open_count = 0; tiny->timer = NULL; tiny_table[index] = tiny; } down(&tiny->sem); /* save our structure within the tty structure */ tty->driver_data = tiny; tiny->tty = tty; ~~~ 在這個代碼中, tiny_serial 結構被保存在 tty 結構中. 這允許 tiny_write, tiny_write_room, 和 tiny_close 函數來獲取 tiny_serial 結構和正確操作它. tiny_serial 結構定義為: ~~~ struct tiny_serial { struct tty_struct *tty; /* pointer to the tty for this device */ int open_count; /* number of times this port has been opened */ struct semaphore sem; /* locks this structure */ struct timer_list *timer; }; ~~~ 如同我們已見到的, open_count 變量初始化為 0 在第一次打開端口的 open 調用中. 這是一個典型的引用計數, 因為一個 tty 驅動的 open 和 close 函數可能對同一個設備多次調用以便多個進程來讀寫數據. 為正確處理所有的事情, 必須保持一個這個端口被打開或者關閉的次數計數; 這個驅動遞增和遞減這個計數在打開使用時. 當打開第一次被打開, 任何必要的硬件初始化和內存分配可以做. 當端口被最后一次關閉, 任何必要的硬件關閉和內存清理可以做. tiny_open 函數的剩下部分展示了如何跟蹤設備被打開的次數: ~~~ ++tiny->open_count; if (tiny->open_count == 1) { /* this is the first time this port is opened */ /* do any hardware initialization needed here */ ~~~ open 函數必須返回或者一個負的錯誤號如果發生事情阻止了成功打開, 或者一個 0 來表示成功. close 函數指針被 tty 核心調用, 在用戶對前面使用 open 調用而創建的文件句柄調用 close 時. 這表示設備應當在這次被關閉. 但是, 因為 open 函數可被多次調用, close函數也可多次調用. 因此這個函數應當跟蹤它被調用的次數來決定是否硬件應當在此次真正被關閉. tiny_tty 驅動做這個使用下面的代碼: ~~~ static void do_close(struct tiny_serial *tiny) { down(&tiny->sem); if (!tiny->open_count) { /* port was never opened */ goto exit; } --tiny->open_count; if (tiny->open_count <= 0) { /* The port is being closed by the last user. */ /* Do any hardware specific stuff here */ /* shut down our timer */ del_timer(tiny->timer); } exit: up(&tiny->sem); } static void tiny_close(struct tty_struct *tty, struct file *file) { struct tiny_serial *tiny = tty->driver_data; if (tiny) do_close(tiny); } ~~~ tiny_close 函數只是調用 do_close 函數來完成實際的關閉設備工作. 因此關閉邏輯不必在這里和驅動被卸載和端口被打開時重復. close 函數沒有返回值, 因為它不被認為會失敗. ### 18.2.2.?數據流 write 函數被用戶在有數據發送給硬件時調用. 首先 tty 核心接收到調用, 接著它傳遞數據到 tty 驅動的 write 函數. tty 核心還告知 tty 驅動要發送的數據大小. 有時, 因為速度和 tty 硬件的緩沖區容量, 不是所有的寫程序要求的字符可以在調用寫函數時發送. 這個寫函數應當返回能夠發送給硬件的字符數( 或者在以后時間可排隊發送 ), 因此用戶程序可以檢查是否所有的數據真正寫入. 這種檢查在用戶空間非常容易完成, 比一個內核驅動站著睡眠直到所有的請求數據能夠被發送. 如果任何錯誤發生在 wirte 調用期間, 一個負的錯誤值應當被返回代替被寫入的字節數. write 函數可從中斷上下文和用戶上下文中被調用. 知道這一點是重要的, 因為 tty 驅動不應當調用任何可能當它在中斷上下文中睡眠的函數. 這些包括任何可能調用調度的函數, 例如普通的函數 copy_from_user, kmalloc, 和 printk. 如果你確實想睡眠, 確信去首先檢查是否驅動在中斷上下文, 通過調用 calling_in_interrupt. 這個例子 tiny tty 驅動沒有連接到任何真實的硬件, 因此它的寫函數簡單地將要寫的什么數據記錄到內核調試日志. 它使用下面的代碼做這個: ~~~ static int tiny_write(struct tty_struct *tty, const unsigned char *buffer, int count) { struct tiny_serial *tiny = tty->driver_data; int i; int retval = -EINVAL; if (!tiny) return -ENODEV; down(&tiny->sem); if (!tiny->open_count) /* port was not opened */ goto exit; /* fake sending the data out a hardware port by * writing it to the kernel debug log. */ printk(KERN_DEBUG "%s - ", __FUNCTION__); for (i = 0; i < count; ++i) printk("%02x ", buffer[i]); printk("\n"); exit: up(&tiny->sem); return retval; } ~~~ 當 tty 子系統自己需要發送數據到 tty 設備之外, write 函數被調用. 如果 tty 驅動在 tty_struct 中沒有實現 put_char 函數, 這會發生. 在這種情況下, tty 核心用一個數據大小為 1 來使用 write 函數回調. 這普遍發生在 tty 核心想轉換一個新行字符為一個換行和新行字符. 這里的最大的問題是 tty 驅動的 write 函數必須不返回 0 對于這類的調用. 這意味著驅動必須寫那個數據的字節到設備, 因為調用者( tty 核心 ) 不緩沖數據和在之后的時間重試. 因為 write 函數不能知道是否它在被調用來替代 put_char, 即便只有一個字節的數據被發送, 盡力實現 write 函數以至于它一直至少在返回前寫一個字節. 許多當前的 USB-到-串口的 tty 驅動沒有遵照這個規則, 并且因此, 一些終端類型不能正確工作當連接到它們時. write_room 函數被調用當 tty 核心想知道多少空間在寫緩沖中 tty 驅動可用. 這個數字時時改變隨著字符清空寫緩沖以及調用寫函數時, 添加字符到這個緩沖. ~~~ static int tiny_write_room(struct tty_struct *tty) { struct tiny_serial *tiny = tty->driver_data; int room = -EINVAL; if (!tiny) return -ENODEV; down(&tiny->sem); if (!tiny->open_count) { /* port was not opened */ goto exit; } /* calculate how much room is left in the device */ room = 255; exit: up(&tiny->sem); return room; } ~~~ ### 18.2.3.?其他緩沖函數 一個工作的 tty 驅動不需要在 tty_driver 結構中的 chars_in_buffer 函數, 但是它被推薦. 這個函數被調用當 tty 核心想知道多少字符仍然保留在 tty 驅動的寫緩沖中要被發送. 如果驅動能夠存儲字符在它發送它們到硬件之前, 它應當實現這個函數為了 tty 核心能夠知道是否所有的驅動中的數據已經流出. 3 個 tty_driver 結構中的函數回調可以用來刷新任何驅動保留的數據. 它們不被要求實現, 但是推薦如果 tty 驅動能夠緩沖數據在它發送給硬件之前. 前 2 個函數回調稱為 flush_chars 和 wait_until_sent. 這些函數被調用當 tty 核心使用 put_char 函數回調已發送了許多字符給 tty 驅動. flush_chars 函數回調被調用當 tty 核心要 tty 驅動啟動發送這些字符到硬件, 如果它尚未啟動. 這個函數被允許在所有的數據發送給硬件之前返回. wait_until_sent 函數回調以非常相同的發生工作; 但是它必須等待直到所有的字符在返回到 tty 核心前被發送, 或者知道超時值到時. 如果這個傳遞給 wait_until_sent 函數回調的超時值設為 0, 函數應當等待直到它完成這個操作. 剩下的數據刷新函數回調是 flush_buffer. 它被 tty 核心調用當 tty 驅動要刷新所有的仍然在它的寫緩沖的數據. 任何保留在緩沖中的數據被丟失并且沒發送給設備. ### 18.2.4.?無 read 函數? 只使用這些函數, tiny_tty 驅動可被注冊, 可打開一個設備節點, 數據被寫入設備, 關閉設備節點, 以驅動注銷和從內核中卸載. 但是 tty 核心和 tty_driver 結構沒有提供一個 read 函數; 換句話說, 沒有函數調用存在來從驅動到 tty 核心獲取數據. 替代一個傳統的 read 函數, tty 驅動負責發送任何從硬件收到的數據到 tty 核心. tty 核心緩沖數據直到它被用戶請求. 因為 tty 核心提供的緩沖邏輯, 對每個 tty 驅動不必要實現它自己的緩沖邏輯. tty 核心通知 tty 驅動當一個用戶要驅動停止和開始發送數據, 但是如果內部的 tty 緩沖滿, 沒有這樣的通知發生. tty 核心緩沖由 tty 驅動接收到的數據, 在一個稱為 struct tty_flip_buffer 的結構中. 一個 flip 緩沖是一個結構包含 2 個主要數據數組. 從 tty 設備接收到的數據被存儲于第一個數組. 當這個數組滿, 任何等待數據的用戶被通知數據可以讀. 當用戶從這個數組讀數據, 任何新到的數據被存儲在第 2 個數組. 當那個數組被讀空, 數據再次刷新給用戶, 并且驅動開始填充第 1 個數組. 本質上, 被接收的數據 "flips" 從一個緩沖到另一個, 期望不會溢出它們 2 個. 為試圖阻止數據丟失, 一個 tty 驅動可以監視到來的數組多大, 并且, 如果它添滿, 及時告知 tty 驅動在這個時刻刷新緩沖, 而不是等待下一個可用的機會. struct tty_flip_buffer 結構的細節對 tty 驅動沒有關系, 只有一個例外, 可用的計數. 這個變量包含多少字節當前留在緩沖里可用來接收數據. 如果這個值等于值 TTY_FLIPBUF_SIZE, 這個 flip 緩沖需要被刷新到用戶, 使用一個對 tty_flip_buffer_push 的調用. 這展示在下面的代碼: ~~~ for (i = 0; i < data_size; ++i) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) tty_flip_buffer_push(tty); tty_insert_flip_char(tty, data[i], TTY_NORMAL); } tty_flip_buffer_push(tty); ~~~ 從 tty 驅動接收來的要發送給用戶的字符被添加到 flip 緩沖, 使用對 tty_insert_flip_char 的調用. 這個函數的第一個參數是數據應當保存入的 struct tty_struct, 第 2 個參數是要保存的字符, 第 3 個參數是任何應當為這個字符設置的標志. 這個標志值應當設為 TTY_NORMAL 如果這個是一個正常的被接收的字符. 如果這是一個特殊類型的指示錯誤接收數據的字符, 它應當設為 TTY_BREAK, TTY_PARITY, 或者 TTY_OVERRUN, 取決于錯誤. 為了"推"數據給用戶, 進行一個對 tty_flip_buffer_push 的調用. 這個函數應當也被調用如果 flip 緩沖將要溢出, 如同在這個例子中展示的. 因此無論何時數據被加到 flip 緩沖, 或者當 flip 緩沖滿, tty 驅動必須調用 tty_flip_buffer_push. 如果 tty 驅動可高速接收數據, tty->low_latency 標志應當設置, 它是對 tty_flip_buffer_pus 的調用被立刻執行當調用時. 否則, tty_flip_buffer_push 調用會調度它自己來將數據推出緩沖, 在之后近期的一個時間點.
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看