1、字符型驅動設備你是怎么創建設備文件的,就是/dev/下面的設備文件,供上層應用程序打開使用的文件?
答:mknod命令結合設備的主設備號和次設備號,可創建一個設備文件。評:這只是其中一種方式,也叫手動創建設備文件。還有UDEV/MDEV自動創建設備文件的方式,UDEV/MDEV是運行在用戶態的程序,可以動態管理設備文件,包括創建和刪除設備文件,運行在用戶態意味著系統要運行之后。那么在系統啟動期間還有devfs創建了設備文件。一共有三種方式可以創建設備文件。
答:中斷處理例程應該盡量短,把能放在后半段(tasklet,等待隊列等)的任務盡量放在后半段。
評:寫一個中斷服務程序要注意快進快出,在中斷服務程序里面盡量快速采集信息,包括硬件信息,然后推出中斷,要做其它事情可以使用工作隊列或者tasklet方式。也就是中斷上半部和下半部。
第二:中斷服務程序中不能有阻塞操作。為什么?大家可以討論。? ?? ?
第三:中斷服務程序注意返回值,要用操作系統定義的宏做為返回值,而不是自己定義的OK,FAIL之類的。
答:使用自旋鎖的進程不能睡眠,使用信號量的進程可以睡眠。中斷服務例程中的互斥使用的是自旋鎖,原因是在中斷處理例程中,硬中斷是關閉的,這樣會丟失可能到來的中斷。
4、原子操作你怎么理解?為了實現一個互斥,自己定義一個變量作為標記來作為一個資源只有一個使用者行不行?
答:原子操作指的是無法被打斷的操作。我沒懂第二句是什么意思,自己定義一個變量怎么可能標記資源的使用情況?其他進程又看不見這個變量
評:第二句話的意思是:
??定義一個變量,比如 int flag =0;
? ?if(flag == 0)
??{
? ?? ? flag = 1;
? ?? ? 操作臨界區;
? ?? ?flag = 0;
? ?}這樣可否?
答:insmod調用init函數,rmmod調用exit函數。這兩個函數在設計時要注意什么?卸載模塊時曾出現卸載失敗的情形,原因是存在進程正在使用模塊,檢查代碼后發現產生了死鎖的問題。
評:要注意在init函數中申請的資源在exit函數中要釋放,包括存儲,ioremap,定時器,工作隊列等等。也就是一個模塊注冊進內核,退出內核時要清理所帶來的影響,帶走一切不留下一點痕跡。
6、在驅動調試過程中遇到過oops沒?你是怎么處理的?
7、ioctl和unlock_ioctl有什么區別?
答:因為內核沒有辦法直接訪問物理內存地址,必須先通過ioremap獲得對應的虛擬地址。
9、設備驅動模型三個重要成員是?platfoem總線的匹配規則是?在具體應用上要不要先注冊驅動再注冊設備?有先后順序沒?
10、Linux中內核空間及用戶空間的區別?用戶空間與內核通信方式有哪些?
11、linux中內存劃分及如何使用?虛擬地址及物理地址的概念及彼此之間的轉化,高端內存概念?
12、linux中中斷的實現機制,tasklet與workqueue的區別及底層實現區別?為什么要區分上半部和下半部?
13、linux中斷的響應執行流程?中斷的申請及何時執行(何時執行中斷處理函數)?
14、linux中的同步機制?spinlock與信號量的區別?
15、linux中RCU原理?
16、linux中軟中斷的實現原理?
17、linux系統實現原子操作有哪些方法??
18、MIPS Cpu中空間地址是怎么劃分的?如在uboot中如何操作設備的特定的寄存器?
19、linux中系統調用過程?如:應用程序中read()在linux中執行過程即從用戶空間到內核空間?
20、linux內核的啟動過程(源代碼級)?
21、linux調度原理?
22、linux網絡子系統的認識?
23、linux內核里面,內存申請有哪幾個函數,各自的區別?
Kmalloc() ? __get_free_page() ?mempool_create() ?
?
24. IRQ和FIQ有什么區別,在CPU里面是是怎么做的?
?
25. 中斷的上半部分和下半部分的問題:講下分成上半部分和下半部分的原因,為何要分?講下如何實現?
上半部分執行與硬件相關的處理要求快, 而有些驅動在中斷處理程序中又需要完成大量工作,這構成矛盾,所以Linux有所謂的bottom half機制,中斷處理程序中所有不要求立即完成的,在開中斷的環境下,由底半程序隨后完成.
Linux的底半處理實際上是建立在內核的軟中斷機制上的.
Linux 的底半 機制主要有Tasklet 和 work queue 以及 softirq ( 2.4內核則有BH , Task queue , softirq , tasklet 沒有work queue),其實底半可以理解成一種工作的延遲。所以實際使用時跟timer機制基本上一個意思。
26. 內核函數mmap的實現原理,機制?
mmap函數實現把一個文件映射到一個內存區域,從而我們可以像讀寫內存一樣讀寫文件,他比單純調用read/write也要快上許多。在某些時候我們可以把內存的內容拷貝到一個文件中實現內存備份,當然,也可以把文件的內容映射到內存來恢復某些服務。另外,mmap實現共享內存也是其主要應用之一,mmap系統調用使得進程之間通過映射同一個普通文件實現共享內存。
?
27. 驅動里面為什么要有并發、互斥的控制?如何實現?講個例子?
?
28. spinlock自旋鎖是如何實現的?
自旋鎖在同一時刻只能被最多一個內核任務持有,所以一個時刻只有一個線程允許存在于臨界區中。這點可以應用在多處理機器、或運行在單處理器上的搶占式內核中需要的鎖定服務。
這里也介紹下信號量的概念,因為它的用法和自旋鎖有相似的地方。linux中的信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然后讓其睡眠。這時處理器獲得自由去執行其它代碼。當持有信號量的進程將信號量釋放后,在等待隊列中的一個任務將被喚醒,從而便可以獲得這個信號量。
?
29. 任務調度的機制?
?
30. 嵌入式linux和wince操作系統的特點和特性?
?
31. 嵌入式linux中tty設備驅動的體系結構?
?
32. 嵌入式設備,為加快啟動速度,可以做哪些方面的優化?
?
33. USB設備的枚舉過程?
(1) Get Device Descriptor。主機的第一個命令要求得到設備描述符,此SETUP 包為8 個字節數據(80,06,00,01,00,00,40,00),發向地址0,端口0。“40”表示返回數據長度最大為40H 個字節。實際上,只返回一個包,即數組DEV_DESC[ ]中的前8 個字節,用于說明設備的描述符的真實長度和設備的類型。
(2) Set Address。接著是設置設備地址處理事件,主機發送一個含有指定地址的數據包(00,05,02,00,00,00,00,00),在主機只有一個USB 設備的時候,這個地址一般會是2,最大地址127,USB 協議中可以連接127 個設備。設置地址事件處理結束后,設備進入地址狀態,主機以后會在新的指定地址處訪問設備。
(3) Get Device Descriptor。主機再次發送請求得到設備描述符的數據包(80,06,00,01,00,00,12,00),與上次不同的是,要求的數據的長度是實際的數據長度,同時是發送到Set Address命令所設置的地址。
(4) 讀取全部Configuration Descriptor。接著主機要求得到設備全部的配置描述符、接口描述符和節點描述符(80,06,00,02,00,00,40,00),由于主機不知道設備描述符的真實長度,因此它要求得到64個字節。
(5) Set Interface,主機發送數據包(01,0B,00,00,00,00,00,00),設置接口值為0。
(6) Set Conifguration,確定USB設備工作在哪一個配置下。對于U盤設備來說,一般只有1個配置值,其值為01。主機發送數據包(00,09,01,00,00,00,00,00)。
(7) 如果以上步驟都正確,主機將找到新設備,并且配置成功,該設備可以正常使用,可以進行后續的U盤枚舉過程了。
(8) 用busHound觀察計算機對于U盤的枚舉過程,發現上述步驟后還有一個GetMaxLun的操作,但是實際上對于U盤來說忽略該步驟也沒有問題。
?
34. PSRAM、SDRAM、DDR、DDR2的時序特性?
35.什么是GPIO?
general purpose input/output ?
GPIO是相對于芯片本身而言的,如某個管腳是芯片的GPIO腳,則該腳可作為輸入或輸出高或低電平使用,當然某個腳具有復用的功能,即可做GPIO也可做其他用途。?
也就是說你可以把這些引腳拿來用作任何一般用途的輸入輸出,例如用一根引腳連到led的一極來控制它的亮滅,也可以用一根(一些)引腳連到一個傳感器上以獲得該傳感器的狀態,這給cpu提供了一個方便的控制周邊設備的途經。如果沒有足夠多的gpio管腳,在控制一些外圍設備時就會力有不逮,這時可采取的方案是使用CPLD來幫助管理。
36.觸摸屏的硬件原理?
觸摸屏的主要三大種類是:電阻技術觸摸屏、 表面聲波技術觸摸屏、 電容技術觸摸屏。
電阻觸摸屏的主要部分是一塊與顯示器表面非常配合的電阻薄膜屏, 這是一種多層的復合薄膜,它以一層玻璃或硬塑料平板作為基層,表面圖有一層透明氧化金屬 (ITO氧化銦,透明的導電電阻) 導電層,上面在蓋有一層外表面硬化處理、光滑防擦的塑料層 、它的內表面也涂有一層ITO涂層 、在他們之間有許多細小的(小于1/1000英寸)的透明隔離點把兩層導電層隔開絕緣 。當手指觸摸屏幕時,兩層導電層在觸摸點位置就有了接觸,控制器偵測到這一接觸并計算出(X,Y )的位置,再根據模擬鼠標的方式運作。這就是電阻技術觸摸屏的最基本的原理。
表面聲波技術是利用聲波在物體的表面進行傳輸,當有物體觸摸到表面時,阻礙聲波的傳輸,換能器偵測到這個變化,反映給計算機,進而進行鼠標的模擬。
電容技術觸摸屏利用人體的電流感應進行工作 。用戶觸摸屏幕時 ,由于人體電場,用戶和觸摸屏表面形成以一個耦合電容, 對于高頻電流來說,電容是直接導體,于是手指從接觸點吸走一個很小的電流
37.在Linux C中,ls這個命令是怎么被執行的?
使用fork創建一個進程或exec函數族覆蓋原進程。
38.在一個只有128M內存并且沒有交換分區的機器上,說說下面兩個程序的運行結果
1
#define MEMSIZE 1024*1024
int count = 0;
void *p = NULL;
while(1) {
? p = (void *)malloc(MEMSIZE);
? if (!p) break;
? printf("Current allocation %d MB\n", ++count);
}
2
while(1) {
? p = (void *)malloc(MEMSIZE);
? if (!p) break;
? memset(p, 1, MEMSIZE);
? printf("Current allocation %d MB\n", ++count);
}
第一道程序分配內存但沒有填充,編譯器可能會把內存分配優化掉,程序死循環;第二道,程序分配內存并進行填充,系統會一直分配內存,直到內存不足,退出循環。
39.請定義一個宏,比較兩個數a、b的大小,不能使用大于、小于、if語句
搞的比較復雜。主要思想就是a-b的值的最高位是否為0;但是又得考慮整數溢出的問題,所以很復雜。不知道哪位大俠有更好的辦法,指點指點。
#include<stdio.h>
#define ZHENG(i)((i>> 31)== 0)
#define FU(i)((i>> 31)!= 0)
#define COMPARE(a,b)((ZHENG(a)&& FU(b))||(((ZHENG(a)&& ZHENG(b))||(FU(a)&&FU(b)))&&((((a)-(b))>> 31)== 0)))
void main()
{
? ? int a = 0x80000001;
? ? int b = 0x6FFFFFFF;
? ? if(COMPARE(a,b))
? ? {
? ? ? ? printf("a >= b\n");
? ? }
? ? else
? ? {
? ? ? ? printf("a < b\n");
? ? }
}
?
40、LINUX下的Socket套接字和Windows下的WinSock有什么共同點?請從C/C++語言開發的角度描述,至少說出兩點共同點。
參考答案:
第1題,答中一個得5分,答出其它正確答案的,也得5分。
a)都基于TCP/IP協議,都提供了面向連接的TCP SOCK和無連接的UDP SOCK。
b)都是一個sock結構體。
c)都是使用sock文件句柄進行訪問。
d)都具有緩沖機制。
41、請編寫一個標準Shell腳本testd,實現如下功能:
A、在Linux操作系統啟動的時候,自動加載/mnt/test/test程序。
B、當test異常退出之后,自動重新啟動。
C、當test程序重啟次數超過100次,自動復位操作系統。
假設你所擁有的資源:
A、目標機器是一臺具有標準shell的嵌入式計算機,CPU為ARM7 56MB,內存16MB,軟件環境基于Linux2.6.11和BusyBox1.2構建。
B、當前已有11個用戶進程在運行,占用了大部分的CPU時間和內存,你可使用的內存只有2MB左右,CPU時間由系統分派。
本題是考查LINUX和嵌入式編程功底的,寫出程序來的不少,但是95%以上的人竟無視我假設的資源,不知道在重啟test程序的時候需要加上一個適當的掩飾時間,以便資源緊張的操作系統有時間回收資源。85%的人不知道寫完testd之后,要在init里邊加載這個腳本,才能實現啟動時自動加載的功能。
參考答案:
########################################
#testd is a daemon script to start an watch the program test
########################################
#!/bin/sh
#load *.so that may need
if [ -r /sbin/ldconfig ]; then
ldconfig
fi
#add the libs PATH that may need
export LD_LIBRARY_PATH="/lib"
#count is the counter of test started times
count=0
#main loop
while [ 1 ] ;do
#add execute property for /mnt/test/test
chmod +x /mnt/test/test
#start test
/mnt/test/test
#the running times counter
let count=count+1
echo "test running times is $count"
#Is test running too many times?
if [ "$count" -gt 100 ]; then
echo "Will reboot because of test running too many times"
reboot
fi
#wait for test stoping...
sleep 3
done
#########################################
?
42.你平常是怎么用C寫嵌入式系統的死循環的?
43.寫一條命令,實現在dir以及其子目錄下找出所有包含“hello world”字符串的文件
44.下面的兩段程序中,循環能否執行?為什么?
A: unsigned short i; unsigned short index = 0; for(i = 0; i <index-1; i++){ ? ? printf(“a\n”); }
B: unsigned short i; unsigned long index = 0; for(i = 0; i <index-1; i++){ ? ? ?printf(“b\n”); } ?
? ? ? ? ? ? ? ??
45.一個計劃跑LINUX系統的ARM系統把bootloader燒錄進去后,上電后串口上沒有任何輸出,硬件和軟件各應該去檢查什么? ??
提示: 1.跑LINUX的系統一般都需要外擴DRAM,一般的系統也經常有NOR或NAND FLASH ? ? ? ? ?
?
476列舉最少3種你所知道的嵌入式的體系結構,并請說明什么是ARM體系結構。
?
47.請簡述下面這段代碼的功能
mov r12, #0x0 ? ? ? ?
ldr r13, =0x30100000?
mov r14, #4096?
loop: ??
ldmia ? ? ?r12!, {r0-r11} ?
stmia ? ? ?r13!, {r0-r11} ? ?
cmp ? ? ? r12, r14 ??
bl ? ? ? ? ?loop
48.嵌入式中常用的文件系統有哪些?說出它們的主要特點和應用場合??
?
49.某外設寄存器rGpioBase的地址是0x56000000,寄存器的0~15位有效,請寫出給外設寄存器高八位(8~`15位)設置成0xc3的代碼
?
50.如何編寫一個LINUX驅動??
提示:主要說字符設備的編寫過程 ?
51.簡述LINUX驅動中字符設備和塊設備的區別??
52.試總結單片機底層開發與LINUX驅動開發有哪些異同?
?
53.請從網卡、USB HOST、LCD驅動器、NAND FLASH、WIFI 、音頻芯片中選擇一個或者2個(可以以具體的芯片為例),對下面的問題做答:?
1)如果是外部擴展芯片,請說出你用的芯片的型號?
2)畫出上題中你選定相應硬件模塊與CPU的主要引腳連線?
3) 編寫上題中你選定相應硬件模塊相應LINUX驅動的流程??
??
54、linux驅動分類
Linux設備驅動的分類
(1)字符設備。
(2) 塊設備。
(3) 網絡設備。
字符設備指那些必須以串行順序依次進行訪問的設備,如觸摸屏、磁帶驅動器、鼠標等。塊設備可以用任意順序進行訪問,以塊為單位進行操作,如硬盤、軟驅等。字符設備不經過系統的快速緩沖,而塊設備經過系統的快速緩沖。但是,字符設備和塊設備并沒有明顯的界限,如對于Flash設備,符合塊設備的特點,但是我們仍然可以把它作為一個字符設備來訪問。網絡設備在Linux里做專門的處理。Linux的網絡系統主要是基于BSD unix的socket 機制。在系統和驅動程序之間定義有專門的數據結構(sk_buff)進行數據的傳遞。系統里支持對發送數據和接收數據的緩存,提供流量控制機制,提供對多協議的支持。
55、信號量與自旋鎖
自旋鎖
自旋鎖是專為防止多處理器并發而引入的一種鎖,它應用于中斷處理等部分。對于單處理器來說,防止中斷處理中的并發可簡單采用關閉中斷的方式,不需要自旋鎖。
自旋鎖最多只能被一個內核任務持有,如果一個內核任務試圖請求一個已被爭用(已經被持有)的自旋鎖,那么這個任務就會一直進行忙循環——旋轉——等待鎖重新可用。要是鎖未被爭用,請求它的內核任務便能立刻得到它并且繼續進行。自旋鎖可以在任何時刻防止多于一個的內核任務同時進入臨界區,因此這種鎖可有效地避免多處理器上并發運行的內核任務競爭共享資源。
事實上,自旋鎖的初衷就是:在短期間內進行輕量級的鎖定。一個被爭用的自旋鎖使得請求它的線程在等待鎖重新可用的期間進行自旋(特別浪費處理器時間),所以自旋鎖不應該被持有時間過長。如果需要長時間鎖定的話, 最好使用信號量。但是自旋鎖節省了上下文切換的開銷。
自旋鎖的基本形式如下:
spin_lock(&mr_lock);
//臨界區
spin_unlock(&mr_lock);
因為自旋鎖在同一時刻只能被最多一個內核任務持有,所以一個時刻只有一個線程允許存在于臨界區中。這點很好地滿足了對稱多處理機器需要的鎖定服務。在單處理器上,自旋鎖僅僅當作一個設置內核搶占的開關。如果內核搶占也不存在,那么自旋鎖會在編譯時被完全剔除出內核。
簡單的說,自旋鎖在內核中主要用來防止多處理器中并發訪問臨界區,防止內核搶占造成的競爭。另外自旋鎖不允許任務睡眠(持有自旋鎖的任務睡眠會造成自死鎖——因為睡眠有可能造成持有鎖的內核任務被重新調度,而再次申請自己已持有的鎖),它能夠在中斷上下文中使用。
死鎖:假設有一個或多個內核任務和一個或多個資源,每個內核都在等待其中的一個資源,但所有的資源都已經被占用了。這便會發生所有內核任務都在相互等待,但它們永遠不會釋放已經占有的資源,于是任何內核任務都無法獲得所需要的資源,無法繼續運行,這便意味著死鎖發生了。自死瑣是說自己占有了某個資源,然后自己又申請自己已占有的資源,顯然不可能再獲得該資源,因此就自縛手腳了。遞歸使用一個自旋鎖就會出現這種情況。
?
信號量
信號量是一種睡眠鎖。如果有一個任務試圖獲得一個已被持有的信號量時,信號量會將其推入等待隊列,然后讓其睡眠。這時處理器獲得自由去執行其它代碼。當持有信號量的進程將信號量釋放后,在等待隊列中的一個任務將被喚醒,從而便可以獲得這個信號量。
信號量的睡眠特性,使得信號量適用于鎖會被長時間持有的情況;只能在進程上下文中使用,因為中斷上下文中是不能被調度的;另外當代碼持有信號量時,不可以再持有自旋鎖。
信號量基本使用形式為:
static DECLARE_MUTEX(mr_sem);//聲明互斥信號量
if(down_interruptible(&mr_sem))
? ? ? ? ? ?//可被中斷的睡眠,當信號來到,睡眠的任務被喚醒
? ? ? ? ? ?//臨界區
? ? ? ?up(&mr_sem); ?
信號量和自旋鎖區別
從嚴格意義上講,信號量和自旋鎖屬于不同層次的互斥手段,前者的實現有賴于后者。
注意以下原則:
? ? ? ?如果代碼需要睡眠——這往往是發生在和用戶空間同步時——使用信號量是唯一的選擇。由于不受睡眠的限制,使用信號量通常來說更加簡單一些。如果需要在自旋鎖和信號量中作選擇,應該取決于鎖被持有的時間長短。理想情況是所有的鎖都應該盡可能短的被持有,但是如果鎖的持有時間較長的話,使用信號量是更好的選擇。另外,信號量不同于自旋鎖,它不會關閉內核搶占,所以持有信號量的代碼可以被搶占。這意味者信號量不會對影響調度反應時間帶來負面影響。
?
自旋鎖對信號量
需求 建議的加鎖方法
低開銷加鎖 優先使用自旋鎖
短期鎖定 優先使用自旋鎖
長期加鎖 優先使用信號量
中斷上下文中加鎖 使用自旋鎖
持有鎖是需要睡眠、調度 使用信號量?
56、platform總線設備及總線設備如何編寫
57、kmalloc和vmalloc的區別
kmalloc()和vmalloc()介紹
kmalloc()
用于申請較小的、連續的物理內存
1. 以字節為單位進行分配,在<linux/slab.h>中
2. void *kmalloc(size_t size, int flags) 分配的內存物理地址上連續,虛擬地址上自然連續
3. gfp_mask標志:什么時候使用哪種標志?如下:
———————————————————————————————-
情形 ? ? ? ?相應標志
———————————————————————————————-
進程上下文,可以睡眠 GFP_KERNEL
進程上下文,不可以睡眠 GFP_ATOMIC
中斷處理程序 GFP_ATOMIC
軟中斷 GFP_ATOMIC
Tasklet GFP_ATOMIC
用于DMA的內存,可以睡眠 GFP_DMA | GFP_KERNEL
用于DMA的內存,不可以睡眠 GFP_DMA | GFP_ATOMIC
———————————————————————————————-
4. void kfree(const void *ptr)
釋放由kmalloc()分配出來的內存塊
vmalloc()
用于申請較大的內存空間,虛擬內存是連續的
1. 以字節為單位進行分配,在<linux/vmalloc.h>中
2. void *vmalloc(unsigned long size) 分配的內存虛擬地址上連續,物理地址不連續
3. 一般情況下,只有硬件設備才需要物理地址連續的內存,因為硬件設備往往存在于MMU之外,根本不了解虛擬地址;但為了性能上的考慮,內核中一般使用 kmalloc(),而只有在需要獲得大塊內存時才使用vmalloc(),例如當模塊被動態加載到內核當中時,就把模塊裝載到由vmalloc()分配 的內存上。
4.void vfree(void *addr),這個函數可以睡眠,因此不能從中斷上下文調用。
malloc(), vmalloc()和kmalloc()區別
[*]kmalloc和vmalloc是分配的是內核的內存,malloc分配的是用戶的內存
[*]kmalloc保證分配的內存在物理上是連續的,vmalloc保證的是在虛擬地址空間上的連續,malloc不保證任何東西(這點是自己猜測的,不一定正確)
[*]kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大
[*]內存只有在要被DMA訪問的時候才需要物理上連續
[*]vmalloc比kmalloc要慢
58、module_init的級別
59、添加驅動
靜態加載和動態加載:
靜態加載是系統啟動的時候由內核自動加載的,這個要事先將驅動編譯進內核才行;
動態加載,也就是模塊加載方式,這種方式下驅動以模塊的形式存放在文件系統中,需要時動態載入內核,這種主要用在調試的時候,比較方便靈活。insmod module.ko
60、IIC原理,總線框架,設備編寫方法,i2c_msg
61、kernel panic
62、USB總線,USB傳輸種類,urb等
USB總線:
USB總線屬于一種輪詢式總線,主機控制端口初始化所有的數據傳輸。每一總線動作最多傳送三個數據包,包括令牌(Token)、數據(Data)、聯絡(HandShake)。按照傳輸前制定好的原則,在每次傳送開始時,主機送一個描述傳輸動作的種類、方向、USB設備地址和終端號的USB數據包,這個數據包通常被稱為令牌包(TokenPacket)。USB設備從解碼后的數據包的適當位置取出屬于自己的數據。數據傳輸方向不是從主機到設備就是從設備到主機。在傳輸開始時,由標志包來標志數據的傳輸方向,然后發送端開始發送包含信息的數據包或表明沒有數據傳送。接收端也要相應發送一個握手的數據包表明是否傳送成功。發送端和接收端之間的USB數據傳輸,在主機和設備的端口之間,可視為一個通道。USB中有一個特殊的通道一缺省控制通道,它屬于消息通道,設備一啟動即存在,從而為設備的設置、狀態查詢和輸入控制信息提供一個入口。
USB總線的四種傳輸類型:
1、中斷傳輸:由OUT事務和IN事務構成,用于鍵盤、鼠標等HID設備的數據傳輸中 2、批量傳輸:由OUT事務和IN事務構成,用于大容量數據傳輸,沒有固定的傳輸速率,也不占用帶寬,當總線忙時,USB會優先進行其他類型的數據傳輸,而暫時停止批量轉輸。 3、同步傳輸:由OUT事務和IN事務構成,有兩個特別地方,第一,在同步傳輸的IN和OUT事務中是沒有返回包階段的;第二,在數據包階段任何的數據包都為DATA0 4、控制傳輸:最重要的也是最復雜的傳輸,控制傳輸由三個階段構成(初始配置階段、可選數據階段、狀態信息步驟),每一個階段能夠看成一個的傳輸,也就是說控制傳輸其實是由三個傳輸構成的,用來于USB設備初次加接到主機之后,主機通過控制傳輸來交換信息,設備地址和讀取設備的描述符,使得主機識別設備,并安裝相應的驅動程式,這是每一個USB研發者都要關心的問題。
URB:
USB請求塊(USB request block,urb)是USB設備驅動中用來描述與USB設備通信所用的基本載體和核心數據結構,非常類似于網絡設備驅動中的sk_buff結構體,是USB主機與設備通信的“電波”。
63、同步和互斥
同步和互斥
相交進程之間的關系主要有兩種,同步與互斥。所謂互斥,是指散步在不同進程之間的若干程序片斷,當某個進程運行其中一個程序片段時,其它進程就不能運行它們之中的任一程序片段,只能等到該進程運行完這個程序片段后才可以運行。所謂同步,是指散步在不同進程之間的若干程序片斷,它們的運行必須嚴格按照規定的某種先后次序來運行,這種先后次序依賴于要完成的特定的任務。
顯然,同步是一種更為復雜的互斥,而互斥是一種特殊的同步。也就是說互斥是兩個線程之間不可以同時運行,他們會相互排斥,必須等待一個線程運行完畢,另一個才能運行,而同步也是不能同時運行,但他是必須要安照某種次序來運行相應的線程(也是一種互斥)!
總結:
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源
64、 Linux設備中字符設備與塊設備有什么主要的區別?請分別列舉一些實際的設備說出它們是屬于哪一類設備。
?答:字符設備:字符設備是個能夠像字節流(類似文件)一樣被訪問的設備,由字符設備驅動程序來實現這種特性。字符設備驅動程序通常至少實現open,close,read和write系統調用。字符終端、串口、鼠標、鍵盤、攝像頭、聲卡和顯卡等就是典型的字符設備。
塊設備:和字符設備類似,塊設備也是通過/dev目錄下的文件系統節點來訪問。塊設備上能夠容納文件系統,如:u盤,SD卡,磁盤等。
? ? 字符設備和塊設備的區別僅僅在于內核內部管理數據的方式,也就是內核及驅動程序之間的軟件接口,而這些不同對用戶來講是透明的。在內核中,和字符驅動程序相比,塊驅動程序具有完全不同的接口
65、查看驅動模塊中打印信息應該使用什么命令?如何查看內核中已有的字符設備的信息?如何查看正在使用的有哪些中斷號?
答:1) 查看驅動模塊中打印信息的命令:dmesg
? ? ?2) 查看字符設備信息可以用lsmod 和modprobe,lsmod可以查看模塊的依賴關系,modprobe在加載模塊時會加載其他依賴的模塊。
? ? ?3)顯示當前使用的中斷號cat /proc/interrupt
66、Linux中引入模塊機制有什么好處?
答:首先,模塊是預先注冊自己以便服務于將來的某個請求,然后他的初始化函數就立即結束。換句話說,模塊初始化函數的任務就是為以后調用函數預先作準備。
好處:
1) 應用程序在退出時,可以不管資源的釋放或者其他的清除工作,但是模塊的退出函數卻必須仔細此撤銷初始化函數所作的一切。
2) 該機制有助于縮短模塊的開發周期。即:注冊和卸載都很靈活方便。
67、copy_to_user()和copy_from_user()主要用于實現什么功能?一般用于file_operations結構的哪些函數里面?
答:由于內核空間和用戶空間是不能互相訪問的,如果需要訪問就必須借助內核函數進行數據讀寫。copy_to_user():完成內核空間到用戶空間的復制,copy_from_user():是完成用戶空間到內核空間的復制。一般用于file_operations結構里的read,write,ioctl等內存數據交換作用的函數。當然,如果ioctl沒有用到內存數據復制,那么就不會用到這兩個函數。
68、請簡述主設備號和次設備號的用途。如果執行mknod chartest c 4 64,創建chartest設備。請分析chartest使用的是那一類設備驅動程序。
答:
1)主設備號:主設備號標識設備對應的驅動程序。雖然現代的linux內核允許多個驅動程序共享主設備號,但我們看待的大多數設備仍然按照“一個主設備對應一個驅動程序”的原則組織。
? 次設備號:次設備號由內核使用,用于正確確定設備文件所指的設備。依賴于驅動程序的編寫方式,我們可以通過次設備號獲得一個指向內核設備的直接指針,也可將此設備號當作設備本地數組的索引。
2)chartest 由驅動程序4管理,該文件所指的設備是64號設備。(感覺類似于串口終端或者字符設備終端)。
69、設備驅動程序中如何注冊一個字符設備?分別解釋一下它的幾個參數的含義。
答:注冊一個字符設備驅動有兩種方法:
1) void cdev_init(struct cdev *cdev, struct file_operations *fops)
該注冊函數可以將cdev結構嵌入到自己的設備特定的結構中。cdev是一個指向結構體cdev的指針,而fops是指向一個類似于file_operations結構(可以是file_operations結構,但不限于該結構)的指針.
2) int register_chrdev(unsigned int major, const char *namem , struct file)operations *fopen);
該注冊函數是早期的注冊函數,major是設備的主設備號,name是驅動程序的名稱,而fops是默認的file_operations結構(這是只限于file_operations結構)。對于register_chrdev的調用將為給定的主設備號注冊0-255作為次設備號,并為每個設備建立一個對應的默認cdev結構。
70、請簡述中斷與DMA的區別。Linux設備驅動程序中,使用哪個函數注冊和注銷中斷處理程序?
答:1)DMA:是一種無須CPU的參與就可以讓外設與系統內存之間進行雙向數據傳輸的硬件機制,使用DMA可以使系統CPU從實際的I/O數據傳輸過程中擺脫出來,從而大大提高系統的吞吐率。
中斷:是指CPU在執行程序的過程中,出現了某些突發事件時CPU必須暫停執行當前的程序,轉去處理突發事件,處理完畢后CPU又返回源程序被中斷的位置并繼續執行。
所以中斷和MDA的區別就是MDA不需CPU參與而中斷是需要CPU參與的。
2)中斷注冊函數和中斷注銷函數
注冊中斷:
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);
參數意義依次是:中斷號,中斷處理函數,中斷管理有關的掩碼,中斷請求設備名,中斷信號線。
過程是:dev_name設備請求中斷->cpu分配中斷號->設置中斷管理的掩碼->分配中斷信號線->處理中斷函數->完成之后再根據設置情況返回原處理程序處繼續處理程序。
注銷中斷;
Void free_irq(unsigned int irq, void *dev_id);
釋放中斷和中斷信號線
71、中斷和輪詢哪個效率高?怎樣決定是采用中斷方式還是采用輪詢方式去實現驅動?
答:中斷是CPU處于被中狀態下來接受設備的信號,而輪詢是CPU主動去查詢該設備是否有請求。凡事都是兩面性,所以,看效率不能簡單的說那個效率高。如果是請求設備是一個頻繁請求cpu的設備,或者有大量數據請求的網絡設備,那么輪詢的效率是比中斷高。如果是一般設備,并且該設備請求cpu的頻率比較底,則用中斷效率要高一些。
72、簡單描述在cs8900的驅動設計中, 發送數據frame和接收數據frame的過程。
答:1)發送流程如下:
(1) 網絡設備驅動程序從上層協議傳遞過來的sk_buff參數獲得數據包的有效數據和長度,將有效數據放入臨時緩沖區。
(2) 對于以太網,如果有效數據的長度小于以太網沖突檢測所要求的數據楨的最小長度,則給臨時緩沖區的末尾填充0
(3) 設置硬件寄存器,驅使網絡設備進行數據發送操作。
? ?2)接收流程
? ?網絡設備接收數據主要是由中斷引發設備的中斷處理函數,中斷處理函數判斷中斷類型,如果為接收中斷,則讀取接受到的數據,分配sk_buff數據結構和數據緩沖區,將接收到的數據復制到數據緩沖區,并調用netif_rx()函數將sk_buff傳遞給上層協議。
73、cs8900.c的驅動中,發送數據frame的過程為什么需要關中斷?接收數據frame的過程為什么不需要關中斷?
答:在發送過程中是不能被打斷的,在發送的過程中,不關中斷,這時候如果有一個中斷到來,那么cpu有可能會去相應該中斷,如果該中斷需要改寫的數據是發送數據的緩沖區,那么緩沖區將被改寫,這樣即使cpu相應完畢該中斷,再發送數據,接收方也不認識該數據不能接收。
在接收數據的時候,需要打開中斷,是因為要及時的相應接收到的數據。如果關閉該中斷,那么接收方有可能因為相應優先級高的中斷而接收不到該數據。
74、簡單描述skbuff這個數據結構在網絡結構中所起到的作用,為什么需要一個skbuff,它的分配和釋放主要都在什么部位
答:sk_buff結構非常重要,它的含義為“套接字緩沖區”,用于在linux網絡子系統中的各層之間傳遞數據。
當發送數據包時,linux內核的網絡處理模塊必須建立一個包含要傳輸的數據包的sk_buff,然后將sk_buff遞交給下層,各層在sk_buff中添加不同的協議頭直至交給網絡設備發送。同樣的,當網絡設備從網絡媒介上接受到數據包后,它必須將接受到的數據轉換為sk_buff數據結構并傳遞給上層,蓋層不拋去相應的協議頭直至交給用戶。分配sk_buff在接收一開始就應該分配,在發送完畢數據之后可以釋放sk_buff。