mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
Check return from nxsem_wait_initialize()
Resolution of Issue 619 will require multiple steps, this part of the first step in that resolution: Every call to nxsem_wait_uninterruptible() must handle the return value from nxsem_wait_uninterruptible properly. This commit is only for those files under drivers/pipes and drivers/wireless.
This commit is contained in:
committed by
Abdelatif Guettouche
parent
836fef358b
commit
986e594563
+76
-57
@@ -1,36 +1,20 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* drivers/pipes/pipe_common.c
|
* drivers/pipes/pipe_common.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008-2009, 2011, 2015-2016, 2018 Gregory Nutt. All
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* rights reserved.
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
*
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* License for the specific language governing permissions and limitations
|
||||||
* the documentation and/or other materials provided with the
|
* under the License.
|
||||||
* distribution.
|
|
||||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
||||||
* used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
||||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@@ -79,12 +63,6 @@
|
|||||||
# define pipe_dumpbuffer(m,a,n)
|
# define pipe_dumpbuffer(m,a,n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Function Prototypes
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void pipecommon_semtake(sem_t *sem);
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -93,9 +71,9 @@ static void pipecommon_semtake(sem_t *sem);
|
|||||||
* Name: pipecommon_semtake
|
* Name: pipecommon_semtake
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void pipecommon_semtake(FAR sem_t *sem)
|
static int pipecommon_semtake(FAR sem_t *sem)
|
||||||
{
|
{
|
||||||
nxsem_wait_uninterruptible(sem);
|
return nxsem_wait_uninterruptible(sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -201,7 +179,8 @@ int pipecommon_open(FAR struct file *filep)
|
|||||||
DEBUGASSERT(dev != NULL);
|
DEBUGASSERT(dev != NULL);
|
||||||
|
|
||||||
/* Make sure that we have exclusive access to the device structure. The
|
/* Make sure that we have exclusive access to the device structure. The
|
||||||
* nxsem_wait() call should fail only if we are awakened by a signal.
|
* nxsem_wait() call should fail if we are awakened by a signal or if the
|
||||||
|
* thread was canceled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = nxsem_wait(&dev->d_bfsem);
|
ret = nxsem_wait(&dev->d_bfsem);
|
||||||
@@ -232,8 +211,9 @@ int pipecommon_open(FAR struct file *filep)
|
|||||||
{
|
{
|
||||||
dev->d_nwriters++;
|
dev->d_nwriters++;
|
||||||
|
|
||||||
/* If this this is the first writer, then the read semaphore indicates the
|
/* If this this is the first writer, then the read semaphore indicates
|
||||||
* number of readers waiting for the first writer. Wake them all up.
|
* the number of readers waiting for the first writer. Wake them all
|
||||||
|
* up.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (dev->d_nwriters == 1)
|
if (dev->d_nwriters == 1)
|
||||||
@@ -276,8 +256,8 @@ int pipecommon_open(FAR struct file *filep)
|
|||||||
ret = nxsem_wait(&dev->d_rdsem);
|
ret = nxsem_wait(&dev->d_rdsem);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
/* The nxsem_wait() call should fail only if we are awakened by
|
/* The nxsem_wait() call should fail if we are awakened by a
|
||||||
* a signal.
|
* signal or if the task is canceled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ferr("ERROR: nxsem_wait failed: %d\n", ret);
|
ferr("ERROR: nxsem_wait failed: %d\n", ret);
|
||||||
@@ -301,6 +281,7 @@ int pipecommon_close(FAR struct file *filep)
|
|||||||
FAR struct inode *inode = filep->f_inode;
|
FAR struct inode *inode = filep->f_inode;
|
||||||
FAR struct pipe_dev_s *dev = inode->i_private;
|
FAR struct pipe_dev_s *dev = inode->i_private;
|
||||||
int sval;
|
int sval;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(dev && filep->f_inode->i_crefs > 0);
|
DEBUGASSERT(dev && filep->f_inode->i_crefs > 0);
|
||||||
|
|
||||||
@@ -309,7 +290,13 @@ int pipecommon_close(FAR struct file *filep)
|
|||||||
* I've never seen anyone check that.
|
* I've never seen anyone check that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pipecommon_semtake(&dev->d_bfsem);
|
ret = pipecommon_semtake(&dev->d_bfsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
/* The close will not be performed if the task was canceled */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Decrement the number of references on the pipe. Check if there are
|
/* Decrement the number of references on the pipe. Check if there are
|
||||||
* still outstanding references to the pipe.
|
* still outstanding references to the pipe.
|
||||||
@@ -325,8 +312,8 @@ int pipecommon_close(FAR struct file *filep)
|
|||||||
|
|
||||||
if ((filep->f_oflags & O_WROK) != 0)
|
if ((filep->f_oflags & O_WROK) != 0)
|
||||||
{
|
{
|
||||||
/* If there are no longer any writers on the pipe, then notify all of the
|
/* If there are no longer any writers on the pipe, then notify all
|
||||||
* waiting readers that they must return end-of-file.
|
* of the waiting readers that they must return end-of-file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (--dev->d_nwriters <= 0)
|
if (--dev->d_nwriters <= 0)
|
||||||
@@ -424,6 +411,10 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||||||
ret = nxsem_wait(&dev->d_bfsem);
|
ret = nxsem_wait(&dev->d_bfsem);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
/* May fail because a signal was received or if the task was
|
||||||
|
* canceled.
|
||||||
|
*/
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,6 +447,10 @@ ssize_t pipecommon_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||||||
|
|
||||||
if (ret < 0 || (ret = nxsem_wait(&dev->d_bfsem)) < 0)
|
if (ret < 0 || (ret = nxsem_wait(&dev->d_bfsem)) < 0)
|
||||||
{
|
{
|
||||||
|
/* May fail because a signal was received or if the task was
|
||||||
|
* canceled.
|
||||||
|
*/
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,16 +522,16 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* At present, this method cannot be called from interrupt handlers. That
|
/* At present, this method cannot be called from interrupt handlers. That
|
||||||
* is because it calls nxsem_wait (via pipecommon_semtake below) and
|
* is because it calls nxsem_wait() and nxsem_wait() cannot be called from
|
||||||
* nxsem_wait cannot be called from interrupt level. This actually
|
* interrupt level. This actually happens fairly commonly IF [a-z]err()
|
||||||
* happens fairly commonly IF [a-z]err() is called from interrupt handlers
|
* is called from interrupt handlers and stdout is being redirected via a
|
||||||
* and stdout is being redirected via a pipe. In that case, the debug
|
* pipe. In that case, the debug output will try to go out the pipe
|
||||||
* output will try to go out the pipe (interrupt handlers should use the
|
* (interrupt handlers should use the _err() APIs).
|
||||||
* _err() APIs).
|
|
||||||
*
|
*
|
||||||
* On the other hand, it would be very valuable to be able to feed the pipe
|
* On the other hand, it would be very valuable to be able to feed the pipe
|
||||||
* from an interrupt handler! TODO: Consider disabling interrupts instead
|
* from an interrupt handler! TODO: Consider disabling interrupts instead
|
||||||
* of taking semaphores so that pipes can be written from interrupt handlers
|
* of taking semaphores so that pipes can be written from interrupt
|
||||||
|
* handlers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(up_interrupt_context() == false);
|
DEBUGASSERT(up_interrupt_context() == false);
|
||||||
@@ -546,6 +541,10 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
ret = nxsem_wait(&dev->d_bfsem);
|
ret = nxsem_wait(&dev->d_bfsem);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
/* May fail because a signal was received or if the task was
|
||||||
|
* canceled.
|
||||||
|
*/
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,13 +625,23 @@ ssize_t pipecommon_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There is more to be written.. wait for data to be removed from the pipe */
|
/* There is more to be written.. wait for data to be removed fro
|
||||||
|
* the pipe
|
||||||
|
*/
|
||||||
|
|
||||||
sched_lock();
|
sched_lock();
|
||||||
nxsem_post(&dev->d_bfsem);
|
nxsem_post(&dev->d_bfsem);
|
||||||
pipecommon_semtake(&dev->d_wrsem);
|
ret = nxsem_wait(&dev->d_wrsem);
|
||||||
sched_unlock();
|
sched_unlock();
|
||||||
pipecommon_semtake(&dev->d_bfsem);
|
|
||||||
|
if (ret < 0 || (ret = nxsem_wait(&dev->d_bfsem)) < 0)
|
||||||
|
{
|
||||||
|
/* Either call nxsem_wait may fail because a signal was
|
||||||
|
* received or if the task was canceled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return nwritten == 0 ? (ssize_t)ret : nwritten;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -648,14 +657,19 @@ int pipecommon_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|||||||
FAR struct pipe_dev_s *dev = inode->i_private;
|
FAR struct pipe_dev_s *dev = inode->i_private;
|
||||||
pollevent_t eventset;
|
pollevent_t eventset;
|
||||||
pipe_ndx_t nbytes;
|
pipe_ndx_t nbytes;
|
||||||
int ret = OK;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DEBUGASSERT(dev && fds);
|
DEBUGASSERT(dev && fds);
|
||||||
|
|
||||||
/* Are we setting up the poll? Or tearing it down? */
|
/* Are we setting up the poll? Or tearing it down? */
|
||||||
|
|
||||||
pipecommon_semtake(&dev->d_bfsem);
|
ret = pipecommon_semtake(&dev->d_bfsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (setup)
|
if (setup)
|
||||||
{
|
{
|
||||||
/* This is a request to set up the poll. Find an available
|
/* This is a request to set up the poll. Find an available
|
||||||
@@ -778,7 +792,11 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pipecommon_semtake(&dev->d_bfsem);
|
ret = pipecommon_semtake(&dev->d_bfsem);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
@@ -851,6 +869,7 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
ret = -ENOTTY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
* See "GS2200MS2W Adapter Command Reference Guide" for the explanation
|
* See "GS2200MS2W Adapter Command Reference Guide" for the explanation
|
||||||
* of AT commands. You can find the document at:
|
* of AT commands. You can find the document at:
|
||||||
* https://www.telit.com/m2m-iot-products/wifi-bluetooth-modules/wi-fi-gs2200m/
|
* https://www.telit.com/m2m-iot-products/wifi-bluetooth-modules/wi-fi-gs2200m/
|
||||||
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -672,9 +673,9 @@ errout:
|
|||||||
* Name: gs2200m_lock
|
* Name: gs2200m_lock
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void gs2200m_lock(FAR struct gs2200m_dev_s *dev)
|
static int gs2200m_lock(FAR struct gs2200m_dev_s *dev)
|
||||||
{
|
{
|
||||||
nxsem_wait_uninterruptible(&dev->dev_sem);
|
return nxsem_wait_uninterruptible(&dev->dev_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -713,6 +714,7 @@ static ssize_t gs2200m_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
{
|
{
|
||||||
FAR struct inode *inode;
|
FAR struct inode *inode;
|
||||||
FAR struct gs2200m_dev_s *dev;
|
FAR struct gs2200m_dev_s *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(filep);
|
DEBUGASSERT(filep);
|
||||||
inode = filep->f_inode;
|
inode = filep->f_inode;
|
||||||
@@ -722,7 +724,15 @@ static ssize_t gs2200m_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
|
|
||||||
ASSERT(1 == len);
|
ASSERT(1 == len);
|
||||||
|
|
||||||
gs2200m_lock(dev);
|
ret = nxsem_wait(dev);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
/* Return if a signal is received or if the the task was canceled
|
||||||
|
* while we were waiting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(0 < _notif_q_count(dev));
|
ASSERT(0 < _notif_q_count(dev));
|
||||||
char cid = _notif_q_pop(dev);
|
char cid = _notif_q_pop(dev);
|
||||||
@@ -744,7 +754,7 @@ static ssize_t gs2200m_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
static ssize_t gs2200m_write(FAR struct file *filep, FAR const char *buffer,
|
static ssize_t gs2200m_write(FAR struct file *filep, FAR const char *buffer,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0; /* REVISIT: Zero is not a legal return value from write() */
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -2528,7 +2538,13 @@ static int gs2200m_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
|
|
||||||
/* Lock the device */
|
/* Lock the device */
|
||||||
|
|
||||||
gs2200m_lock(dev);
|
ret = gs2200m_lock(dev);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
/* Return only if the task was canceled */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable gs2200m irq to poll dready */
|
/* Disable gs2200m irq to poll dready */
|
||||||
|
|
||||||
@@ -2649,7 +2665,13 @@ static int gs2200m_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
|||||||
DEBUGASSERT(inode && inode->i_private);
|
DEBUGASSERT(inode && inode->i_private);
|
||||||
dev = (FAR struct gs2200m_dev_s *)inode->i_private;
|
dev = (FAR struct gs2200m_dev_s *)inode->i_private;
|
||||||
|
|
||||||
gs2200m_lock(dev);
|
ret = gs2200m_lock(dev);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
/* Return if the task was canceled */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Are we setting up the poll? Or tearing it down? */
|
/* Are we setting up the poll? Or tearing it down? */
|
||||||
|
|
||||||
@@ -2708,11 +2730,22 @@ static void gs2200m_irq_worker(FAR void *arg)
|
|||||||
char c_cid;
|
char c_cid;
|
||||||
int n;
|
int n;
|
||||||
int ec;
|
int ec;
|
||||||
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(arg != NULL);
|
DEBUGASSERT(arg != NULL);
|
||||||
dev = (FAR struct gs2200m_dev_s *)arg;
|
dev = (FAR struct gs2200m_dev_s *)arg;
|
||||||
|
|
||||||
gs2200m_lock(dev);
|
do
|
||||||
|
{
|
||||||
|
ret = gs2200m_lock(dev);
|
||||||
|
|
||||||
|
/* The only failure would be if the worker thread were canceled. That
|
||||||
|
* is very unlikely, however.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(ret == OK || ret == -ECANCELED);
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
|
|
||||||
n = dev->lower->dready(&ec);
|
n = dev->lower->dready(&ec);
|
||||||
wlinfo("== start (dready=%d, ec=%d) \n", n, ec);
|
wlinfo("== start (dready=%d, ec=%d) \n", n, ec);
|
||||||
@@ -2893,6 +2926,7 @@ static int gs2200m_start(FAR struct gs2200m_dev_s *dev)
|
|||||||
|
|
||||||
#if CONFIG_WL_GS2200M_LOGLEVEL > 0
|
#if CONFIG_WL_GS2200M_LOGLEVEL > 0
|
||||||
/* Set log level */
|
/* Set log level */
|
||||||
|
|
||||||
t = gs2200m_set_loglevel(dev, CONFIG_WL_GS2200M_LOGLEVEL);
|
t = gs2200m_set_loglevel(dev, CONFIG_WL_GS2200M_LOGLEVEL);
|
||||||
ASSERT(TYPE_OK == t);
|
ASSERT(TYPE_OK == t);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,35 +1,20 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* drivers/wireless/spirit/drivers/spirit_netdev.c
|
* drivers/wireless/spirit/drivers/spirit_netdev.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
*
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* License for the specific language governing permissions and limitations
|
||||||
* the documentation and/or other materials provided with the
|
* under the License.
|
||||||
* distribution.
|
|
||||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
||||||
* used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
||||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
@@ -53,11 +38,11 @@
|
|||||||
* interrupt handling, but the primary things are: (1) receipt of incoming
|
* interrupt handling, but the primary things are: (1) receipt of incoming
|
||||||
* packets, and (2) handling of the completion of TX transfers.
|
* packets, and (2) handling of the completion of TX transfers.
|
||||||
*
|
*
|
||||||
* The receipt of the incoming packet is handled on the HP work worker thread.
|
* The receipt of the incoming packet is handled on the HP work worker
|
||||||
* The received packet is extracted from the hardware, saved in an I/O
|
* thread. The received packet is extracted from the hardware, saved in an
|
||||||
* buffer (IOB), and queued in the RX packet queue. Processing of the
|
* I/O buffer (IOB), and queued in the RX packet queue. Processing of the
|
||||||
* received packet is scheduled to occur on the LP worker thread where each IOB
|
* received packet is scheduled to occur on the LP worker thread where each
|
||||||
* removed from RX packet queue is passed to the network via
|
* IOB removed from RX packet queue is passed to the network via
|
||||||
* sixlowpan_input().
|
* sixlowpan_input().
|
||||||
*
|
*
|
||||||
* The entire network logic runs on the LP worker thread. If the receipt of
|
* The entire network logic runs on the LP worker thread. If the receipt of
|
||||||
@@ -72,12 +57,12 @@
|
|||||||
* previous transfer and that the hardware is ready to send another packet.
|
* previous transfer and that the hardware is ready to send another packet.
|
||||||
*
|
*
|
||||||
* In this way, the interrupt handling and TX processing is serialized on
|
* In this way, the interrupt handling and TX processing is serialized on
|
||||||
* the HP worker thread and no special interlocking is required. Network level
|
* the HP worker thread and no special interlocking is required. Network
|
||||||
* work is similar serialized on the LP worker thread (and also via the network
|
* level work is similar serialized on the LP worker thread (and also via
|
||||||
* locking mechanism). So the only real interactions between the logic
|
* the network locking mechanism). So the only real interactions between
|
||||||
* running on the LP and HP worker threads is in the access to the RX and TX
|
* the logic running on the LP and HP worker threads is in the access to the
|
||||||
* packet queues. Semaphore protection is necessary while accessing these
|
* RX and TX packet queues. Semaphore protection is necessary while
|
||||||
* queues.
|
* accessing these queues.
|
||||||
*
|
*
|
||||||
* A special case is the TX timeout which must be handled on the HP work
|
* A special case is the TX timeout which must be handled on the HP work
|
||||||
* queue since it will reset the spirit interface.
|
* queue since it will reset the spirit interface.
|
||||||
@@ -99,7 +84,8 @@
|
|||||||
* for example, disabling the Spirit interrupt tears down the the entire
|
* for example, disabling the Spirit interrupt tears down the the entire
|
||||||
* interrupt setup so, for example, any interrupts that are received while
|
* interrupt setup so, for example, any interrupts that are received while
|
||||||
* interrupts are disable, aka torn down, will be lost. Hence, it may be
|
* interrupts are disable, aka torn down, will be lost. Hence, it may be
|
||||||
* necessary to process pending interrupts whenever interrupts are re-enabled.
|
* necessary to process pending interrupts whenever interrupts are re-
|
||||||
|
* enabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -260,13 +246,13 @@ enum spirit_driver_state_e
|
|||||||
|
|
||||||
/* SPIRIT1 device instance
|
/* SPIRIT1 device instance
|
||||||
*
|
*
|
||||||
* Make sure that struct ieee802154_radio_s remains first. If not it will break the
|
* Make sure that struct ieee802154_radio_s remains first. If not it will
|
||||||
* code
|
* break the code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct spirit_driver_s
|
struct spirit_driver_s
|
||||||
{
|
{
|
||||||
struct radio_driver_s radio; /* Interface understood by the network */
|
struct radio_driver_s radio; /* Interface understood by the network */
|
||||||
struct spirit_library_s spirit; /* Spirit library state */
|
struct spirit_library_s spirit; /* Spirit library state */
|
||||||
FAR const struct spirit_lower_s *lower; /* Low-level MCU-specific support */
|
FAR const struct spirit_lower_s *lower; /* Low-level MCU-specific support */
|
||||||
FAR struct pktradio_metadata_s *txhead; /* Head of pending TX transfers */
|
FAR struct pktradio_metadata_s *txhead; /* Head of pending TX transfers */
|
||||||
@@ -389,7 +375,7 @@ static const struct radio_init_s g_radio_init =
|
|||||||
static const struct spirit_pktstack_init_s g_pktstack_init =
|
static const struct spirit_pktstack_init_s g_pktstack_init =
|
||||||
{
|
{
|
||||||
SPIRIT_SYNC_WORD, /* syncword selected in board.h */
|
SPIRIT_SYNC_WORD, /* syncword selected in board.h */
|
||||||
SPIRIT_PREAMBLE_LENGTH, /* premblen selected in board.h*/
|
SPIRIT_PREAMBLE_LENGTH, /* premblen selected in board.h */
|
||||||
SPIRIT_SYNC_LENGTH, /* synclen selected in board.h */
|
SPIRIT_SYNC_LENGTH, /* synclen selected in board.h */
|
||||||
PKT_LENGTH_VAR, /* fixvarlen variable packet length */
|
PKT_LENGTH_VAR, /* fixvarlen variable packet length */
|
||||||
PKT_LENGTH_WIDTH, /* pktlenwidth from CONFIG_SPIRIT_PKTLEN */
|
PKT_LENGTH_WIDTH, /* pktlenwidth from CONFIG_SPIRIT_PKTLEN */
|
||||||
@@ -486,7 +472,21 @@ static struct spirit_pktstack_address_s g_addrinit =
|
|||||||
|
|
||||||
static void spirit_rxlock(FAR struct spirit_driver_s *priv)
|
static void spirit_rxlock(FAR struct spirit_driver_s *priv)
|
||||||
{
|
{
|
||||||
nxsem_wait_uninterruptible(&priv->rxsem);
|
int ret;
|
||||||
|
|
||||||
|
/* The only error that can be reported by nxsem_wait_uninterruptible() is
|
||||||
|
* ECANCELED if the the thread is canceled. All of the work runs on the
|
||||||
|
* LP work thread, however. It is very unlikely that the LP worker thread
|
||||||
|
* will be canceled and, if so, it should finish the work in progress
|
||||||
|
* before dying anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = nxsem_wait_uninterruptible(&priv->rxsem);
|
||||||
|
DEBUGASSERT(ret == 0 || ret == -ECANCELED);
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -524,7 +524,21 @@ static inline void spirit_rxunlock(FAR struct spirit_driver_s *priv)
|
|||||||
|
|
||||||
static void spirit_txlock(FAR struct spirit_driver_s *priv)
|
static void spirit_txlock(FAR struct spirit_driver_s *priv)
|
||||||
{
|
{
|
||||||
nxsem_wait_uninterruptible(&priv->txsem);
|
int ret;
|
||||||
|
|
||||||
|
/* The only error that can be reported by nxsem_wait_uninterruptible() is
|
||||||
|
* ECANCELED if the the thread is canceled. All of the work runs on the
|
||||||
|
* LP work thread, however. It is very unlikely that the LP worker thread
|
||||||
|
* will be canceled and, if so, it should finish the work in progress
|
||||||
|
* before dying anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = nxsem_wait_uninterruptible(&priv->txsem);
|
||||||
|
DEBUGASSERT(ret == 0 || ret == -ECANCELED);
|
||||||
|
}
|
||||||
|
while (ret < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -728,12 +742,13 @@ static void spirit_transmit_work(FAR void *arg)
|
|||||||
wlinfo("txhead=%p state=%u\n", priv->txhead, priv->state);
|
wlinfo("txhead=%p state=%u\n", priv->txhead, priv->state);
|
||||||
|
|
||||||
/* Take the TX packet queue lock to assure that it is not currently being
|
/* Take the TX packet queue lock to assure that it is not currently being
|
||||||
* modified on the LP worker thread. NOTE that it is not harmful to hold the
|
* modified on the LP worker thread. NOTE that it is not harmful to hold
|
||||||
* TX packet queue lock throughout this function; the LP worker thread cannot
|
* the TX packet queue lock throughout this function; the LP worker thread
|
||||||
* run until this completes.
|
* cannot run until this completes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spirit_txlock(priv);
|
spirit_txlock(priv);
|
||||||
|
|
||||||
while (priv->txhead != NULL && priv->state == DRIVER_STATE_IDLE)
|
while (priv->txhead != NULL && priv->state == DRIVER_STATE_IDLE)
|
||||||
{
|
{
|
||||||
/* Peek at the packet at the head of the TX queue */
|
/* Peek at the packet at the head of the TX queue */
|
||||||
@@ -982,8 +997,8 @@ static void spirit_schedule_transmit_work(FAR struct spirit_driver_s *priv)
|
|||||||
|
|
||||||
static int spirit_txpoll_callback(FAR struct net_driver_s *dev)
|
static int spirit_txpoll_callback(FAR struct net_driver_s *dev)
|
||||||
{
|
{
|
||||||
/* If zero is returned, the polling will continue until all connections have
|
/* If zero is returned, the polling will continue until all connections
|
||||||
* been examined.
|
* have been examined.
|
||||||
*
|
*
|
||||||
* REVISIT: Should we halt polling if there are packets in flight.
|
* REVISIT: Should we halt polling if there are packets in flight.
|
||||||
*/
|
*/
|
||||||
@@ -1021,9 +1036,10 @@ static void spirit_receive_work(FAR void *arg)
|
|||||||
* queued asynchronously by interrupt level logic.
|
* queued asynchronously by interrupt level logic.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spirit_rxlock(priv);
|
|
||||||
while (priv->rxhead != NULL)
|
while (priv->rxhead != NULL)
|
||||||
{
|
{
|
||||||
|
spirit_rxlock(priv);
|
||||||
|
|
||||||
/* Remove the contained IOB from the RX queue */
|
/* Remove the contained IOB from the RX queue */
|
||||||
|
|
||||||
pktmeta = priv->rxhead;
|
pktmeta = priv->rxhead;
|
||||||
@@ -1070,13 +1086,7 @@ static void spirit_receive_work(FAR void *arg)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pktradio_metadata_free(pktmeta);
|
pktradio_metadata_free(pktmeta);
|
||||||
|
|
||||||
/* Get exclusive access as needed at the top of the loop */
|
|
||||||
|
|
||||||
spirit_rxlock(priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spirit_rxunlock(priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -1096,7 +1106,8 @@ static void spirit_receive_work(FAR void *arg)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline void spirit_schedule_receive_work(FAR struct spirit_driver_s *priv)
|
static inline void
|
||||||
|
spirit_schedule_receive_work(FAR struct spirit_driver_s *priv)
|
||||||
{
|
{
|
||||||
/* Schedule to perform the RX processing on the worker thread. */
|
/* Schedule to perform the RX processing on the worker thread. */
|
||||||
|
|
||||||
@@ -1332,8 +1343,8 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
|
irqstatus.IRQ_RX_FIFO_ALMOST_FULL = 0;
|
||||||
|
|
||||||
/* There should be a packet buffer that was allocated when the data sync
|
/* There should be a packet buffer that was allocated when the data
|
||||||
* interrupt was processed.
|
* sync interrupt was processed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
iob = priv->rxbuffer;
|
iob = priv->rxbuffer;
|
||||||
@@ -1397,7 +1408,8 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Read the remainder of the packet into the I/O buffer */
|
/* Read the remainder of the packet into the I/O buffer */
|
||||||
|
|
||||||
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset], count));
|
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset],
|
||||||
|
count));
|
||||||
iob->io_len = spirit_pktstack_get_rxpktlen(spirit);
|
iob->io_len = spirit_pktstack_get_rxpktlen(spirit);
|
||||||
iob->io_offset = 0;
|
iob->io_offset = 0;
|
||||||
iob->io_pktlen = iob->io_len;
|
iob->io_pktlen = iob->io_len;
|
||||||
@@ -1408,8 +1420,9 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
DEBUGVERIFY(spirit_command(spirit, CMD_FLUSHRXFIFO));
|
DEBUGVERIFY(spirit_command(spirit, CMD_FLUSHRXFIFO));
|
||||||
priv->state = DRIVER_STATE_IDLE;
|
priv->state = DRIVER_STATE_IDLE;
|
||||||
|
|
||||||
/* Create the packet meta data and forward to the network. This
|
/* Create the packet meta data and forward to the network.
|
||||||
* must be done on the LP worker thread with the network locked.
|
* This must be done on the LP worker thread with the network
|
||||||
|
* locked.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pktmeta = pktradio_metadata_allocate();
|
pktmeta = pktradio_metadata_allocate();
|
||||||
@@ -1485,8 +1498,8 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
|
|
||||||
wlinfo("RX FIFO almost full\n");
|
wlinfo("RX FIFO almost full\n");
|
||||||
|
|
||||||
/* There should be a packet buffer that was allocated when the data sync
|
/* There should be a packet buffer that was allocated when the data
|
||||||
* interrupt was processed.
|
* sync interrupt was processed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->rxbuffer != NULL)
|
if (priv->rxbuffer != NULL)
|
||||||
@@ -1532,7 +1545,8 @@ static void spirit_interrupt_work(FAR void *arg)
|
|||||||
{
|
{
|
||||||
/* Read more of the packet into the I/O buffer */
|
/* Read more of the packet into the I/O buffer */
|
||||||
|
|
||||||
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset], count));
|
DEBUGVERIFY(spirit_fifo_read(spirit, &iob->io_data[offset],
|
||||||
|
count));
|
||||||
iob->io_len = count + offset;
|
iob->io_len = count + offset;
|
||||||
iob->io_offset = 0;
|
iob->io_offset = 0;
|
||||||
iob->io_pktlen = iob->io_len;
|
iob->io_pktlen = iob->io_len;
|
||||||
@@ -1754,7 +1768,8 @@ static void spirit_txtimeout_expiry(int argc, wdparm_t arg, ...)
|
|||||||
|
|
||||||
static void spirit_txpoll_work(FAR void *arg)
|
static void spirit_txpoll_work(FAR void *arg)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)arg;
|
FAR struct spirit_driver_s *priv =
|
||||||
|
(FAR struct spirit_driver_s *)arg;
|
||||||
|
|
||||||
/* Lock the network and serialize driver operations if necessary.
|
/* Lock the network and serialize driver operations if necessary.
|
||||||
* NOTE: Serialization is only required in the case where the driver work
|
* NOTE: Serialization is only required in the case where the driver work
|
||||||
@@ -1784,7 +1799,8 @@ static void spirit_txpoll_work(FAR void *arg)
|
|||||||
/* Perform the periodic poll */
|
/* Perform the periodic poll */
|
||||||
|
|
||||||
priv->needpoll = false;
|
priv->needpoll = false;
|
||||||
devif_timer(&priv->radio.r_dev, SPIRIT_WDDELAY, spirit_txpoll_callback);
|
devif_timer(&priv->radio.r_dev, SPIRIT_WDDELAY,
|
||||||
|
spirit_txpoll_callback);
|
||||||
|
|
||||||
/* Setup the watchdog poll timer again */
|
/* Setup the watchdog poll timer again */
|
||||||
|
|
||||||
@@ -1851,7 +1867,8 @@ static void spirit_txpoll_expiry(int argc, wdparm_t arg, ...)
|
|||||||
|
|
||||||
static int spirit_ifup(FAR struct net_driver_s *dev)
|
static int spirit_ifup(FAR struct net_driver_s *dev)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)dev->d_private;
|
FAR struct spirit_driver_s *priv =
|
||||||
|
(FAR struct spirit_driver_s *)dev->d_private;
|
||||||
FAR struct spirit_library_s *spirit;
|
FAR struct spirit_library_s *spirit;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1968,7 +1985,8 @@ error_with_ifalmostup:
|
|||||||
|
|
||||||
static int spirit_ifdown(FAR struct net_driver_s *dev)
|
static int spirit_ifdown(FAR struct net_driver_s *dev)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)dev->d_private;
|
FAR struct spirit_driver_s *priv =
|
||||||
|
(FAR struct spirit_driver_s *)dev->d_private;
|
||||||
FAR struct spirit_library_s *spirit;
|
FAR struct spirit_library_s *spirit;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
@@ -2061,7 +2079,8 @@ static int spirit_ifdown(FAR struct net_driver_s *dev)
|
|||||||
|
|
||||||
static int spirit_txavail(FAR struct net_driver_s *dev)
|
static int spirit_txavail(FAR struct net_driver_s *dev)
|
||||||
{
|
{
|
||||||
FAR struct spirit_driver_s *priv = (FAR struct spirit_driver_s *)dev->d_private;
|
FAR struct spirit_driver_s *priv =
|
||||||
|
(FAR struct spirit_driver_s *)dev->d_private;
|
||||||
|
|
||||||
/* Schedule to serialize the poll on the LP worker thread. */
|
/* Schedule to serialize the poll on the LP worker thread. */
|
||||||
|
|
||||||
@@ -2086,7 +2105,8 @@ static int spirit_txavail(FAR struct net_driver_s *dev)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_NET_MCASTGROUP
|
#ifdef CONFIG_NET_MCASTGROUP
|
||||||
static int spirit_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
|
static int spirit_addmac(FAR struct net_driver_s *dev,
|
||||||
|
FAR const uint8_t *mac)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
@@ -2252,7 +2272,8 @@ static int spirit_ioctl(FAR struct net_driver_s *dev, int cmd,
|
|||||||
static int spirit_get_mhrlen(FAR struct radio_driver_s *netdev,
|
static int spirit_get_mhrlen(FAR struct radio_driver_s *netdev,
|
||||||
FAR const void *meta)
|
FAR const void *meta)
|
||||||
{
|
{
|
||||||
DEBUGASSERT(netdev != NULL && netdev->r_dev.d_private != NULL && meta != NULL);
|
DEBUGASSERT(netdev != NULL && netdev->r_dev.d_private != NULL &&
|
||||||
|
meta != NULL);
|
||||||
|
|
||||||
/* There is no header on the Spirit radio payload */
|
/* There is no header on the Spirit radio payload */
|
||||||
|
|
||||||
@@ -2683,7 +2704,8 @@ int spirit_hw_initialize(FAR struct spirit_driver_s *priv,
|
|||||||
SQI_ABOVE_THRESHOLD);
|
SQI_ABOVE_THRESHOLD);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
wlerr("ERROR: spirit_timer_set_rxtimeout_stopcondition failed: %d\n", ret);
|
wlerr("ERROR: spirit_timer_set_rxtimeout_stopcondition failed: %d\n",
|
||||||
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2773,7 +2795,8 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
|
|||||||
|
|
||||||
/* Allocate a driver state structure instance */
|
/* Allocate a driver state structure instance */
|
||||||
|
|
||||||
priv = (FAR struct spirit_driver_s *)kmm_zalloc(sizeof(struct spirit_driver_s));
|
priv = (FAR struct spirit_driver_s *)
|
||||||
|
kmm_zalloc(sizeof(struct spirit_driver_s));
|
||||||
if (priv == NULL)
|
if (priv == NULL)
|
||||||
{
|
{
|
||||||
wlerr("ERROR: Failed to allocate device structure\n");
|
wlerr("ERROR: Failed to allocate device structure\n");
|
||||||
@@ -2830,9 +2853,9 @@ int spirit_netdev_initialize(FAR struct spi_dev_s *spi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NET_6LOWPAN
|
#ifdef CONFIG_NET_6LOWPAN
|
||||||
/* Make sure the our single packet buffer is attached. We must do this before
|
/* Make sure the our single packet buffer is attached. We must do this
|
||||||
* registering the device since, once the device is registered, a packet may
|
* before registering the device since, once the device is registered, a
|
||||||
* be attempted to be forwarded and require the buffer.
|
* packet may be attempted to be forwarded and require the buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
priv->radio.r_dev.d_buf = g_iobuffer.rb_buf;
|
priv->radio.r_dev.d_buf = g_iobuffer.rb_buf;
|
||||||
|
|||||||
Reference in New Issue
Block a user