2009年10月28日 星期三

如何撰寫一個ethernet實體層的driver

ethernet現在已成為很多設備的主要通訊介面,因為它除了快速以及便宜之外,更可以讓它可以很容易架設網路,使多個設備可以互相通訊,這是網路通訊七層中最為底層的device driver, 它必須和硬體相關聯, 而現在的SoC中通常都會將這個通用元件SoC進來, 而如果你將這個driver完成將會讓網路的其它通訊堆疊馬上可以使用, 因以從Link層開始都會是屬於軟體的事情和硬體無關, 所以這部分也是Linux中最強最穩定的程式, 所以你就可以不用撰寫這部分的程式, 你只要專心地將ethernet完成即可。首先我們先來看網路的軟體架構:















以下為這個驅動程式的撰寫重點 :
  • 驅動程式的進入點, 則依照Linux驅動程式的標準寫法, 若是PCI bus則在初始化時依照PCI client驅程式的登錄方式, 若是SoC則依照platform driver的登錄方式。以下是一個範例說明:
static struct platform_driver victor_mac_driver = {
.driver.name = DRV_NAME,
.probe = victor_mac_probe,
.remove = victor_mac_remove,
};

static int __init victor_mac_module_init(void)
{
printk("%s \n",__FUNCTION__);
return platform_driver_register(&victor_mac_driver);
}
module_init(victor_mac_module_init);
  • 當你登錄完畢後則會進入probe的進入點, 在這裏我們需要初始化ethernet device driver。而在probe callback function中會做以下幾件事:
  1. 取得硬體資源 (memory & IRQ no), 並且將其做ioremap以取得virtual address
  2. 初始化硬體, 並註冊interrupt service routine
  3. allocate ethernet device structure, register a ethernet device
以下是範例程式:
static const struct net_device_ops victor_netdev_mac_ops = {
.ndo_init = victor_mac_init,
.ndo_open = victor_mac_open,
.ndo_stop = victor_mac_stop,
.ndo_start_xmit = victor_mac_start_xmit,
.ndo_get_stats = victor_mac_get_stats,
.ndo_set_multicast_list = victor_mac_set_mcast_list,
.ndo_do_ioctl = victor_mac_ioctl,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
struct net_device *ndev;
struct resource *res;
ndev = alloc_etherdev(sizeof(victor_gmac_priv_t));
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ndev->netdev_ops = (struct net_device_ops *)&victor_netdev_mac_ops;
retval = register_netdev(ndev);

而以上在註冊ethernet device driver時會有幾個call back function需要給予撰寫, 其說明如下:

ndo_init
這是在註冊ethernet driver時馬上會被呼叫的call back function, 在此可以做一些初始化的動作

ndo_open
當使用者up該網路介面時會呼叫這個call back function, 通常會在此啓動該ethernet的硬體動作

ndo_stop
當使用者down該網路介面時會呼叫這個call back function, 通常會在此停止該ethernet的硬體動作

ndo_start_xmit
這是網路最後要將資料在硬體線路傳輸, 在這裏該driver不用對內容做任何更動, 而source MAC address通常是由硬體自動填入, 另外有一個很重要的事, 就是網路傳輸由開始者 (TCP or UDP) allocate skb_buff來儲存資料, 而在ethernet driver在送至硬體時需要free該skb_buff, 若沒有做這個動作將會由系統的記憶體越來越少

ndo_get_stats
由此來取得系統所定統計資料, 統計資籵必須由driver自行記錄, 並非由系統協助記錄

ndo_set_multicast_list
設定multicast MAC位址,驅動程式必須將這些位址設至硬體

ndo_do_ioctl
這是對於該元件的ioctl,通常一些運用程式會使用,如bridge程式就會使用,又如設定phy時也會使用。

ndo_change_mtu
設定網路的mtu值,通常是不會更動。

ndo_set_mac_address
設定該網路介面的MAC位址,通常MAC位址都是在初始化時讀取設定在硬體中,所以不會是任意更改,因為MAC位址是全世界上有所管制的,必須是唯一性。

ndo_validate_addr
設定validate MAC address

撰寫好以上各個call back function之後就是interrupt service routine, 而在interrupt service routine中就是要處理收和送的資料, 這部分和IC硬體有很大的關連, 隨著硬體而有所不同, 所以必須要好好地研讀硬體的軟體說明書.

沒有留言:

張貼留言