ether_bf537.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*
  2. * ADI Blackfin 537 MAC Ethernet
  3. *
  4. * Copyright (c) 2005 Analog Device, Inc.
  5. *
  6. * See file CREDITS for list of people who contributed to this
  7. * project.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of
  12. * the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22. * MA 02111-1307 USA
  23. */
  24. #include <common.h>
  25. #include <config.h>
  26. #include <asm/blackfin.h>
  27. #include <net.h>
  28. #include <command.h>
  29. #include <malloc.h>
  30. #include "ether_bf537.h"
  31. #ifdef CONFIG_POST
  32. #include <post.h>
  33. #endif
  34. #undef DEBUG_ETHERNET
  35. #ifdef DEBUG_ETHERNET
  36. #define DEBUGF(fmt,args...) printf(fmt,##args)
  37. #else
  38. #define DEBUGF(fmt,args...)
  39. #endif
  40. #if (CONFIG_COMMANDS & CFG_CMD_NET)
  41. #define RXBUF_BASE_ADDR 0xFF900000
  42. #define TXBUF_BASE_ADDR 0xFF800000
  43. #define TX_BUF_CNT 1
  44. #define TOUT_LOOP 1000000
  45. ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT];
  46. ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX];
  47. static u16 txIdx; /* index of the current RX buffer */
  48. static u16 rxIdx; /* index of the current TX buffer */
  49. u8 SrcAddr[6];
  50. u16 PHYregs[NO_PHY_REGS]; /* u16 PHYADDR; */
  51. /* DMAx_CONFIG values at DMA Restart */
  52. const ADI_DMA_CONFIG_REG rxdmacfg = { 1, 1, 2, 0, 0, 0, 0, 5, 7 };
  53. #if 0
  54. rxdmacfg.b_DMA_EN = 1; /* enabled */
  55. rxdmacfg.b_WNR = 1; /* write to memory */
  56. rxdmacfg.b_WDSIZE = 2; /* wordsize is 32 bits */
  57. rxdmacfg.b_DMA2D = 0; /* N/A */
  58. rxdmacfg.b_RESTART= 0; /* N/A */
  59. rxdmacfg.b_DI_SEL = 0; /* N/A */
  60. rxdmacfg.b_DI_EN = 0; /* no interrupt */
  61. rxdmacfg.b_NDSIZE = 5; /* 5 half words is desc size. */
  62. rxdmacfg.b_FLOW = 7; /* large desc flow */
  63. #endif
  64. const ADI_DMA_CONFIG_REG txdmacfg = { 1, 0, 2, 0, 0, 0, 0, 5, 7 };
  65. #if 0
  66. txdmacfg.b_DMA_EN = 1; /* enabled */
  67. txdmacfg.b_WNR = 0; /* read from memory */
  68. txdmacfg.b_WDSIZE = 2; /* wordsize is 32 bits */
  69. txdmacfg.b_DMA2D = 0; /* N/A */
  70. txdmacfg.b_RESTART= 0; /* N/A */
  71. txdmacfg.b_DI_SEL = 0; /* N/A */
  72. txdmacfg.b_DI_EN = 0; /* no interrupt */
  73. txdmacfg.b_NDSIZE = 5; /* 5 half words is desc size. */
  74. txdmacfg.b_FLOW = 7; /* large desc flow */
  75. #endif
  76. ADI_ETHER_BUFFER *SetupRxBuffer(int no);
  77. ADI_ETHER_BUFFER *SetupTxBuffer(int no);
  78. static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd);
  79. static void bfin_EMAC_halt(struct eth_device *dev);
  80. static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet,
  81. int length);
  82. static int bfin_EMAC_recv(struct eth_device *dev);
  83. int bfin_EMAC_initialize(bd_t * bis)
  84. {
  85. struct eth_device *dev;
  86. dev = (struct eth_device *)malloc(sizeof(*dev));
  87. if (dev == NULL)
  88. hang();
  89. memset(dev, 0, sizeof(*dev));
  90. sprintf(dev->name, "BF537 ETHERNET");
  91. dev->iobase = 0;
  92. dev->priv = 0;
  93. dev->init = bfin_EMAC_init;
  94. dev->halt = bfin_EMAC_halt;
  95. dev->send = bfin_EMAC_send;
  96. dev->recv = bfin_EMAC_recv;
  97. eth_register(dev);
  98. return 1;
  99. }
  100. static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet,
  101. int length)
  102. {
  103. int i;
  104. int result = 0;
  105. unsigned int *buf;
  106. buf = (unsigned int *)packet;
  107. if (length <= 0) {
  108. printf("Ethernet: bad packet size: %d\n", length);
  109. goto out;
  110. }
  111. if ((*pDMA2_IRQ_STATUS & DMA_ERR) != 0) {
  112. printf("Ethernet: tx DMA error\n");
  113. goto out;
  114. }
  115. for (i = 0; (*pDMA2_IRQ_STATUS & DMA_RUN) != 0; i++) {
  116. if (i > TOUT_LOOP) {
  117. puts("Ethernet: tx time out\n");
  118. goto out;
  119. }
  120. }
  121. txbuf[txIdx]->FrmData->NoBytes = length;
  122. memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length);
  123. txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData;
  124. *pDMA2_NEXT_DESC_PTR = &txbuf[txIdx]->Dma[0];
  125. *pDMA2_CONFIG = *(u16 *) (void *)(&txdmacfg);
  126. *pEMAC_OPMODE |= TE;
  127. for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) {
  128. if (i > TOUT_LOOP) {
  129. puts("Ethernet: tx error\n");
  130. goto out;
  131. }
  132. }
  133. result = txbuf[txIdx]->StatusWord;
  134. txbuf[txIdx]->StatusWord = 0;
  135. if ((txIdx + 1) >= TX_BUF_CNT)
  136. txIdx = 0;
  137. else
  138. txIdx++;
  139. out:
  140. DEBUGF("BFIN EMAC send: length = %d\n", length);
  141. return result;
  142. }
  143. static int bfin_EMAC_recv(struct eth_device *dev)
  144. {
  145. int length = 0;
  146. for (;;) {
  147. if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) {
  148. length = -1;
  149. break;
  150. }
  151. if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) {
  152. printf("Ethernet: rx dma overrun\n");
  153. break;
  154. }
  155. if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) {
  156. printf("Ethernet: rx error\n");
  157. break;
  158. }
  159. length = rxbuf[rxIdx]->StatusWord & 0x000007FF;
  160. if (length <= 4) {
  161. printf("Ethernet: bad frame\n");
  162. break;
  163. }
  164. NetRxPackets[rxIdx] =
  165. (volatile uchar *)(rxbuf[rxIdx]->FrmData->Dest);
  166. NetReceive(NetRxPackets[rxIdx], length - 4);
  167. *pDMA1_IRQ_STATUS |= DMA_DONE | DMA_ERR;
  168. rxbuf[rxIdx]->StatusWord = 0x00000000;
  169. if ((rxIdx + 1) >= PKTBUFSRX)
  170. rxIdx = 0;
  171. else
  172. rxIdx++;
  173. }
  174. return length;
  175. }
  176. /**************************************************************
  177. *
  178. * Ethernet Initialization Routine
  179. *
  180. *************************************************************/
  181. static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd)
  182. {
  183. u32 opmode;
  184. int dat;
  185. int i;
  186. DEBUGF("Eth_init: ......\n");
  187. txIdx = 0;
  188. rxIdx = 0;
  189. /* Initialize System Register */
  190. if (SetupSystemRegs(&dat) < 0)
  191. return -1;
  192. /* Initialize EMAC address */
  193. SetupMacAddr(SrcAddr);
  194. /* Initialize TX and RX buffer */
  195. for (i = 0; i < PKTBUFSRX; i++) {
  196. rxbuf[i] = SetupRxBuffer(i);
  197. if (i > 0) {
  198. rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR =
  199. &(rxbuf[i]->Dma[0]);
  200. if (i == (PKTBUFSRX - 1))
  201. rxbuf[i]->Dma[1].NEXT_DESC_PTR =
  202. &(rxbuf[0]->Dma[0]);
  203. }
  204. }
  205. for (i = 0; i < TX_BUF_CNT; i++) {
  206. txbuf[i] = SetupTxBuffer(i);
  207. if (i > 0) {
  208. txbuf[i - 1]->Dma[1].NEXT_DESC_PTR =
  209. &(txbuf[i]->Dma[0]);
  210. if (i == (TX_BUF_CNT - 1))
  211. txbuf[i]->Dma[1].NEXT_DESC_PTR =
  212. &(txbuf[0]->Dma[0]);
  213. }
  214. }
  215. /* Set RX DMA */
  216. *pDMA1_NEXT_DESC_PTR = &rxbuf[0]->Dma[0];
  217. *pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG);
  218. /* Wait MII done */
  219. PollMdcDone();
  220. /* We enable only RX here */
  221. /* ASTP : Enable Automatic Pad Stripping
  222. PR : Promiscuous Mode for test
  223. PSF : Receive frames with total length less than 64 bytes.
  224. FDMODE : Full Duplex Mode
  225. LB : Internal Loopback for test
  226. RE : Receiver Enable */
  227. if (dat == FDMODE)
  228. opmode = ASTP | FDMODE | PSF;
  229. else
  230. opmode = ASTP | PSF;
  231. opmode |= RE;
  232. #ifdef CONFIG_BFIN_MAC_RMII
  233. opmode |= TE | RMII;
  234. #endif
  235. /* Turn on the EMAC */
  236. *pEMAC_OPMODE = opmode;
  237. return 0;
  238. }
  239. static void bfin_EMAC_halt(struct eth_device *dev)
  240. {
  241. DEBUGF("Eth_halt: ......\n");
  242. /* Turn off the EMAC */
  243. *pEMAC_OPMODE = 0x00000000;
  244. /* Turn off the EMAC RX DMA */
  245. *pDMA1_CONFIG = 0x0000;
  246. *pDMA2_CONFIG = 0x0000;
  247. }
  248. void SetupMacAddr(u8 * MACaddr)
  249. {
  250. char *tmp, *end;
  251. int i;
  252. /* this depends on a little-endian machine */
  253. tmp = getenv("ethaddr");
  254. if (tmp) {
  255. for (i = 0; i < 6; i++) {
  256. MACaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
  257. if (tmp)
  258. tmp = (*end) ? end + 1 : end;
  259. }
  260. #ifndef CONFIG_NETCONSOLE
  261. printf("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n",
  262. MACaddr[0], MACaddr[1],
  263. MACaddr[2], MACaddr[3], MACaddr[4], MACaddr[5]);
  264. #endif
  265. *pEMAC_ADDRLO = MACaddr[0] | MACaddr[1] << 8 |
  266. MACaddr[2] << 16 | MACaddr[3] << 24;
  267. *pEMAC_ADDRHI = MACaddr[4] | MACaddr[5] << 8;
  268. }
  269. }
  270. void PollMdcDone(void)
  271. {
  272. /* poll the STABUSY bit */
  273. while (*pEMAC_STAADD & STABUSY) ;
  274. }
  275. void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data)
  276. {
  277. PollMdcDone();
  278. *pEMAC_STADAT = Data;
  279. *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
  280. STAOP | STAIE | STABUSY;
  281. }
  282. /*********************************************************************************
  283. * Read an off-chip register in a PHY through the MDC/MDIO port *
  284. *********************************************************************************/
  285. u16 RdPHYReg(u16 PHYAddr, u16 RegAddr)
  286. {
  287. u16 Data;
  288. PollMdcDone();
  289. *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
  290. STAIE | STABUSY;
  291. PollMdcDone();
  292. Data = (u16) * pEMAC_STADAT;
  293. PHYregs[RegAddr] = Data; /* save shadow copy */
  294. return Data;
  295. }
  296. void SoftResetPHY(void)
  297. {
  298. u16 phydat;
  299. /* set the reset bit */
  300. WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET);
  301. /* and clear it again */
  302. WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000);
  303. do {
  304. /* poll until reset is complete */
  305. phydat = RdPHYReg(PHYADDR, PHY_MODECTL);
  306. } while ((phydat & PHY_RESET) != 0);
  307. }
  308. int SetupSystemRegs(int *opmode)
  309. {
  310. u16 sysctl, phydat;
  311. int count = 0;
  312. /* Enable PHY output */
  313. *pVR_CTL |= PHYCLKOE;
  314. /* MDC = 2.5 MHz */
  315. sysctl = SET_MDCDIV(24);
  316. /* Odd word alignment for Receive Frame DMA word */
  317. /* Configure checksum support and rcve frame word alignment */
  318. sysctl |= RXDWA | RXCKS;
  319. *pEMAC_SYSCTL = sysctl;
  320. /* auto negotiation on */
  321. /* full duplex */
  322. /* 100 Mbps */
  323. phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
  324. WrPHYReg(PHYADDR, PHY_MODECTL, phydat);
  325. do {
  326. udelay(1000);
  327. phydat = RdPHYReg(PHYADDR, PHY_MODESTAT);
  328. if (count > 3000) {
  329. printf
  330. ("Link is down, please check your network connection\n");
  331. return -1;
  332. }
  333. count++;
  334. } while (!(phydat & 0x0004));
  335. phydat = RdPHYReg(PHYADDR, PHY_ANLPAR);
  336. if ((phydat & 0x0100) || (phydat & 0x0040))
  337. *opmode = FDMODE;
  338. else
  339. *opmode = 0;
  340. *pEMAC_MMC_CTL = RSTC | CROLL;
  341. /* Initialize the TX DMA channel registers */
  342. *pDMA2_X_COUNT = 0;
  343. *pDMA2_X_MODIFY = 4;
  344. *pDMA2_Y_COUNT = 0;
  345. *pDMA2_Y_MODIFY = 0;
  346. /* Initialize the RX DMA channel registers */
  347. *pDMA1_X_COUNT = 0;
  348. *pDMA1_X_MODIFY = 4;
  349. *pDMA1_Y_COUNT = 0;
  350. *pDMA1_Y_MODIFY = 0;
  351. return 0;
  352. }
  353. ADI_ETHER_BUFFER *SetupRxBuffer(int no)
  354. {
  355. ADI_ETHER_FRAME_BUFFER *frmbuf;
  356. ADI_ETHER_BUFFER *buf;
  357. int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
  358. int total_size = nobytes_buffer + RECV_BUFSIZE;
  359. buf = (ADI_ETHER_BUFFER *) (RXBUF_BASE_ADDR + no * total_size);
  360. frmbuf =
  361. (ADI_ETHER_FRAME_BUFFER *) (RXBUF_BASE_ADDR + no * total_size +
  362. nobytes_buffer);
  363. memset(buf, 0x00, nobytes_buffer);
  364. buf->FrmData = frmbuf;
  365. memset(frmbuf, 0xfe, RECV_BUFSIZE);
  366. /* set up first desc to point to receive frame buffer */
  367. buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
  368. buf->Dma[0].START_ADDR = (u32) buf->FrmData;
  369. buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
  370. buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */
  371. buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
  372. buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
  373. buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
  374. /* set up second desc to point to status word */
  375. buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
  376. buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum;
  377. buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
  378. buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
  379. buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
  380. buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
  381. buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */
  382. buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */
  383. return buf;
  384. }
  385. ADI_ETHER_BUFFER *SetupTxBuffer(int no)
  386. {
  387. ADI_ETHER_FRAME_BUFFER *frmbuf;
  388. ADI_ETHER_BUFFER *buf;
  389. int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */
  390. int total_size = nobytes_buffer + RECV_BUFSIZE;
  391. buf = (ADI_ETHER_BUFFER *) (TXBUF_BASE_ADDR + no * total_size);
  392. frmbuf =
  393. (ADI_ETHER_FRAME_BUFFER *) (TXBUF_BASE_ADDR + no * total_size +
  394. nobytes_buffer);
  395. memset(buf, 0x00, nobytes_buffer);
  396. buf->FrmData = frmbuf;
  397. memset(frmbuf, 0x00, RECV_BUFSIZE);
  398. /* set up first desc to point to receive frame buffer */
  399. buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]);
  400. buf->Dma[0].START_ADDR = (u32) buf->FrmData;
  401. buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */
  402. buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */
  403. buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
  404. buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */
  405. buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */
  406. /* set up second desc to point to status word */
  407. buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]);
  408. buf->Dma[1].START_ADDR = (u32) & buf->StatusWord;
  409. buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */
  410. buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */
  411. buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */
  412. buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */
  413. buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */
  414. buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */
  415. return buf;
  416. }
  417. #if defined(CONFIG_POST) && defined(CFG_POST_ETHER)
  418. int ether_post_test(int flags)
  419. {
  420. uchar buf[64];
  421. int i, value = 0;
  422. int length;
  423. printf("\n--------");
  424. bfin_EMAC_init(NULL, NULL);
  425. /* construct the package */
  426. buf[0] = buf[6] = (unsigned char)(*pEMAC_ADDRLO & 0xFF);
  427. buf[1] = buf[7] = (unsigned char)((*pEMAC_ADDRLO & 0xFF00) >> 8);
  428. buf[2] = buf[8] = (unsigned char)((*pEMAC_ADDRLO & 0xFF0000) >> 16);
  429. buf[3] = buf[9] = (unsigned char)((*pEMAC_ADDRLO & 0xFF000000) >> 24);
  430. buf[4] = buf[10] = (unsigned char)(*pEMAC_ADDRHI & 0xFF);
  431. buf[5] = buf[11] = (unsigned char)((*pEMAC_ADDRHI & 0xFF00) >> 8);
  432. buf[12] = 0x08; /* Type: ARP */
  433. buf[13] = 0x06;
  434. buf[14] = 0x00; /* Hardware type: Ethernet */
  435. buf[15] = 0x01;
  436. buf[16] = 0x08; /* Protocal type: IP */
  437. buf[17] = 0x00;
  438. buf[18] = 0x06; /* Hardware size */
  439. buf[19] = 0x04; /* Protocol size */
  440. buf[20] = 0x00; /* Opcode: request */
  441. buf[21] = 0x01;
  442. for (i = 0; i < 42; i++)
  443. buf[i + 22] = i;
  444. printf("--------Send 64 bytes......\n");
  445. bfin_EMAC_send(NULL, (volatile void *)buf, 64);
  446. for (i = 0; i < 100; i++) {
  447. udelay(10000);
  448. if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) {
  449. value = 1;
  450. break;
  451. }
  452. }
  453. if (value == 0) {
  454. printf("--------EMAC can't receive any data\n");
  455. eth_halt();
  456. return -1;
  457. }
  458. length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4;
  459. for (i = 0; i < length; i++) {
  460. if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) {
  461. printf("--------EMAC receive error data!\n");
  462. eth_halt();
  463. return -1;
  464. }
  465. }
  466. printf("--------receive %d bytes, matched\n", length);
  467. bfin_EMAC_halt(NULL);
  468. return 0;
  469. }
  470. #endif
  471. #endif /* CFG_CMD_NET */