Eth.c工作之前的初始化
static struct eth_device *eth_devices, *eth_current;
Eth.c中有个eth_devices需要外部调用函数eth_register做初始化工作,其它函数(除eth_initialize外)都必须在这个初始化之后才能使用。
结构eth_devices是个循环链表,可包含多个eth_device。eth_register每次调用添加一个结构,调用多次可生成循环链表。eth_devices指向链表的第1个元素。
at91sam9260ek中先调用eth_initialize,在此函数中调用Eth.c:eth_register:
board.c:调用Eth.c:eth_initialize()
调用at91sam9260ek.c: board_eth_init()
调用macb.c: macb_eth_initialize()
调用Eth.c: eth_register()。
int eth_register(struct eth_device* dev) { struct eth_device *d;
if (!eth_devices) { eth_current = eth_devices = dev; #ifdef CONFIG_NET_MULTI /* update current ethernet name */ { char *act = getenv("ethact"); if (act == NULL || strcmp(act, eth_current->name) != 0) setenv("ethact", eth_current->name); } #endif } else { for (d=eth_devices; d->next!=eth_devices; d=d->next) ; d->next = dev; }
dev->state = ETH_STATE_INIT; dev->next = eth_devices;
return 0; } |
如果移植新的网卡驱动的话,应在board_eth_init中初始dev并调用eth_register。
eth_initialize
int eth_initialize(bd_t *bis) { unsigned char env_enetaddr[6]; int eth_number = 0;
eth_devices = NULL; eth_current = NULL;
show_boot_progress (64); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_init(); #endif /* Try board-specific initialization first. If it fails or isn't * present, try the cpu-specific initialization */ if (board_eth_init(bis) < 0) //调用board_eth_init,此函数内部实现初始化eth_devices和eth_current,并调用eth_register(struct eth_device* dev)。 cpu_eth_init(bis);
#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750) mv6436x_eth_initialize(bis); #endif #if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx) mv6446x_eth_initialize(bis); #endif if (!eth_devices) { puts ("No ethernet found./n"); show_boot_progress (-64); } else { struct eth_device *dev = eth_devices; char *ethprime = getenv ("ethprime");
show_boot_progress (65); do { if (eth_number) puts (", ");
printf("%s", dev->name);
//如果找到环境变量”ethprime”,则将eth_current指向当前eth_device。 if (ethprime && strcmp (dev->name, ethprime) == 0) { eth_current = dev; puts (" [PRIME]"); }
//读取环境变量“ethaddr”、“eth1addr”…设置的网络地址 eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);
//复制环境变量的网络地址到dev->enetadddr中。如果dev->write_hwaddr有效,写入到网卡的实际设备中。 if (memcmp(env_enetaddr, "/0/0/0/0/0/0", 6)) { if (memcmp(dev->enetaddr, "/0/0/0/0/0/0", 6) && memcmp(dev->enetaddr, env_enetaddr, 6)) { printf ("/nWarning: %s MAC addresses don't match:/n", dev->name); printf ("Address in SROM is %pM/n", dev->enetaddr); printf ("Address in environment is %pM/n", env_enetaddr); }
memcpy(dev->enetaddr, env_enetaddr, 6); } if (dev->write_hwaddr && !eth_mac_skip(eth_number) && is_valid_ether_addr(dev->enetaddr)) { dev->write_hwaddr(dev); }
eth_number++; dev = dev->next; } while(dev != eth_devices);
#ifdef CONFIG_NET_MULTI /* update current ethernet name */ if (eth_current) { char *act = getenv("ethact"); if (act == NULL || strcmp(act, eth_current->name) != 0) setenv("ethact", eth_current->name); } else setenv("ethact", NULL); #endif
putc ('/n'); }
return eth_number; } |
eth_init函数
使用eth_init必须定义宏CONFIG_RESET_PHY_R。在board.c:start_armboot函数中它调用reset_phy,再调用eth_init。
eth_init主要是要调用eth_current->init.
int eth_init(bd_t *bis) { int eth_number; struct eth_device *old_current, *dev;
if (!eth_current) { puts ("No ethernet found./n"); return -1; }
/* Sync environment with network devices */ eth_number = 0; dev = eth_devices; do { uchar env_enetaddr[6];
if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr)) memcpy(dev->enetaddr, env_enetaddr, 6);
++eth_number; dev = dev->next; } while (dev != eth_devices);
old_current = eth_current; do { debug("Trying %s/n", eth_current->name);
if (eth_current->init(eth_current,bis) >= 0) { eth_current->state = ETH_STATE_ACTIVE;
return 0; } debug("FAIL/n");
eth_try_another(0); } while (old_current != eth_current);
return -1; } |
NET有关的环境变量
(1) “ethaddr”表示网络地址,“eth1addr”、“eth2addr”表示第2个和第3个的网络地址;
(2) "ethact"表示eth_current网络地址的名称,eth_current改变后重新写入此环境变量;
(3) "ethprime"表示上电后初始eth_current的名称;
Env_common.c中有一个default_environment数组,可以在板子配置文件中定义相应的宏来定义相应的环境变量。