uboot中ethernet網口實現分析
作者:[email protected]部落格:fireaxe.blog.chinaunix.net
一、底層介面封裝
假如要為圖中裝置編寫驅動,首先要做什麼?
我認為應該是對各個器件進行抽象,也就是把可能的各種操作封裝成介面並把需要的資料封裝成結構體。這樣作有兩個好處,一是可以不再考慮器件的實現細節,直接呼叫介面就可完成各種操作;而是通過對介面的測試,可以較早的完成對器件的驗證。
以上圖為例,包含兩個器件,MAC與PHY。
PHY需要的介面也是讀寫暫存器的介面與資料暫存器基址。
char tsec_phy_read(phy_dev *phydev, char *regAddr);
void tsec_phy_write(phy_dev *phydev, char *regAddr, char value);
phy_regs = PHY_REG_BASE;
MAC需要的介面是讀寫暫存器的介面,需要的資料是暫存器基址。
char tsec_mac_read(mac_dev *macdev, char *regAddr);
void tsec_mac_write(mac_dev *macdev, char *regAddr, char value);
mac_regs = MAC_REG_BASE;
因為需要通過MIIM傳送資料PHY,還需要一組操作MIIM的介面。當需要配置PHY的暫存器時,PHY暫存器讀寫介面會呼叫這組介面。
char tsec_mii_read(mac_dev * macdev, char *regAddr);
void tsec_mii_write(mac_dev * macdev, char *regAddr, char value);
二、功能抽象
我們已經有個所需的各種介面,剩下的就是對功能進行抽象。作為一個網口晶片,不考慮特殊配置,最常用的介面也就三四個。
int tsec_init(eth_device *dev);
void tsec_halt(eth_device *dev);
int tsec_send(eth_device *dev, void *pack, int len);
int tsec_recv(eth_device *dev, void *pack, int len);
tsec_init與tsec_halt需要對PHY與MAC的暫存器進行設定,完成所需配置,因此需要使用MAC與PHY的暫存器設定介面。tsec_read與tsec_write只需要把起始地址與長度通知MAC晶片,然後啟動傳送就可以了。因此只需MAC暫存器設定介面。
三、資料結構
現在,所需介面都有了,但還有一個問題,各層函式的第一個引數是什麼?
這個引數與面向物件有關。假如是使用C++實現,我們的第一步就不再是設定介面,而是劃分類,然後再為各個類實現介面。即使用C實現,也是可以C++的面向物件功能。(說白了C++也不過是從語言層面做了層封裝,一個標準的C++類的成員函式,其實是第一個入參為this指標的C函式)
為了更清楚看到這一點,下面列一下這三個結構體的定義:
struct eth_device {
int (*init) (eth_device *dev);
int (*send) (eth_device *dev, void *pack, int len);
int (*recv) (eth_device *dev, void *pack, int len);
void (*halt) (eth_device *dev);
struct *phy_dev;
struct *mac_dev;
};
struct phy_dev {
regs = PHY_REG_BASE;
int (*read) (phy_dev *phydev, char *regAddr);
int (*write) (phy_dev *phydev, char *regAddr, char value);
struct *mac_dev;
};
struct mac_dev {
regs = PHY_REG_BASE;
int (*read) (mac_dev *macdev, char *regAddr);
int (*write) (mac_dev *macdev, char *regAddr, char value);
int (*mii_read) (mac_dev * macdev, char *regAddr);
int (*mii_write) (mac_dev * macdev, char *regAddr, char value);
};
四、資料結構初始化介面
一個裝置上可能會有多個網口,我們為每個網口例項化一個eth_device結構體(或者叫物件),初始化時為它連線所需的mac與phy。之後既可以通過它實現各種操作。當然每個結構體都是需要初始化的,因此我們再建立一組初始化函式。
eth_int();
mac_init();
phy_init();
五、設備註冊介面
關於多個網口問題。網口多了管理起來也麻煩,比如說交換機,可能有20口甚至40口之多。因此有必要建立一組資料結構來管理。常見的管理結構是連結串列,可以方便的查詢與遍歷。下面提供一組連結串列管理介面。
mac_register(mac_dev *macdev);
phy_register(phy_dev *phydev);
eth_register(eth_dev *ethdev);
五、回到uboot
整理完開發過程後,回到uboot的實現。把uboot的實現與上述進行對比,發現還是有些不同的。這沒關係,因為在實際實現時,可能會根據需要進行一些簡化與抽象,但並不影響整個結構。
有些差別的是PHY初始化這一部分。我所用的PHY晶片是Davicom的DM9161,uboot中存在著davicom.c 。它與phy.c的關係是,phy.c實現phy晶片公用部分,這個檔案實現某個晶片,如DM9161的一些特殊操作,如狀態查詢、初始配置等。沒關係,我們在phy_dev中增加對應介面即可。
下面是uboot的函式呼叫關係,
Uboot的資料收發需要主動呼叫,沒有采用中斷或輪詢方式。具體實現可參照NetLoop()
本文乃fireaxe原創,使用GPL釋出,可以自由拷貝,轉載。但轉載請保持文件的完整性,並註明原作者及原連結。內容可任意使用,但對因使用該內容引起的後果不做任何保證。作者:[email protected]部落格:fireaxe.blog.chinaunix.net
相關推薦
uboot中ethernet網口實現分析
本文乃fireaxe原創,使用GPL釋出,可以自由拷貝,轉載。但轉載請保持文件的完整性,並註明原作者及原連結。內容可任意使用,但對因使用該內容引起的後果不做任何保證。作者:[email protected]部落格:fireaxe.blog.chinaunix.net
JDK中LinkedList的實現分析
LinkedList JDK中的LinkedList是繼承自AbstractSequentialList,並實現了List、Deque、Queue等介面,並支援拷貝和序列化。 public class LinkedList<E> extends
ReactiveCocoa 中 RACCommand底層實現分析
前言 在ReactiveCocoa 過程中,除去RACSignal和RACSubject這些訊號類以外,有些時候我們可能還需要封裝一些固定的操作集合。這些操作集合都是固定的,每次只要一觸發就會執行事先定義好的一個過程。在iOS開發過程中,按鈕的點選事件就可能有這種需求。那麼
ThreadPoolExecutor的應用和實現分析(中)—— 任務處理相關源碼分析
stateless 自身 tran als row exce 繼承 break attribute 轉自:http://www.tuicool.com/articles/rmqYjq 前面一篇文章從Executors中的工廠方法入手,已經對ThreadPoolExecuto
Java中HashMap底層實現原理(JDK1.8)源碼分析
blank imp dash logs || 屬性 lte das ces 這幾天學習了HashMap的底層實現,但是發現好幾個版本的,代碼不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一樣,原來他們沒有指定JDK版本,很多文章都是舊版本J
uboot中rtc頂層分析
number ssi clas software printf one int lar app uboot一般不會要求開啟rtc,只是還是支持rtc以備特殊需求的。底層驅動移植前面兩篇已經介紹。這裏介紹頂層的調用過程。頂層在uboot/common/cm
SylixOS中ARM架構的MMU實現分析
SylixOS ARM MMU 1. 理論知識 1.1 快表(TLB)與頁表 在虛擬頁式存儲管理中設置了快表(TLB),用於保存正在運行進程頁表的子集,通常快表存放在高速緩沖存儲器(Cache)中。而頁表存放在內存中,並通過特殊功能寄存器(TTB)等告知系統頁表存儲在內存中的基址。 1.2 一
嵌入式開發環境搭建(一) 虛擬機實現橋接Ethernet網口 並且通過WIFI進行NAT聯網
war bubuko 搭建服務器 6.4 網線 16.4 聯網 橋接 圖片 背景: 目前手頭上有一塊JZ2440的板子,之前有搭建完整套開發環境,由於虛擬機故障需要從新搭建服務器端,故在此記錄搭建步驟 環境: Ubuntu16.4 VMWare 12 先行條件:
SpringBatch中的retry和skip機制實現分析
pub 限制次數 else boolean exceptio 2個 let move vat 本文主要分析SpringBatch中的retry和skip機制的實現。先簡單說明下SpringBatch在SpringBoot中的使用。如果要在springboot中使用batch
推薦系統中協同過濾演算法實現分析(重要兩個圖!!)
“協”,指許多人協力合作。 “協同”,就是指協調兩個或者兩個以上的不同資源或者個體,協同一致地完成某一目標的過程。 “協同過濾”,簡單來說,就是利用興趣相投或擁有共同經驗的群體的喜好來給使用者推薦感興趣的資訊,記錄下來個人對於資訊相當程度的迴應(如評分),以達到過濾的目的,進而幫助別人篩
Lucene筆記38-Lucene在專案中的實現分析
一、實時搜尋中存在的問題 上一節我們提到NRT實時搜尋,實時搜尋的提交併不是實時的,可能要好幾個小時才能提交一次,為什麼搜尋這麼快呢,因為索引資料更新都在記憶體中實現的,那麼,假設有這麼一種情況,還沒有提交,機器突然掛掉了,那硬碟上的資料還是舊的,就會存在資料不一致的問題了。現在有一個解決方
ReentrantLock在Java中Lock的實現原理拿鎖過程分析
import java.util.concurrent.locks.ReentrantLock; public class App { public static void main(String[] args) throws Exception {
WebRTC中丟包重傳NACK實現分析
在WebRTC中,前向糾錯(FEC)和丟包重傳(NACK)是抵抗網路錯誤的重要手段。FEC在傳送端將資料包新增冗餘糾錯碼,糾錯碼連同資料包一起傳送到接收端;接收端根據糾錯碼對資料進行檢查和糾正。RFC5109[1]定義FEC資料包的格式。NACK則在接收端檢測到資料丟包後,傳
JAVA中的集合原始碼分析一:ArrayList的內部實現原理
作為以java為語言開發的android開發者,集合幾乎天天都要打交道,無論是使用頻率最高的ArrayList還是HashSet,都頻繁的出現在平時的工作中。但是其中的原理之前卻一直沒深入探究,接下來記錄一下這次自己學習ArrayList原始碼的過程。 一.構造方法:
JDK8中的HashMap實現原理及原始碼分析
本篇所述原始碼基於JDK1.8.0_121 在寫上一篇線性表的文章的時候,筆者看的是Android原始碼中support24中的Java程式碼,當時發現這個ArrayList和LinkedList的原始碼和Java官方的沒有什麼區別,然而在閱讀HashMap原
《Java併發程式設計的藝術》-Java併發包中的讀寫鎖及其實現分析
1. 前言 在Java併發包中常用的鎖(如:ReentrantLock),基本上都是排他鎖,這些鎖在同一時刻只允許一個執行緒進行訪問,而讀寫鎖在同一時刻可以允許多個讀執行緒訪問,但是在寫執行緒訪問時,所有的讀執行緒和其他寫執行緒均被阻塞。讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,通過分離讀鎖和
C++11中once_flag,call_once實現分析
本文的分析基於llvm的libc++,而不是gun的libstdc++,因為libstdc++的程式碼裡太多巨集了,看起來蛋疼。 在多執行緒程式設計中,有一個常見的情景是某個任務只需要執行一次。在C++11中提供了很方便的輔助類once_flag,call_once。 宣告 首先來看一下
Java中HashMap底層實現原理(JDK1.8)原始碼分析
在JDK1.6,JDK1.7中,HashMap採用位桶+連結串列實現,即使用連結串列處理衝突,同一hash值的連結串列都儲存在一個連結串列裡。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查詢的效率較低。而JDK1.8中,HashMap採用位桶+
(轉載)Java中HashMap底層實現原理(JDK1.8)原始碼分析
近期在看一些java底層的東西,看到一篇分析hashMap不錯的文章,跟大家分享一下。 在JDK1.6,JDK1.7中,HashMap採用位桶+連結串列實現,即使用連結串列處理衝突,同一hash值的連結串列都儲存在一個連結串列裡。但是當位於一個桶中的元素較多,即hash值
C++虛擬函式在g++中的實現分析
本文是我在追查一個詭異core問題的過程中收穫的一點心得,把公司專案相關的背景和特定條件去掉後,僅取其中通用的C++虛擬函式實現部分知識記錄於此。 在開始之前,原諒我先借用一張圖黑一下C++: “無敵”的C++ 如果你也在寫C++,請一定小心…至少,你要先有所瞭解: 當你在寫虛擬函式的時候,g