linux設備驅動視頻
❶ 如何學習linux設備驅動
我學linux的時候都把win7卸載了,然後就一直在ubuntu上作業。先學linux的基本操作,建議看《鳥哥的私房菜基礎篇》學linux下編程(還沒到驅動),建議看《unix高級環境編程》最後就是你說的驅動編程,建議看《Linux設備驅動程序》。。。當然這里寫成3步走,還是有點簡單了,還要看你的學習能力。最好把linux的0.11的內核看看吧,0.11內核才1w左右行代碼,比起現在2.6內核都上千萬行了,有助你把握linux內核的框架,以後看2.6內核就不會像盲人摸象一樣。
❷ 學習Linux的步驟是怎樣的
對於Linux的學習,可以分為四個階段,Linux初級入門階段→Linux中級進階→Linux高級進階→Linux資深方向細化階段
第一階段:初級階段
初級階段需要把linux學習路線搞清楚,任何學習都是循序漸進的,所以學linux也是需要有一定的路線。
1. Linux基礎知識、基本命令;
2. Linux用戶及許可權基礎;
3. Linux系統進程管理進階;
4. linux高效文本、文件處理命令;
5. shell腳本入門
第二階段:中級進階
中級進階需要在充分了解linux原理和基礎知識之後,對上層的應用和服務進行深入學習,其中說到服務肯定涉及到網路的相關知識,是需要花時間學習的。
1. TCP/IP網路基礎;
2. Linux企業常用服務;
3. Linux企業級安全原理和防範技巧;
4. 加密/解密原理及數據安全、系統服務訪問控制及服務安全基礎;
5. iptables安全策略構建;
6. shell腳本進階;
7. MySQL應用原理及管理入門
第三階段:Linux高級進階
1. http服務代理緩存加速;
2. 企業級負載集群;
3. 企業級高可用集群;
4. 運維監控zabbix詳解;
5. 運維自動化學習;
第四階段:Linux資深方向細化
1. 大數據方向;
2. 雲計算方向;
3. 運維開發;
4. 自動化運維;
5. 運維架構師
以上是Linux的一個學習方向和路線,對於Linux學習是一個需要堅持的過程,也許通過自學或者培訓,3至6個月都可以把基本知識學會,但是重在實踐,深入的思考和不斷的摸索,你會發現Linux更多的美!
❸ 小白看過來,新人如何入門嵌入式
作為一個新人,怎樣學習嵌入式Linux
原文鏈接:網頁鏈接
作為一個新人,怎樣學習嵌入式Linux?被問過太多次,特寫這篇文章來回答一下。
在學習嵌入式Linux之前,肯定要有C語言基礎。匯編基礎有沒有無所謂(就那麼幾條匯編指令,用到了一看就會)。C語言要學到什麼程度呢?越熟當然越好,不熟的話也要具備基本技能。比如寫一個數組排序、輸入數字求和什麼的。學C語言唯一的方法是多寫程序多練習,編譯出錯沒關系,自己去解決;執行出錯沒關系,自己去分析。以前我是用VC來練習C語言的,經常去嘗試著寫一些C語言競賽的題目。它們是純C、純數學、純邏輯的題目,不涉及界面這些東西,很適合煅煉你的編程能力。
回到主題,首先我們要明白你的目的是什麼,大概來說所謂嵌入式Linux可以分為兩部分:底層系統、應用開發。如果你是想做應用開發,那麼你去把C語言、數據結構、JAVA什麼的學好吧。嵌入式應用開發和PC上的應用開發並沒有什麼特別要注意的。也許你說在嵌入式上要做些優化,是的,要優化,但是未經優化的程序和PC上的程序開發沒什麼差別。另外,當你有能力去優化時,你已經不用來問這個問題了。具體到某個例子,比如說開發界面,在PC上我們用VC;在嵌入式Linux里也許我們用QT也許用Android,這個時候你應該去學學QT、Android的編程。但是基礎還是C或JAVA,在此基礎上去熟悉它們的介面。你學過VC的話,也是要花時間去了解那些類、控制項的。
如果你的目的是想學習底層系統,這是我的專長,倒是可以說一點。在回答這個問題之前,我先回答:不少人問我,到底是學驅動還是學應用?
我只能說憑興趣,並且驅動和應用並不是截然分開的
我們說的驅動,其實並不局限於硬體的操作,還有操作系統的原理、進程的休眠喚醒調度等概念。 想寫出一個好的應用,想比較好的解決應用碰到的問題,這些知識你應該懂
做應用門檻低,特別是現在的ANDROID,純JAVA。做應用的發展路徑個人認為就是業務純熟。比如在通信行業、IPTV行業、手機行業,你了解行業的需求。所以,當領導的人,多是做應用的。
做驅動,其實我不想稱為「做驅動」,而是想稱為「做底層系統」,做好了這是通殺各行業。我工作幾年,做過手機、IPTV、會議電視,但是這些產品對我毫無差別,因為我只做底層。他們的業務跟我沒關系。當應用出現問題,他們解決不了時,我就會從內核角度給他們出主意,給他們提供工具。 做底層的發展方向,個人認為是技術專家。
其實,做底層還是做應用,之間並沒有一個界線,有底層經驗,再去做應用,你會感覺很踏實。有了業務經驗,你再了解一下底層,很快就可以組成一個團隊。
電腦一開機,那些界面是誰顯示的?是BIOS,它做什麼?一些自檢,然後從硬碟上讀入windows,並啟動它。類似的,這個BIOS對應於嵌入式Linux里的bootloader。這個bootloader要去Flash上讀入Linux內核,並啟動它。
啟動windows的目的是什麼?當然是上網聊天什麼的了。這些上網、聊天工具在哪?
在C盤、D盤上。所以, windows要先識別出C盤、D盤。在Linux下我們稱為根文件系統。
windows能識別出C盤、D盤,那麼肯定能讀寫硬碟才行。這涉及的東西稱為驅動程序。當然不僅僅是硬碟,還有網卡、USB等等。嵌入式Linux能從Flash上讀出並執行應用程序,肯定也得有Flash的驅動程序啊,當然也不僅僅是Flash。
對硬體的操作
對ARM體系處理器的了解
程序的基本概念:重定位、棧、代碼段數據段BSS段什麼的。
用繪圖板畫圖講解──相當於學校里老師在黑板上畫圖講解,很直觀絕對不是對著PPT念。
用source insight當場寫程序,從第1行開始寫,每一課都是這樣。我講了20多個驅動,就寫了20多個程序。
寫完就編譯、測試。
很全面,字元設備驅動、塊設備、網卡驅動3大類齊全,硬體介紹、驅動框架分析、測試3大類齊全。
我在學校時讀的是物理電子專業,其實課程里沒有教怎麼設計電路,只是教了些電子電路方面的知識。PCB的設計是在實驗室里自學的,只設計過2層板,現在忘記得差不多了。但是保留了看原理圖、看晶元手冊的能力。
選修了軟體學位,對軟體設計挺感興趣,但是也只是學了C語言、資料庫而已。憑著興趣做了不少競賽題。沒能力去參加競賽,但是把C語言練得很扎實。
在實驗室、在第1家公司,就是設計些簡單的PCI卡,寫一下windows的驅動程序
在第2家公司,用51單片機做車載電話,開始走上純軟體的道路。
開始感到單片機的不足,辭職半年閉門學Linux,從red hat怎麼操作開始。步驟就是先看<ARM體系架構與編程>,再自己寫裸板程序操作硬體,接著到分析u-boot。同時看<linux內核完全注釋>,對LINUX框架有所了解。在寫裸板時,建議各位加強對中斷的理解,內核就是用中斷來完成各種功能的。
分析完u-boot,就開始進行簡單的驅動編程了,這時候,能力還很弱。
開始去中興上班,工作2年,編寫各類驅動、解決各類問題(驅動問題、幫助定位應用問題),能力得到煅煉。
韋東山Linux視頻第1期(基於S3C2440錄制): ARM實驗,u-boot,文件系統,初級驅動
韋東山Linux視頻第1期(基於S3C6410錄制): 裸板程序
韋東山Linux視頻第2期: 高級驅動
韋東山Linux視頻第3期:項目實戰
韋東山Linux視頻第4期:Android驅動
回到怎麼學的問題上。嵌入式Linux底層系統包含哪些東西?不要急,舉一個例子你就知道了。
先說到這里吧,嵌入式LINUX里含有bootloader, 內核, 驅動程序、根文件系統這4大塊。
一、bootloader:
它就是一個稍微復雜的裸板程序。但是要把這裸板程序看懂寫好一點都不容易。Windows下好用的工具弱化了我們的編程能力。
很多人一玩嵌入式就用ADS、KEIL。你能回答這幾個問題嗎?
1. 一上電,CPU從哪裡取指令執行?
答:一般從Flash上指令。
2. 但是Flash一般是只能讀不能直接寫的,如果我用到全局變數,這些全局變數在哪裡?
答:全局變數應該在內存里
3. 那麼誰把全局變數放到內存里去?
答:長期用ADS、KEIL的朋友,你能回答嗎?這需要"重定位"。在ADS或KEIL里,重定位的代碼是製作這些工具的公司幫你寫好了。你可曾去閱讀過?
4. 內存那麼大,我怎麼知道把"原來存在Flash上的內容"讀到內存的"哪個地址去"?
答:這個地址用"鏈接腳本"決定,在ADS里有scatter文件,KEIL里也有類似的文件。但是,你去研究過嗎?
5. 你說重定位是把程序從Flash復制到內存,那麼這個程序可以讀Flash啊?
答:是的,要能操作Flash。當然不僅僅是這些,還有設置時鍾讓系統運行得更快等等。
自問自答到這里吧,bootloader這一個裸板程序,其實有3部分要點:
對硬體的操作,需要看原理圖、晶元手冊。這需要一定的硬體知識,不求你能設計硬體,但是至少能看懂; 不求能看懂模擬電路,但是要能看懂數字電路。這方面的能力我是在學校里學到的,微機原理、數字電路這2本書(書名忘了)就足夠了。但是我懷疑你有無耐心把這2本書看完。我不知道現在有沒有更快捷的書。想速成的話,就先放掉這塊吧,不懂就問GOOGLE、發貼。
另外,晶元手冊是肯定要讀的,別去找中文的,就看英文的。開始是非常痛苦,以後就會發現那些語法、詞彙一旦熟悉後,讀任何晶元手冊都很容易。對ARM體系處理器的了解, 看杜春蕾的<ARM體系架構與編程>吧,裡面講有匯編指令,有異常模式、MMU等。也就這3塊內容需要你了解。
程序的基本概念,王道當然是去看編譯原理了。可惜,這類書絕對是天書級別的。勸你若非超級天才還是別去看了。就看我寫的<嵌入式Linux應用開發完全手冊>和第1期視頻吧,別擔心,不用花錢。照著視頻把硬體相關的實驗做了,這些概念就清楚了。我還沒有
發現第2套講這些概念的書或視頻。
對於bootloader,我學習時是先看了<ARM體系架構與編程>,然後自己寫程序把各個硬體的實驗都做了一遍,比如GPIO、時鍾、SDRAM、UART、NAND。把它們都弄清楚了,組台在一起就很容易看懂u-boot了
總結一下,看懂硬體原理圖、看晶元手冊,這需要你自己去找資料。剩下的,就按<嵌入式Linux應用開發完全手冊>和第1期視頻的章節目錄去學習吧。
二、內核:
想速成的人,先跨過內核的學習,直接學習怎麼寫驅動。
想成為高手,內核必須深刻了解。注意,我說的是了解,我沒奢望去寫出一個內核。
要對裡面的調度機制、內存管理機制、文件管理機制等等有所了解。
推薦兩本書:
1. 通讀<linux內核完全注釋>,請看薄的那本(浮燥的社會講求速度, 呵),
2. 選讀<Linux內核情景分析>, 想了解哪一塊就讀哪一節
三、驅動:
驅動包含兩部分:硬體本身的操作、驅動程序的框架。
又是硬體,還是要看得懂原理圖、讀得懂晶元手冊,多練吧。
說到驅動框架,有一些書介紹一下。LDD3,即<Linux設備驅動>,老外寫的那本,裡面介紹了不少概念,值得一讀。但是,它的作用也就限於介紹概念了。我基本上是入門之前用它來熟悉一下概念,入門後就扔掉了。
驅動方面比較全的介紹,應該是宋寶華的<linux設備驅動開發詳解>了,老實說我只看過目錄,有不少人說好,這里推薦一下。要想深入了解某一塊,<Linux內核情景分析>絕對是超5星級推薦。你別指望把它讀完,1800多頁,上下兩冊呢。我是某一塊不清楚時,就去翻一下它。任何一部分,這書都可以講上2、3百頁,非常詳細。並且是以某個目標來帶你分析內核源碼。它以linux 2.4為例,但是原理相通,同樣適用於其它版本的linux。
還有沒有其他介紹?呵呵,當然有了,韋東山Linux視頻第2期。<嵌入式Linux應用開發完全手冊>里對驅動講得不多,不夠深入。於是我錄制了這期視頻。不僅僅教你怎麼寫怎麼改驅動,還教你為什麼這樣寫這樣改驅動。
每一個驅動都是現場編寫:
培訓機構里教的內容,遠不及這期視頻豐富。我在多個培訓機構講過課,從沒看到哪個老師敢每一課都當場講解當場編寫代碼,當場測試,除我之外!也沒看到哪個培訓機構講完這些內容──因為時間不夠,講完起碼要一個月,但是這部分基本只有2周授課時間。
把你手上的開發板所涉及的硬體,都去嘗試寫一個驅動吧。有問題就先"痛苦地思考",思考的過程中你會把很多不相關的知識串聯起來,最終貫通。
四、根文件系統:
大家有沒有想過這2個問題:
1. 對於Linux做出來的產品,有些用作監控、有些做手機、有些做平板。那麼內核啟動後,掛載根文件系統後,應該啟動哪一個應用程序呢?
答:內核不知道也不管應該啟動哪一個用戶程序。它只啟動init這一個應用程序,它對應/sbin/init。顯然,這個應用程序就要讀取配置文件,根據配置文件去啟動用戶程序(監控、手冊界面、平板界面等等)這個問題提示我們,文件系統的內容是有一些約定的,比如要有/sbin/init,要有配置文件
2. 你寫的hello,world程序,有沒有想過裡面用到的printf是誰實現的?
答:這個函數不是你實現的,是庫函數實現的。它運行時,得找到庫。這個問題提示我們,文件系統里還要有庫。
簡單的自問自答到這里,要想深入了解,可以看一下busybox的init.c,就可以知道init進程做的事情了。當然,也可以看<嵌入式Linux應用開發完全手冊>里構建根文件系統那章。
說一下我的學習經歷吧。
總結一下:
1. 硬體方面的書: 微機原理、數字電路,高校里的教材。畢業多年,忘名了。
2. Linux方面的書:
<ARM體系架構與編程>
<嵌入式Linux應用開發完全手冊>
<Linux設備驅動>,老外寫的那本
<linux設備驅動開發詳解>
<linux內核完全注釋>
<Linux內核情景分析>
3. 視頻:
視頻信息請看網頁鏈接
————————————————
版權聲明:本文為博主「韋東山」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/thisway_diy/article/details/51887326
❹ 如何在Linux下開發攝像頭驅動
在linux下所有設備都是文件。所以對攝像頭的操作其實就是對文件的操作。USB攝像頭的設備文件就是在/dev目錄下的video0(假如只有一個攝像頭)。在linux下操作攝像頭就是使用v4l2對攝像頭進行視頻的操作,操作步驟如下
1. 打開設備文件。
int fd=open(」/dev/video0″,O_RDWR);
2. 取得設備的capability,看看設備具有什麼功能,比如是否具有視頻輸入,或者音頻輸入輸出等。VIDIOC_QUERYCAP,struct v4l2_capability
v4l2_std_id std;
do {
ret= ioctl(fd, VIDIOC_QUERYSTD, &std);
} while (ret == -1 && errno == EAGAIN);
switch (std) {
case V4L2_STD_NTSC:
//……
case V4L2_STD_PAL:
//……
}
3. 選擇視頻輸入,一個視頻設備可以有多個視頻輸入。VIDIOC_S_INPUT,struct v4l2_input(可不要)
4. 設置視頻的制式和幀格式,制式包括PAL,NTSC,幀的格式個包括寬度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
struct v4l2_format fmt;
memset ( &fmt, 0, sizeof(fmt) );
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 320;
fmt.fmt.pix.height = 240;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)
{
printf("set format failed\n");
//return 0;
}
5. 向驅動申請幀緩沖,一般不超過5個。struct v4l2_requestbuffers
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof (req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(fd,VIDIOC_REQBUFS,&req) == -1)
{
perror("VIDIOC_REQBUFS error \n");
//return -1;
}
6.申請物理內存
將申請到的幀緩沖映射到用戶空間,這樣就可以直接操作採集到的幀了,而不必去復制。將申請到的幀緩沖全部入隊列,以便存放採集到的數據.VIDIOC_QBUF,struct v4l2_buffer
VideoBuffer* buffers = calloc( req.count, sizeof(VideoBuffer) );
printf("sizeof(VideoBuffer) is %d\n",sizeof(VideoBuffer));
struct v4l2_buffer buf;
for (numBufs = 0; numBufs < req.count; numBufs++)
{
memset( &buf, 0, sizeof(buf) );
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0)
{
printf("VIDIOC_QUERYBUF error\n");
//return -1;
}
printf("buf len is %d\n",sizeof(buf));
//內存映射
buffers[numBufs].length = buf.length;
buffers[numBufs].offset = (size_t) buf.m.offset;
buffers[numBufs].start = mmap (NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
printf("buffers.length = %d,buffers.offset = %d ,buffers.start[0] = %d\n",buffers[num
❺ LINUX設備驅動程序如何與硬體通信
LINUX設備驅動程序是怎麼樣和硬體通信的?下面將由我帶大家來解答這個疑問吧,希望對大家有所收獲!
LINUX設備驅動程序與硬體設備之間的通信
設備驅動程序是軟體概念和硬體電路之間的一個抽象層,因此兩方面都要討論。到目前為止,我們已經討論詳細討論了軟體概念上的一些細節,現在討論另一方面,介紹驅動程序在Linux上如何在保持可移植性的前提下訪問I/O埠和I/O內存。
我們在需要示例的場合會使用簡單的數字I/O埠來講解I/O指令,並使用普通的幀緩沖區顯存來講解內存映射I/O。
I/O埠和I/O內存
計算機對每種外設都是通過讀寫它的寄存器進行控制的。大部分外設都有幾個寄存器,不管是在內存地址空間還是在I/O地址空間,這些寄存器的訪問地址都是連續的。
I/O埠就是I/O埠,設備會把寄存器映射到I/O埠,不管處理器是否具有獨立的I/O埠地址空間。即使沒有在訪問外設時也要模擬成讀寫I/O埠。
I/O內存是設備把寄存器映射到某個內存地址區段(如PCI設備)。這種I/O內存通常是首先方案,它不需要特殊的處理器指令,而且CPU核心訪問內存更有效率。
I/O寄存器和常規內存
盡管硬體寄存器和內存非常相似,但程序員在訪問I/O寄存器的時候必須注意避免由於CPU或編譯器不恰當的優化而改變預期的I/O動作。
I/O寄存器和RAM最主要的區別就是I/O操作具有邊際效應,而內存操作則沒有:由於內存沒有邊際效應,所以可以用多種 方法 進行優化,如使用高速緩存保存數值、重新排序讀/寫指令等。
編譯器能夠將數值緩存在CPU寄存器中而不寫入內存,即使儲存數據,讀寫操作也都能在高速緩存中進行而不用訪問物理RAM。無論是在編譯器一級或是硬體一級,指令的重新排序都有可能發生:一個指令序列如果以不同於程序文本中的次序運行常常能執行得更快。
在對常規內存進行這些優化的時候,優化過程是透明的,而且效果良好,但是對I/O操作來說這些優化很可能造成致命的錯誤,這是因為受到邊際效應的干擾,而這卻是驅動程序訪問I/O寄存器的主要目的。處理器無法預料某些 其它 進程(在另一個處理器上運行,或在在某個I/O控制器中發生的操作)是否會依賴於內存訪問的順序。編譯器或CPU可能會自作聰明地重新排序所要求的操作,結果會發生奇怪的錯誤,並且很難調度。因此,驅動程序必須確保不使用高速緩沖,並且在訪問寄存器時不發生讀或寫指令的重新排序。
由硬體自身引起的問題很解決:只要把底層硬體配置成(可以是自動的或是由Linux初始化代碼完成)在訪問I/O區域(不管是內存還是埠)時禁止硬體緩存即可。
由編譯器優化和硬體重新排序引起的問題的解決辦法是:對硬體(或其他處理器)必須以特定順序的操作之間設置內存屏障(memory barrier)。Linux提供了4個宏來解決所有可能的排序問題:
#include <linux/kernel.h>
void barrier(void)
這個函數通知編譯器插入一個內存屏障,但對硬體沒有影響。編譯後的代碼會把當前CPU寄存器中的所有修改過的數值保存到內存中,需要這些數據的時候再重新讀出來。對barrier的調用可避免在屏障前後的編譯器優化,但硬體完成自己的重新排序。
#include <asm/system.h>
void rmb(void);
void read_barrier_depends(void);
void wmb(void);
void mb(void);
這些函數在已編譯的指令流中插入硬體內存屏障;具體實現方法是平台相關的。rmb(讀內存屏障)保證了屏障之前的讀操作一定會在後來的讀操作之前完成。wmb保證寫操作不會亂序,mb指令保證了兩者都不會。這些函數都是barrier的超集。
void smp_rmb(void);
void smp_read_barrier_depends(void);
void smp_wmb(void);
void smp_mb(void);
上述屏障宏版本也插入硬體屏障,但僅僅在內核針對SMP系統編譯時有效;在單處理器系統上,它們均會被擴展為上面那些簡單的屏障調用。
設備驅動程序中使用內存屏障的典型形式如下:
writel(dev->registers.addr, io_destination_address);
writel(dev->registers.size, io_size);
writel(dev->registers.operation, DEV_READ);
wmb();
writel(dev->registers.control, DEV_GO);
在這個例子中,最重要的是要確保控制某種特定操作的所有設備寄存器一定要在操作開始之前已被正確設置。其中的內存屏障會強制寫操作以要求的順序完成。
因為內存屏障會影響系統性能,所以應該只用於真正需要的地方。不同類型的內存屏障對性能的影響也不盡相同,所以最好盡可能使用最符合需要的特定類型。
值得注意的是,大多數處理同步的內核原語,如自旋鎖和atomic_t操作,也能作為內存屏障使用。同時還需要注意,某些外設匯流排(比如PCI匯流排)存在自身的高速緩存問題,我們將在後面的章節中討論相關問題。
在某些體系架構上,允許把賦值語句和內存屏障進行合並以提高效率。內核提供了幾個執行這種合並的宏,在默認情況下,這些宏的定義如下:
#define set_mb(var, value) do {var = value; mb();} while 0
#define set_wmb(var, value) do {var = value; wmb();} while 0
#define set_rmb(var, value) do {var = value; rmb();} while 0
在適當的地方,<asm/system.h>中定義的這些宏可以利用體系架構特有的指令更快的完成任務。注意只有小部分體系架構定義了set_rmb宏。
使用I/O埠
I/O埠是驅動程序與許多設備之間的通信方式——至少在部分時間是這樣。本節講解了使用I/O埠的不同函數,另外也涉及到一些可移植性問題。
I/O埠分配
下面我們提供了一個注冊的介面,它允允許驅動程序聲明自己需要操作的埠:
#include <linux/ioport.h>
struct resource *request_region(unsigned long first, unsigned long n, const char *name);
它告訴內核,我們要使用起始於first的n個埠。name是設備的名稱。如果分配成功返回非NULL,如果失敗返回NULL。
所有分配的埠可從/proc/ioports中找到。如果我們無法分配到我們要的埠集合,則可以查看這個文件哪個驅動程序已經分配了這些埠。
如果不再使用這些埠,則用下面函數返回這些埠給系統:
void release_region(unsigned long start, unsigned long n);
下面函數允許驅動程序檢查給定的I/O埠是否可用:
int check_region(unsigned long first, unsigned long n);//不可用返回負的錯誤代碼
我們不贊成用這個函數,因為它返回成功並不能確保分配能夠成功,因為檢查和其後的分配並不是原子操作。我們應該始終使用request_region,因為這個函數執行了必要的鎖定,以確保分配過程以安全原子的方式完成。
操作I/O埠
當驅動程序請求了需要使用的I/O埠范圍後,必須讀取和/或寫入這些埠。為此,大多數硬體都會把8位、16位、32位區分開來。它們不能像訪問系統內存那樣混淆使用。
因此,C語言程序必須調用不同的函數訪問大小不同的埠。那些只支持映射的I/O寄存器的計算機體系架構通過把I/O埠地址重新映射到內存地址來偽裝埠I/O,並且為了易於移植,內核對驅動程序隱藏了這些細節。Linux內核頭文件中(在與體系架構相關的頭文件<asm/io.h>中)定義了如下一些訪問I/O埠的內聯函數:
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
位元組讀寫埠。
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
訪問16位埠
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
訪問32位埠
在用戶空間訪問I/O埠
上面這些函數主要是提供給設備驅動程序使用的,但它們也可以用戶空間使用,至少在PC類計算機上可以使用。GNU的C庫在<sys/io.h>中定義了這些函數。如果要要用戶空間使用inb及相關函數,則必須滿足正下面這些條件:
編譯程序時必須帶有-O選項來強制內聯函數的展開。
必須用ioperm(獲取單個埠的許可權)或iopl(獲取整個I/O空間)系統調用來獲取對埠進行I/O操作的許可權。這兩個函數都是x86平台特有的。
必須以root身份運行該程序才能調用ioperm或iopl。或者進程的祖先進程之一已經以root身份獲取對埠的訪問。
如果宿主平台沒有以上兩個系統調用,則用戶空間程序仍然可以使用/dev/port設備文件訪問I/O埠。不過要注意,該設備文件的含義與平台密切相關,並且除PC平台以處,它幾乎沒有什麼用處。
串操作
以上的I/O操作都是一次傳輸一個數據,作為補充,有些處理器實現了一次傳輸一個數據序列的特殊指令,序列中的數據單位可以是位元組、字、雙字。這些指令稱為串操作指令,它們執行這些任務時比一個C語言編寫的循環語句快得多。下面列出的宏實現了串I/O:
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);從內存addr開始連續讀/寫count數目的位元組。只對單一埠port讀取或寫入數據
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);對一個16位埠讀寫16位數據
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);對一個32位埠讀寫32位數據
在使用串I/O操作函數時,需要銘記的是:它們直接將位元組流從埠中讀取或寫入。因此,當埠和主機系統具有不同的位元組序時,將導致不可預期的結果。使用inw讀取埠將在必要時交換位元組,以便確保讀入的值匹配於主機的位元組序。然而,串函數不會完成這種交換。
暫停式I/O
在處理器試圖從匯流排上快速傳輸數據時,某些平台(特別是i386)就會出現問題。當處理器時鍾比外設時鍾(如ISA)快時就會出現問題,並且在設備板上特別慢時表現出來。為了防止出現丟失數據的情況,可以使用暫停式的I/O函數來取代通常的I/O函數,這些暫停式的I/O函數很像前面介紹的那些I/O函數,不同之處是它們的名字用_p結尾,如inb_p、outb_p等等。在linux支持的大多數平台上都定義了這些函數,不過它們常常擴展為非暫停式I/O同樣的代碼,因為如果不使用過時的外設匯流排就不需要額外的暫停。
平台相關性
I/O指令是與處理器密切相關的。因為它們的工作涉及到處理器移入移出數據的細節,所以隱藏平台間的差異非常困難。因此,大部分與I/O埠相關的源代碼都與平台相關。
回顧前面函數列表可以看到有一處不兼容的地方,即數據類型。函數的參數根據各平台體系架構上的不同要相應地使用不同的數據類型。例如,port參數在x86平台上(處理器只支持64KB的I/O空間)上定義為unsigned short,但在其他平台上定義為unsigned long,在這些平台上,埠是與內存在同一地址空間內的一些特定區域。
感興趣的讀者可以從io.h文件獲得更多信息,除了本章介紹的函數,一些與體系架構相關的函數有時也由該文件定義。
值得注意的是,x86家族之外的處理器都不為埠提供獨立的地址空間。
I/O操作在各個平台上執行的細節在對應平台的編程手冊中有詳細的敘述;也可以從web上下載這些手冊的PDF文件。
I/O埠示例
演示設備驅動程序的埠I/O的示例代碼運行於通用的數字I/O埠上,這種埠在大多數計算機平台上都能找到。
數字I/O埠最常見的一種形式是一個位元組寬度的I/O區域,它或者映射到內存,或者映射到埠。當把數字寫入到輸出區域時,輸出引腳上的電平信號隨著寫入的各位而發生相應變化。從輸入區域讀取到的數據則是輸入引腳各位當前的邏輯電平值。
這類I/O埠的具體實現和軟體介面是因系統而異的。大多數情況下,I/O引腳由兩個I/O區域控制的:一個區域中可以選擇用於輸入和輸出的引腳,另一個區域中可以讀寫實際的邏輯電平。不過有時情況簡單些,每個位不是輸入就是輸出(不過這種情況下就不能稱為“通用I/O"了);在所有個人計算機上都能找到的並口就是這樣的非通用的I/O埠。
並口簡介
並口的最小配置由3個8位埠組成。第一個埠是一個雙向的數據寄存器,它直接連接到物理連接器的2~9號引腳上。第二個埠是一個只讀的狀態寄存器;當並口連接列印機時,該寄存器 報告 列印機狀態,如是否是線、缺紙、正忙等等。第三個埠是一個只用於輸出的控制寄存器,它的作用之一是控制是否啟用中斷。
如下所示:並口的引腳
示例驅動程序
while(count--) {
outb(*(ptr++), port);
wmb();
}
使用I/O內存
除了x86上普遍使的I/O埠之外,和設備通信的另一種主要機制是通過使用映射到內存的寄存器或設備內存,這兩種都稱為I/O內存,因為寄存器和內存的差別對軟體是透明的。
I/O內存僅僅是類似RAM的一個區域,在那裡處理器可以通過匯流排訪問設備。這種內存有很多用途,比如存放視頻數據或乙太網數據包,也可以用來實現類似I/O埠的設備寄存器(也就是說,對它們的讀寫也存在邊際效應)。
根據計算機平台和所使用匯流排的不同,i/o內存可能是,也可能不是通過頁表訪問的。如果訪問是經由頁表進行的,內核必須首先安排物理地址使其對設備驅動程序可見(這通常意味著在進行任何I/O之前必須先調用ioremap)。如果訪問無需頁表,那麼I/O內存區域就非常類似於I/O埠,可以使用適當形式的函數讀取它們。
不管訪問I/O內存是否需要調用ioremap,都不鼓勵直接使用指向I/O內存的指針。相反使用包裝函數訪問I/O內存,這一方面在所有平台上都是安全的,另一方面,在可以直接對指針指向的內存區域執行操作的時候,這些函數是經過優化的。並且直接使用指針會影響程序的可移植性。
I/O內存分配和映射
在使用之前,必須首先分配I/O區域。分配內存區域的介面如下(在<linux/ioport.h>中定義):
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
該函數從start開始分配len位元組長的內存區域。如果成功返回非NULL,否則返回NULL值。所有的I/O內存分配情況可從/proc/iomem得到。
不再使用已分配的內存區域時,使用如下介面釋放:
void release_mem_region(unsigned long start, unsigned long len);
下面函數用來檢查給定的I/O內存區域是否可用的老函數:
int check_mem_region(unsigned long start, unsigned long len);//這個函數和check_region一樣不安全,應避免使用
分配內存之後我們還必須確保該I/O內存對內存而言是可訪問的。獲取I/O內存並不意味著可引用對應的指針;在許多系統上,I/O內存根本不能通過這種方式直接訪問。因此,我們必須由ioremap函數建立映射,ioremap專用於為I/O內存區域分配虛擬地址。
我們根據以下定義來調用ioremap函數:
#include <asm/io.h>
void *ioremap(unsigned long phys_addr, unsigned long size);
void *ioremap_nocache(unsigned long phys_addr, unsigned long size);在大多數計算機平台上,該函數和ioremap相同:當所有I/O內存已屬於非緩存地址時,就沒有必要實現ioremap的獨立的,非緩沖版本。
void iounmap(void *addr);
記住,由ioremap返回的地址不應該直接引用,而應該使用內核提供的accessor函數。
訪問I/O內存
在某些平台上我們可以將ioremap的返回值直接當作指針使用。但是,這種使用不具有可移植性,訪問I/O內存的正確方法是通過一組專用於些目的的函數(在<asm/io.h>中定義)。
從I/O內存中讀取,可使用以下函數之一:
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
其中,addr是從ioremap獲得的地址(可能包含一個整數偏移量);返回值是從給定I/O內存讀取到的值。
寫入I/O內存的函數如下:
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
如果必須在給定的I/O內存地址處讀/寫一系列值,則可使用上述函數的重復版本:
void ioread8_rep(void *addr, void *buf, unsigned long count);
void ioread16_rep(void *addr, void *buf, unsigned long count);
void ioread32_rep(void *addr, void *buf, unsigned long count);
void iowrite8_rep(void *addr, const void *buf, unsigned long count);
void iowrite16_rep(void *addr, const void *buf, unsigned long count);
void iowrite32_rep(void *addr, const void *buf, unsigned long count);
上述函數從給定的buf向給定的addr讀取或寫入count個值。count以被寫入數據的大小為單位。
上面函數均在給定的addr處執行所有的I/O操作,如果我們要在一塊I/O內存上執行操作,則可以使用下面的函數:
void memset_io(void *addr, u8 value, unsigned int count);
void memcpy_fromio(void *dest, void *source, unsigned int count);
void memcpy_toio(void *dest, void *source, unsigned int count);
上述函數和C函數庫的對應函數功能一致。
像I/O內存一樣使用I/O埠
某些硬體具有一種有趣的特性:某些版本使用I/O埠,而其他版本則使用I/O內存。導出給處理器的寄存器在兩種情況下都是一樣的,但訪問方法卻不同。為了讓處理這類硬體的驅動程序更加易於編寫,也為了最小化I/O埠和I/O內存訪問這間的表面區別,2.6內核引入了ioport_map函數:
void *ioport_map(unsigned long port, unsigned int count);
該函數重新映射count個I/O埠,使其看起來像I/O內存。此後,驅動程序可在該函數返回的地址上使用ioread8及其相關函數,這樣就不必理會I/O埠和I/O內存之間的區別了。
當不需要這種映射時使用下面函數一撤消:
void ioport_unmap(void *addr);
這些函數使得I/O埠看起來像內存。但需要注意的是,在重新映射之前,我們必須通過request_region來分配這些I/O埠。
為I/O內存重用short
前面介紹的short示例模塊訪問的是I/O埠,它也可以訪問I/O內存。為此必須在載入時通知它使用I/O內存,另外還要修改base地址以使其指向I/O區域。
下例是在MIPS開發板上點亮調試用的LED:
mips.root# ./short_load use_mem=1 base = 0xb7ffffc0
mips.root# echo -n 7 > /dev/short0
下面代碼是short寫入內存區域時使用的循環:
while(count--) {
iowrite8(*ptr++, address);
wmb();
}
1MB地址空間之下的ISA內存
最廣為人知的I/O內存區之一就是個人計算機上的ISA內存段。它的內存范圍在64KB(0xA0000)到1MB(0x100000)之間,因此它正好出現在常規系統RAM的中間。這種地址看上去有點奇怪,因為這個設計決策是20世紀80年代早期作出的,在當時看來沒有人會用到640KB以上的內存。
❻ 如何學習Linux設備驅動
通常,內核的升級對從事linux應用程序開發的人員來說影響較小,因為系統調用基本保持兼容,影響比較大的是驅動開發人員。每次內核的更新都可能導致許多內核函數原型上的變化,其中既有內核本身提供的函數,也有硬體平台代碼提供的函數,後者變化的更加頻繁。這一點從許多經典書籍就可驗證,當你按照手裡的經典著作,如:Alessandro的《linux設備驅動程序》,編寫驅動時,發現並不能夠成功的在你的linux平台上編譯通過、或不能正常執行,原因就在於你用的內核和書里的不一致。
本文從兩個方面去解釋這個問題,一方面是如何寫好linux設備驅動,另一方面是如何應對不斷升級的內核。
如何寫好Linux設備驅動
Linux設備驅動是linux內核的一部分,是用來屏蔽硬體細節,為上層提供標准介面的一種技術手段。為了能夠編寫出質量比較高的驅動程序,要求工程師必須具備以下幾個方面的知識:
● 熟悉處理器的性能
如:處理器的體系結構、匯編語言、工作模式、異常處理等。對於初學者來說,在還不熟悉驅動編寫方法的情況下,可以先不把重心放在這一項上,因為可能因為它的枯燥、抽象而影響到你對設備驅動的興趣。隨著你不斷地熟悉驅動的編寫,你會很自然的意識到此項的重要性。
● 掌握驅動目標的硬體工作原理及通訊協議
如:串口控制器、顯卡控制器、硬體編解碼、存儲卡控制器、I2C通訊、SPI通訊、USB通訊、SDIO通訊、I2S通訊、PCI通訊等。編寫設備驅動的前提就是需要了解設備的操作方法,所以這些內容的重要程度不言而喻。但不是說要把所有設備的操作方法都熟悉了以後才可以寫驅動,你只需要了解你要驅動的硬體就可以了。
● 掌握硬體的控制方法
如:中斷、輪詢、DMA 等,通常一個硬體控制器會有多種控制方法,你需要根據系統性能的需要合理的選擇操作方法。初學階段以實現功能為目的,掌握的順序應該是,輪詢->中斷->DMA。隨著學習的深入,需要綜合考慮系統的性能需求,採取合適的方法。
● 良好的GNU C語言編程基礎
如:C語言的指針、結構體、內存操作、鏈表、隊列、棧、C和匯編混合編程等。這些編程語法是編寫設備驅動的基礎,無論對於初學者還是有經驗者都非常重要。
● 良好的linux操作系統概念
如:多進程、多線程、進程調度、進程搶占、進程上下文、虛擬內存、原子操作、阻塞、睡眠、同步等概念及它們之間的關系。這些概念及方法在設備驅動里的使用是linux設備驅動區別單片機編程的最大特點,只有理解了它們才會編寫出高質量的驅動。
● 掌握linux內核中設備驅動的編寫介面
如:字元設備的cdev、塊設備的gendisk、網路設備的net_device,以及基於這些基本介面的framebuffer設備的fb_info、mtd設備的mtd_info、tty設備的tty_driver、usb設備的usb_driver、mmc設備的mmc_host等。
Linux內核為設備驅動編寫者提供了標準的介面,驅動編寫者無需精通內核的各個部分,只需要明確內核提供給我們的介面,並實現此介面就可以了。內核提供的介面採用的是面向對象的思路,即把目標設備抽象成一個對象,通常利用一個結構體來描述這個對象。驅動工程師的任務就是實現這個對象。這個結構體中會包含設備的屬性(用變數表示)和操作方法(用函數指針表示)。如:字元設備的cdev
struct cdev {
struct kobject kobj;
struct mole *owner;
const struct file_operations *ops; // 操作方法結合,其它項都是屬性
struct list_head list;
dev_t dev;
unsigned int count;
};
開始階段可以以模仿為主,即套用一些固定的模板、參考常式。
如何應對不斷升級的內核
內核升級對驅動的影響主要體現在,(1)驅動介面定義的變化;(2)內核的一些功能函數的名稱、參數、頭文件、宏定義的變化;(3)平台代碼關於硬體操作方面封裝的一些函數的變化;(4)設備模型的影響。
● 驅動介面定義的變化
如:2.4內核中字元設備驅動的注冊介面是:
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
而2.6內核中已經不建議使用這種方法了,改為:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
這種介面定義及注冊方法帶來的變化,發生的並不頻繁。解決方案是:參考內核中的代碼。這種介面定義及注冊方法在內核中非常容易找到,如:字元設備驅動的注冊方法及介面定義可以參照內核driver/char/目錄下的很多實例。
● 內核的一些功能函數的名稱、參數、頭文件、宏定義的變化
如:中斷注冊函數的格式及參數在2.4內核、2.6內核低版本和高版本之間都存在差別,在2.6.8中,中斷注冊函數的定義為:
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long irq_flags, const char * devname, void *dev_id)
irq_flags的取值主要為下面的某一種或組合: SA_INTERRUPT、SA_SAMPLE_RANDOM、SA_SHIRQ
在2.6.26中,中斷注冊函數的定義為:
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
typedef irqreturn_t (*irq_handler_t)(int, void *); irq_flags的取值主要為下面的某一種或組合:(功能和2.6.8的對應)IRQF_DISABLED、IRQF_SAMPLE_RANDOM、IRQF_SHARED
當出現這些問題時,編譯過程中,編譯器會給我們比較明確的錯誤提示,根據這些提示你可以判斷出是否是缺少頭文件問題、是否是函數參數定義有誤等。解決問題的最好辦法還是到你的目標內核中找信息。此時找問題的方法可以藉助於搜索,如:你可以在新的內核中搜索request_irq,看新內核中的驅動是如何使用它的,這種方法非常有效。
● 平台代碼關於硬體操作方面封裝的一些函數的變化
內核中,硬體平台相關的代碼在內核更新過程中變化比較頻繁,和我們的設備驅動也是息息相關,所以在針對一個新內核編寫設備驅動前,一定要熟悉你的平台代碼的結構。有時平台雖然提供了內核要求的介面函數,但使用起來功能卻並不完善。下面還是先舉個例子說明平台代碼更新對設備驅動的影響。
如:在linux-2.6.8內核中,調用set_irq_type(IRQ_EINT0,IRQT_FALLING);去設置S3C2410的IRQ_EINT0的中斷觸發信號類型,你會發現不會有什麼效果。跟蹤代碼發現內核的set_irq_type函數需要平台提供一個針對硬體平台的實現函數
static struct irqchip s3c_irqext_chip = {
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
.type = s3c_irqext_type
};
s3c_irqext_type就是linux內核需要的實現函數,而s3c_irqext_type在2.6.8中的實現為: static int s3c_irqext_type(unsigned int irq, unsigned int type)
{
irqdbf("s3c_irqext_type: called for irq %d, type %d\n", irq, type);
return 0;
}
原來並沒有實現。而在較高版本的內核,如2.6.26內核中,這個函數是實現了的。所以你一定要小心。當平台函數不好用時,一定要查查原因,或者直接操作硬體寄存器來達到目的。
● 2.6內核設備模型對驅動的影響
在2.6內核中寫設備驅動和在2.4內核中有著很大的不同,主要就是在設備驅動中融入了比設備驅動本身結構還復雜、還難以理解的設備模型。初學驅動時你可以不理會設備模型,但你會發現內核里的驅動代碼基本上都是融入了設備模型的了。所以很多時候你不得不面對現實,還是要弄懂它,並且它也的注冊方法也會隨著內核的升級而發生變化。解決此類問題的最好方法還是參考目標內核驅動代碼。
❼ 如何學習嵌入式Linux驅動
學習嵌入式Linux驅動,首先我們需要的是去了解整個嵌入式開發的整個流程分為四個層次:底層硬體設計、嵌入式驅動開發、內核開發、應用層開發。其中底層硬體設計必須要有一定的硬體功底,我建議你若不是科班出身(數電、模電、高頻學的比較好)的人不要去考慮。內核開發需要你有很好的軟體功底(C語言、C++學的很好,有過一定的項目經驗最好),這個事嵌入式驅動開發的人以後可以考慮發展的方向,不建議一開始就學。如果你是面臨著急需找工作的人並且你有一定的商業頭腦、創新思維,我認為學習應用層開發是最好不過的選擇,但是你別忘了因為簡單容易學所以學的人比較多。如果你把前面三個選擇都否定了,而且你C語言學的還可以,有學過C51或者STM32這些簡單的東西,你不妨看下去。如果你覺得這些對你沒用或者不感興趣,請就此打住不要再往下看不要再浪費你的時間了。親,去做你該做的事吧!
一、入門者:了解嵌入式
了解嵌入式開發我覺得最好的東西還是《嵌入式系統設計師教程》,這本書寫的很爛,無非是用來應付考試的。但是我認為對我們了解嵌入式開發需要學習些什麼東西還是有一點用處的,可以在網上瀏覽一下,你就可以知道嵌入式大概要學的東西,不建議精讀。另外如果想大致了解一下嵌入式開發的四個層次,可以看下韋東山韋老師的《作為一個新人,怎樣學習嵌入式Linux》http://blog.sina.com.cn/s/blog_13955cfdb0102v3it.html
二、初學者:學習使用Linux
我這里的初學者者指的是已經回了解了嵌入式,有慾望想往深處學習的碼農們。這個時候我們已經找到了感覺了。嵌入式操作系統有Vxworks、WINCE、uCLinux、Embedded Linux等操作,但是我們一般選擇Linux。原因有二:Linux代碼開源,可供學習免費使用。Linux學習的資料非常多,很容易找到小夥伴。學習嵌入式Linux驅動,就必須先學習使用Linux。但是我們對於Linux的使用其實不必學的太多,多了反而會在這浪費的時間。像大家都說可以的《鳥哥的linux私房菜》我不建議大家讀,我認為像《Linux就該這么學》這樣范范而談的書籍反而更適合我們初學者。我們對Linux的定位是:基本命令會用,不懂再查。
http://www.linuxprobe.com/chapter-00.html如果覺的適合自己可以去看下
二、菜鳥們:加強C語言,看得懂電路圖
我相信到這一階段你已經深深的愛上了Linux,當然你也可能恨死她了,恨她為什麼有那麼多命令,恨她為什麼不去想Windows那麼傻瓜式啊,點點就可以了,但是你別忘了其實Windows也有DOS命令行,只是你沒有用過而已吧。我對沒有去Linux命令界面敲過幾行命令的人視為不會使用操作系統的人,你覺得啦?
既然你愛上她了(不愛請不要再往下看),那請問你為了一個愛你的人做件可能對你難的事,你願意嗎?願意的話,我們就要去加強自己的C語言基礎,我覺得書看的多,視頻看的多,還不如看懂一本書,把一本書的程序題好好敲敲,你覺得啦?所以我還是推薦最好的入門的C語言書籍《C程序設計》譚浩強前輩寫的。對於看得懂電路圖我認為最好的是去下一個畫電路板的軟體隨便找幾個電路圖畫畫,慢慢就會了,當然你也可以跳過,我相信如果你真的愛上這一行了以後的學習工作中會逼出來的。
三、碼農們:選擇一塊合適的開發板,然後看書、看數據手冊、敲代碼、看視頻
嵌入式Linux驅動開發是一個敲代碼的過程,所以稱之為碼農。對於嵌入式Linux驅動開發來說是一個偏軟體的工作,而碼農們就是一個看書、看資料、看視頻學習理論知識,然後自己實現的反反復復的過程。只有你不斷Debug不斷解決不斷充實理論知識,才可能往更高層次走。對於書籍我推薦韋東山韋老師的《嵌入式Linux驅動開發完全手冊》,當然我覺得成為中國化的S3C2440數據手冊更好些(至於為什麼學ARM9的S3C2440可以往下看),當然這本書也有他的不好之處:太過於實踐,理論知識不全。我覺得配合杜春雷老師的《ARM體系結構與編程》看會非常好,有比較詳細的對ARM的介紹。另外既然我們學習S3C2440的話,《S3C2440數據手冊》我們是非看不可。另外老外寫的《設備驅動開發》也就是所謂的LDD,還有就是宋寶華老師的《Linux設備驅動開發詳解》,挺不錯的。視頻的話我力頂《嵌入式Linux驅動開發完全手冊》的作者韋東山韋老師的視頻,可以去百問網http://www.100ask.org/ 自行查看。開發板的話我覺得可以自行選擇,最好選擇S3c2440或者S3c2410的晶元,因為ARM9的資料最多,隨便上網搜就是一大把。
四、大神們:研究Linux
毛德操/ 胡希明寫的《Linux內核源代碼情景分析》、 趙炯《Linux內核完全注釋》、《unix環境高級編程》還有更多的可以去看一看瞧一瞧了,我相信你學到這里就可以自找出路了,我也目前在前面階段,以後把這些學習完再做補充了。
我相信能夠學習嵌入式Linux驅動的人都能夠知道有好的學習資料學習能夠事半功倍的,本人也是學習驅動的菜鳥,歷經了學習的滄桑,今天在這里分享一下自己學習嵌入式Linux驅動過程中自認為好的資料,不好請勿噴。有興趣的可以轉載分享給你的朋友。以後有時間我會整理我在學習過程中的東西,加我關注以後一起學習叫流。
❽ arm上移植linux操作系統後,是怎麼驅動LCD顯示系統界面的
這要看LCD接在哪了,不過正常肯定是接在lcd控制器上,剩下的是如何配置控制器,可以看一下手冊對其配置,你說arm上移植linux操作系統後 那麼mmu是開啟的就不能直接訪問io,不過linux肯定有對應的驅動,如果想自己寫的可以寫成模塊,然後載入模塊的方式去驅動lcd,可以看一下內核的其他模塊是怎麼寫的。如果有問題可以再問我!
❾ linux下的設備驅動
你好,解決驅動問題,最簡單最容易最有效的詳細方法就是:
直接到www.drivergenius.com下載「驅動精靈」軟體,一定要是最新的,舊版的「驅動精靈」不好用,安裝好它後,雙擊打開--驅動更新--自動安裝--開始更新,它會自動在網上搜索最新的最適合你電腦的所有驅動,它會自動下載並自動完整安裝好,根本不用你動手。
這個軟體的最大優點就是:如果你電腦缺少什麼驅動它會一一幫你裝上最適合的,如果你電腦驅動殘舊問題多多它會自動更新好並自動修復。是不是非常非常的方便,推薦不怎麼懂電腦的人使用這個方法。
如果還不行,一定要先採納我的答案再+我314345040,因為這樣電腦會及時提示我,什麼問題被採納了,你具體的問題情況我也能及時打開網頁了解到,要相信你的電腦問題我會盡全力幫你解決的。g
❿ 如何在arm下開發linux視頻採集卡驅動程序
你可能需要手動創建設備節點,首先cat /proc/device 看看能否找到video的設備號,再用mknod命令創建/dev/下的設備節點,如果沒有再考慮去內核make menuconfig查看相關驅動選項有沒有勾上。