Linux裝置驅動程式第三版學習(12)- 與硬體通訊

來源:互聯網
上載者:User

繼續往下學習第九章的內容。從這一章開始才接觸到了一些實際的硬體裝置,硬體是我的強項啊,呵呵。加油!

 

一、I/O連接埠和I/O記憶體

   在學習這部分之前,需要先明確一個概念:side effect。明確這個概念有助於理解記憶體操作和IO寄存器操作的不同。LDD3中將這個詞翻譯成了“邊際效應”,對此我持保留意見,至少我當時學習的時候就被這個詞搞得一頭霧水(我本身是搞硬體的,自認為對寄存器還是很瞭解的,這裡完全被這個詞搞暈,我勒個去以為是什麼進階的東東)。LDD2中將此翻譯成“副作用”,這至少比“邊際效應”更容易理解一些,但是“副作用”本身多指一件事物不好的方面的影響,不太符合國人的習慣。所以這裡我想把它叫做“側面影響”或者“連帶效應”(一家之言,也未必準確),相對於對寄存器值本身的變化的“正面影響”或“表面效應”。 這裡我姑且叫他“連帶效應”吧。不同於普通記憶體沒有連帶效應,對寄存器的操作所產生的連帶效應可能是多方面的。一個例子是:對於S3C2440的時鐘控制寄存器CLKCON的操作,不僅僅是變化了寄存器本身的值(表面效應),更重要的是每一位都控制了相應外設的時鐘使能(連帶效應)。另外一個例子:同樣對於S3C2440,CLKSLOW寄存器中MPLL_OFF位置1(表面效應)可以Turn off PLL(連帶效應),但同時必須要SLOW_BIT位置1才可以實現(表面效應),此時對SLOW_BIT位的操作限制了對MPLL_OFF位操作的結果(連帶效應)。這是在同一寄存器不同位的情況,同樣的,在不同寄存器之間也會有這樣的影響,對一個寄存器的操作能否去的預期的效果取決於另一個寄存器的狀態。可以看出,連帶效應才是我們進行寄存器操作的目的。這樣我們就容易理解為什麼對寄存器的操作順序如此重要。

   編譯器工作時往往會對程式進行最佳化,這種最佳化可能會改變記憶體或者寄存器的訪問順序,如果發生這樣的情況,IO操作就會出現問題。所以Linux提供了4個宏來確保操作的執行順序。我們可以在需要嚴格執行順序的地方插入這些宏。具體如下:
#include <asm/system.h><br />#include <linux/kernel.h><br />void barrier(void);<br />void rmb(void);<br />void read_barrier_depends(void);<br />void wmb(void);<br />void mb(void);</p><p>void smp_rmb(void);<br />void smp_read_barrier_depends(void);<br />void smp_wmb(void);<br />void smp_mb(void);

關於這些宏的具體應用參考本部落格轉載的一篇文章“核心同步機制-最佳化屏障和記憶體屏障”。

 

二、使用I/O連接埠

   驅動程式中使用一些函數來進行I/O連接埠的分配和操作。具體如下(linux 2.6.32):

   分配相關的函數:

#include <linux/ioport.h><br />#define request_region(start,n,name)__request_region(&ioport_resource, (start), (n), (name), 0)<br />#define release_region(start,n)__release_region(&ioport_resource, (start), (n))</p><p>extern struct resource * __request_region(struct resource *,<br />resource_size_t start,<br />resource_size_t n,<br />const char *name, int flags);<br />extern void __release_region(struct resource *, resource_size_t, resource_size_t);<br />

 

下面詳細看一下__request_region的實現,定義在kernel/resource.c中。

/**<br /> * __request_region - create a new busy resource region<br /> * @parent: parent resource descriptor<br /> * @start: resource start address<br /> * @n: resource region size<br /> * @name: reserving caller's ID string<br /> * @flags: IO resource flags<br /> */<br />struct resource * __request_region(struct resource *parent,<br /> resource_size_t start, resource_size_t n,<br /> const char *name, int flags)<br />{<br />struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); /* 首先,調用kmalloc()函數在SLAB分配器緩衝中分配並清零一個resource結構*/</p><p>if (!res)<br />return NULL;<br /> /*初始化所分配的resource結構*/<br />res->name = name;<br />res->start = start;<br />res->end = start + n - 1;<br />res->flags = IORESOURCE_BUSY;<br />res->flags |= flags;</p><p>write_lock(&resource_lock); /*寫者獲得讀寫鎖*/</p><p>for (;;) {<br />struct resource *conflict;</p><p>conflict = __request_resource(parent, res); /*首先,調用__request_resource函數進行資源分派,成功則返回NULL*/<br />if (!conflict)<br />break; /*如果分配成功,直接退出*/<br />if (conflict != parent) { /*如果分配不成功,則判斷衝突資源節點是不是父資源節點parent,如果不是,則試圖在當前衝突的資源節點中進行分配*/<br />parent = conflict;<br />if (!(conflict->flags & IORESOURCE_BUSY))<br />continue;<br />}</p><p>/* Uhhuh, that didn't work out.. */<br /> /*如果衝突節點就是父節點,則分配失敗。kfree掉所有分配的resource結構,設定res指標為NULL,然後break*/<br />kfree(res);<br />res = NULL;<br />break;<br />}<br />write_unlock(&resource_lock); /*寫者釋放讀寫鎖*/<br />return res; /*返回所分配的resource結構指標*/<br />}

 

 

 下面看一下__release_region的實現:
/**<br /> * __release_region - release a previously reserved resource region<br /> * @parent: parent resource descriptor<br /> * @start: resource start address<br /> * @n: resource region size<br /> *<br /> * The described resource region must match a currently busy region.<br /> */<br />void __release_region(struct resource *parent, resource_size_t start,<br />resource_size_t n)<br />{<br />struct resource **p;<br />resource_size_t end;</p><p>p = &parent->child;<br />end = start + n - 1;</p><p>write_lock(&resource_lock);</p><p>for (;;) {<br />struct resource *res = *p; /*res指向當前被掃描的子資源節點*/</p><p>if (!res)/*res為NULL說明整個child鏈表掃描完了,退出for*/<br />break;<br />if (res->start <= start && res->end >= end) {<br />if (!(res->flags & IORESOURCE_BUSY)) {<br />p = &res->child;<br />continue;<br />}<br />if (res->start != start || res->end != end)<br />break;<br />*p = res->sibling;<br />write_unlock(&resource_lock);<br />kfree(res);<br />return;<br />}<br />p = &res->sibling;<br />}</p><p>write_unlock(&resource_lock);</p><p>printk(KERN_WARNING "Trying to free nonexistent resource "/**<br /> * __release_region - release a previously reserved resource region<br /> * @parent: parent resource descriptor<br /> * @start: resource start address<br /> * @n: resource region size<br /> *<br /> * The described resource region must match a currently busy region.<br /> */<br />void __release_region(struct resource *parent, resource_size_t start,<br />resource_size_t n)<br />{<br />struct resource **p;<br />resource_size_t end;</p><p>p = &parent->child;<br />end = start + n - 1;</p><p>write_lock(&resource_lock);</p><p>for (;;) {<br />struct resource *res = *p;</p><p>if (!res)<br />break;<br />if (res->start <= start && res->end >= end) {<br />if (!(res->flags & IORESOURCE_BUSY)) {<br />p = &res->child;<br />continue;<br />}<br />if (res->start != start || res->end != end)<br />break;<br />*p = res->sibling;<br />write_unlock(&resource_lock);<br />kfree(res);<br />return;<br />}<br />p = &res->sibling;<br />}</p><p>write_unlock(&resource_lock);</p><p>printk(KERN_WARNING "Trying to free nonexistent resource "<br />"<%016llx-%016llx>/n", (unsigned long long)start,<br />(unsigned long long)end);<br />}

 

   操作I/O連接埠的函數:

/*讀寫8位連接埠*/<br />unsigned inb(unsigned port);<br />void outb(unsigned char byte, unsigned port);</p><p>/*讀寫16位連接埠*/<br />unsigned inw(unsigned port);<br />void outw(unsigned short word, unsigned port);</p><p>/*讀寫32位連接埠*/<br />unsigned inl(unsigned port);<br />void outl(unsigned longword, unsigned port);

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.