cs89x0.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. /****************************************************************************
  2. * drivers/net/cs89x0.c
  3. *
  4. * Copyright (C) 2009-2011 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #if defined(CONFIG_NET) && defined(CONFIG_NET_CS89x0)
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <time.h>
  43. #include <string.h>
  44. #include <debug.h>
  45. #include <wdog.h>
  46. #include <errno.h>
  47. #include <nuttx/irq.h>
  48. #include <nuttx/arch.h>
  49. #include <nuttx/net/uip/uip.h>
  50. #include <nuttx/net/uip/uip-arp.h>
  51. #include <nuttx/net/uip/uip-arch.h>
  52. /****************************************************************************
  53. * Definitions
  54. ****************************************************************************/
  55. #error "Under construction -- do not use"
  56. /* CONFIG_CS89x0_NINTERFACES determines the number of physical interfaces
  57. * that will be supported.
  58. */
  59. #ifndef CONFIG_CS89x0_NINTERFACES
  60. # define CONFIG_CS89x0_NINTERFACES 1
  61. #endif
  62. /* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
  63. #define CS89x0_WDDELAY (1*CLK_TCK)
  64. #define CS89x0_POLLHSEC (1*2)
  65. /* TX timeout = 1 minute */
  66. #define CS89x0_TXTIMEOUT (60*CLK_TCK)
  67. /* This is a helper pointer for accessing the contents of the Ethernet header */
  68. #define BUF ((struct uip_eth_hdr *)cs89x0->cs_dev.d_buf)
  69. /* If there is only one CS89x0 instance, then mapping the CS89x0 IRQ to
  70. * a driver state instance is trivial.
  71. */
  72. #if CONFIG_CS89x0_NINTERFACES == 1
  73. # define cs89x0_mapirq(irq) g_cs89x0[0]
  74. #endif
  75. /****************************************************************************
  76. * Private Types
  77. ****************************************************************************/
  78. /****************************************************************************
  79. * Private Data
  80. ****************************************************************************/
  81. static FAR struct cs89x0_driver_s *g_cs89x0[CONFIG_CS89x0_NINTERFACES];
  82. /****************************************************************************
  83. * Private Function Prototypes
  84. ****************************************************************************/
  85. /* CS89x0 register access */
  86. static uint16_t cs89x0_getreg(struct cs89x0_driver_s *cs89x0, int offset);
  87. static void cs89x0_putreg(struct cs89x0_driver_s *cs89x0, int offset,
  88. uint16_t value);
  89. static uint16_t cs89x0_getppreg(struct cs89x0_driver_s *cs89x0, int addr);
  90. static void cs89x0_putppreg(struct cs89x0_driver_s *cs89x0, int addr,
  91. uint16_t value);
  92. /* Common TX logic */
  93. static int cs89x0_transmit(struct cs89x0_driver_s *cs89x0);
  94. static int cs89x0_uiptxpoll(struct uip_driver_s *dev);
  95. /* Interrupt handling */
  96. static void cs89x0_receive(struct cs89x0_driver_s *cs89x0);
  97. static void cs89x0_txdone(struct cs89x0_driver_s *cs89x0, uint16_t isq);
  98. #if CONFIG_CS89x0_NINTERFACES > 1
  99. static inline FAR struct cs89x0_driver_s *cs89x0_mapirq(int irq);
  100. #endif
  101. static int cs89x0_interrupt(int irq, FAR void *context);
  102. /* Watchdog timer expirations */
  103. static void cs89x0_polltimer(int argc, uint32_t arg, ...);
  104. static void cs89x0_txtimeout(int argc, uint32_t arg, ...);
  105. /* NuttX callback functions */
  106. static int cs89x0_ifup(struct uip_driver_s *dev);
  107. static int cs89x0_ifdown(struct uip_driver_s *dev);
  108. static int cs89x0_txavail(struct uip_driver_s *dev);
  109. #ifdef CONFIG_NET_IGMP
  110. static int cs89x0_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
  111. static int cs89x0_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
  112. #endif
  113. /****************************************************************************
  114. * Private Functions
  115. ****************************************************************************/
  116. /****************************************************************************
  117. * Function: cs89x0_getreg and cs89x0_putreg
  118. *
  119. * Description:
  120. * Read from and write to a CS89x0 register
  121. *
  122. * Parameters:
  123. * cs89x0 - Reference to the driver state structure
  124. * offset - Offset to the CS89x0 register
  125. * value - Value to be written (cs89x0_putreg only)
  126. *
  127. * Returned Value:
  128. * cs89x0_getreg: The 16-bit value of the register
  129. * cs89x0_putreg: None
  130. *
  131. ****************************************************************************/
  132. static uint16_t cs89x0_getreg(struct cs89x0_driver_s *cs89x0, int offset)
  133. {
  134. #ifdef CONFIG_CS89x0_ALIGN16
  135. return getreg16(s89x0->cs_base + offset);
  136. #else
  137. return (uint16_t)getreg32(s89x0->cs_base + offset);
  138. #endif
  139. }
  140. static void cs89x0_putreg(struct cs89x0_driver_s *cs89x0, int offset, uint16_t value)
  141. {
  142. #ifdef CONFIG_CS89x0_ALIGN16
  143. return putreg16(value, s89x0->cs_base + offset);
  144. #else
  145. return (uint16_t)putreg32((uint32_t)value, s89x0->cs_base + offset);
  146. #endif
  147. }
  148. /****************************************************************************
  149. * Function: cs89x0_getppreg and cs89x0_putppreg
  150. *
  151. * Description:
  152. * Read from and write to a CS89x0 page packet register
  153. *
  154. * Parameters:
  155. * cs89x0 - Reference to the driver state structure
  156. * addr - Address of the CS89x0 page packet register
  157. * value - Value to be written (cs89x0_putppreg only)
  158. *
  159. * Returned Value:
  160. * cs89x0_getppreg: The 16-bit value of the page packet register
  161. * cs89x0_putppreg: None
  162. *
  163. ****************************************************************************/
  164. static uint16_t cs89x0_getppreg(struct cs89x0_driver_s *cs89x0, int addr)
  165. {
  166. /* In memory mode, the CS89x0's internal registers and frame buffers are mapped
  167. * into a contiguous 4kb block providing direct access to the internal registers
  168. * and frame buffers.
  169. */
  170. #ifdef CONFIG_CS89x0_MEMMODE
  171. if (cs89x0->cs_memmode)
  172. {
  173. #ifdef CONFIG_CS89x0_ALIGN16
  174. return getreg16(s89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??));
  175. #else
  176. return (uint16_t)getreg32(s89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??));
  177. #endif
  178. }
  179. /* When configured in I/O mode, the CS89x0 is accessed through eight, 16-bit
  180. * I/O ports that in the host system's I/O space.
  181. */
  182. else
  183. #endif
  184. {
  185. #ifdef CONFIG_CS89x0_ALIGN16
  186. putreg16((uint16_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET);
  187. return getreg16(s89x0->cs_base + CS89x0_PDATA_OFFSET);
  188. #else
  189. putreg32((uint32_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET);
  190. return (uint16_t)getreg32(s89x0->cs_base + CS89x0_PDATA_OFFSET);
  191. #endif
  192. }
  193. }
  194. static void cs89x0_putppreg(struct cs89x0_driver_s *cs89x0, int addr, uint16_t value)
  195. {
  196. /* In memory mode, the CS89x0's internal registers and frame buffers are mapped
  197. * into a contiguous 4kb block providing direct access to the internal registers
  198. * and frame buffers.
  199. */
  200. #ifdef CONFIG_CS89x0_MEMMODE
  201. if (cs89x0->cs_memmode)
  202. {
  203. #ifdef CONFIG_CS89x0_ALIGN16
  204. putreg16(value), cs89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??));
  205. #else
  206. putreg32((uint32_t)value, cs89x0->cs_ppbase + (CS89x0_PDATA_OFFSET << ??));
  207. #endif
  208. }
  209. /* When configured in I/O mode, the CS89x0 is accessed through eight, 16-bit
  210. * I/O ports that in the host system's I/O space.
  211. */
  212. else
  213. #endif
  214. {
  215. #ifdef CONFIG_CS89x0_ALIGN16
  216. putreg16((uint16_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET);
  217. putreg16(value, cs89x0->cs_base + CS89x0_PDATA_OFFSET);
  218. #else
  219. putreg32((uint32_t)addr, cs89x0->cs_base + CS89x0_PPTR_OFFSET);
  220. putreg32((uint32_t)value, cs89x0->cs_base + CS89x0_PDATA_OFFSET);
  221. #endif
  222. }
  223. }
  224. /****************************************************************************
  225. * Function: cs89x0_transmit
  226. *
  227. * Description:
  228. * Start hardware transmission. Called either from the txdone interrupt
  229. * handling or from watchdog based polling.
  230. *
  231. * Parameters:
  232. * cs89x0 - Reference to the driver state structure
  233. *
  234. * Returned Value:
  235. * OK on success; a negated errno on failure
  236. *
  237. * Assumptions:
  238. *
  239. ****************************************************************************/
  240. static int cs89x0_transmit(struct cs89x0_driver_s *cs89x0)
  241. {
  242. /* Verify that the hardware is ready to send another packet */
  243. #warning "Missing logic"
  244. /* Increment statistics */
  245. #warning "Missing logic"
  246. /* Disable Ethernet interrupts */
  247. #warning "Missing logic"
  248. /* Send the packet: address=cs89x0->cs_dev.d_buf, length=cs89x0->cs_dev.d_len */
  249. #warning "Missing logic"
  250. /* Restore Ethernet interrupts */
  251. #warning "Missing logic"
  252. /* Setup the TX timeout watchdog (perhaps restarting the timer) */
  253. (void)wd_start(cs89x0->cs_txtimeout, CS89x0_TXTIMEOUT, cs89x0_txtimeout, 1, (uint32_t)cs89x0);
  254. return OK;
  255. }
  256. /****************************************************************************
  257. * Function: cs89x0_uiptxpoll
  258. *
  259. * Description:
  260. * The transmitter is available, check if uIP has any outgoing packets ready
  261. * to send. This is a callback from uip_poll(). uip_poll() may be called:
  262. *
  263. * 1. When the preceding TX packet send is complete,
  264. * 2. When the preceding TX packet send timesout and the interface is reset
  265. * 3. During normal TX polling
  266. *
  267. * Parameters:
  268. * dev - Reference to the NuttX driver state structure
  269. *
  270. * Returned Value:
  271. * OK on success; a negated errno on failure
  272. *
  273. * Assumptions:
  274. *
  275. ****************************************************************************/
  276. static int cs89x0_uiptxpoll(struct uip_driver_s *dev)
  277. {
  278. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private;
  279. /* If the polling resulted in data that should be sent out on the network,
  280. * the field d_len is set to a value > 0.
  281. */
  282. if (cs89x0->cs_dev.d_len > 0)
  283. {
  284. uip_arp_out(&cs89x0->cs_dev);
  285. cs89x0_transmit(cs89x0);
  286. /* Check if there is room in the CS89x0 to hold another packet. If not,
  287. * return a non-zero value to terminate the poll.
  288. */
  289. #warning "Missing logic"
  290. }
  291. /* If zero is returned, the polling will continue until all connections have
  292. * been examined.
  293. */
  294. return 0;
  295. }
  296. /****************************************************************************
  297. * Function: cs89x0_receive
  298. *
  299. * Description:
  300. * An interrupt was received indicating the availability of a new RX packet
  301. *
  302. * Parameters:
  303. * cs89x0 - Reference to the driver state structure
  304. * isq - Interrupt status queue value read by interrupt handler
  305. *
  306. * Returned Value:
  307. * None
  308. *
  309. * Assumptions:
  310. *
  311. ****************************************************************************/
  312. static void cs89x0_receive(struct cs89x0_driver_s *cs89x0, uint16_t isq)
  313. {
  314. uint16_t *dest;
  315. uint16_t rxlength;
  316. int nbytes;
  317. /* Check for errors and update statistics */
  318. rxlength = cs89x0_getreg(PPR_RXLENGTH);
  319. if ((isq & RX_OK) == 0)
  320. {
  321. #ifdef CONFIG_C89x0_STATISTICS
  322. cd89x0->cs_stats.rx_errors++;
  323. if ((isq & RX_RUNT) != 0)
  324. {
  325. cd89x0->cs_stats.rx_lengtherrors++;
  326. }
  327. if ((isq & RX_EXTRA_DATA) != 0)
  328. {
  329. cd89x0->cs_stats.rx_lengtherrors++;
  330. }
  331. if (isq & RX_CRC_ERROR) != 0)
  332. {
  333. if (!(isq & (RX_EXTRA_DATA|RX_RUNT)))
  334. {
  335. cd89x0->cs_stats.rx_crcerrors++;
  336. }
  337. }
  338. if ((isq & RX_DRIBBLE) != 0)
  339. {
  340. cd89x0->cs_stats.rx_frameerrors++;
  341. }
  342. #endif
  343. return;
  344. }
  345. /* Check if the packet is a valid size for the uIP buffer configuration */
  346. if (rxlength > ???)
  347. {
  348. #ifdef CONFIG_C89x0_STATISTICS
  349. cd89x0->cs_stats.rx_errors++;
  350. cd89x0->cs_stats.rx_lengtherrors++;
  351. #endif
  352. return;
  353. }
  354. /* Copy the data data from the hardware to cs89x0->cs_dev.d_buf. Set
  355. * amount of data in cs89x0->cs_dev.d_len
  356. */
  357. dest = (uint16_t*)cs89x0->cs_dev.d_buf;
  358. for (nbytes = 0; nbytes < rxlength; nbytes += sizeof(uint16_t))
  359. {
  360. *dest++ = cs89x0_getreg(PPR_RXFRAMELOCATION);
  361. }
  362. #ifdef CONFIG_C89x0_STATISTICS
  363. cd89x0->cs_stats.rx_packets++;
  364. #endif
  365. /* We only accept IP packets of the configured type and ARP packets */
  366. #ifdef CONFIG_NET_IPv6
  367. if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
  368. #else
  369. if (BUF->type == HTONS(UIP_ETHTYPE_IP))
  370. #endif
  371. {
  372. uip_arp_ipin(&cs89x0->cs_dev);
  373. uip_input(&cs89x0->cs_dev);
  374. /* If the above function invocation resulted in data that should be
  375. * sent out on the network, the field d_len will set to a value > 0.
  376. */
  377. if (cs89x0->cs_dev.d_len > 0)
  378. {
  379. uip_arp_out(&cs89x0->cs_dev);
  380. cs89x0_transmit(cs89x0);
  381. }
  382. }
  383. else if (BUF->type == htons(UIP_ETHTYPE_ARP))
  384. {
  385. uip_arp_arpin(&cs89x0->cs_dev);
  386. /* If the above function invocation resulted in data that should be
  387. * sent out on the network, the field d_len will set to a value > 0.
  388. */
  389. if (cs89x0->cs_dev.d_len > 0)
  390. {
  391. cs89x0_transmit(cs89x0);
  392. }
  393. }
  394. }
  395. /****************************************************************************
  396. * Function: cs89x0_txdone
  397. *
  398. * Description:
  399. * An interrupt was received indicating that the last TX packet(s) is done
  400. *
  401. * Parameters:
  402. * cs89x0 - Reference to the driver state structure
  403. *
  404. * Returned Value:
  405. * None
  406. *
  407. * Assumptions:
  408. *
  409. ****************************************************************************/
  410. static void cs89x0_txdone(struct cs89x0_driver_s *cs89x0, uint16_t isq)
  411. {
  412. /* Check for errors and update statistics. The lower 6-bits of the ISQ
  413. * hold the register address causing the interrupt. We got here because
  414. * those bits indicated */
  415. #ifdef CONFIG_C89x0_STATISTICS
  416. cd89x0->cs_stats.tx_packets++;
  417. if ((isq & ISQ_TXEVENT_TXOK) == 0)
  418. {
  419. cd89x0->cs_stats.tx_errors++;
  420. }
  421. if ((isq & ISQ_TXEVENT_LOSSOFCRS) != 0)
  422. {
  423. cd89x0->cs_stats.tx_carriererrors++;
  424. }
  425. if ((isq & ISQ_TXEVENT_SQEERROR) != 0)
  426. {
  427. cd89x0->cs_stats.tx_heartbeaterrors++;
  428. }
  429. if (i(sq & ISQ_TXEVENT_OUTWINDOW) != 0)
  430. {
  431. cd89x0->cs_stats.tx_windowerrors++;
  432. }
  433. if (isq & TX_16_COL)
  434. {
  435. cd89x0->cs_stats.tx_abortederrors++;
  436. }
  437. #endif
  438. /* If no further xmits are pending, then cancel the TX timeout */
  439. wd_cancel(cs89x0->cs_txtimeout);
  440. /* Then poll uIP for new XMIT data */
  441. (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll);
  442. }
  443. /****************************************************************************
  444. * Function: cs89x0_mapirq
  445. *
  446. * Description:
  447. * Map an IRQ number to a CS89x0 device state instance. This is only
  448. * necessary to handler the case where the architecture includes more than
  449. * on CS89x0 chip.
  450. *
  451. * Parameters:
  452. * irq - Number of the IRQ that generated the interrupt
  453. *
  454. * Returned Value:
  455. * A reference to device state structure (NULL if irq does not correspond
  456. * to any CS89x0 device).
  457. *
  458. * Assumptions:
  459. *
  460. ****************************************************************************/
  461. #if CONFIG_CS89x0_NINTERFACES > 1
  462. static inline FAR struct cs89x0_driver_s *cs89x0_mapirq(int irq)
  463. {
  464. int i;
  465. for (i = 0; i < CONFIG_CS89x0_NINTERFACES; i++)
  466. {
  467. if (g_cs89x0[i] && g_cs89x0[i].irq == irq)
  468. {
  469. return g_cs89x0[i];
  470. }
  471. }
  472. return NULL;
  473. }
  474. #endif
  475. /****************************************************************************
  476. * Function: cs89x0_interrupt
  477. *
  478. * Description:
  479. * Hardware interrupt handler
  480. *
  481. * Parameters:
  482. * irq - Number of the IRQ that generated the interrupt
  483. * context - Interrupt register state save info (architecture-specific)
  484. *
  485. * Returned Value:
  486. * OK on success
  487. *
  488. * Assumptions:
  489. *
  490. ****************************************************************************/
  491. static int cs89x0_interrupt(int irq, FAR void *context)
  492. {
  493. register struct cs89x0_driver_s *cs89x0 = s89x0_mapirq(irq);
  494. uint16_t isq;
  495. #ifdef CONFIG_DEBUG
  496. if (!cs89x0)
  497. {
  498. return -ENODEV;
  499. }
  500. #endif
  501. /* Read and process all of the events from the ISQ */
  502. while ((isq = cs89x0_getreg(dev, CS89x0_ISQ_OFFSET)) != 0)
  503. {
  504. nvdbg("ISQ: %04x\n", isq);
  505. switch (isq & ISQ_EVENTMASK)
  506. {
  507. case ISQ_RXEVENT:
  508. cs89x0_receive(cs89x0);
  509. break;
  510. case ISQ_TXEVENT:
  511. cs89x0_txdone(cs89x0, isq);
  512. break;
  513. case ISQ_BUFEVENT:
  514. if ((isq & ISQ_BUFEVENT_TXUNDERRUN) != 0)
  515. {
  516. ndbg("Transmit underrun\n");
  517. #ifdef CONFIG_CS89x0_XMITEARLY
  518. cd89x0->cs_txunderrun++;
  519. if (cd89x0->cs_txunderrun == 3)
  520. {
  521. cd89x0->cs_txstart = PPR_TXCMD_TXSTART381;
  522. }
  523. else if (cd89x0->cs_txunderrun == 6)
  524. {
  525. cd89x0->cs_txstart = PPR_TXCMD_TXSTARTFULL;
  526. }
  527. #endif
  528. }
  529. break;
  530. case ISQ_RXMISSEVENT:
  531. #ifdef CONFIG_C89x0_STATISTICS
  532. cd89x0->cs_stats.rx_missederrors += (isq >>6);
  533. #endif
  534. break;
  535. case ISQ_TXCOLEVENT:
  536. #ifdef CONFIG_C89x0_STATISTICS
  537. cd89x0->cs_stats.collisions += (isq >>6);
  538. #endif
  539. break;
  540. }
  541. }
  542. return OK;
  543. }
  544. /****************************************************************************
  545. * Function: cs89x0_txtimeout
  546. *
  547. * Description:
  548. * Our TX watchdog timed out. Called from the timer interrupt handler.
  549. * The last TX never completed. Reset the hardware and start again.
  550. *
  551. * Parameters:
  552. * argc - The number of available arguments
  553. * arg - The first argument
  554. *
  555. * Returned Value:
  556. * None
  557. *
  558. * Assumptions:
  559. *
  560. ****************************************************************************/
  561. static void cs89x0_txtimeout(int argc, uint32_t arg, ...)
  562. {
  563. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)arg;
  564. /* Increment statistics and dump debug info */
  565. #warning "Missing logic"
  566. /* Then reset the hardware */
  567. #warning "Missing logic"
  568. /* Then poll uIP for new XMIT data */
  569. (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll);
  570. }
  571. /****************************************************************************
  572. * Function: cs89x0_polltimer
  573. *
  574. * Description:
  575. * Periodic timer handler. Called from the timer interrupt handler.
  576. *
  577. * Parameters:
  578. * argc - The number of available arguments
  579. * arg - The first argument
  580. *
  581. * Returned Value:
  582. * None
  583. *
  584. * Assumptions:
  585. *
  586. ****************************************************************************/
  587. static void cs89x0_polltimer(int argc, uint32_t arg, ...)
  588. {
  589. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)arg;
  590. /* Check if there is room in the send another TXr packet. */
  591. #warning "Missing logic"
  592. /* If so, update TCP timing states and poll uIP for new XMIT data */
  593. (void)uip_timer(&cs89x0->cs_dev, cs89x0_uiptxpoll, CS89x0_POLLHSEC);
  594. /* Setup the watchdog poll timer again */
  595. (void)wd_start(cs89x0->cs_txpoll, CS89x0_WDDELAY, cs89x0_polltimer, 1, arg);
  596. }
  597. /****************************************************************************
  598. * Function: cs89x0_ifup
  599. *
  600. * Description:
  601. * NuttX Callback: Bring up the Ethernet interface when an IP address is
  602. * provided
  603. *
  604. * Parameters:
  605. * dev - Reference to the NuttX driver state structure
  606. *
  607. * Returned Value:
  608. * None
  609. *
  610. * Assumptions:
  611. *
  612. ****************************************************************************/
  613. static int cs89x0_ifup(struct uip_driver_s *dev)
  614. {
  615. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private;
  616. ndbg("Bringing up: %d.%d.%d.%d\n",
  617. dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
  618. (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 );
  619. /* Initialize the Ethernet interface */
  620. #warning "Missing logic"
  621. /* Set and activate a timer process */
  622. (void)wd_start(cs89x0->cs_txpoll, CS89x0_WDDELAY, cs89x0_polltimer, 1, (uint32_t)cs89x0);
  623. /* Enable the Ethernet interrupt */
  624. cs89x0->cs_bifup = true;
  625. up_enable_irq(CONFIG_CS89x0_IRQ);
  626. return OK;
  627. }
  628. /****************************************************************************
  629. * Function: cs89x0_ifdown
  630. *
  631. * Description:
  632. * NuttX Callback: Stop the interface.
  633. *
  634. * Parameters:
  635. * dev - Reference to the NuttX driver state structure
  636. *
  637. * Returned Value:
  638. * None
  639. *
  640. * Assumptions:
  641. *
  642. ****************************************************************************/
  643. static int cs89x0_ifdown(struct uip_driver_s *dev)
  644. {
  645. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private;
  646. irqstate_t flags;
  647. /* Disable the Ethernet interrupt */
  648. flags = irqsave();
  649. up_disable_irq(CONFIG_CS89x0_IRQ);
  650. /* Cancel the TX poll timer and TX timeout timers */
  651. wd_cancel(cs89x0->cs_txpoll);
  652. wd_cancel(cs89x0->cs_txtimeout);
  653. /* Reset the device */
  654. cs89x0->cs_bifup = false;
  655. irqrestore(flags);
  656. return OK;
  657. }
  658. /****************************************************************************
  659. * Function: cs89x0_txavail
  660. *
  661. * Description:
  662. * Driver callback invoked when new TX data is available. This is a
  663. * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
  664. * latency.
  665. *
  666. * Parameters:
  667. * dev - Reference to the NuttX driver state structure
  668. *
  669. * Returned Value:
  670. * None
  671. *
  672. * Assumptions:
  673. * Called in normal user mode
  674. *
  675. ****************************************************************************/
  676. static int cs89x0_txavail(struct uip_driver_s *dev)
  677. {
  678. struct cs89x0_driver_s *cs89x0 = (struct cs89x0_driver_s *)dev->d_private;
  679. irqstate_t flags;
  680. flags = irqsave();
  681. /* Ignore the notification if the interface is not yet up */
  682. if (cs89x0->cs_bifup)
  683. {
  684. /* Check if there is room in the hardware to hold another outgoing packet. */
  685. #warning "Missing logic"
  686. /* If so, then poll uIP for new XMIT data */
  687. (void)uip_poll(&cs89x0->cs_dev, cs89x0_uiptxpoll);
  688. }
  689. irqrestore(flags);
  690. return OK;
  691. }
  692. /****************************************************************************
  693. * Function: cs89x0_addmac
  694. *
  695. * Description:
  696. * NuttX Callback: Add the specified MAC address to the hardware multicast
  697. * address filtering
  698. *
  699. * Parameters:
  700. * dev - Reference to the NuttX driver state structure
  701. * mac - The MAC address to be added
  702. *
  703. * Returned Value:
  704. * None
  705. *
  706. * Assumptions:
  707. *
  708. ****************************************************************************/
  709. #ifdef CONFIG_NET_IGMP
  710. static int cs89x0_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
  711. {
  712. FAR struct cs89x0_driver_s *priv = (FAR struct cs89x0_driver_s *)dev->d_private;
  713. /* Add the MAC address to the hardware multicast routing table */
  714. #warning "Multicast MAC support not implemented"
  715. return OK;
  716. }
  717. #endif
  718. /****************************************************************************
  719. * Function: cs89x0_rmmac
  720. *
  721. * Description:
  722. * NuttX Callback: Remove the specified MAC address from the hardware multicast
  723. * address filtering
  724. *
  725. * Parameters:
  726. * dev - Reference to the NuttX driver state structure
  727. * mac - The MAC address to be removed
  728. *
  729. * Returned Value:
  730. * None
  731. *
  732. * Assumptions:
  733. *
  734. ****************************************************************************/
  735. #ifdef CONFIG_NET_IGMP
  736. static int cs89x0_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
  737. {
  738. FAR struct cs89x0_driver_s *priv = (FAR struct cs89x0_driver_s *)dev->d_private;
  739. /* Add the MAC address to the hardware multicast routing table */
  740. #warning "Multicast MAC support not implemented"
  741. return OK;
  742. }
  743. #endif
  744. /****************************************************************************
  745. * Public Functions
  746. ****************************************************************************/
  747. /****************************************************************************
  748. * Function: cs89x0_initialize
  749. *
  750. * Description:
  751. * Initialize the Ethernet driver
  752. *
  753. * Parameters:
  754. * impl - decribes the implementation of the cs89x00 implementation.
  755. * This reference is retained so so must remain stable throughout the
  756. * life of the driver instance.
  757. * devno - Identifies the device number. This must be a number between
  758. * zero CONFIG_CS89x0_NINTERFACES and the same devno must not be
  759. * initialized twice. The associated network device will be referred
  760. * to with the name "eth" followed by this number (eth0, eth1, etc).
  761. *
  762. * Returned Value:
  763. * OK on success; Negated errno on failure.
  764. *
  765. * Assumptions:
  766. *
  767. ****************************************************************************/
  768. /* Initialize the CS89x0 chip and driver */
  769. int cs89x0_initialize(FAR const cs89x0_driver_s *cs89x0, int devno)
  770. {
  771. /* Sanity checks -- only performed with debug enabled */
  772. #ifdef CONFIG_DEBUG
  773. if (!cs89x0 || (unsigned)devno > CONFIG_CS89x0_NINTERFACES || g_cs89x00[devno])
  774. {
  775. return -EINVAL;
  776. }
  777. #endif
  778. /* Check if a Ethernet chip is recognized at its I/O base */
  779. #warning "Missing logic"
  780. /* Attach the IRQ to the driver */
  781. if (irq_attach(cs89x0->irq, cs89x0_interrupt))
  782. {
  783. /* We could not attach the ISR to the ISR */
  784. return -EAGAIN;
  785. }
  786. /* Initialize the driver structure */
  787. g_cs89x[devno] = cs89x0; /* Used to map IRQ back to instance */
  788. cs89x0->cs_dev.d_ifup = cs89x0_ifup; /* I/F down callback */
  789. cs89x0->cs_dev.d_ifdown = cs89x0_ifdown; /* I/F up (new IP address) callback */
  790. cs89x0->cs_dev.d_txavail = cs89x0_txavail; /* New TX data callback */
  791. #ifdef CONFIG_NET_IGMP
  792. cs89x0->cs_dev.d_addmac = cs89x0_addmac; /* Add multicast MAC address */
  793. cs89x0->cs_dev.d_rmmac = cs89x0_rmmac; /* Remove multicast MAC address */
  794. #endif
  795. cs89x0->cs_dev.d_private = (void*)cs89x0; /* Used to recover private state from dev */
  796. /* Create a watchdog for timing polling for and timing of transmisstions */
  797. cs89x0->cs_txpoll = wd_create(); /* Create periodic poll timer */
  798. cs89x0->cs_txtimeout = wd_create(); /* Create TX timeout timer */
  799. /* Read the MAC address from the hardware into cs89x0->cs_dev.d_mac.ether_addr_octet */
  800. /* Register the device with the OS so that socket IOCTLs can be performed */
  801. (void)netdev_register(&cs89x0->cs_dev);
  802. return OK;
  803. }
  804. #endif /* CONFIG_NET && CONFIG_NET_CS89x0 */