skeleton.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. /****************************************************************************
  2. * drivers/net/skeleton.c
  3. *
  4. * Copyright (C) 2018 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. #include <stdint.h>
  40. #include <stdbool.h>
  41. #include <time.h>
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <assert.h>
  45. #include <debug.h>
  46. #include <arpa/inet.h>
  47. #include <nuttx/arch.h>
  48. #include <nuttx/irq.h>
  49. #include <nuttx/wdog.h>
  50. #include <nuttx/wqueue.h>
  51. #include <nuttx/net/arp.h>
  52. #include <nuttx/net/netdev.h>
  53. #ifdef CONFIG_NET_PKT
  54. # include <nuttx/net/pkt.h>
  55. #endif
  56. #ifdef CONFIG_NET_skeleton
  57. /****************************************************************************
  58. * Pre-processor Definitions
  59. ****************************************************************************/
  60. /* Work queue support is required. */
  61. #if !defined(CONFIG_SCHED_WORKQUEUE)
  62. # error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
  63. #else
  64. /* The low priority work queue is preferred. If it is not enabled, LPWORK
  65. * will be the same as HPWORK.
  66. *
  67. * NOTE: However, the network should NEVER run on the high priority work
  68. * queue! That queue is intended only to service short back end interrupt
  69. * processing that never suspends. Suspending the high priority work queue
  70. * may bring the system to its knees!
  71. */
  72. #define ETHWORK LPWORK
  73. /* CONFIG_skeleton_NINTERFACES determines the number of physical interfaces
  74. * that will be supported.
  75. */
  76. #ifndef CONFIG_skeleton_NINTERFACES
  77. # define CONFIG_skeleton_NINTERFACES 1
  78. #endif
  79. /* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
  80. #define skeleton_WDDELAY (1*CLK_TCK)
  81. /* TX timeout = 1 minute */
  82. #define skeleton_TXTIMEOUT (60*CLK_TCK)
  83. /* This is a helper pointer for accessing the contents of the Ethernet header */
  84. #define BUF ((struct eth_hdr_s *)priv->sk_dev.d_buf)
  85. /****************************************************************************
  86. * Private Types
  87. ****************************************************************************/
  88. /* The skel_driver_s encapsulates all state information for a single hardware
  89. * interface
  90. */
  91. struct skel_driver_s
  92. {
  93. bool sk_bifup; /* true:ifup false:ifdown */
  94. WDOG_ID sk_txpoll; /* TX poll timer */
  95. WDOG_ID sk_txtimeout; /* TX timeout timer */
  96. struct work_s sk_irqwork; /* For deferring interrupt work to the work queue */
  97. struct work_s sk_pollwork; /* For deferring poll work to the work queue */
  98. /* This holds the information visible to the NuttX network */
  99. struct net_driver_s sk_dev; /* Interface understood by the network */
  100. };
  101. /****************************************************************************
  102. * Private Data
  103. ****************************************************************************/
  104. /* These statically allocated structures would mean that only a single
  105. * instance of the device could be supported. In order to support multiple
  106. * devices instances, this data would have to be allocated dynamically.
  107. */
  108. /* A single packet buffer per device is used in this example. There might
  109. * be multiple packet buffers in a more complex, pipelined design. Many
  110. * contemporary Ethernet interfaces, for example, use multiple, linked DMA
  111. * descriptors in rings to implement such a pipeline. This example assumes
  112. * much simpler hardware that simply handles one packet at a time.
  113. *
  114. * NOTE that if CONFIG_skeleton_NINTERFACES were greater than 1, you would
  115. * need a minimum on one packet buffer per instance. Much better to be
  116. * allocated dynamically in cases where more than one are needed.
  117. */
  118. static uint8_t g_pktbuf[MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE];
  119. /* Driver state structure */
  120. static struct skel_driver_s g_skel[CONFIG_skeleton_NINTERFACES];
  121. /****************************************************************************
  122. * Private Function Prototypes
  123. ****************************************************************************/
  124. /* Common TX logic */
  125. static int skel_transmit(FAR struct skel_driver_s *priv);
  126. static int skel_txpoll(FAR struct net_driver_s *dev);
  127. /* Interrupt handling */
  128. static void skel_reply(struct skel_driver_s *priv)
  129. static void skel_receive(FAR struct skel_driver_s *priv);
  130. static void skel_txdone(FAR struct skel_driver_s *priv);
  131. static void skel_interrupt_work(FAR void *arg);
  132. static int skel_interrupt(int irq, FAR void *context, FAR void *arg);
  133. /* Watchdog timer expirations */
  134. static void skel_txtimeout_work(FAR void *arg);
  135. static void skel_txtimeout_expiry(int argc, wdparm_t arg, ...);
  136. static void skel_poll_work(FAR void *arg);
  137. static void skel_poll_expiry(int argc, wdparm_t arg, ...);
  138. /* NuttX callback functions */
  139. static int skel_ifup(FAR struct net_driver_s *dev);
  140. static int skel_ifdown(FAR struct net_driver_s *dev);
  141. static void skel_txavail_work(FAR void *arg);
  142. static int skel_txavail(FAR struct net_driver_s *dev);
  143. #if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
  144. static int skel_addmac(FAR struct net_driver_s *dev,
  145. FAR const uint8_t *mac);
  146. #ifdef CONFIG_NET_MCASTGROUP
  147. static int skel_rmmac(FAR struct net_driver_s *dev,
  148. FAR const uint8_t *mac);
  149. #endif
  150. #ifdef CONFIG_NET_ICMPv6
  151. static void skel_ipv6multicast(FAR struct skel_driver_s *priv);
  152. #endif
  153. #endif
  154. #ifdef CONFIG_NETDEV_IOCTL
  155. static int skel_ioctl(FAR struct net_driver_s *dev, int cmd,
  156. unsigned long arg);
  157. #endif
  158. /****************************************************************************
  159. * Private Functions
  160. ****************************************************************************/
  161. /****************************************************************************
  162. * Name: skel_transmit
  163. *
  164. * Description:
  165. * Start hardware transmission. Called either from the txdone interrupt
  166. * handling or from watchdog based polling.
  167. *
  168. * Input Parameters:
  169. * priv - Reference to the driver state structure
  170. *
  171. * Returned Value:
  172. * OK on success; a negated errno on failure
  173. *
  174. * Assumptions:
  175. * The network is locked.
  176. *
  177. ****************************************************************************/
  178. static int skel_transmit(FAR struct skel_driver_s *priv)
  179. {
  180. /* Verify that the hardware is ready to send another packet. If we get
  181. * here, then we are committed to sending a packet; Higher level logic
  182. * must have assured that there is no transmission in progress.
  183. */
  184. /* Increment statistics */
  185. NETDEV_TXPACKETS(priv->sk_dev);
  186. /* Send the packet: address=priv->sk_dev.d_buf, length=priv->sk_dev.d_len */
  187. /* Enable Tx interrupts */
  188. /* Setup the TX timeout watchdog (perhaps restarting the timer) */
  189. (void)wd_start(priv->sk_txtimeout, skeleton_TXTIMEOUT,
  190. skel_txtimeout_expiry, 1, (wdparm_t)priv);
  191. return OK;
  192. }
  193. /****************************************************************************
  194. * Name: skel_txpoll
  195. *
  196. * Description:
  197. * The transmitter is available, check if the network has any outgoing
  198. * packets ready to send. This is a callback from devif_poll().
  199. * devif_poll() may be called:
  200. *
  201. * 1. When the preceding TX packet send is complete,
  202. * 2. When the preceding TX packet send timesout and the interface is reset
  203. * 3. During normal TX polling
  204. *
  205. * Input Parameters:
  206. * dev - Reference to the NuttX driver state structure
  207. *
  208. * Returned Value:
  209. * OK on success; a negated errno on failure
  210. *
  211. * Assumptions:
  212. * The network is locked.
  213. *
  214. ****************************************************************************/
  215. static int skel_txpoll(FAR struct net_driver_s *dev)
  216. {
  217. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  218. /* If the polling resulted in data that should be sent out on the network,
  219. * the field d_len is set to a value > 0.
  220. */
  221. if (priv->sk_dev.d_len > 0)
  222. {
  223. /* Look up the destination MAC address and add it to the Ethernet
  224. * header.
  225. */
  226. #ifdef CONFIG_NET_IPv4
  227. #ifdef CONFIG_NET_IPv6
  228. if (IFF_IS_IPv4(priv->sk_dev.d_flags))
  229. #endif
  230. {
  231. arp_out(&priv->sk_dev);
  232. }
  233. #endif /* CONFIG_NET_IPv4 */
  234. #ifdef CONFIG_NET_IPv6
  235. #ifdef CONFIG_NET_IPv4
  236. else
  237. #endif
  238. {
  239. neighbor_out(&priv->sk_dev);
  240. }
  241. #endif /* CONFIG_NET_IPv6 */
  242. /* Check if the network is sending this packet to the IP address of
  243. * this device. If so, just loop the packet back into the network but
  244. * don't attmpt to put it on the wire.
  245. */
  246. if (!devif_loopback(&priv->sk_dev))
  247. {
  248. /* Send the packet */
  249. skel_transmit(priv);
  250. /* Check if there is room in the device to hold another packet. If not,
  251. * return a non-zero value to terminate the poll.
  252. */
  253. }
  254. }
  255. /* If zero is returned, the polling will continue until all connections have
  256. * been examined.
  257. */
  258. return 0;
  259. }
  260. /****************************************************************************
  261. * Name: skel_reply
  262. *
  263. * Description:
  264. * After a packet has been received and dispatched to the network, it
  265. * may return return with an outgoing packet. This function checks for
  266. * that case and performs the transmission if necessary.
  267. *
  268. * Input Parameters:
  269. * priv - Reference to the driver state structure
  270. *
  271. * Returned Value:
  272. * None
  273. *
  274. * Assumptions:
  275. * The network is locked.
  276. *
  277. ****************************************************************************/
  278. static void skel_reply(struct skel_driver_s *priv)
  279. {
  280. /* If the packet dispatch resulted in data that should be sent out on the
  281. * network, the field d_len will set to a value > 0.
  282. */
  283. if (priv->sk_dev.d_len > 0)
  284. {
  285. /* Update the Ethernet header with the correct MAC address */
  286. #ifdef CONFIG_NET_IPv4
  287. #ifdef CONFIG_NET_IPv6
  288. /* Check for an outgoing IPv4 packet */
  289. if (IFF_IS_IPv4(priv->sk_dev.d_flags))
  290. #endif
  291. {
  292. arp_out(&priv->sk_dev);
  293. }
  294. #endif
  295. #ifdef CONFIG_NET_IPv6
  296. #ifdef CONFIG_NET_IPv4
  297. /* Otherwise, it must be an outgoing IPv6 packet */
  298. else
  299. #endif
  300. {
  301. neighbor_out(&skel->sk_dev);
  302. }
  303. #endif
  304. /* And send the packet */
  305. skel_transmit(priv);
  306. }
  307. }
  308. /****************************************************************************
  309. * Name: skel_receive
  310. *
  311. * Description:
  312. * An interrupt was received indicating the availability of a new RX packet
  313. *
  314. * Input Parameters:
  315. * priv - Reference to the driver state structure
  316. *
  317. * Returned Value:
  318. * None
  319. *
  320. * Assumptions:
  321. * The network is locked.
  322. *
  323. ****************************************************************************/
  324. static void skel_receive(FAR struct skel_driver_s *priv)
  325. {
  326. do
  327. {
  328. /* Check for errors and update statistics */
  329. /* Check if the packet is a valid size for the network buffer
  330. * configuration.
  331. */
  332. /* Copy the data data from the hardware to priv->sk_dev.d_buf. Set
  333. * amount of data in priv->sk_dev.d_len
  334. */
  335. #ifdef CONFIG_NET_PKT
  336. /* When packet sockets are enabled, feed the frame into the packet tap */
  337. pkt_input(&priv->sk_dev);
  338. #endif
  339. #ifdef CONFIG_NET_IPv4
  340. /* Check for an IPv4 packet */
  341. if (BUF->type == HTONS(ETHTYPE_IP))
  342. {
  343. ninfo("IPv4 frame\n");
  344. NETDEV_RXIPV4(&priv->sk_dev);
  345. /* Handle ARP on input, then dispatch IPv4 packet to the network
  346. * layer.
  347. */
  348. arp_ipin(&priv->sk_dev);
  349. ipv4_input(&priv->sk_dev);
  350. /* Check for a reply to the IPv4 packet */
  351. skel_reply(priv);
  352. }
  353. else
  354. #endif
  355. #ifdef CONFIG_NET_IPv6
  356. /* Check for an IPv6 packet */
  357. if (BUF->type == HTONS(ETHTYPE_IP6))
  358. {
  359. ninfo("Iv6 frame\n");
  360. NETDEV_RXIPV6(&priv->sk_dev);
  361. /* Dispatch IPv6 packet to the network layer */
  362. ipv6_input(&priv->sk_dev);
  363. /* Check for a reply to the IPv6 packet */
  364. skel_reply(priv);
  365. }
  366. else
  367. #endif
  368. #ifdef CONFIG_NET_ARP
  369. /* Check for an ARP packet */
  370. if (BUF->type == htons(ETHTYPE_ARP))
  371. {
  372. /* Dispatch ARP packet to the network layer */
  373. arp_arpin(&priv->sk_dev);
  374. NETDEV_RXARP(&priv->sk_dev);
  375. /* If the above function invocation resulted in data that should be
  376. * sent out on the network, the field d_len will set to a value > 0.
  377. */
  378. if (priv->sk_dev.d_len > 0)
  379. {
  380. skel_transmit(priv);
  381. }
  382. }
  383. else
  384. #endif
  385. {
  386. NETDEV_RXDROPPED(&priv->sk_dev);
  387. }
  388. }
  389. while (); /* While there are more packets to be processed */
  390. }
  391. /****************************************************************************
  392. * Name: skel_txdone
  393. *
  394. * Description:
  395. * An interrupt was received indicating that the last TX packet(s) is done
  396. *
  397. * Input Parameters:
  398. * priv - Reference to the driver state structure
  399. *
  400. * Returned Value:
  401. * None
  402. *
  403. * Assumptions:
  404. * The network is locked.
  405. *
  406. ****************************************************************************/
  407. static void skel_txdone(FAR struct skel_driver_s *priv)
  408. {
  409. int delay;
  410. /* Check for errors and update statistics */
  411. NETDEV_TXDONE(priv->sk_dev);
  412. /* Check if there are pending transmissions */
  413. /* If no further transmissions are pending, then cancel the TX timeout and
  414. * disable further Tx interrupts.
  415. */
  416. wd_cancel(priv->sk_txtimeout);
  417. /* And disable further TX interrupts. */
  418. /* In any event, poll the network for new TX data */
  419. (void)devif_poll(&priv->sk_dev, skel_txpoll);
  420. }
  421. /****************************************************************************
  422. * Name: skel_interrupt_work
  423. *
  424. * Description:
  425. * Perform interrupt related work from the worker thread
  426. *
  427. * Input Parameters:
  428. * arg - The argument passed when work_queue() was called.
  429. *
  430. * Returned Value:
  431. * OK on success
  432. *
  433. * Assumptions:
  434. * Runs on a worker thread.
  435. *
  436. ****************************************************************************/
  437. static void skel_interrupt_work(FAR void *arg)
  438. {
  439. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  440. /* Lock the network and serialize driver operations if necessary.
  441. * NOTE: Serialization is only required in the case where the driver work
  442. * is performed on an LP worker thread and where more than one LP worker
  443. * thread has been configured.
  444. */
  445. net_lock();
  446. /* Process pending Ethernet interrupts */
  447. /* Get and clear interrupt status bits */
  448. /* Handle interrupts according to status bit settings */
  449. /* Check if we received an incoming packet, if so, call skel_receive() */
  450. skel_receive(priv);
  451. /* Check if a packet transmission just completed. If so, call skel_txdone.
  452. * This may disable further Tx interrupts if there are no pending
  453. * transmissions.
  454. */
  455. skel_txdone(priv);
  456. net_unlock();
  457. /* Re-enable Ethernet interrupts */
  458. up_enable_irq(CONFIG_skeleton_IRQ);
  459. }
  460. /****************************************************************************
  461. * Name: skel_interrupt
  462. *
  463. * Description:
  464. * Hardware interrupt handler
  465. *
  466. * Input Parameters:
  467. * irq - Number of the IRQ that generated the interrupt
  468. * context - Interrupt register state save info (architecture-specific)
  469. *
  470. * Returned Value:
  471. * OK on success
  472. *
  473. * Assumptions:
  474. * Runs in the context of a the Ethernet interrupt handler. Local
  475. * interrupts are disabled by the interrupt logic.
  476. *
  477. ****************************************************************************/
  478. static int skel_interrupt(int irq, FAR void *context, FAR void *arg)
  479. {
  480. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  481. DEBUGASSERT(priv != NULL);
  482. /* Disable further Ethernet interrupts. Because Ethernet interrupts are
  483. * also disabled if the TX timeout event occurs, there can be no race
  484. * condition here.
  485. */
  486. up_disable_irq(CONFIG_skeleton_IRQ);
  487. /* TODO: Determine if a TX transfer just completed */
  488. {
  489. /* If a TX transfer just completed, then cancel the TX timeout so
  490. * there will be no race condition between any subsequent timeout
  491. * expiration and the deferred interrupt processing.
  492. */
  493. wd_cancel(priv->sk_txtimeout);
  494. }
  495. /* Schedule to perform the interrupt processing on the worker thread. */
  496. work_queue(ETHWORK, &priv->sk_irqwork, skel_interrupt_work, priv, 0);
  497. return OK;
  498. }
  499. /****************************************************************************
  500. * Name: skel_txtimeout_work
  501. *
  502. * Description:
  503. * Perform TX timeout related work from the worker thread
  504. *
  505. * Input Parameters:
  506. * arg - The argument passed when work_queue() as called.
  507. *
  508. * Returned Value:
  509. * OK on success
  510. *
  511. ****************************************************************************/
  512. static void skel_txtimeout_work(FAR void *arg)
  513. {
  514. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  515. /* Lock the network and serialize driver operations if necessary.
  516. * NOTE: Serialization is only required in the case where the driver work
  517. * is performed on an LP worker thread and where more than one LP worker
  518. * thread has been configured.
  519. */
  520. net_lock();
  521. /* Increment statistics and dump debug info */
  522. NETDEV_TXTIMEOUTS(priv->sk_dev);
  523. /* Then reset the hardware */
  524. /* Then poll the network for new XMIT data */
  525. (void)devif_poll(&priv->sk_dev, skel_txpoll);
  526. net_unlock();
  527. }
  528. /****************************************************************************
  529. * Name: skel_txtimeout_expiry
  530. *
  531. * Description:
  532. * Our TX watchdog timed out. Called from the timer interrupt handler.
  533. * The last TX never completed. Reset the hardware and start again.
  534. *
  535. * Input Parameters:
  536. * argc - The number of available arguments
  537. * arg - The first argument
  538. *
  539. * Returned Value:
  540. * None
  541. *
  542. * Assumptions:
  543. * Runs in the context of a the timer interrupt handler. Local
  544. * interrupts are disabled by the interrupt logic.
  545. *
  546. ****************************************************************************/
  547. static void skel_txtimeout_expiry(int argc, wdparm_t arg, ...)
  548. {
  549. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  550. /* Disable further Ethernet interrupts. This will prevent some race
  551. * conditions with interrupt work. There is still a potential race
  552. * condition with interrupt work that is already queued and in progress.
  553. */
  554. up_disable_irq(CONFIG_skeleton_IRQ);
  555. /* Schedule to perform the TX timeout processing on the worker thread. */
  556. work_queue(ETHWORK, &priv->sk_irqwork, skel_txtimeout_work, priv, 0);
  557. }
  558. /****************************************************************************
  559. * Name: skel_poll_work
  560. *
  561. * Description:
  562. * Perform periodic polling from the worker thread
  563. *
  564. * Input Parameters:
  565. * arg - The argument passed when work_queue() as called.
  566. *
  567. * Returned Value:
  568. * OK on success
  569. *
  570. * Assumptions:
  571. * Run on a work queue thread.
  572. *
  573. ****************************************************************************/
  574. static void skel_poll_work(FAR void *arg)
  575. {
  576. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  577. /* Lock the network and serialize driver operations if necessary.
  578. * NOTE: Serialization is only required in the case where the driver work
  579. * is performed on an LP worker thread and where more than one LP worker
  580. * thread has been configured.
  581. */
  582. net_lock();
  583. /* Perform the poll */
  584. /* Check if there is room in the send another TX packet. We cannot perform
  585. * the TX poll if he are unable to accept another packet for transmission.
  586. */
  587. /* If so, update TCP timing states and poll the network for new XMIT data.
  588. * Hmmm.. might be bug here. Does this mean if there is a transmit in
  589. * progress, we will missing TCP time state updates?
  590. */
  591. (void)devif_timer(&priv->sk_dev, skel_txpoll);
  592. /* Setup the watchdog poll timer again */
  593. (void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry, 1,
  594. (wdparm_t)priv);
  595. net_unlock();
  596. }
  597. /****************************************************************************
  598. * Name: skel_poll_expiry
  599. *
  600. * Description:
  601. * Periodic timer handler. Called from the timer interrupt handler.
  602. *
  603. * Input Parameters:
  604. * argc - The number of available arguments
  605. * arg - The first argument
  606. *
  607. * Returned Value:
  608. * None
  609. *
  610. * Assumptions:
  611. * Runs in the context of a the timer interrupt handler. Local
  612. * interrupts are disabled by the interrupt logic.
  613. *
  614. ****************************************************************************/
  615. static void skel_poll_expiry(int argc, wdparm_t arg, ...)
  616. {
  617. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  618. /* Schedule to perform the interrupt processing on the worker thread. */
  619. work_queue(ETHWORK, &priv->sk_pollwork, skel_poll_work, priv, 0);
  620. }
  621. /****************************************************************************
  622. * Name: skel_ifup
  623. *
  624. * Description:
  625. * NuttX Callback: Bring up the Ethernet interface when an IP address is
  626. * provided
  627. *
  628. * Input Parameters:
  629. * dev - Reference to the NuttX driver state structure
  630. *
  631. * Returned Value:
  632. * None
  633. *
  634. * Assumptions:
  635. * The network is locked.
  636. *
  637. ****************************************************************************/
  638. static int skel_ifup(FAR struct net_driver_s *dev)
  639. {
  640. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  641. #ifdef CONFIG_NET_IPv4
  642. ninfo("Bringing up: %d.%d.%d.%d\n",
  643. dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
  644. (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
  645. #endif
  646. #ifdef CONFIG_NET_IPv6
  647. ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  648. dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
  649. dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5],
  650. dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
  651. #endif
  652. /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */
  653. /* Instantiate the MAC address from priv->sk_dev.d_mac.ether.ether_addr_octet */
  654. #ifdef CONFIG_NET_ICMPv6
  655. /* Set up IPv6 multicast address filtering */
  656. skel_ipv6multicast(priv);
  657. #endif
  658. /* Set and activate a timer process */
  659. (void)wd_start(priv->sk_txpoll, skeleton_WDDELAY, skel_poll_expiry, 1,
  660. (wdparm_t)priv);
  661. /* Enable the Ethernet interrupt */
  662. priv->sk_bifup = true;
  663. up_enable_irq(CONFIG_skeleton_IRQ);
  664. return OK;
  665. }
  666. /****************************************************************************
  667. * Name: skel_ifdown
  668. *
  669. * Description:
  670. * NuttX Callback: Stop the interface.
  671. *
  672. * Input Parameters:
  673. * dev - Reference to the NuttX driver state structure
  674. *
  675. * Returned Value:
  676. * None
  677. *
  678. * Assumptions:
  679. * The network is locked.
  680. *
  681. ****************************************************************************/
  682. static int skel_ifdown(FAR struct net_driver_s *dev)
  683. {
  684. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  685. irqstate_t flags;
  686. /* Disable the Ethernet interrupt */
  687. flags = enter_critical_section();
  688. up_disable_irq(CONFIG_skeleton_IRQ);
  689. /* Cancel the TX poll timer and TX timeout timers */
  690. wd_cancel(priv->sk_txpoll);
  691. wd_cancel(priv->sk_txtimeout);
  692. /* Put the EMAC in its reset, non-operational state. This should be
  693. * a known configuration that will guarantee the skel_ifup() always
  694. * successfully brings the interface back up.
  695. */
  696. /* Mark the device "down" */
  697. priv->sk_bifup = false;
  698. leave_critical_section(flags);
  699. return OK;
  700. }
  701. /****************************************************************************
  702. * Name: skel_txavail_work
  703. *
  704. * Description:
  705. * Perform an out-of-cycle poll on the worker thread.
  706. *
  707. * Input Parameters:
  708. * arg - Reference to the NuttX driver state structure (cast to void*)
  709. *
  710. * Returned Value:
  711. * None
  712. *
  713. * Assumptions:
  714. * Runs on a work queue thread.
  715. *
  716. ****************************************************************************/
  717. static void skel_txavail_work(FAR void *arg)
  718. {
  719. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)arg;
  720. /* Lock the network and serialize driver operations if necessary.
  721. * NOTE: Serialization is only required in the case where the driver work
  722. * is performed on an LP worker thread and where more than one LP worker
  723. * thread has been configured.
  724. */
  725. net_lock();
  726. /* Ignore the notification if the interface is not yet up */
  727. if (priv->sk_bifup)
  728. {
  729. /* Check if there is room in the hardware to hold another outgoing packet. */
  730. /* If so, then poll the network for new XMIT data */
  731. (void)devif_poll(&priv->sk_dev, skel_txpoll);
  732. }
  733. net_unlock();
  734. }
  735. /****************************************************************************
  736. * Name: skel_txavail
  737. *
  738. * Description:
  739. * Driver callback invoked when new TX data is available. This is a
  740. * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
  741. * latency.
  742. *
  743. * Input Parameters:
  744. * dev - Reference to the NuttX driver state structure
  745. *
  746. * Returned Value:
  747. * None
  748. *
  749. * Assumptions:
  750. * The network is locked.
  751. *
  752. ****************************************************************************/
  753. static int skel_txavail(FAR struct net_driver_s *dev)
  754. {
  755. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  756. /* Is our single work structure available? It may not be if there are
  757. * pending interrupt actions and we will have to ignore the Tx
  758. * availability action.
  759. */
  760. if (work_available(&priv->sk_pollwork))
  761. {
  762. /* Schedule to serialize the poll on the worker thread. */
  763. work_queue(ETHWORK, &priv->sk_pollwork, skel_txavail_work, priv, 0);
  764. }
  765. return OK;
  766. }
  767. /****************************************************************************
  768. * Name: skel_addmac
  769. *
  770. * Description:
  771. * NuttX Callback: Add the specified MAC address to the hardware multicast
  772. * address filtering
  773. *
  774. * Input Parameters:
  775. * dev - Reference to the NuttX driver state structure
  776. * mac - The MAC address to be added
  777. *
  778. * Returned Value:
  779. * Zero (OK) on success; a negated errno value on failure.
  780. *
  781. ****************************************************************************/
  782. #if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
  783. static int skel_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
  784. {
  785. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  786. /* Add the MAC address to the hardware multicast routing table */
  787. return OK;
  788. }
  789. #endif
  790. /****************************************************************************
  791. * Name: skel_rmmac
  792. *
  793. * Description:
  794. * NuttX Callback: Remove the specified MAC address from the hardware multicast
  795. * address filtering
  796. *
  797. * Input Parameters:
  798. * dev - Reference to the NuttX driver state structure
  799. * mac - The MAC address to be removed
  800. *
  801. * Returned Value:
  802. * Zero (OK) on success; a negated errno value on failure.
  803. *
  804. ****************************************************************************/
  805. #ifdef CONFIG_NET_MCASTGROUP
  806. static int skel_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
  807. {
  808. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  809. /* Add the MAC address to the hardware multicast routing table */
  810. return OK;
  811. }
  812. #endif
  813. /****************************************************************************
  814. * Name: skel_ipv6multicast
  815. *
  816. * Description:
  817. * Configure the IPv6 multicast MAC address.
  818. *
  819. * Input Parameters:
  820. * priv - A reference to the private driver state structure
  821. *
  822. * Returned Value:
  823. * Zero (OK) on success; a negated errno value on failure.
  824. *
  825. ****************************************************************************/
  826. #ifdef CONFIG_NET_ICMPv6
  827. static void skel_ipv6multicast(FAR struct skel_driver_s *priv)
  828. {
  829. FAR struct net_driver_s *dev;
  830. uint16_t tmp16;
  831. uint8_t mac[6];
  832. /* For ICMPv6, we need to add the IPv6 multicast address
  833. *
  834. * For IPv6 multicast addresses, the Ethernet MAC is derived by
  835. * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00,
  836. * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map
  837. * to the Ethernet MAC address 33:33:00:01:00:03.
  838. *
  839. * NOTES: This appears correct for the ICMPv6 Router Solicitation
  840. * Message, but the ICMPv6 Neighbor Solicitation message seems to
  841. * use 33:33:ff:01:00:03.
  842. */
  843. mac[0] = 0x33;
  844. mac[1] = 0x33;
  845. dev = &priv->dev;
  846. tmp16 = dev->d_ipv6addr[6];
  847. mac[2] = 0xff;
  848. mac[3] = tmp16 >> 8;
  849. tmp16 = dev->d_ipv6addr[7];
  850. mac[4] = tmp16 & 0xff;
  851. mac[5] = tmp16 >> 8;
  852. ninfo("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n",
  853. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  854. (void)skel_addmac(dev, mac);
  855. #ifdef CONFIG_NET_ICMPv6_AUTOCONF
  856. /* Add the IPv6 all link-local nodes Ethernet address. This is the
  857. * address that we expect to receive ICMPv6 Router Advertisement
  858. * packets.
  859. */
  860. (void)skel_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet);
  861. #endif /* CONFIG_NET_ICMPv6_AUTOCONF */
  862. #ifdef CONFIG_NET_ICMPv6_ROUTER
  863. /* Add the IPv6 all link-local routers Ethernet address. This is the
  864. * address that we expect to receive ICMPv6 Router Solicitation
  865. * packets.
  866. */
  867. (void)skel_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet);
  868. #endif /* CONFIG_NET_ICMPv6_ROUTER */
  869. }
  870. #endif /* CONFIG_NET_ICMPv6 */
  871. /****************************************************************************
  872. * Name: skel_ioctl
  873. *
  874. * Description:
  875. * Handle network IOCTL commands directed to this device.
  876. *
  877. * Input Parameters:
  878. * dev - Reference to the NuttX driver state structure
  879. * cmd - The IOCTL command
  880. * arg - The argument for the IOCTL command
  881. *
  882. * Returned Value:
  883. * OK on success; Negated errno on failure.
  884. *
  885. * Assumptions:
  886. * The network is locked.
  887. *
  888. ****************************************************************************/
  889. #ifdef CONFIG_NETDEV_IOCTL
  890. static int skel_ioctl(FAR struct net_driver_s *dev, int cmd,
  891. unsigned long arg)
  892. {
  893. FAR struct skel_driver_s *priv = (FAR struct skel_driver_s *)dev->d_private;
  894. int ret;
  895. /* Decode and dispatch the driver-specific IOCTL command */
  896. switch (cmd)
  897. {
  898. /* Add cases here to support the IOCTL commands */
  899. default:
  900. nerr("ERROR: Unrecognized IOCTL command: %d\n", command);
  901. return -ENOTTY; /* Special return value for this case */
  902. }
  903. return OK;
  904. }
  905. #endif
  906. /****************************************************************************
  907. * Public Functions
  908. ****************************************************************************/
  909. /****************************************************************************
  910. * Name: skel_initialize
  911. *
  912. * Description:
  913. * Initialize the Ethernet controller and driver
  914. *
  915. * Input Parameters:
  916. * intf - In the case where there are multiple EMACs, this value
  917. * identifies which EMAC is to be initialized.
  918. *
  919. * Returned Value:
  920. * OK on success; Negated errno on failure.
  921. *
  922. * Assumptions:
  923. * Called early in initialization before multi-tasking is initiated.
  924. *
  925. ****************************************************************************/
  926. int skel_initialize(int intf)
  927. {
  928. FAR struct skel_driver_s *priv;
  929. /* Get the interface structure associated with this interface number. */
  930. DEBUGASSERT(intf < CONFIG_skeleton_NINTERFACES);
  931. priv = &g_skel[intf];
  932. /* Check if a Ethernet chip is recognized at its I/O base */
  933. /* Attach the IRQ to the driver */
  934. if (irq_attach(CONFIG_skeleton_IRQ, skel_interrupt, priv))
  935. {
  936. /* We could not attach the ISR to the interrupt */
  937. return -EAGAIN;
  938. }
  939. /* Initialize the driver structure */
  940. memset(priv, 0, sizeof(struct skel_driver_s));
  941. priv->sk_dev.d_buf = g_pktbuf; /* Single packet buffer */
  942. priv->sk_dev.d_ifup = skel_ifup; /* I/F up (new IP address) callback */
  943. priv->sk_dev.d_ifdown = skel_ifdown; /* I/F down callback */
  944. priv->sk_dev.d_txavail = skel_txavail; /* New TX data callback */
  945. #ifdef CONFIG_NET_MCASTGROUP
  946. priv->sk_dev.d_addmac = skel_addmac; /* Add multicast MAC address */
  947. priv->sk_dev.d_rmmac = skel_rmmac; /* Remove multicast MAC address */
  948. #endif
  949. #ifdef CONFIG_NETDEV_IOCTL
  950. priv->sk_dev.d_ioctl = skel_ioctl; /* Handle network IOCTL commands */
  951. #endif
  952. priv->sk_dev.d_private = (FAR void *)g_skel; /* Used to recover private state from dev */
  953. /* Create a watchdog for timing polling for and timing of transmissions */
  954. priv->sk_txpoll = wd_create(); /* Create periodic poll timer */
  955. priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */
  956. DEBUGASSERT(priv->sk_txpoll != NULL && priv->sk_txtimeout != NULL);
  957. /* Put the interface in the down state. This usually amounts to resetting
  958. * the device and/or calling skel_ifdown().
  959. */
  960. /* Read the MAC address from the hardware into priv->sk_dev.d_mac.ether.ether_addr_octet
  961. * Applies only if the Ethernet MAC has its own internal address.
  962. */
  963. /* Register the device with the OS so that socket IOCTLs can be performed */
  964. (void)netdev_register(&priv->sk_dev, NET_LL_ETHERNET);
  965. return OK;
  966. }
  967. #endif /* CONFIG_NET_skeleton */