mac802154_device.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. /****************************************************************************
  2. * wireless/ieee802154/mac802154_device.c
  3. *
  4. * Copyright (C) 2017 Verge Inc. All rights reserved.
  5. * Author: Anthony Merlino <anthony@vergeaero.com>
  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 <stdio.h>
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <time.h>
  45. #include <fcntl.h>
  46. #include <nuttx/arch.h>
  47. #include <nuttx/kmalloc.h>
  48. #include <nuttx/signal.h>
  49. #include <nuttx/mm/iob.h>
  50. #include <nuttx/wireless/ieee802154/ieee802154_device.h>
  51. #include <nuttx/wireless/ieee802154/ieee802154_mac.h>
  52. #include "mac802154.h"
  53. /****************************************************************************
  54. * Pre-processor Definitions
  55. ****************************************************************************/
  56. /* Device naming ************************************************************/
  57. #define DEVNAME_FMT "/dev/ieee%d"
  58. #define DEVNAME_FMTLEN (9 + 3 + 1)
  59. /****************************************************************************
  60. * Private Types
  61. ****************************************************************************/
  62. /* This structure describes the state of one open mac driver instance */
  63. struct mac802154dev_open_s
  64. {
  65. /* Supports a singly linked list */
  66. FAR struct mac802154dev_open_s *md_flink;
  67. /* The following will be true if we are closing */
  68. volatile bool md_closing;
  69. };
  70. struct mac802154dev_callback_s
  71. {
  72. /* This holds the information visible to the MAC layer */
  73. struct mac802154_maccb_s mc_cb; /* Interface understood by the MAC layer */
  74. FAR struct mac802154_chardevice_s *mc_priv; /* Our priv data */
  75. };
  76. struct mac802154_chardevice_s
  77. {
  78. MACHANDLE md_mac; /* Saved binding to the mac layer */
  79. struct mac802154dev_callback_s md_cb; /* Callback information */
  80. sem_t md_exclsem; /* Exclusive device access */
  81. /* Hold a list of events */
  82. bool enableevents : 1; /* Are events enabled? */
  83. bool geteventpending : 1; /* Is there a get event using the semaphore? */
  84. sem_t geteventsem; /* Signaling semaphore for waiting get event */
  85. sq_queue_t primitive_queue; /* For holding primitives to pass along */
  86. /* The following is a singly linked list of open references to the
  87. * MAC device.
  88. */
  89. FAR struct mac802154dev_open_s *md_open;
  90. /* Hold a list of transactions as a "readahead" buffer */
  91. bool readpending; /* Is there a read using the semaphore? */
  92. sem_t readsem; /* Signaling semaphore for waiting read */
  93. sq_queue_t dataind_queue;
  94. /* MAC Service notification information */
  95. bool md_notify_registered;
  96. pid_t md_notify_pid;
  97. struct sigevent md_notify_event;
  98. struct sigwork_s md_notify_work;
  99. };
  100. /****************************************************************************
  101. * Private Function Prototypes
  102. ****************************************************************************/
  103. /* Semaphore helpers */
  104. static inline int mac802154dev_takesem(sem_t *sem);
  105. #define mac802154dev_givesem(s) nxsem_post(s);
  106. static int mac802154dev_notify(FAR struct mac802154_maccb_s *maccb,
  107. FAR struct ieee802154_primitive_s *primitive);
  108. static int mac802154dev_rxframe(FAR struct mac802154_chardevice_s *dev,
  109. FAR struct ieee802154_data_ind_s *ind);
  110. static int mac802154dev_open(FAR struct file *filep);
  111. static int mac802154dev_close(FAR struct file *filep);
  112. static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer,
  113. size_t len);
  114. static ssize_t mac802154dev_write(FAR struct file *filep,
  115. FAR const char *buffer, size_t len);
  116. static int mac802154dev_ioctl(FAR struct file *filep, int cmd,
  117. unsigned long arg);
  118. /****************************************************************************
  119. * Private Data
  120. ****************************************************************************/
  121. static const struct file_operations mac802154dev_fops =
  122. {
  123. mac802154dev_open , /* open */
  124. mac802154dev_close, /* close */
  125. mac802154dev_read , /* read */
  126. mac802154dev_write, /* write */
  127. NULL, /* seek */
  128. mac802154dev_ioctl, /* ioctl */
  129. NULL /* poll */
  130. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  131. , NULL /* unlink */
  132. #endif
  133. };
  134. /****************************************************************************
  135. * Private Functions
  136. ****************************************************************************/
  137. /****************************************************************************
  138. * Name: mac802154dev_semtake
  139. *
  140. * Description:
  141. * Acquire the semaphore used for access serialization.
  142. *
  143. ****************************************************************************/
  144. static inline int mac802154dev_takesem(sem_t *sem)
  145. {
  146. int ret;
  147. /* Take the semaphore (perhaps waiting) */
  148. ret = nxsem_wait(sem);
  149. /* The only case that an error should occur here is if the wait were
  150. * awakened by a signal.
  151. */
  152. DEBUGASSERT(ret == OK || ret == -EINTR);
  153. return ret;
  154. }
  155. /****************************************************************************
  156. * Name: mac802154dev_open
  157. *
  158. * Description:
  159. * Open the 802.15.4 MAC character device.
  160. *
  161. ****************************************************************************/
  162. static int mac802154dev_open(FAR struct file *filep)
  163. {
  164. FAR struct inode *inode;
  165. FAR struct mac802154_chardevice_s *dev;
  166. FAR struct mac802154dev_open_s *opriv;
  167. int ret;
  168. DEBUGASSERT(filep != NULL && filep->f_inode != NULL);
  169. inode = filep->f_inode;
  170. dev = inode->i_private;
  171. DEBUGASSERT(dev != NULL);
  172. /* Get exclusive access to the MAC driver data structure */
  173. ret = mac802154dev_takesem(&dev->md_exclsem);
  174. if (ret < 0)
  175. {
  176. wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
  177. return ret;
  178. }
  179. /* Allocate a new open struct */
  180. opriv = (FAR struct mac802154dev_open_s *)
  181. kmm_zalloc(sizeof(struct mac802154dev_open_s));
  182. if (!opriv)
  183. {
  184. wlerr("ERROR: Failed to allocate new open struct\n");
  185. ret = -ENOMEM;
  186. goto errout_with_sem;
  187. }
  188. /* Attach the open struct to the device */
  189. opriv->md_flink = dev->md_open;
  190. dev->md_open = opriv;
  191. /* Attach the open struct to the file structure */
  192. filep->f_priv = (FAR void *)opriv;
  193. ret = OK;
  194. errout_with_sem:
  195. mac802154dev_givesem(&dev->md_exclsem);
  196. return ret;
  197. }
  198. /****************************************************************************
  199. * Name: mac802154dev_close
  200. *
  201. * Description:
  202. * Close the 802.15.4 MAC character device.
  203. *
  204. ****************************************************************************/
  205. static int mac802154dev_close(FAR struct file *filep)
  206. {
  207. FAR struct inode *inode;
  208. FAR struct mac802154_chardevice_s *dev;
  209. FAR struct mac802154dev_open_s *opriv;
  210. FAR struct mac802154dev_open_s *curr;
  211. FAR struct mac802154dev_open_s *prev;
  212. irqstate_t flags;
  213. bool closing;
  214. int ret;
  215. DEBUGASSERT(filep && filep->f_priv && filep->f_inode);
  216. opriv = filep->f_priv;
  217. inode = filep->f_inode;
  218. DEBUGASSERT(inode->i_private);
  219. dev = (FAR struct mac802154_chardevice_s *)inode->i_private;
  220. /* Handle an improbable race conditions with the following atomic test
  221. * and set.
  222. *
  223. * This is actually a pretty feeble attempt to handle this. The
  224. * improbable race condition occurs if two different threads try to
  225. * close the driver at the same time. The rule: don't do
  226. * that! It is feeble because we do not really enforce stale pointer
  227. * detection anyway.
  228. */
  229. flags = enter_critical_section();
  230. closing = opriv->md_closing;
  231. opriv->md_closing = true;
  232. leave_critical_section(flags);
  233. if (closing)
  234. {
  235. /* Another thread is doing the close */
  236. return OK;
  237. }
  238. /* Get exclusive access to the driver structure */
  239. ret = mac802154dev_takesem(&dev->md_exclsem);
  240. if (ret < 0)
  241. {
  242. wlerr("ERROR: mac802154_takesem failed: %d\n", ret);
  243. return ret;
  244. }
  245. /* Find the open structure in the list of open structures for the device */
  246. for (prev = NULL, curr = dev->md_open;
  247. curr && curr != opriv;
  248. prev = curr, curr = curr->md_flink);
  249. DEBUGASSERT(curr);
  250. if (!curr)
  251. {
  252. wlerr("ERROR: Failed to find open entry\n");
  253. ret = -ENOENT;
  254. goto errout_with_exclsem;
  255. }
  256. /* Remove the structure from the device */
  257. if (prev)
  258. {
  259. prev->md_flink = opriv->md_flink;
  260. }
  261. else
  262. {
  263. dev->md_open = opriv->md_flink;
  264. }
  265. /* And free the open structure */
  266. kmm_free(opriv);
  267. /* If there are now no open instances of the driver and a signal handler is
  268. * not registered, purge the list of events.
  269. */
  270. if (dev->md_open)
  271. {
  272. FAR struct ieee802154_primitive_s *primitive;
  273. primitive =
  274. (FAR struct ieee802154_primitive_s *)sq_remfirst(&dev->primitive_queue);
  275. while (primitive)
  276. {
  277. ieee802154_primitive_free(primitive);
  278. primitive =
  279. (FAR struct ieee802154_primitive_s *)sq_remfirst(&dev->primitive_queue);
  280. }
  281. }
  282. ret = OK;
  283. errout_with_exclsem:
  284. mac802154dev_givesem(&dev->md_exclsem);
  285. return ret;
  286. }
  287. /****************************************************************************
  288. * Name: mac802154dev_read
  289. *
  290. * Description:
  291. * Return the last received packet.
  292. *
  293. ****************************************************************************/
  294. static ssize_t mac802154dev_read(FAR struct file *filep, FAR char *buffer,
  295. size_t len)
  296. {
  297. FAR struct inode *inode;
  298. FAR struct mac802154_chardevice_s *dev;
  299. FAR struct mac802154dev_rxframe_s *rx;
  300. FAR struct ieee802154_data_ind_s *ind;
  301. struct ieee802154_get_req_s req;
  302. int ret;
  303. DEBUGASSERT(filep && filep->f_inode);
  304. inode = filep->f_inode;
  305. DEBUGASSERT(inode->i_private);
  306. dev = (FAR struct mac802154_chardevice_s *)inode->i_private;
  307. /* Check to make sure the buffer is the right size for the struct */
  308. if (len != sizeof(struct mac802154dev_rxframe_s))
  309. {
  310. wlerr("ERROR: buffer isn't a mac802154dev_rxframe_s: %lu\n",
  311. (unsigned long)len);
  312. return -EINVAL;
  313. }
  314. DEBUGASSERT(buffer != NULL);
  315. rx = (FAR struct mac802154dev_rxframe_s *)buffer;
  316. while (1)
  317. {
  318. /* Get exclusive access to the driver structure */
  319. ret = mac802154dev_takesem(&dev->md_exclsem);
  320. if (ret < 0)
  321. {
  322. wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
  323. return ret;
  324. }
  325. /* Try popping a data indication off the list */
  326. ind = (FAR struct ieee802154_data_ind_s *)sq_remfirst(&dev->dataind_queue);
  327. /* If the indication is not null, we can exit the loop and copy the data */
  328. if (ind != NULL)
  329. {
  330. mac802154dev_givesem(&dev->md_exclsem);
  331. break;
  332. }
  333. /* If this is a non-blocking call, or if there is another read operation
  334. * already pending, don't block. This driver returns EAGAIN even when
  335. * configured as non-blocking if another read operation is already pending
  336. * This situation should be rare. It will only occur when there are 2 calls
  337. * to read from separate threads and there was no data in the rx list.
  338. */
  339. if ((filep->f_oflags & O_NONBLOCK) || dev->readpending)
  340. {
  341. mac802154dev_givesem(&dev->md_exclsem);
  342. return -EAGAIN;
  343. }
  344. dev->readpending = true;
  345. mac802154dev_givesem(&dev->md_exclsem);
  346. /* Wait to be signaled when a frame is added to the list */
  347. ret = nxsem_wait(&dev->readsem);
  348. if (ret < 0)
  349. {
  350. DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
  351. dev->readpending = false;
  352. return ret;
  353. }
  354. /* Let the loop wrap back around, we will then pop a indication and this
  355. * time, it should have a data indication
  356. */
  357. }
  358. /* Check if the MAC layer is in promiscuous mode. */
  359. req.attr = IEEE802154_ATTR_MAC_PROMISCUOUS_MODE;
  360. ret = mac802154_ioctl(dev->md_mac, MAC802154IOC_MLME_GET_REQUEST,
  361. (unsigned long)&req);
  362. if (ret == 0 && req.attrval.mac.promisc_mode)
  363. {
  364. /* If it is, add the FCS back into the frame by increasing the length
  365. * by the PHY layer's FCS length.
  366. */
  367. req.attr = IEEE802154_ATTR_PHY_FCS_LEN;
  368. ret = mac802154_ioctl(dev->md_mac, MAC802154IOC_MLME_GET_REQUEST,
  369. (unsigned long)&req);
  370. if (ret == OK)
  371. {
  372. rx->length = ind->frame->io_len + req.attrval.phy.fcslen;
  373. rx->offset = ind->frame->io_offset;
  374. }
  375. /* Copy the entire frame from the IOB to the user supplied struct */
  376. memcpy(&rx->payload[0], &ind->frame->io_data[0], rx->length);
  377. }
  378. else
  379. {
  380. rx->length = (ind->frame->io_len - ind->frame->io_offset);
  381. rx->offset = 0;
  382. /* Copy just the payload from the IOB to the user supplied struct */
  383. memcpy(&rx->payload[0], &ind->frame->io_data[ind->frame->io_offset],
  384. rx->length);
  385. }
  386. memcpy(&rx->meta, ind, sizeof(struct ieee802154_data_ind_s));
  387. /* Zero out the forward link and IOB reference */
  388. rx->meta.flink = NULL;
  389. rx->meta.frame = NULL;
  390. /* Free the IOB */
  391. iob_free(ind->frame, IOBUSER_WIRELESS_MAC802154_CHARDEV);
  392. /* Deallocate the data indication */
  393. ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)ind);
  394. return OK;
  395. }
  396. /****************************************************************************
  397. * Name: mac802154dev_write
  398. *
  399. * Description:
  400. * Send a packet over the IEEE802.15.4 network.
  401. *
  402. ****************************************************************************/
  403. static ssize_t mac802154dev_write(FAR struct file *filep,
  404. FAR const char *buffer, size_t len)
  405. {
  406. FAR struct inode *inode;
  407. FAR struct mac802154_chardevice_s *dev;
  408. FAR struct mac802154dev_txframe_s *tx;
  409. FAR struct iob_s *iob;
  410. int ret;
  411. DEBUGASSERT(filep && filep->f_inode);
  412. inode = filep->f_inode;
  413. DEBUGASSERT(inode->i_private);
  414. dev = (FAR struct mac802154_chardevice_s *)inode->i_private;
  415. /* Check if the struct is the correct size */
  416. if (len != sizeof(struct mac802154dev_txframe_s))
  417. {
  418. wlerr("ERROR: buffer isn't a mac802154dev_txframe_s: %lu\n",
  419. (unsigned long)len);
  420. return -EINVAL;
  421. }
  422. DEBUGASSERT(buffer != NULL);
  423. tx = (FAR struct mac802154dev_txframe_s *)buffer;
  424. /* Allocate an IOB to put the frame in */
  425. iob = iob_alloc(false, IOBUSER_WIRELESS_MAC802154_CHARDEV);
  426. DEBUGASSERT(iob != NULL);
  427. iob->io_flink = NULL;
  428. iob->io_len = 0;
  429. iob->io_offset = 0;
  430. iob->io_pktlen = 0;
  431. /* Get the MAC header length */
  432. ret = mac802154_get_mhrlen(dev->md_mac, &tx->meta);
  433. if (ret < 0)
  434. {
  435. wlerr("ERROR: TX meta-data is invalid");
  436. return ret;
  437. }
  438. iob->io_offset = ret;
  439. iob->io_len = iob->io_offset;
  440. memcpy(&iob->io_data[iob->io_offset], tx->payload, tx->length);
  441. iob->io_len += tx->length;
  442. /* Pass the request to the MAC layer */
  443. ret = mac802154_req_data(dev->md_mac, &tx->meta, iob);
  444. if (ret < 0)
  445. {
  446. iob_free(iob, IOBUSER_WIRELESS_MAC802154_CHARDEV);
  447. wlerr("ERROR: req_data failed %d\n", ret);
  448. return ret;
  449. }
  450. return OK;
  451. }
  452. /****************************************************************************
  453. * Name: mac802154dev_ioctl
  454. *
  455. * Description:
  456. * Control the MAC layer via IOCTL commands.
  457. *
  458. ****************************************************************************/
  459. static int mac802154dev_ioctl(FAR struct file *filep, int cmd,
  460. unsigned long arg)
  461. {
  462. FAR struct inode *inode;
  463. FAR struct mac802154_chardevice_s *dev;
  464. FAR union ieee802154_macarg_u *macarg =
  465. (FAR union ieee802154_macarg_u *)((uintptr_t)arg);
  466. int ret;
  467. DEBUGASSERT(filep != NULL && filep->f_priv != NULL &&
  468. filep->f_inode != NULL);
  469. inode = filep->f_inode;
  470. DEBUGASSERT(inode->i_private);
  471. dev = (FAR struct mac802154_chardevice_s *)inode->i_private;
  472. /* Get exclusive access to the driver structure */
  473. ret = mac802154dev_takesem(&dev->md_exclsem);
  474. if (ret < 0)
  475. {
  476. wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
  477. return ret;
  478. }
  479. switch (cmd)
  480. {
  481. /* Command: MAC802154IOC_NOTIFY_REGISTER
  482. * Description: Register to receive a signal whenever there is a
  483. * event primitive sent from the MAC layer.
  484. * Argument: The signal number to use.
  485. * Return: Zero (OK) on success. Minus one will be returned on
  486. * failure with the errno value set appropriately.
  487. */
  488. case MAC802154IOC_NOTIFY_REGISTER:
  489. {
  490. /* Save the notification events */
  491. dev->md_notify_event = macarg->event;
  492. dev->md_notify_pid = getpid();
  493. dev->md_notify_registered = true;
  494. ret = OK;
  495. }
  496. break;
  497. case MAC802154IOC_GET_EVENT:
  498. {
  499. FAR struct ieee802154_primitive_s *primitive;
  500. while (1)
  501. {
  502. /* Try popping an event off the queue */
  503. primitive = (FAR struct ieee802154_primitive_s *)
  504. sq_remfirst(&dev->primitive_queue);
  505. /* If there was an event to pop off, copy it into the user data and
  506. * free it from the MAC layer's memory.
  507. */
  508. if (primitive != NULL)
  509. {
  510. memcpy(&macarg->primitive, primitive, sizeof(struct ieee802154_primitive_s));
  511. /* Free the notification */
  512. ieee802154_primitive_free(primitive);
  513. ret = OK;
  514. break;
  515. }
  516. /* If this is a non-blocking call, or if there is another getevent
  517. * operation already pending, don't block. This driver returns
  518. * EAGAIN even when configured as non-blocking if another getevent
  519. * operation is already pending This situation should be rare.
  520. * It will only occur when there are 2 calls from separate threads
  521. * and there was no events in the queue.
  522. */
  523. if ((filep->f_oflags & O_NONBLOCK) || dev->geteventpending)
  524. {
  525. ret = -EAGAIN;
  526. break;
  527. }
  528. dev->geteventpending = true;
  529. mac802154dev_givesem(&dev->md_exclsem);
  530. /* Wait to be signaled when an event is queued */
  531. ret = nxsem_wait(&dev->geteventsem);
  532. if (ret < 0)
  533. {
  534. DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
  535. dev->geteventpending = false;
  536. return ret;
  537. }
  538. /* Get exclusive access again, then loop back around and try and
  539. * pop an event off the queue
  540. */
  541. ret = mac802154dev_takesem(&dev->md_exclsem);
  542. if (ret < 0)
  543. {
  544. wlerr("ERROR: mac802154dev_takesem failed: %d\n", ret);
  545. return ret;
  546. }
  547. }
  548. }
  549. break;
  550. case MAC802154IOC_ENABLE_EVENTS:
  551. {
  552. dev->enableevents = macarg->enable;
  553. ret = OK;
  554. }
  555. break;
  556. default:
  557. {
  558. /* Forward any unrecognized commands to the MAC layer */
  559. ret = mac802154_ioctl(dev->md_mac, cmd, arg);
  560. }
  561. break;
  562. }
  563. mac802154dev_givesem(&dev->md_exclsem);
  564. return ret;
  565. }
  566. static int mac802154dev_notify(FAR struct mac802154_maccb_s *maccb,
  567. FAR struct ieee802154_primitive_s *primitive)
  568. {
  569. FAR struct mac802154dev_callback_s *cb =
  570. (FAR struct mac802154dev_callback_s *)maccb;
  571. FAR struct mac802154_chardevice_s *dev;
  572. DEBUGASSERT(cb != NULL && cb->mc_priv != NULL);
  573. dev = cb->mc_priv;
  574. /* Handle the special case for data indications or "incoming frames" */
  575. if (primitive->type == IEEE802154_PRIMITIVE_IND_DATA)
  576. {
  577. return mac802154dev_rxframe(dev, &primitive->u.dataind);
  578. }
  579. /* If there is a registered notification receiver, queue the event and signal
  580. * the receiver. Events should be popped from the queue from the application
  581. * at a reasonable rate in order for the MAC layer to be able to allocate new
  582. * notifications.
  583. */
  584. if (dev->enableevents && (dev->md_open != NULL || dev->md_notify_registered))
  585. {
  586. /* Get exclusive access to the driver structure. We don't care about any
  587. * signals so if we see one, just go back to trying to get access again */
  588. while (mac802154dev_takesem(&dev->md_exclsem) != 0);
  589. sq_addlast((FAR sq_entry_t *)primitive, &dev->primitive_queue);
  590. /* Check if there is a read waiting for data */
  591. if (dev->geteventpending)
  592. {
  593. /* Wake the thread waiting for the data transmission */
  594. dev->geteventpending = false;
  595. nxsem_post(&dev->geteventsem);
  596. }
  597. if (dev->md_notify_registered)
  598. {
  599. dev->md_notify_event.sigev_value.sival_int = primitive->type;
  600. nxsig_notification(dev->md_notify_pid, &dev->md_notify_event,
  601. SI_QUEUE, &dev->md_notify_work);
  602. }
  603. mac802154dev_givesem(&dev->md_exclsem);
  604. return OK;
  605. }
  606. /* By returning a negative value, we let the MAC know that we don't want the
  607. * primitive and it will free it for us
  608. */
  609. return -1;
  610. }
  611. /****************************************************************************
  612. * Name: mac802154dev_rxframe
  613. *
  614. * Description:
  615. * Handle received frames forward by the IEEE 802.15.4 MAC.
  616. *
  617. * Returned Value:
  618. * any failure. On success, the ind and its contained iob will be freed.
  619. * The ind will be intact if this function returns a failure.
  620. *
  621. ****************************************************************************/
  622. static int mac802154dev_rxframe(FAR struct mac802154_chardevice_s *dev,
  623. FAR struct ieee802154_data_ind_s *ind)
  624. {
  625. /* Get exclusive access to the driver structure. We don't care about any
  626. * signals so if we see one, just go back to trying to get access again */
  627. while (mac802154dev_takesem(&dev->md_exclsem) != 0);
  628. /* Push the indication onto the list */
  629. sq_addlast((FAR sq_entry_t *)ind, &dev->dataind_queue);
  630. /* Check if there is a read waiting for data */
  631. if (dev->readpending)
  632. {
  633. /* Wake the thread waiting for the data transmission */
  634. dev->readpending = false;
  635. nxsem_post(&dev->readsem);
  636. }
  637. /* Release the driver */
  638. mac802154dev_givesem(&dev->md_exclsem);
  639. return OK;
  640. }
  641. /****************************************************************************
  642. * Public Functions
  643. ****************************************************************************/
  644. /****************************************************************************
  645. * Name: mac802154dev_register
  646. *
  647. * Description:
  648. * Register a character driver to access the IEEE 802.15.4 MAC layer from
  649. * user-space
  650. *
  651. * Input Parameters:
  652. * mac - Pointer to the mac layer struct to be registerd.
  653. * minor - The device minor number. The IEEE802.15.4 MAC character device
  654. * will be registered as /dev/ieeeN where N is the minor number
  655. *
  656. * Returned Value:
  657. * Zero (OK) is returned on success. Otherwise a negated errno value is
  658. * returned to indicate the nature of the failure.
  659. *
  660. ****************************************************************************/
  661. int mac802154dev_register(MACHANDLE mac, int minor)
  662. {
  663. FAR struct mac802154_chardevice_s *dev;
  664. FAR struct mac802154_maccb_s *maccb;
  665. char devname[DEVNAME_FMTLEN];
  666. int ret;
  667. dev = kmm_zalloc(sizeof(struct mac802154_chardevice_s));
  668. if (!dev)
  669. {
  670. wlerr("ERROR: Failed to allocate device structure\n");
  671. return -ENOMEM;
  672. }
  673. /* Initialize the new mac driver instance */
  674. dev->md_mac = mac;
  675. nxsem_init(&dev->md_exclsem, 0, 1); /* Allow the device to be opened once
  676. * before blocking */
  677. nxsem_init(&dev->readsem, 0, 0);
  678. nxsem_setprotocol(&dev->readsem, SEM_PRIO_NONE);
  679. dev->readpending = false;
  680. sq_init(&dev->dataind_queue);
  681. dev->geteventpending = false;
  682. nxsem_init(&dev->geteventsem, 0, 0);
  683. nxsem_setprotocol(&dev->geteventsem, SEM_PRIO_NONE);
  684. sq_init(&dev->primitive_queue);
  685. dev->enableevents = true;
  686. dev->md_notify_registered = false;
  687. /* Initialize the MAC callbacks */
  688. dev->md_cb.mc_priv = dev;
  689. maccb = &dev->md_cb.mc_cb;
  690. maccb->flink = NULL;
  691. maccb->prio = CONFIG_IEEE802154_MACDEV_RECVRPRIO;
  692. maccb->notify = mac802154dev_notify;
  693. /* Bind the callback structure */
  694. ret = mac802154_bind(mac, maccb);
  695. if (ret < 0)
  696. {
  697. nerr("ERROR: Failed to bind the MAC callbacks: %d\n", ret);
  698. /* Free memory and return the error */
  699. kmm_free(dev);
  700. return ret;
  701. }
  702. /* Create the character device name */
  703. snprintf(devname, DEVNAME_FMTLEN, DEVNAME_FMT, minor);
  704. /* Register the mac character driver */
  705. ret = register_driver(devname, &mac802154dev_fops, 0666, dev);
  706. if (ret < 0)
  707. {
  708. wlerr("ERROR: register_driver failed: %d\n", ret);
  709. goto errout_with_priv;
  710. }
  711. return OK;
  712. errout_with_priv:
  713. nxsem_destroy(&dev->md_exclsem);
  714. kmm_free(dev);
  715. return ret;
  716. }