淺析uboot網絡程序結構

這篇文章主要講解uboo/net目錄下的部分源代碼。主要是 net.c,eth.c,ip3912.c 中的代碼。本例用的是xxxx公司yyyy系列的zzzzCPU, 網卡是IP173(和IP3912兼容)。

 

本文主要分三部分  網口設備的檢測,網口設備的註冊,應用程序(ping)的執行流程

(檢測網口設備

先從Arch/arm/lib/board.c講起,uboot執行完彙編程序後,會跳轉到該文件中的start_armboot函數。該函數先會爲全局變量gd分配空間,並清零。然後執行函數指針數組init_sequence裏的各種初始化函數。初始化函數一般都是和具體的開發板相關聯的,所以這些函數的源碼是在board目錄下,本例就是在borad/xxxx/yyyy下。

 

init_sequence數組中有個指針指向board_init,一般可以board_init函數內,初始化CPUIP173相連的引腳,reset網卡後,可以通過讀寫CPU的相關寄存器向IP173發送讀寫命令來檢測IP173是否正常。

 

例如:IP173寄存器23是芯片ID寄存器(5PHY共用)(見圖一),可以通過讀寫寄存器 23來判斷IP173是否存在。

具體檢測函數如下:

[objc]  view plain  copy
  1.    
  2. #define CONFIG_IP3912_ETN1_BASE  0xC1600000   //見圖二  
  3. #define CONFIG_IP3912_ETN2_BASE  0xC1700000  
  4.    
  5. #define ETN1_BASE    CONFIG_IP3912_ETN1_BASE  
  6. #define ETN2_BASE    CONFIG_IP3912_ETN2_BASE  
  7.    
  8. #define ETN_MAC1     0x0000  
  9. #define ETN_MAC2     0x0004  
  10. #define ETN_IPGT         0x0008  
  11. #define ETN_IPGR         0x000c  
  12. #define ETN_CLRT     0x0010  
  13. #define ETN_MAXF     0x0014  
  14. #define ETN_SUPP     0x0018  
  15. #define ETN_TEST     0x001c  
  16. #define ETN_MCFG     0x0020  
  17. #define ETN_MCMD     0x0024  
  18. #define ETN_MADR     0x0028  
  19.    
  20.    
  21. #define VEGA_IP173_PHY_ADDR  0x01  
  22. #define ICPLUS_IP173T_PHYID1     0x02  
  23. #define ICPLUS_IP173T_PHYID2     0x03  
  24. #define ICPLUS_OUI_MASK  0x0000ffff  
  25. #define ICPLUS_OUI   0x90c3  
  26.    
  27. int board_init(void)  
  28. {  
  29.     ...  
  30.     board_detect();  
  31.     ...  
  32. }  
  33. void board_detect(void)  
  34. {  
  35.     init_etn0();  
  36.     detect_IC_PLUS_173T(VEGA_IP173_PHY_ADDR);  
  37. }  
  38.    
  39. static int detect_IC_PLUS_173T(int addr)  
  40. {  
  41.     u32 phyid = 0;  
  42.     u16 reg = 0;  
  43.    
  44.     clear_gpioc(28); //IP173 reset引腳  
  45.     udelay(12000);  
  46.     udelay(12000);  
  47.     udelay(12000);  
  48.    
  49.     set_gpioc(28);  //IP173 reset引腳  
  50.     udelay(1000);  
  51.     udelay(1000);  
  52.     udelay(1000);  
  53.    
  54.     reg = detect_phy_read(addr,ICPLUS_IP173T_PHYID1); // 讀ID1寄存器  
  55.     phyid = (u32)reg << 6;  
  56.     reg = detect_phy_read(addr, ICPLUS_IP173T_PHYID2); // 讀ID2寄存器  
  57.     phyid |= ((u32)reg)>>10;  
  58.     phyid &= ICPLUS_OUI_MASK;  
  59.     /* IC+ IP173T */  
  60.     printf("phyid = 0x%x\n",phyid );  
  61.     if (phyid == ICPLUS_OUI)  
  62.         return 1;  
  63.     return 0;  
  64. }  
  65. static void detect_phy_wait(void)  
  66. {  
  67.         int i, status;  
  68.         for (i = 0; i < 1000; i++) {  
  69.         status = readl((voidvoid *)(ETN1_BASE + ETN_MIND)) & 0x7//  
  70.         if (!status)  
  71.             return;  
  72.         udelay(1);  
  73.     }  
  74. }  
  75.    
  76. static u16 detect_phy_read(u8 address, u8 reg)  
  77. {  
  78.     u16 value;  
  79.     writel((address << 8) | reg, (voidvoid *)(ETN1_BASE + ETN_MADR)); //PHY地址右移或上  
  80.                                                             //reg地址  
  81.     writel(0x00000001, (voidvoid *)(ETN1_BASE + ETN_MCMD));  
  82.     detect_phy_wait();  
  83.    
  84.     value = readl((voidvoid *)(ETN1_BASE + ETN_MRDD));  
  85.     writel(0x00000000, (voidvoid *)(ETN1_BASE + ETN_MCMD));  
  86.     return value;  
  87. }  
  88.  int detect_phy_write(u8 address, u8 reg,int value)  
  89. {  
  90.     writel(address << 8 | reg,(voidvoid *)(ETN1_BASE + ETN_MADR));  
  91.     __raw_writel(value, (voidvoid *)(ETN1_BASE + ETN_MWTD));  
  92.     detect_phy_wait();  
  93. }  

解釋

 init_etn0();主要工作是初始化CPU Ethernet Mac模塊,GPIO口等等.

 detect_IC_PLUS_173T檢測IP173,成功返回1,反之返回0.

 讀寄存器流程:

    將PHY地址右移或上地址寫入地址寄存器(見圖三),因爲zzzz有兩種讀,循環讀和單次讀,所以需要寫1到命令寄存器。等待讀完成。從讀寄存器讀出值。

 寫寄存器流程:

    將PHY地址右移或上地址寫入地址寄存器,將要寫的值寫入寫寄存器。等待寫完成。

 

                                                          圖(一)

  

                                     圖(二) CPU Ethernet Mac 模塊的寄存器(部分)

  

 

      

                                                                           圖(三)

    

(向網口設備虛擬層eth_device註冊各類操作函數和數據。

檢測到IP173之後,start_armboot會繼續完成其他初始化工作,如FLASHSDRAM,串口、中斷、環境變量等等,期間會設置IP地址

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

然後調用eth_initialize()函數。之後等待用戶輸入命令或者啓動kernel 

 

eth_initialize()大致流程是調用具體的網卡驅動程序(ip3912_send,ip3912_recv)來初始化網口設備虛擬層的框架(eth_device->send,eth_device->recv),這些程序爲應用程序如pingtftpboot提供服務(如PingSendTftpSend等)

 

 

eth_initialize()位於net/eth.c文件內,eth.c就是網口設備虛擬層的源碼,其提供eth_initializeeth_registereth_get_deveth_initeth_halteth_sendeth_rxeth_receiveeth_try_another

eth_set_current等函數。

 

eth.c文件被#ifdef CONFIG_NET_MULTI分成兩部分,關於CONFIG_NET_MULTI的含義參考附錄一。

eth.c的主要數據結構如下:

[objc]  view plain  copy
  1. struct eth_device {  
  2.     char name[NAMESIZE]; //設備名  
  3.     unsigned char enetaddr[6];  // mac 地址  
  4.     int iobase;  
  5.     int state;   
  6.     int  (*init) (struct eth_device*, bd_t*);  
  7.     int  (*send) (struct eth_device*, volatile void* packet, int length);  
  8.     int  (*recv) (struct eth_device*);  
  9.     void (*halt) (struct eth_device*);  
  10.     #ifdef CONFIG_MCAST_TFTP  
  11.         int (*mcast) (struct eth_device*, u32 ip, u8 set);  
  12.     #endif  
  13.     int  (*write_hwaddr) (struct eth_device*);  //設置MAC的函數  
  14.     struct eth_device *next; // 指向下一個網口設備  
  15.     voidvoid *priv;  
  16. };  


當要支持多播TFTP時,必須開啓CONFIG_MCAST_TFTP,並定義mcast()函數(見readme)。 

下面來具體看下 eth_initialize函數

[objc]  view plain  copy
  1. int eth_initialize(bd_t *bis)  
  2. {  
  3.     unsigned char env_enetaddr[6];  
  4.     int eth_number = 0;  
  5.    
  6.     eth_devices = NULL;  
  7.     eth_current = NULL;  //註釋1  
  8.    
  9.     show_boot_progress (64);  
  10.       
  11.     miiphy_init(); //註釋2  
  12.    
  13.     //設置 eth_devices =eth_current = netdev, netdev含有IP3912的 init,send ,recv ,priv等    
  14.     //信息,也會設置 mii_devs和 current_mii   
  15.     if (board_eth_init(bis) < 0)  //註釋3   
  16.         cpu_eth_init(bis);  
  17.     if (!eth_devices) {  
  18.         puts ("No ethernet found.\n");  
  19.         show_boot_progress (-64);  
  20.     } else {  
  21.         struct eth_device *dev = eth_devices;  
  22.         charchar *ethprime = getenv ("ethprime");   
  23.         show_boot_progress (65);  
  24.     do {   
  25.          // 比較dev->enetaddr中MAC地址和environment中的MAC地址是否一致,  
  26.          // 不一致則調用dev->write_hwaddr 函數來修改MAC地址,以environment中的    
  27.          // 爲準,如果dev->write_hwaddr 爲空,或者設置了環境變量ethmacskip就會跳   
  28.          //過該步驟。如果有多個網口設備,會循環執行上述步驟。  
  29.          if (eth_number)  
  30.              puts (", ");  
  31.          printf("%s", dev->name);  
  32.          if (ethprime && strcmp (dev->name, ethprime) == 0) {  
  33.             eth_current = dev;  
  34.             puts (" [PRIME]");  
  35.         }  
  36.         if (strchr(dev->name, ' '))  
  37.             puts("\nWarning: eth device name has a space!\n");  
  38.    
  39.         eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);  
  40.    
  41.         if (memcmp(env_enetaddr, "\0\0\0\0\0\0"6)) {  
  42.             if (memcmp(dev->enetaddr, "\0\0\0\0\0\0"6) &&  
  43.                memcmp(dev->enetaddr, env_enetaddr, 6))  
  44.             {  
  45.                 printf ("\nWarning: %s MAC addresses don't match:\n",dev->name);  
  46.                 printf ("Address in SROM is         %pM\n",dev->enetaddr);  
  47.                 printf ("Address in environment is  %pM\n",env_enetaddr);  
  48.             }  
  49.             memcpy(dev->enetaddr, env_enetaddr, 6);  
  50.         }  
  51.         if (dev->write_hwaddr &&  
  52.             !eth_mac_skip(eth_number) &&  
  53.             is_valid_ether_addr(dev->enetaddr)) {  
  54.                  dev->write_hwaddr(dev);  
  55.         }  
  56.         eth_number++;  
  57.         dev = dev->next;  
  58.     } while(dev != eth_devices);  
  59.     /* update current ethernet name */  
  60.     if (eth_current) {  
  61.         charchar *act = getenv("ethact");  
  62.         if (act == NULL || strcmp(act, eth_current->name) != 0)  
  63.             setenv("ethact", eth_current->name);  
  64.         } else  
  65.             setenv("ethact"NULL);  
  66.          putc ('\n');  
  67.     }  
  68.     return eth_number;  
  69. }  


執行完該函數後,eth_current指向正在使用的eth_device,該結構體裏有init,send,recv 等函數以及MAC地址enetaddr,狀態state,設備名name等等。如果有多個網口設備,則他們的eth_device會依次存放在eth_device->next所指向的鏈表裏。

 

瀏覽IP3912.c會發現若要編寫網口的驅動程序,需要編寫ip3912_eth_initialize初始化函數,用來向網口設備虛擬層註冊,編寫ip3912_haltip3912_recvip3912_sendip3912_init

網口設備虛擬層eth_device所需要的函數。若需要註冊MII設備,則還需要編寫ip3912_miiphy_write ip3912_miiphy_read等函數。

 

 

註釋1

eth_current比較重要,因爲tftpsend等函數最終會調用該變量指向的eth_device中的函數。

[objc]  view plain  copy
  1. int eth_send(volatile voidvoid *packet, int length)  
  2. {  
  3.     if (!eth_current)  
  4.         return -1;  
  5.     return eth_current->send(eth_current, packet, length);  
  6. }  


註釋2

[objc]  view plain  copy
  1. void miiphy_init(void)  
  2. {  
  3.     INIT_LIST_HEAD (&mii_devs);  
  4.     current_mii = NULL;  
  5. }  
  6. struct mii_dev {  
  7.     struct list_head link;  
  8.     const charchar *name;  
  9.     int (*read) (const charchar *devname, unsigned char addr,unsigned char reg, unsigned shortshort *value);  
  10.     int (*write) (const charchar *devname, unsigned char addr,  
  11. };  

IP3912 屬於 PHY 層,其驅動程序會調用 miiphy_register  註冊一個 mii_dev

註釋3

board_eth_init() 是屬於具體開發板範疇,本例位於board/dspg/firetux/firetux.c內,

主要工作是調用板子所用網口芯片(IP3912)的初始化函數。

[objc]  view plain  copy
  1. int board_eth_init(bd_t *bis)  
  2. {  
  3.     ...  
  4.     ip3912_miiphy_initialize(gd->bd);  
  5.     ...  
  6.     ip3912_eth_initialize(0,CONFIG_IP3912_ETN1_BASE,CONFIG_IP3912_ETN1_BASE, 0x01);  
  7.     ...  
  8.     setenv("ethact""ETN1");  
  9.     eth_set_current(); //一般會在ip3912_eth_initialize這些具體設備的初始化函數中調用。  
  10. }  

int ip3912_miiphy_initialize(bd_t *bis)

[objc]  view plain  copy
  1. {  
  2.     miiphy_register("ip3912", ip3912_miiphy_read, ip3912_miiphy_write);  
  3.     return 0;  
  4. }  

[objc]  view plain  copy
  1. void miiphy_register(const charchar *name,  
  2.       int (*read) (const charchar *devname, unsigned char addr,  
  3.    unsigned char reg, unsigned shortshort *value),  
  4.       int (*write) (const charchar *devname, unsigned char addr,  
  5.     unsigned char reg, unsigned short value))  
  6. {  
  7.     ...  
  8.     //檢查是否已經註冊了一個同名的mii設備  
  9.     new_dev = miiphy_get_dev_by_name(name, 1);  
  10.     // 是則直接退出  
  11.     if (new_dev) {   
  12.         printf("miiphy_register: non unique device name '%s'\n", name);  
  13.         return;  
  14.     }  
  15.     // 反之,分配一個新的MII設備  
  16.     name_len = strlen (name);  
  17.     new_dev =  (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1);  
  18.     //隨後初始化這個新的MII設備, 如read ,write函數  
  19.     memset (new_dev, 0sizeof (struct mii_dev) + name_len);  
  20.    
  21.     /* initalize mii_dev struct fields */  
  22.     INIT_LIST_HEAD (&new_dev->link);  
  23.     new_dev->read = read;  
  24.     new_dev->write = write;  
  25.     new_dev->name = new_name = (charchar *)(new_dev + 1);  
  26.     strncpy (new_name, name, name_len);  
  27.     new_name[name_len] = '\0';  
  28.     // 將新的MII設備 添加到 mii_devs 列表中,並設置current_mii   
  29.     // mii_devs 和current_mii 在eth_initialize()中初始化  
  30.     list_add_tail (&new_dev->link, &mii_devs);  
  31.     if (!current_mii)  
  32.     current_mii = new_dev;  
  33. }  

接着分析函數 ip3912_eth_initialize (),其主要數據結構是

[objc]  view plain  copy
  1. struct ip3912_device {  
  2.     unsigned int     etn_base;  
  3.     unsigned int     phy_base;  
  4.     unsigned char    nr;  
  5.     unsigned char    phy_addr;  
  6.     unsigned char    autonegotiate;  
  7.     unsigned char    speed;  
  8.     unsigned char    duplex;  
  9.     unsigned char    rmii;  
  10.    
  11.     const struct device *  dev;  
  12.     struct eth_device *    netdev;  
  13. };  


可以看到ip3912_device包含了基本的eth_device結構。

 

[objc]  view plain  copy
  1. int ip3912_eth_initialize(unsigned char nr, unsigned int etn_base, unsigned int phy_base, unsigned char phy_addr, unsigned char rmii)  
  2. {  
  3.     struct ip3912_device *ip3912;   
  4.     struct eth_device *netdev;  
  5.    
  6.     // 分配 eth_device 和 ip3912_device設備所需內存,並初始化。  
  7.     netdev = malloc(sizeof(struct eth_device));  
  8.     ip3912 = malloc(sizeof(struct ip3912_device));  
  9.     if ((!ip3912) || (!netdev)) {  
  10.         printf("Error: Failed to allocate memory for ETN%d\n", nr + 1);  
  11.         return -1;  
  12.     }  
  13.    
  14.     memset(ip39120sizeof(struct ip3912_device));  
  15.     memset(netdev, 0sizeof(struct eth_device));  
  16.    
  17.     //初始化具體網口設備的私有數據  
  18.     ip3912->nr = nr;  
  19.     ip3912->etn_base = etn_base;  
  20.     ip3912->phy_base = phy_base;  
  21.     ip3912->phy_addr = phy_addr;  
  22.     ip3912->autonegotiate = 0;  
  23.     ip3912->rmii = rmii;  
  24.     ip3912->speed = 0;  
  25.     ip3912->duplex = 0;  
  26.     ip3912->netdev = netdev;  
  27.    
  28.     // 用具體網口設備IP3912的操作函數來初始化網口設備虛擬層netdev,  
  29.     // 注意最後一項  
  30.     sprintf(netdev->name, "ETN%d", nr + 1);  
  31.     netdev->init = ip3912_init;  
  32.     netdev->send = ip3912_send;  
  33.     netdev->recv = ip3912_recv;  
  34.     netdev->halt = ip3912_halt;  
  35.     netdev->priv = (voidvoid *)ip3912;   
  36.    
  37.     //將eth_current 設置爲新的netdev,並設置「ethact」,並設置狀態state = ETH_STATE_INIT  
  38.     eth_register(netdev); // 註釋3.1   
  39.     eth_set_current();  
  40.     ip3912_macreset(); // 初始化CPU Ethernet Mac模塊   
  41.     /* we have to set the mac address, because we have no SROM */  
  42.     //讀取環境變量,設置MAC地址  
  43.     ip3912_setmac(netdev); // 註釋3.2    
  44.     return 0;  
  45. }  


註釋3.1

[objc]  view plain  copy
  1. int eth_register(struct eth_device* dev)  
  2. {  
  3.     struct eth_device *d;  
  4.    
  5.     if (!eth_devices) {  
  6.         eth_current = eth_devices = dev;  
  7.         {  
  8.         charchar *act = getenv("ethact");  
  9.         if (act == NULL || strcmp(act, eth_current->name) != 0)  
  10.         setenv("ethact", eth_current->name);  
  11.         }  
  12.     } else {  
  13.         for (d=eth_devices; d->next!=eth_devices; d=d->next)  
  14.         ;  
  15.         d->next = dev;  
  16.     }  
  17.    
  18.     dev->state = ETH_STATE_INIT;  
  19.     dev->next  = eth_devices;  
  20.     return 0;  
  21. }  

註釋3.2

[objc]  view plain  copy
  1. void ip3912_setmac(struct eth_device *netdev)  
  2. {  
  3.     struct ip3912_device *ip3912;  
  4.     unsigned char i, use_etn1addr = 0;  
  5.     charchar *mac_string, *pmac, *end;  
  6.     char tmp[18];  
  7.    
  8.     ip3912 = netdev->priv;  
  9.    
  10.     mac_string = getenv("ethaddr");  
  11.     if (ip3912->nr) {  
  12.         /* we use ETN2 */  
  13.         mac_string = getenv("eth1addr");  
  14.         if (!mac_string) {  
  15.             mac_string = getenv("ethaddr");  
  16.             use_etn1addr = 1;  
  17.         }  
  18.     }  
  19.     pmac = mac_string;  
  20.     for (i = 0; i < 6; i++) {  
  21.         netdev->enetaddr[i] = pmac ? simple_strtoul(pmac, &end, 16) : 0;  
  22.         if (pmac)  
  23.             pmac = (*end) ? end + 1 : end;  
  24.     }  
  25.    
  26.     if (use_etn1addr) {  
  27.         /* flip last bit of mac address */  
  28.         debug("ip3912_setmac %s flipping last bit\n", netdev->name);  
  29.         if (netdev->enetaddr[5] & 1)  
  30.             netdev->enetaddr[5] &= 0xfe;  
  31.         else  
  32.             netdev->enetaddr[5] |= 0x01;  
  33.             sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X",  
  34.             netdev->enetaddr[0], netdev->enetaddr[1],  
  35.             netdev->enetaddr[2], netdev->enetaddr[3],  
  36.             netdev->enetaddr[4], netdev->enetaddr[5]);  
  37.             setenv("eth1addr", tmp);  
  38.             mac_string = tmp;  
  39.     }  
  40.     debug("ip3912_setmac set %s to address %s\n", netdev->name, mac_string);  
  41.    
  42.     writel((netdev->enetaddr[5] << 8) | netdev->enetaddr[4],  
  43.         (voidvoid *)(ip3912->etn_base + ETN_SA0));  
  44.     writel((netdev->enetaddr[3] << 8) | netdev->enetaddr[2],  
  45.         (voidvoid *)(ip3912->etn_base + ETN_SA1));  
  46.     writel((netdev->enetaddr[1] << 8) | netdev->enetaddr[0],  
  47.         (voidvoid *)(ip3912->etn_base + ETN_SA2));  
  48. }  

 

 

(三)應用層執行流程分析

Uboot支持的網絡協議有以下幾種

typedef enum 

{ BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP } proto_t;

 

 

先看下比較簡單的ping

[objc]  view plain  copy
  1. U_BOOT_CMD(  
  2.     ping,   2,  1,  do_ping,  
  3.     "send ICMP ECHO_REQUEST to network host",  
  4.     "pingAddress"  
  5. );  

[objc]  view plain  copy
  1. int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, charchar * const argv[])  
  2. {  
  3.     if (argc < 2)  
  4.         return -1;  
  5.     NetPingIP = string_to_ip(argv[1]);  
  6.     if (NetPingIP == 0)  
  7.         return cmd_usage(cmdtp);  
  8.     if (NetLoop(PING) < 0) {  
  9.         printf("ping failed; host %s is not alive\n", argv[1]);  
  10.         return 1;  
  11.     }  
  12.     printf("host %s is alive\n", argv[1]);  
  13. return 0;  
  14. }  


NetLoop像是一個應用層和網口設備虛擬層之間的一個接口,很多協議的處理都要經過該函數,如do_ping()函數中的NetLoop(PING)do_cdp()函數中的NetLoop(CDP), do_sntp()函數中的NetLoop(SNTP),.do_dns()函數中的NetLoop(DNS)。另外do_bootp() 會調用 netboot_common (BOOTP, cmdtp, argc, argv); do_tftpb() 會調用 netboot_common (TFTP, cmdtp, argc, argv);do_rarpb() 會調用netboot_common (RARP, cmdtp, argc, argv);do_dhcp()會調用netboot_common(DHCP, cmdtp, argc, argv);do_nfs ()會調用 netboot_common(NFS, cmdtp, argc, argv);netboot_common( (proto_t proto ,.....)仍會調用 NetLoop(proto)

 

do_ping()函數從命令行讀取IP地址後,存放在NetPingIP中。

接着執行NetLoop(PING)函數

 

下面分析int NetLoop(proto_t protocol)函數。

 

[objc]  view plain  copy
  1. #ifdef CONFIG_SYS_RX_ETH_BUFFER  
  2. # define PKTBUFSRX  CONFIG_SYS_RX_ETH_BUFFER  
  3. #else  
  4. # define PKTBUFSRX  4  
  5. #endif  
  6. #define PKTALIGN    32  
  7. #define PKTSIZE  1518  
  8. #define PKTSIZE_ALIGN    1536  
  9.    
  10. //靜態分配一個buffer  
  11. volatile uchar  PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];  
  12.    
  13. volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets  */  
  14.    
  15. volatile uchar *NetTxPacket = 0;    /* THE transmit packet   */  
  16.    
  17.    
  18.    
  19. Int NetLoop(proto_t protocol)  
  20. {  
  21.     bd_t *bd = gd->bd;  
  22.    
  23. <pre code_snippet_id="270100" snippet_file_name="blog_20140402_15_3725530" name="code" class="objc"><span style="font-family: Arial, Helvetica, sans-serif;">    #ifdef CONFIG_NET_MULTI</span></pre> NetRestarted = 0; NetDevExists = 0; #endif /* XXX problem with bss workaround */ NetArpWaitPacketMAC = NULL; NetArpWaitTxPacket = NULL; NetArpWaitPacketIP = 0; NetArpWaitReplyIP = 0; NetArpWaitTxPacket = NULL; NetTxPacket = NULL; NetTryCount  
  24.  = 1// 初始化各類發送,接收buffer指針。 if (!NetTxPacket) { int i; /* * Setup packet buffers, aligned correctly. */ NetTxPacket = &PktBuf[0] + (PKTALIGN - 1); NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; for (i = 0; i < PKTBUFSRX; i++) { NetRxPackets[i] = NetTxPacket  
  25.  + (i+1)*PKTSIZE_ALIGN; } } if (!NetArpWaitTxPacket) { NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1); NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN; NetArpWaitTxPacketSize = 0; } eth_halt(); //註釋1 #ifdef CONFIG_NET_MULTI eth_set_current();  
  26.  //設置環境變量"ethact"。如果已經設置,就直接退出。 #endif if (eth_init(bd) < 0) { //註釋2 eth_halt(); return(-1); } restart: #ifdef CONFIG_NET_MULTI memcpy (NetOurEther, eth_get_dev()->enetaddr, 6); // 設置 NetOurEther #else eth_getenv_enetaddr("ethaddr", NetOurEther); #endif NetState  
  27.  = NETLOOP_CONTINUE; // 設置 NetOurEther /* * Start the ball rolling with the given start function. From * here on, this code is a state machine driven by received * packets and timer events. */ // 設置 NetOurIP NetOurGatewayIP NetOurSubnetMask NetServerIP NetOurNativeVLAN  
  28.  // NetOurVLAN NetOurDNSIP NetInitLoop(protocol); switch (net_check_prereq (protocol)) { // 檢查所需要的參數是否都有合適的值 case 1: /* network not configured */ eth_halt(); return (-1); #ifdef CONFIG_NET_MULTI case 2: /* network device not configured */ break; #endif /* CONFIG_NET_MULTI  
  29.  */ case 0: #ifdef CONFIG_NET_MULTI NetDevExists = 1; #endif switch (protocol) { case TFTP/* always use ARP to get server ethernet address */ TftpStart(); break; #if defined(CONFIG_CMD_DHCP) case DHCP: BootpTry = 0; NetOurIP = 0; DhcpRequest(); /* Basically 
  30.  same as BOOTP */ break; #endif case BOOTP: BootpTry = 0; NetOurIP = 0; BootpRequest (); breakcase RARP: RarpTry = 0; NetOurIP = 0; RarpRequest (); break; #if defined(CONFIG_CMD_PING) case PING// 註釋3,執行ping 的實質函數。會發送ECHO REQUEST 數據包,並設置接收數據包時的處理函數和超時函數。  
  31.  PingStart(); break; #endif #if defined(CONFIG_CMD_NFS) case NFS: NfsStart(); break; #endif #if defined(CONFIG_CMD_CDP) case CDP: CDPStart(); break; #endif #ifdef CONFIG_NETCONSOLE case NETCONS: NcStart(); break; #endif #if defined(CONFIG_CMD_SNTP) case SNTP:  
  32.  SntpStart(); break; #endif #if defined(CONFIG_CMD_DNS) case DNS: DnsStart(); break; #endif defaultbreak; } NetBootFileXferSize = 0break; } /* * Main packet reception loop. Loop receiving packets until * someone sets `NetState' to a state that terminates. 
  33.  */ for (;;) { WATCHDOG_RESET();/* * Check the ethernet for a new packet. The ethernet * receive routine will process it. */ eth_rx(); // 循環接受數據包,註釋4/* * Abort if ctrl-c was pressed. */ if (ctrlc()) { eth_halt(); puts ("\nAbort\n"); return (-1); } ArpTimeoutCheck();  
  34.  /* * Check for a timeout, and run the timeout handler * if we have one. */ if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) { thand_f *x; x = timeHandler; timeHandler = (thand_f *)0; (*x)(); } switch (NetState) { case NETLOOP_RESTART: #ifdef CONFIG_NET_MULTI  
  35.  NetRestarted = 1; #endif goto restart; case NETLOOP_SUCCESS//若有接收文件,則打印文件大小,並設置環境變量filesize,fileaddr if (NetBootFileXferSize > 0) { char buf[20]; printf("Bytes transferred = %ld (%lx hex)\n", NetBootFileXferSize, NetBootFileXferSize); sprintf(buf, "%lX",  
  36.  NetBootFileXferSize); setenv("filesize", buf); sprintf(buf, "%lX", (unsigned long)load_addr); setenv("fileaddr", buf); } eth_halt(); return NetBootFileXferSize; case NETLOOP_FAILreturn (-1); } }}<p></p>  
  37. <pre></pre>  
  38. <br>  
  39. <br>  
  40. <p></p>  
  41. <p>註釋<span style="font-family:'Times New Roman'">1</span></p>  
  42. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_16_8643763" name="code" class="objc">void eth_halt(void)  
  43. {  
  44.     if (!eth_current)  
  45.         return;  
  46.     eth_current->halt(eth_current);  
  47.     eth_current->state = ETH_STATE_PASSIVE;  
  48. }</pre><br>  
  49. <p></p>  
  50. <p>調用網口設備虛擬層的<span style="font-family:Times New Roman">halt</span><span style="font-family:宋體">函數,該函數實際是具體網口設備</span><span style="font-family:Times New Roman">IP3912</span><span style="font-family:宋體">的</span><span style="font-family:Times New Roman">halt</span><span style="font-family:宋體">函數,</span></p>  
  51. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_17_738098" name="code" class="objc">static void ip3912_halt(struct eth_device *netdev)  
  52. {  
  53.     struct ip3912_device *ip3912 = netdev->priv;  
  54.    
  55. /* disable rx-path, tx-path, host registers reset 
  56.  * set FullDuplex, enable RMMI, disable rx+tx 
  57.  * no flow control, no frames<64b 
  58.  */  
  59.     writel(0x000006b8, (voidvoid *)(ip3912->etn_base + ETN_COMMAND));  
  60. }</pre><br>  
  61.  註釋<span style="font-family:'Times New Roman'">2</span><p></p>  
  62. <p>同理,<span style="font-family:Times New Roman">eth_init()</span><span style="font-family:宋體">會調用 </span><span style="font-family:Times New Roman">ip3912_init</span><span style="font-family:宋體">。 </span><span style="font-family:Times New Roman">ip3912_init</span><span style="font-family:宋體">主要完成數據包發送和接受之前的初始化工作,要參考</span><span style="font-family:Times New Roman">CPU</span><span style="font-family:宋體">數據手冊中</span><span style="font-family:Times New Roman">Ethernet Mac</span><span style="font-family:宋體">模塊如何收發數據包的文檔。其中,</span><span style="font-family:Times New Roman">ip3912_init_descriptors() </span><span style="font-family:宋體">和 </span><span style="font-family:Times New Roman">ip3912_mii_negotiate_phy()</span><span style="font-family:宋體">比較重要。</span></p>  
  63. <p>註釋<span style="font-family:Times New Roman">2</span><span style="font-family:宋體">、註釋</span><span style="font-family:Times New Roman">3.3</span><span style="font-family:宋體">和註釋</span><span style="font-family:Times New Roman">4</span><span style="font-family:宋體">的一部分 都是和具體網口設備相關的,可以先不看</span><span style="font-family:Times New Roman">,</span><span style="font-family:宋體">先把注意力放在上層程序</span><span style="font-family:Times New Roman">Netloop</span><span style="font-family:宋體">的執行流程和框架上。</span></p>  
  64. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_18_4194852" name="code" class="objc">int eth_init(bd_t *bis)  
  65. {  
  66.     ...  
  67.     eth_current->init(eth_current,bis)  
  68.     ...   
  69. }</pre><br>  
  70. <br>  
  71. <p></p>  
  72. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_19_2352472" name="code" class="objc">static int ip3912_init(struct eth_device *netdev, bd_t *bd)  
  73. {  
  74.     struct ip3912_device *ip3912 = netdev->priv;  
  75.    
  76.     /* update mac address in boardinfo */  
  77.     ip3912_setmac(netdev);  
  78.    
  79.     /* before enabling the rx-path we need to set up rx-descriptors */  
  80.     if (ip3912_init_descriptors(netdev))  
  81.         return -1;  
  82.    
  83.     /* set max packet length to 1536 bytes */  
  84.     writel(MAX_ETH_FRAME_SIZE, (voidvoid *)(ip3912->etn_base + ETN_MAXF));  
  85.     /* full duplex */  
  86.     writel(0x00000023, (voidvoid *)(ip3912->etn_base + ETN_MAC2));  
  87.     /* inter packet gap register */  
  88.     writel(0x15, (voidvoid *)(ip3912->etn_base + ETN_IPGT));  
  89.     writel(0x12, (voidvoid *)(ip3912->etn_base + ETN_IPGR));  
  90.     /* enable rx, receive all frames */  
  91.     writel(0x00000003, (voidvoid *)(ip3912->etn_base + ETN_MAC1));  
  92.     /* accept all multicast, broadcast and station packets */  
  93.     writel(0x00000026, (voidvoid *)(ip3912->etn_base + ETN_RXFILTERCTRL));  
  94.    
  95.     if (!l2_switch_present()) {  
  96.         /* reset MII mgmt, set MII clock */  
  97.         writel(0x0000801c, (voidvoid *)(ip3912->etn_base + ETN_MCFG));  
  98.         writel(0x0000001c, (voidvoid *)(ip3912->etn_base + ETN_MCFG));  
  99.     }  
  100.    /* release rx-path, tx-path, host registers reset 
  101.     * set FullDuplex, enable RMMI, enable rx+tx 
  102.     * no flow control, no frames<64b 
  103.     */  
  104.     writel(0x00000683, (voidvoid *)(ip3912->etn_base + ETN_COMMAND));  
  105.     ip3912_init_descriptors(netdev);  
  106.    
  107.     #ifdef CONFIG_DISCOVER_PHY  
  108.     mii_discover_phy();  
  109.     #endif  
  110.    
  111.     if (!l2_switch_present())            
  112.         /* init phy */  
  113.         mii_init_phy(ip3912->phy_addr);  
  114.     /* check autonegotiation */  
  115.     ip3912_i2cl2switch_negotiate_phy();  
  116.    
  117.     #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)  
  118.     /* check autonegotiation */  
  119.     if (!l2_switch_present())                   
  120.         ip3912_mii_negotiate_phy();  // 用於協商傳輸速率  
  121.     #endif  
  122.    
  123.     return 0;  
  124. }  
  125. static int ip3912_init_descriptors(struct eth_device *netdev)  
  126. {  
  127.     struct ip3912_device *ip3912;  
  128.     static voidvoid *rxbuf;  
  129.     int i;  
  130.    
  131.     ip3912 = netdev->priv;  
  132.    
  133.     /* fill in pointer in regs */  
  134.     writel((unsigned long)etn_rxdescriptor, (voidvoid *)(ip3912->etn_base + ETN_RXDESCRIPTOR));  
  135.     writel((unsigned long)etn_rxstatus, (voidvoid *)(ip3912->etn_base + ETN_RXSTATUS));  
  136.     writel(0x00000000, (voidvoid *)(ip3912->etn_base + ETN_RXCONSUMEINDEX));  
  137.     writel(CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER - 1,(voidvoid *)(ip3912->etn_base + ETN_RXDESCRIPTORNUMBER));  
  138.    
  139.     writel((unsigned long)etn_txdescriptor, (voidvoid *)(ip3912->etn_base + ETN_TXDESCRIPTOR));  
  140.     writel((unsigned long)etn_txstatus, (voidvoid *)(ip3912->etn_base + ETN_TXSTATUS));  
  141.     writel(0x00000000, (voidvoid *)(ip3912->etn_base + ETN_TXPRODUCEINDEX));  
  142.     writel(CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER - 1,(voidvoid *)(ip3912->etn_base + ETN_TXDESCRIPTORNUMBER));  
  143.    
  144.     /* allocate rx-buffers, but only once, we're called multiple times! */  
  145.     if (!rxbuf)  
  146.        rxbuf = malloc(MAX_ETH_FRAME_SIZE * CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER);  
  147.     if (!rxbuf) {  
  148.        puts("ERROR: couldn't allocate rx buffers!\n");  
  149.        return -1;  
  150.     }  
  151.    
  152.     for (i = 0; i < CONFIG_SYS_ETN_RX_DESCRIPTOR_NUMBER; i++) {  
  153.         etn_rxdescriptor[i].packet = rxbuf + i * MAX_ETH_FRAME_SIZE;  
  154.         etn_rxdescriptor[i].control = MAX_ETH_FRAME_SIZE - sizeof(unsigned long);  
  155.         etn_rxstatus[i].info = 0;  
  156.         etn_rxstatus[i].hashCRC = 0;  
  157.     }  
  158.     for (i = 0; i < CONFIG_SYS_ETN_TX_DESCRIPTOR_NUMBER; i++) {  
  159.         etn_txdescriptor[i].packet = 0;  
  160.         etn_txdescriptor[i].control = 0;  
  161.         etn_txstatus[i].info = 0;  
  162.    }  
  163.    return 0;  
  164. }</pre><br>  
  165. <br>  
  166. <p></p>  
  167. <p> </p>  
  168. <p>註釋<span style="font-family:Times New Roman">3 </span></p>  
  169. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_20_1415163" name="code" class="objc">static void PingStart(void)  
  170. {  
  171.     #if defined(CONFIG_NET_MULTI)  
  172.     printf ("Using %s device\n", eth_get_name());  
  173.     #endif  /* CONFIG_NET_MULTI */  
  174.     NetSetTimeout (10000UL, PingTimeout); //設置超時處理函數  
  175.     NetSetHandler (PingHandler);////設置數據包接收處理函數  
  176.    
  177.     PingSend(); //註釋3.1  
  178. }  
  179. Void NetSetTimeout(ulong iv, thand_f * f)  
  180. {  
  181.     if (iv == 0) {  
  182.         timeHandler = (thand_f *)0;  
  183.     } else {  
  184.         timeHandler = f;  
  185.         timeStart = get_timer(0);  
  186.         timeDelta = iv;  
  187.     }  
  188. }  
  189. Void NetSetHandler(rxhand_f * f)  
  190. {  
  191.     packetHandler = f;  
  192. }</pre><br>  
  193. <br>  
  194. <p></p>  
  195. <p> //<span style="font-family:宋體">註釋</span><span style="font-family:Times New Roman">3.1</span></p>  
  196. <p>發送<span style="font-family:Times New Roman">Echo request</span><span style="font-family:宋體">之前需要知道對方的</span><span style="font-family:Times New Roman">MAC</span><span style="font-family:宋體">地址,這需要發送</span><span style="font-family:Times New Roman">ARP</span><span style="font-family:宋體">數據包。所以</span><span style="font-family:Times New Roman">ARP</span><span style="font-family:宋體">數據包放在</span><span style="font-family:Times New Roman">NetTxPacket</span><span style="font-family:宋體">所指向的</span><span style="font-family:Times New Roman">buffer</span><span style="font-family:宋體">裏,而</span><span style="font-family:Times New Roman">Echo request </span><span style="font-family:宋體">數據包放在</span><span style="font-family:Times New Roman">NetArpWaitTxPacket</span><span style="font-family:宋體">所指向的</span><span style="font-family:Times New Roman">buffer</span><span style="font-family:宋體">裏,等查詢到對方的</span><span style="font-family:Times New Roman">MAC</span><span style="font-family:宋體">地址後,再發送出去。</span></p>  
  197. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_21_2221959" name="code" class="objc">int PingSend(void)   
  198. {  
  199.     static uchar mac[6];  
  200.     volatile IP_t *ip;  
  201.     volatile ushort *s;  
  202.     uchar *pkt;  
  203.     
  204.     /* XXX always send arp request */  
  205.    
  206.     /* 構造Echo  request  數據包,該數據包不會馬上發出,因爲目標硬件地址還是空的,   
  207.      * 會先發送ARP request數據包,當收到ARP reply 數據包後,再發送  Echo  request   
  208.      * 數據包 
  209.      */  
  210.     memcpy(mac, NetEtherNullAddr, 6);  
  211.     debug("sending ARP for %08lx\n", NetPingIP);  
  212.     NetArpWaitPacketIP = NetPingIP;  
  213.     NetArpWaitPacketMAC = mac;  
  214.    
  215.     /* 
  216.     *構造Ethernet II 協議頭部,目標硬件地址暫定爲00:00:00:00:00:00 
  217.     *源MAC地址是NetOurEther,是在NetLOOP()中初始化的。 
  218.     *幀類型是0x0806,PROT_ARP 
  219.     */  
  220.    
  221.     pkt = NetArpWaitTxPacket;  
  222.     pkt += NetSetEther(pkt, mac, PROT_IP);  
  223.    
  224.     ip = (volatile IP_t *)pkt;  
  225.    
  226.     /* 
  227.     * 構造IP協議和ICMP 數據包, 
  228.     */  
  229.    
  230.     /* 
  231.      *  Construct an IP and ICMP header.  (need to set no fragment bit - XXX) 
  232.      */  
  233.     ip->ip_hl_v  = 0x45;  /*版本號和 IP_HDR_SIZE / 4 (not including UDP) */  
  234.     ip->ip_tos   = 0;     //服務類型  
  235.     ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8); // 總長度  
  236.     ip->ip_id    = htons(NetIPID++); // 標示  
  237.     ip->ip_off   = htons(IP_FLAGS_DFRAG);    /* Don't fragment */ //片偏移  
  238.     ip->ip_ttl   = 255//生存時間  
  239.     ip->ip_p     = 0x01;  /* ICMP */ //協議類型  
  240.     ip->ip_sum   = 0;   
  241.     /*源IP地址和目的IP地址*/  
  242.     NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */  
  243.     NetCopyIP((void*)&ip->ip_dst, &NetPingIP);      /* - "" - */  
  244.     ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2); 校驗和  
  245.    
  246.     s = &ip->udp_src;     /* XXX ICMP starts here */  
  247.     s[0] = htons(0x0800);    /* echo-request, code *///請求回顯  
  248.     s[1] = 0;    /* checksum */  //校驗和  
  249.     s[2] = 0;    /* identifier */  //標示符  
  250.     s[3] = htons(PingSeqNo++);  /* sequence number */  // 序列號  
  251.     s[1] = ~NetCksum((uchar *)s, 8/2);   
  252.    
  253.     /* size of the waiting packet */  
  254.     NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;  
  255.    
  256.    /* 
  257.     *  設置Arp的超時時間的起始點,ArpTimeoutCheck()會處理ARP超時的問題 
  258.     */  
  259.     /* and do the ARP request */  
  260.     NetArpWaitTry = 1;  
  261.     NetArpWaitTimerStart = get_timer(0);  
  262.    /* 
  263.     *發送ARP request,退出pingsend(),程序會在NetLOOP中循環接收數據包,並調用處     
  264.     *理函數。 
  265.     */  
  266.     ArpRequest(); // 註釋3.2  
  267.     return 1;   /* waiting */  
  268. }</pre><img src="https://img-blog.csdn.net/20140402111638250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmFuYW94dWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>  
  269. <br>  
  270. <p></p>  
  271. <p>                                                         圖      將要發送的<span style="font-family:'Times New Roman'">ping echo request </span><span style="font-family:宋體">數據包</span></p>  
  272. <p>註釋<span style="font-family:Times New Roman">3.2</span></p>  
  273. <p>//<span style="font-family:宋體">發送</span><span style="font-family:Times New Roman">ARP request</span></p>  
  274. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_22_9125059" name="code" class="objc">void ArpRequest (void)  
  275. {  
  276.     int i;  
  277.     volatile uchar *pkt;  
  278.     ARP_t *arp;  
  279.    
  280.     debug("ARP broadcast %d\n", NetArpWaitTry);  
  281.    
  282.     pkt = NetTxPacket;  
  283.     /* 
  284.      *構造Ethernet II 協議頭部,NetBcastAddr是廣播地址,FF:FF:FF:FF:FF:FF 
  285.      *源MAC地址是NetOurEther,是在NetLOOP()中初始化的。 
  286.      *幀類型是0x0806,PROT_ARP 
  287.      */  
  288.     pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);  
  289.     /* 
  290.     * 構造ARP協議數據包, 
  291.     */  
  292.     arp = (ARP_t *) pkt;  
  293.     
  294.     arp->ar_hrd = htons (ARP_ETHER); //硬件類型ARP_ETHER = 1  表示以太網  
  295.     arp->ar_pro = htons (PROT_IP);    // 協議類型 表示要映射的協議地址類型  
  296.     arp->ar_hln = 6;  //硬件地址長度 MAC地址字節數  
  297.     arp->ar_pln = 4;  //協議地址長度 IP地址字節數  
  298.     arp->ar_op = htons (ARPOP_REQUEST); //操作類型ARPOP_REQUEST=1表示ARP請求  
  299.    
  300.     memcpy (&arp->ar_data[0], NetOurEther, 6);    /* source ET addr  */  
  301.     NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP);  /* source IP addr   */  
  302.     for (i = 10; i < 16; ++i) {   
  303.         arp->ar_data[i] = 0;  /* dest ET addr = 0     */  
  304.     }  
  305.     // 接收方的IP地址,若不在同一網段,需要設置環境變量gatewayip  
  306.     if ((NetArpWaitPacketIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) {  
  307.         if (NetOurGatewayIP == 0) {  
  308.             puts ("## Warning: gatewayip needed but not set\n");  
  309.             NetArpWaitReplyIP = NetArpWaitPacketIP;  
  310.         } else {  
  311.             NetArpWaitReplyIP = NetOurGatewayIP;  
  312.         }  
  313.     } else {  
  314.         NetArpWaitReplyIP = NetArpWaitPacketIP;  
  315.     }  
  316.    
  317.     NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);  
  318.     //調用發送函數,  
  319.     (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);註釋3.3  
  320. }</pre><br>  
  321. <img src="https://img-blog.csdn.net/20140402112024453?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmFuYW94dWU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>  
  322. <p></p>  
  323. <p>                                                 圖         發送的<span style="font-family:'Times New Roman'">ARP</span><span style="font-family:宋體">數據包</span></p>  
  324. <p>     </p>  
  325. <p> 註釋<span style="font-family:'Times New Roman'">3.3</span></p>  
  326. <p>//IP3912<span style="font-family:宋體">發送函數的原理,可以參照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋體">模塊章節</span></p>  
  327. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_23_2647853" name="code" class="objc">int eth_send(volatile voidvoid *packet, int length)  
  328. {  
  329.     if (!eth_current)  
  330.         return -1;  
  331.     return eth_current->send(eth_current, packet, length);  
  332. }</pre><span style="background-color:rgb(240,240,240)">static int ip3912_send(struct eth_device *netdev, volatile voidvoid *packet, int length)</span><p></p>  
  333. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_24_6519310" name="code" class="objc">{  
  334.    略  
  335. }</pre><p></p>  
  336. <p> </p>  
  337. <p>註釋<span style="font-family:'Times New Roman'">4</span></p>  
  338. <p>可以只看註釋<span style="font-family:Times New Roman">4.1</span></p>  
  339. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_25_5058614" name="code" class="objc">int eth_rx(void)  
  340. {  
  341.     if (!eth_current)  
  342.         return -1;  
  343.    
  344.     return eth_current->recv(eth_current);  
  345. }</pre><br>  
  346. <br>  
  347. <p></p>  
  348. <p>//IP3912<span style="font-family:宋體">接收函數的原理,可以參照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋體">模塊章節</span></p>  
  349. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_26_5865409" name="code" class="objc">/* Check for received packets */  
  350. static int ip3912_recv(struct eth_device *netdev)  
  351. {  
  352. 略  
  353. }</pre><br>  
  354.    
  355.     return eth_current->recv(eth_current);  
  356. }</pre><br>  
  357. <br>  
  358. <p></p>  
  359. <p>//IP3912<span style="font-family:宋體">接收函數的原理,可以參照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋體">模塊章節</span></p>  
  360. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_26_5865409" name="code" class="objc">/* Check for received packets */  
  361. static int ip3912_recv(struct eth_device *netdev)  
  362. {  
  363. 略  
  364. }</pre><br>  
  365. <p></p>  
  366. }</pre><br>  
  367. <br>  
  368. <p></p>  
  369. <p>//IP3912<span style="font-family:宋體">接收函數的原理,可以參照</span><span style="font-family:Times New Roman">CPU Ethernet </span><span style="font-family:宋體">模塊章節</span></p>  
  370. <p></p><pre code_snippet_id="270100" snippet_file_name="blog_20140402_26_5865409" name="code" class="objc">/* Check for received packets */  
  371. static int ip3912_recv(struct eth_device *netdev)  
  372. {  
  373. 略  
  374. }</pre><br>  
  375. <p></p>  
  376. <p>註釋<span style="font-family:Times New Roman">struct eth_device *netdev)  
相關文章
相關標籤/搜索