## 13.3.?USB 的 Urbs
linux 內核中的 USB 代碼和所有的 USB 設備通訊使用稱為 urb 的東西( USB request block). 這個請求塊用 struct urb 結構描述并且可在 include/linux/usb.h 中找到.
一個 urb 用來發送或接受數據到或者從一個特定 USB 設備上的特定的 USB 端點, 以一種異步的方式. 它用起來非常象一個 kiocb 結構被用在文件系統異步 I/O 代碼, 或者如同一個 struct skbuff 用在網絡代碼中. 一個 USB 設備驅動可能分配許多 urb 給一個端點或者可能重用單個 urb 給多個不同的端點, 根據驅動的需要. 設備中的每個端點都處理一個 urb 隊列, 以至于多個 urb 可被發送到相同的端點, 在隊列清空之前. 一個 urb 的典型生命循環如下:
-
被一個 USB 設備驅動創建.
-
安排給一個特定 USB 設備的特定端點.
-
提交給 USB 核心, 被 USB 設備驅動.
-
提交給特定設備的被 USB 核心指定的 USB 主機控制器驅動, .
-
被 USB 主機控制器處理, 它做一個 USB 傳送到設備.
-
當 urb 完成, USB 主機控制器驅動通知 USB 設備驅動.
urb 也可被提交這個 urb 的驅動在任何時間取消, 或者被 USB 核心如果設備被從系統中移出. urb 被動態創建并且包含一個內部引用計數, 使它們在這個 urb 的最后一個用戶釋放它時被自動釋放.
本章中描述的處理 urb 的過程是有用的, 因為它允許流和其他復雜的, 交疊的通訊以允許驅動來獲得最高可能的數據傳送速度. 但是有更少麻煩的過程可用, 如果你只是想發送單獨的塊或者控制消息, 并且不關心數據吞吐率.(見"USB 傳送不用 urb"一節).
### 13.3.1.?結構 struct urb
struct urb 結構中和 USB 設備驅動有關的成員是:
struct usb_device *dev
指向這個 urb 要發送到的 struct usb_device 的指針. 這個變量必須被 USB 驅動初始化, 在這個 urb 被發送到 USB 核心之前.
unsigned int pipe
端點消息, 給這個 urb 要被發送到的特定 struct usb_device. 這個變量必須被 USB 驅動初始化, 在這個 urb 被發送到 USB 核心之前.
為設置這個結構的成員, 驅動使用下面的函數是適當的, 依據流動的方向. 注意每個端點只可是一個類型.
unsigned int usb_sndctrlpipe(struct usb_device *dev, unsigned int endpoint)
指定一個控制 OUT 端點給特定的帶有特定端點號的 USB 設備.
unsigned int usb_rcvctrlpipe(struct usb_device *dev, unsigned int endpoint)
指定一個控制 IN 端點給帶有特定端點號的特定 USB 設備.
unsigned int usb_sndbulkpipe(struct usb_device *dev, unsigned int endpoint)
指定一個塊 OUT 端點給帶有特定端點號的特定 USB 設備
unsigned int usb_rcvbulkpipe(struct usb_device *dev, unsigned int endpoint)
指定一個塊 IN 端點給帶有特定端點號的特定 USB 設備
unsigned int usb_sndintpipe(struct usb_device *dev, unsigned int endpoint)
指定一個中斷 OUT 端點給帶有特定端點號的特定 USB 設備
unsigned int usb_rcvintpipe(struct usb_device *dev, unsigned int endpoint)
指定一個中斷 IN 端點給帶有特定端點號的特定 USB 設備
unsigned int usb_sndisocpipe(struct usb_device *dev, unsigned int endpoint)
指定一個同步 OUT 端點給帶有特定端點號的特定 USB 設備
unsigned int usb_rcvisocpipe(struct usb_device *dev, unsigned int endpoint)
指定一個同步 IN 端點給帶有特定端點號的特定 USB 設備
unsigned int transfer_flags
這個變量可被設置為不同位值, 根據這個 USB 驅動想這個 urb 發生什么. 可用的值是:
URB_SHORT_NOT_OK
當置位, 它指出任何在一個 IN 端點上可能發生的短讀, 應當被 USB 核心當作一個錯誤. 這個值只對從 USB 設備讀的 urb 有用, 不是寫 urbs.
URB_ISO_ASAP
如果這個 urb 是同步的, 這個位可被置位如果驅動想這個 urb 被調度, 只要帶寬允許它這樣, 并且在此點設置這個 urb 中的 start_frame 變量. 如果對于同步 urb 這個位沒有被置位, 驅動必須指定 start_frame 值并且必須能夠正確恢復, 如果沒有在那個時刻啟動. 見下面的章節關于同步 urb 更多的消息.
URB_NO_TRANSFER_DMA_MAP
應當被置位, 當 urb 包含一個要被發送的 DMA 緩沖. USB 核心使用這個被 transfer_dma 變量指向的緩沖, 不是被 transfer_buffer 變量指向的緩沖.
URB_NO_SETUP_DMA_MAP
象 URB_NO_TRANSFER_DMA_MAP 位, 這個位用來控制有一個 DMA 緩沖已經建立的 urb. 如果它被置位, USB 核心使用這個被 setup_dma 變量而不是 setup_packet 變量指向的緩沖.
URB_ASYNC_UNLINK
如果置位, 給這個 urb 的對 usb_unlink_urb 的調用幾乎立刻返回, 并且這個 urb 在后面被解除連接. 否則, 這個函數等待直到 urb 完全被去鏈并且在返回前結束. 小心使用這個位, 因為它可有非常難于調試的同步問題.
URB_NO_FSBR
只有 UHCI USB 主機控制器驅動使用, 并且告訴它不要試圖做 Front Side Bus Reclamation 邏輯. 這個位通常應當不設置, 因為有 UHCI 主機控制器的機器創建了許多 CPU 負擔, 并且 PCI 總線被等待設置了這個位的 urb 所飽和.
URB_ZERO_PACKET
如果置位, 一個塊 OUT urb 通過發送不包含數據的短報文而結束, 當數據對齊到一個端點報文邊界. 這被一些壞掉的 USB 設備所需要(例如一些 USB 到 IR 的設備) 為了正確的工作..
URB_NO_INTERRUPT
如果置位, 硬件當 urb 結束時可能不產生一個中斷. 這個位應當小心使用并且只在排隊多個到相同端點的 urb 時使用. USB 核心函數使用這個為了做 DMA 緩沖傳送.
void *transfer_buffer
指向用在發送數據到設備(對一個 OUT urb)或者從設備中獲取數據(對于一個 IN urb)的緩沖的指針. 對主機控制器為了正確存取這個緩沖, 它必須被使用一個對 kmalloc 調用來創建, 不是在堆棧或者靜態地. 對控制端點, 這個緩沖是給發送的數據階段.
dma_addr_t transfer_dma
用來使用 DMA 傳送數據到 USB 設備的緩沖.
int transfer_buffer_length
緩沖的長度, 被 transfer_buffer 或者 transfer_dma 變量指向(由于只有一個可被一個 urb 使用). 如果這是 0, 沒有傳送緩沖被 USB 核心所使用.
對于一個 OUT 端點, 如果這個端點最大的大小比這個變量指定的值小, 對這個 USB 設備的傳送被分成更小的塊為了正確的傳送數據. 這種大的傳送發生在連續的 USB 幀. 提交一個大塊數據在一個 urb 中是非常快, 并且使 USB 主機控制器去劃分為更小的快, 比以連續的順序發送小緩沖.
unsigned char *setup_packet
指向給一個控制 urb 的 setup 報文的指針. 它在位于傳送緩沖中的數據之前被傳送. 這個變量只對控制 urb 有效.
dma_addr_t setup_dma
給控制 urb 的 setupt 報文的 DMA 緩沖. 在位于正常傳送緩沖的數據之前被傳送. 這個變量只對控制 urb 有效.
usb_complete_t complete
指向完成處理者函數的指針, 它被 USB 核心調用當這個 urb 被完全傳送或者當 urb 發生一個錯誤. 在這個函數中, USB 驅動可檢查這個 urb, 釋放它, 或者重新提交它給另一次傳送.(見"completingUrbs: 完成回調處理者", 關于完成處理者的更多細節).
usb_complete_t 類型定義如此:
~~~
typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
~~~
void *context
指向數據點的指針, 它可被 USB 驅動設置. 它可在完成處理者中使用當 urb 被返回到驅動. 關于這個變量的細節見后續章節.
int actual_length
當這個 urb 被完成, 這個變量被設置為數據的真實長度, 或者由這個 urb (對于 OUT urb)發送或者由這個 urb(對于 IN urb)接受. 對于 IN urb, 這個必須被用來替代 transfer_buffer_length 變量, 因為接收的數據可能比整個緩沖大小小.
int status
當這個 urb 被結束, 或者開始由 USB 核心處理, 這個變量被設置為 urb 的當前狀態. 一個 USB 驅動可安全存取這個變量的唯一時間是在 urb 完成處理者函數中(在"CompletingUrbs: 完成回調處理者"一節中描述). 這個限制是阻止競爭情況, 發生在這個 urb 被 USB 核心處理當中. 對于同步 urb, 在這個變量中的一個成功的值(0)只指示是否這個 urb 已被去鏈. 為獲得在同步 urb 上的詳細狀態, 應當檢查 iso_frame_desc 變量.
這個變量的有效值包括:
0
這個 urb 傳送是成功的.
-ENOENT
這個 urb 被對 usb_kill_urb 的調用停止.
-ECONNRESET
urb 被對 usb_unlink_urb 的調用去鏈, 并且 transfer_flags 變量被設置為 URB_ASYNC_UNLINK.
-EINPROGRESS
這個 urb 仍然在被 USB 主機控制器處理中. 如果你的驅動曾見到這個值, 它是一個你的驅動中的 bug.
-EPROTO
這個 urb 發生下面一個錯誤:
-
一個 bitstuff 錯誤在傳送中發生.
-
硬件沒有及時收到響應幀.
-EILSEQ
在這個 urb 傳送中有一個 CRC 不匹配.
-EPIPE
這個端點現在被停止. 如果這個包含的端點不是一個控制端點, 這個錯誤可被清除通過一個對函數 usb_clear_halt 的調用.
-ECOMM
在傳送中數據接收快于能被寫入系統內存. 這個錯誤值只對 IN urb.
-ENOSR
在傳送中數據不能從系統內存中獲取得足夠快, 以便可跟上請求的 USB 數據速率. 這個錯誤只對 OUT urb.
-EOVERFLOW
這個 urb 發生一個"babble"錯誤. 一個"babble"錯誤發生當端點接受數據多于端點的特定最大報文大小.
-EREMOTEIO
只發生在當 URB_SHORT_NOT_OK 標志被設置在 urb 的 transfer_flags 變量, 并且意味著 urb 請求的完整數量的數據沒有收到.
-ENODEV
這個 USB 設備現在從系統中消失.
-EXDEV
只對同步 urb 發生, 并且意味著傳送只部分完成. 為了決定傳送什么, 驅動必須看單獨的幀狀態.
-EINVAL
這個 urb 發生了非常壞的事情. USB 內核文檔描述了這個值意味著什么:
ISO 瘋了, 如果發生這個: 退出并回家.
它也可發生, 如果一個參數在 urb 結構中被不正確地設置了, 或者如果在提交這個 urb 給 USB 核心的 usb_submit_urb 調用中, 有一個不正確的函數參數.
-ESHUTDOWN
這個 USB 主機控制器驅動有嚴重的錯誤; 它現在已被禁止, 或者設備和系統去掉連接, 并且這個urb 在設備被去除后被提交. 它也可發生當這個設備的配置改變, 而這個 urb 被提交給設備.
通常, 錯誤值 -EPROTO, -EILSEQ, 和 -EOVERFLOW 指示設備的硬件問題, 設備固件, 或者連接設備到計算機的線纜.int start_frame
設置或返回同步傳送要使用的初始幀號.
int interval
urb 被輪詢的間隔. 這只對中斷或者同步 urb 有效. 這個值的單位依據設備速度而不同. 對于低速和高速的設備, 單位是幀, 它等同于毫秒. 對于設備, 單位是宏幀的設備, 它等同于 1/8 微秒單位. 這個值必須被 USB 驅動設置給同步或者中斷 urb, 在這個 urb被發送到 USB 核心之前.
int number_of_packets
只對同步 urb 有效, 并且指定這個 urb 要處理的同步傳送緩沖的編號. 這個值必須被 USB 驅動設置給同步 urb, 在這個 urb 發送給 USB 核心之前.
int error_count
被 USB 核心設置, 只給同步 urb 在它們完成之后. 它指定報告任何類型錯誤的同步傳送的號碼.
struct usb_iso_packet_descriptor iso_frame_desc[0]
只對同步 urb 有效. 這個變量是組成這個 urb 的一個 struct usb_iso_packet_descriptor 結構數組. 這個結構允許單個 urb 來一次定義多個同步傳送. 它也用來收集每個單獨傳送的傳送狀態.
結構 usb_iso_packet_descriptor 由下列成員組成:
unsigned int offset
報文數據所在的傳送緩沖中的偏移(第一個字節從 0 開始).
unsigned int length
這個報文的傳送緩沖的長度.
unsigned int actual_length
接收到給這個同步報文的傳送緩沖的數據長度.
unsigned int status
這個報文的單獨同步傳送的狀態. 它可采用同樣的返回值如同主 struct urb 結構的狀態變量.
### 13.3.2.?創建和銷毀 urb
struct urb 結構在驅動中必須不被靜態創建, 或者在另一個結構中, 因為這可能破壞 USB 核心給 urb 使用的引用計數方法. 它必須使用對 usb_alloc_urb 函數的調用而被創建. 這個函數有這個原型:
~~~
struct urb *usb_alloc_urb(int iso_packets, int mem_flags);
~~~
第一個參數, iso_packet, 是這個 urb 應當包含的同步報文的數目. 如果你不想創建一個同步 urb, 這個變量應當被設置為 0. 第 2 個參數, mem_flags, 是和傳遞給 kmalloc 函數調用來從內核分配內存的相同的標志類型(見"flags 參數"一節, 第 8 章, 關于這些標志的細節). 如果這個函數在分配足夠內存給這個 urb 成功, 一個指向 urb 的指針被返回給調用者. 如果返回值是 NULL, 某個錯誤在 USB 核心中發生了, 并且驅動需要正確地清理.
在創建了一個 urb 之后, 它必須被正確初始化在它可被 USB 核心使用之前. 如何初始化不同類型 urb 見下一節
為了告訴 USB 核心驅動用完這個 urb, 驅動必須調用 usb_free_urb 函數. 這個函數只有一個參數:
~~~
void usb_free_urb(struct urb *urb);
~~~
參數是一個指向你要釋放的 struct urb 的指針. 在這個函數被調用之后, urb 結構消失, 驅動不能再存取它.
#### 13.3.2.1.?中斷 urb
函數 usb_fill_int_urb 是一個幫忙函數, 來正確初始化一個urb 來發送給 USB 設備的一個中斷端點:
~~~
void usb_fill_int_urb(struct urb *urb, struct usb_device *dev,
unsigned int pipe, void *transfer_buffer,
int buffer_length, usb_complete_t complete,
void *context, int interval);
~~~
這個函數包含許多參數:
struct urb *urb
指向要被初始化的 urb 的指針.
struct usb_device *dev
這個 urb 要發送到的 USB 設備.
unsigned int pipe
這個 urb 要被發送到的 USB 設備的特定端點. 這個值被創建, 使用前面提過的 usb_sndintpipe 或者 usb_rcvintpipe 函數.
void *transfer_buffer
指向緩沖的指針, 從那里外出的數據被獲取或者進入數據被接受. 注意這不能是一個靜態的緩沖并且必須使用 kmalloc 調用來創建.
int buffer_length
緩沖的長度, 被 transfer_buffer 指針指向.
usb_complete_t complete
指針, 指向當這個 urb 完成時被調用的完成處理者.
void *context
指向數據塊的指針, 它被添加到這個 urb 結構為以后被完成處理者函數獲取.
int interval
這個 urb 應當被調度的間隔. 見之前的 struct urb 結構的描述, 來找到這個值的正確單位.
#### 13.3.2.2.?塊 urb
塊 urb 被初始化非常象中斷 urb. 做這個的函數是 usb_fill_bulk_urb, 它看來如此:
~~~
void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev,
unsigned int pipe, void *transfer_buffer,
int buffer_length, usb_complete_t complete,
void *context);
~~~
這個函數參數和 usb_fill_int_urb 函數的都相同. 但是, 沒有 interval 參數因為 bulk urb 沒有間隔值. 請注意這個 unsiged int pipe 變量必須被初始化用對 usb_sndbulkpipe 或者 usb_rcvbulkpipe 函數的調用.
usb_fill_int_urb 函數不設置 urb 中的 transfer_flags 變量, 因此任何對這個成員的修改不得不由這個驅動自己完成.
#### 13.3.2.3.?控制 urb
控制 urb 被初始化幾乎和 塊 urb 相同的方式, 使用對函數 usb_fill_control_urb 的調用:
~~~
void usb_fill_control_urb(struct urb *urb, struct usb_device *dev,
unsigned int pipe, unsigned char *setup_packet,
void *transfer_buffer, int buffer_length,
usb_complete_t complete, void *context);
~~~
函數參數和 usb_fill_bulk_urb 函數都相同, 除了有個新參數, unsigned char *setup_packet, 它必須指向要發送給端點的 setup 報文數據. 還有, unsigned int pipe 變量必須被初始化, 使用對 usb_sndctrlpipe 或者 usb_rcvictrlpipe 函數的調用.
usb_fill_control_urb 函數不設置 transfer_flags 變量在 urb 中, 因此任何對這個成員的修改必須游驅動自己完成. 大部分驅動不使用這個函數, 因為使用在"USB 傳送不用 urb"一節中介紹的同步 API 調用更簡單.
#### 13.3.2.4.?同步 urb
不幸的是, 同步 urb 沒有一個象中斷, 控制, 和塊 urb 的初始化函數. 因此它們必須在驅動中"手動"初始化, 在它們可被提交給 USB 核心之前. 下面是一個如何正確初始化這類 urb 的例子. 它是從 konicawc.c 內核驅動中取得的, 它位于主內核源碼樹的 drivers/usb/media 目錄.
~~~
urb->dev = dev;
urb->context = uvd;
urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
urb->interval = 1;
urb->transfer_flags = URB_ISO_ASAP;
urb->transfer_buffer = cam->sts_buf[i];
urb->complete = konicawc_isoc_irq;
urb->number_of_packets = FRAMES_PER_DESC;
urb->transfer_buffer_length = FRAMES_PER_DESC;
for (j=0; j < FRAMES_PER_DESC; j++) {
urb->iso_frame_desc[j].offset = j;
urb->iso_frame_desc[j].length = 1;
}
~~~
### 13.3.3.?提交 urb
一旦 urb 被正確地創建,并且被 USB 驅動初始化, 它已準備好被提交給 USB 核心來發送出到 USB 設備. 這通過調用函數 usb_submit_urb 實現:
~~~
int usb_submit_urb(struct urb *urb, int mem_flags);
~~~
urb 參數是一個指向 urb 的指針, 它要被發送到設備. mem_flags 參數等同于傳遞給 kmalloc 調用的同樣的參數, 并且用來告訴 USB 核心如何及時分配任何內存緩沖在這個時間.
在 urb 被成功提交給 USB 核心之后, 應當從不試圖存取 urb 結構的任何成員直到完成函數被調用.
因為函數 usb_submit_urb 可被在任何時候被調用(包括從一個中斷上下文), mem_flags 變量的指定必須正確. 真正只有 3 個有效值可用, 根據何時 usb_submit_urb 被調用:
GFP_ATOMIC
這個值應當被使用無論何時下面的是真:
-
調用者處于一個 urb 完成處理者, 一個中斷, 一個后半部, 一個 tasklet, 或者一個時鐘回調.
-
調用者持有一個自旋鎖或者讀寫鎖. 注意如果正持有一個旗標, 這個值不必要.
-
current->state 不是 TASK_RUNNING. 狀態一直是 TASK_RUNNING 除非驅動已自己改變 current 狀態.
GFP_NOIO
這個值應當被使用, 如果驅動在塊 I/O 補丁中. 它還應當用在所有的存儲類型的錯誤處理補丁中.
GFP_KERNEL
這應當用在所有其他的情況中, 不屬于之前提到的類別.
### 13.3.4.?完成 urb: 完成回調處理者
如果對 usb_submit_urb 的調用成功, 傳遞對 urb 的控制給 USB 核心, 這個函數返回 0; 否則, 一個負錯誤值被返回. 如果函數成功, urb 的完成處理者(如同被完成函數指針指定的)被確切地調用一次, 當 urb 被完成. 當這個函數被調用, USB 核心完成這個 urb, 并且對它的控制現在返回給設備驅動.
只有 3 個方法, 一個urb 可被結束并且使完成函數被調用:
-
urb 被成功發送給設備, 并且設備返回正確的確認. 對于一個 OUT urb, 數據被成功發送, 對于一個 IN urb, 請求的數據被成功收到. 如果發生這個, urb 中的狀態變量被設置為 0.
-
一些錯誤連續發生, 當發送或者接受數據從設備中. 被 urb 結構中的 status 變量中的錯誤值所記錄.
-
這個 urb 被從 USB 核心去鏈. 這發生在要么當驅動告知 USB 核心取消一個已提交的 urb 通過調用 usb_unlink_urb 或者 usb_kill_urb, 要么當設備從系統中去除, 以及一個 urb 已經被提交給它.
一個如何測試在一個 urb 完成調用中不同返回值的例子在本章稍后展示.
### 13.3.5.?取消 urb
為停止一個已經提交給 USB 核心的 urb, 函數 usb_kill_urb 或者 usb_unlink_urb 應當被調用:
~~~
int usb_kill_urb(struct urb *urb);
int usb_unlink_urb(struct urb *urb);
~~~
The urb parameter for both of these functions is a pointer to the urb that is to be canceled.
當函數是 usb_kill_urb, 這個 urb 的生命循環就停止了. 這個函數常常在設備從系統去除時被使用, 在去連接回調中.
對一些驅動, 應當用 usb_unlink_urb 函數來告知 USB 核心去停止 urb. 這個函數在返回到調用者之前不等待這個 urb 完全停止. 這對于在中斷處理或者持有一個自旋鎖時停止 urb 時是有用的, 因為等待一個 urb 完全停止需要 USB 核心有能力使調用進程睡眠. 為了正確工作這個函數要求 URB_ASYNC_UNLINK 標志值被設置在正被要求停止的 urb 中.
- Linux設備驅動第三版
- 第 1 章 設備驅動簡介
- 1.1. 驅動程序的角色
- 1.2. 劃分內核
- 1.3. 設備和模塊的分類
- 1.4. 安全問題
- 1.5. 版本編號
- 1.6. 版權條款
- 1.7. 加入內核開發社團
- 1.8. 本書的內容
- 第 2 章 建立和運行模塊
- 2.1. 設置你的測試系統
- 2.2. Hello World 模塊
- 2.3. 內核模塊相比于應用程序
- 2.4. 編譯和加載
- 2.5. 內核符號表
- 2.6. 預備知識
- 2.7. 初始化和關停
- 2.8. 模塊參數
- 2.9. 在用戶空間做
- 2.10. 快速參考
- 第 3 章 字符驅動
- 3.1. scull 的設計
- 3.2. 主次編號
- 3.3. 一些重要數據結構
- 3.4. 字符設備注冊
- 3.5. open 和 release
- 3.6. scull 的內存使用
- 3.7. 讀和寫
- 3.8. 使用新設備
- 3.9. 快速參考
- 第 4 章 調試技術
- 4.1. 內核中的調試支持
- 4.2. 用打印調試
- 4.3. 用查詢來調試
- 4.4. 使用觀察來調試
- 4.5. 調試系統故障
- 4.6. 調試器和相關工具
- 第 5 章 并發和競爭情況
- 5.1. scull 中的缺陷
- 5.2. 并發和它的管理
- 5.3. 旗標和互斥體
- 5.4. Completions 機制
- 5.5. 自旋鎖
- 5.6. 鎖陷阱
- 5.7. 加鎖的各種選擇
- 5.8. 快速參考
- 第 6 章 高級字符驅動操作
- 6.1. ioctl 接口
- 6.2. 阻塞 I/O
- 6.3. poll 和 select
- 6.4. 異步通知
- 6.5. 移位一個設備
- 6.6. 在一個設備文件上的存取控制
- 6.7. 快速參考
- 第 7 章 時間, 延時, 和延后工作
- 7.1. 測量時間流失
- 7.2. 獲知當前時間
- 7.3. 延后執行
- 7.4. 內核定時器
- 7.5. Tasklets 機制
- 7.6. 工作隊列
- 7.7. 快速參考
- 第 8 章 分配內存
- 8.1. kmalloc 的真實故事
- 8.2. 后備緩存
- 8.3. get_free_page 和其友
- 8.4. 每-CPU 的變量
- 8.5. 獲得大量緩沖
- 8.6. 快速參考
- 第 9 章 與硬件通訊
- 9.1. I/O 端口和 I/O 內存
- 9.2. 使用 I/O 端口
- 9.3. 一個 I/O 端口例子
- 9.4. 使用 I/O 內存
- 9.5. 快速參考
- 第 10 章 中斷處理
- 10.1. 準備并口
- 10.2. 安裝一個中斷處理
- 10.3. 前和后半部
- 10.4. 中斷共享
- 10.5. 中斷驅動 I/O
- 10.6. 快速參考
- 第 11 章 內核中的數據類型
- 11.1. 標準 C 類型的使用
- 11.2. 安排一個明確大小給數據項
- 11.3. 接口特定的類型
- 11.4. 其他移植性問題
- 11.5. 鏈表
- 11.6. 快速參考
- 第 12 章 PCI 驅動
- 12.1. PCI 接口
- 12.2. 回顧: ISA
- 12.3. PC/104 和 PC/104+
- 12.4. 其他的 PC 總線
- 12.5. SBus
- 12.6. NuBus 總線
- 12.7. 外部總線
- 12.8. 快速參考
- 第 13 章 USB 驅動
- 13.1. USB 設備基礎知識
- 13.2. USB 和 sysfs
- 13.3. USB 的 Urbs
- 13.4. 編寫一個 USB 驅動
- 13.5. 無 urb 的 USB 傳送
- 13.6. 快速參考
- 第 14 章 Linux 設備模型
- 14.1. Kobjects, Ksets 和 Subsystems
- 14.2. 低級 sysfs 操作
- 14.3. 熱插拔事件產生
- 14.4. 總線, 設備, 和驅動
- 14.5. 類
- 14.6. 集成起來
- 14.7. 熱插拔
- 14.8. 處理固件
- 14.9. 快速參考
- 第 15 章 內存映射和 DMA
- 15.1. Linux 中的內存管理
- 15.2. mmap 設備操作
- 15.3. 進行直接 I/O
- 15.4. 直接內存存取
- 15.5. 快速參考
- 第 16 章 塊驅動
- 16.1. 注冊
- 16.2. 塊設備操作
- 16.3. 請求處理
- 16.4. 一些其他的細節
- 16.5. 快速參考
- 第 17 章 網絡驅動
- 17.1. snull 是如何設計的
- 17.2. 連接到內核
- 17.3. net_device 結構的詳情
- 17.4. 打開與關閉
- 17.5. 報文傳送
- 17.6. 報文接收
- 17.7. 中斷處理
- 17.8. 接收中斷緩解
- 17.9. 連接狀態的改變
- 17.10. Socket 緩存
- 17.11. MAC 地址解析
- 17.12. 定制 ioctl 命令
- 17.13. 統計信息
- 17.14. 多播
- 17.15. 幾個其他細節
- 17.16. 快速參考
- 第 18 章 TTY 驅動
- 18.1. 一個小 TTY 驅動
- 18.2. tty_driver 函數指針
- 18.3. TTY 線路設置
- 18.4. ioctls 函數
- 18.5. TTY 設備的 proc 和 sysfs 處理
- 18.6. tty_driver 結構的細節
- 18.7. tty_operaions 結構的細節
- 18.8. tty_struct 結構的細節
- 18.9. 快速參考