SAMV7 MCAH: Add support for IOCTL commands that manage filters

This commit is contained in:
Gregory Nutt 2015-08-05 12:59:29 -06:00
parent d824223736
commit bb47c7f80e
2 changed files with 339 additions and 2 deletions

View File

@ -756,7 +756,7 @@
# define STDFILTER_S0_SFEC_PRIORITY (4 << STDFILTER_S0_SFEC_SHIFT) /* Set priority ion match */
# define STDFILTER_S0_SFEC_PRIOFIFO0 (5 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 0 on match */
# define STDFILTER_S0_SFEC_PRIOFIFO1 (6 << STDFILTER_S0_SFEC_SHIFT) /* Set priority and store in FIFO 1 on match */
# define STDFILTER_S0_SFEC_BUFFER (7 << STDFILTER_S0_SFEC_SHIFT) /* Store into Rx Buffer or as debug message */
# define STDFILTER_S0_SFEC_BUFFER (7 << STDFILTER_S0_SFEC_SHIFT) /* Store into Rx Buffer or as debug message */
#define STDFILTER_S0_SFT_SHIFT (30) /* Bits 30-31: Standard Filter Type */
#define STDFILTER_S0_SFT_MASK (3 << STDFILTER_S0_SFT_SHIFT)
# define STDFILTER_S0_SFT_RANGE (0 << STDFILTER_S0_SFT_SHIFT) /* Range filter from SF1ID to SF2ID */

View File

@ -866,6 +866,12 @@ struct sam_mcan_s
uint32_t rxints; /* Configured RX interrupts */
uint32_t txints; /* Configured TX interrupts */
#ifdef CONFIG_CAN_EXTID
uint32_t extfilters[2]; /* Extended filter bit allocator. 2*32=64 */
#else
uint32_t stdfilters[4]; /* Standard filter bit allocator. 4*32=128 */
#endif
#ifdef CONFIG_SAMV7_MCAN_REGDEBUG
uintptr_t regaddr; /* Last register address read */
uint32_t regval; /* Last value read from the register */
@ -903,6 +909,14 @@ static uint8_t mcan_dlc2bytes(FAR struct sam_mcan_s *priv, uint8_t dlc);
static uint8_t mcan_bytes2dlc(FAR struct sam_mcan_s *priv, uint8_t nbytes);
#endif
#ifdef CONFIG_CAN_EXTID
static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id,
uint32_t mask);
static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx);
#else
static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id);
static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx);
#endif
/* CAN driver methods */
static void mcan_reset(FAR struct can_dev_s *dev);
@ -1480,6 +1494,239 @@ static uint8_t mcan_bytes2dlc(FAR struct sam_mcan_s *priv, uint8_t nbytes)
}
#endif
/****************************************************************************
* Name: mcan_add_extfilter
*
* Description:
* Add an address filter for a extended 28 bit address.
*
* Input Parameters:
* priv - An instance of the MCAN driver state structure.
* id - The 28-bit extended address to filter
* mask - A 28-bit extended address mask
*
* Returned Value:
* A non-negative filter ID is returned on success. Otherwise a negated
* errno value is returned to indicate the nature of the error.
*
****************************************************************************/
#ifdef CONFIG_CAN_EXTID
static int mcan_add_extfilter(FAR struct sam_mcan_s *priv, uint32_t id,
uint32_t mask)
{
FAR const struct sam_config_s *config;
FAR uint32_t *extfilter;
uint32_t regval;
int word;
int bit;
int ndx;
DEBUGASSERT(priv != NULL && priv->config != NULL &&
id < (1 << 28) && mask < (1 << 28));
config = priv->config;
/* Get exclusive excess to the MCAN hardware */
mcan_dev_lock(priv);
/* Find an unused standard filter */
for (ndx = 0; ndx < config->nextfilters; ndx++)
{
/* Is this filter assigned? */
word = ndx >> 5;
bit = ndx & 0x1f;
if ((priv->extfilters[word] & (1 << bit)) == 0)
{
/* No, then this is the one that we will use */
extfilter = config->msgram.extfilters + (ndx << 1);
/* REVISIT: Here we use only FIFO0. */
extfilter[0] = EXTFILTER_F0_EFEC_FIFO0 | EXTFILTER_F0_EFID1(id);
extfilter[1] = EXTFILTER_F1_EFT_CLASSIC | mask;
/* Flush the filter entry into physical RAM */
arch_clean_dcache((uintptr_t)extfilter, (uintptr_t)exfilter + 8);
mcan_dev_unlock(priv);
return ndx;
}
}
mcan_dev_unlock(priv);
return -EAGAIN;
}
#endif
/****************************************************************************
* Name: mcan_del_extfilter
*
* Description:
* Remove an address filter for a standard 28 bit address.
*
* Input Parameters:
* priv - An instance of the MCAN driver state structure.
* ndx - The filter index previously returned by the mcan_add_extfilter().
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise a negated errno value is
* returned to indicate the nature of the error.
*
****************************************************************************/
#ifdef CONFIG_CAN_EXTID
static int mcan_del_extfilter(FAR struct sam_mcan_s *priv, int ndx)
{
FAR const struct sam_config_s *config;
FAR uint32_t *extfilter;
int word;
int bit;
DEBUGASSERT(priv != NULL && priv->config != NULL);
config = priv->config;
DEBUGASSERT(ndx < config->nextfilters);
/* Get exclusive excess to the MCAN hardware */
mcan_dev_lock(priv);
/* Deactivate the filter */
extfilter = config->msgram.extfilters + (ndx << 1);
*extfilter++ = 0;
*extfilter = 0;
/* Release the filter */
word = ndx >> 5;
bit = ndx & 0x1f;
priv->extfilters[word] &= ~(1 << bit);
mcan_dev_unlock(priv);
return OK;
}
#endif
/****************************************************************************
* Name: mcan_add_stdfilter
*
* Description:
* Add an address filter for a standard 11 bit address.
*
* Input Parameters:
* priv - An instance of the MCAN driver state structure.
* id - The 11-bit extended address to filter
*
* Returned Value:
* A non-negative filter ID is returned on success. Otherwise a negated
* errno value is returned to indicate the nature of the error.
*
****************************************************************************/
#ifndef CONFIG_CAN_EXTID
static int mcan_add_stdfilter(FAR struct sam_mcan_s *priv, uint16_t id)
{
FAR const struct sam_config_s *config;
FAR uint32_t *stdfilter;
uint32_t regval;
int word;
int bit;
int ndx;
DEBUGASSERT(priv != NULL && priv->config != NULL && id < (1 << 11));
config = priv->config;
/* Get exclusive excess to the MCAN hardware */
mcan_dev_lock(priv);
/* Find an unused standard filter */
for (ndx = 0; ndx < config->nstdfilters; ndx++)
{
/* Is this filter assigned? */
word = ndx >> 5;
bit = ndx & 0x1f;
if ((priv->stdfilters[word] & (1 << bit)) == 0)
{
/* No, then this is the one that we will use */
stdfilter = config->msgram.stdfilters + ndx;
regval = STDFILTER_S0_SFT_CLASSIC | STDFILTER_S0_SFID1(id);
/* REVISIT: Here we use only FIFO0. */
regval |= STDFILTER_S0_SFEC_FIFO0;
*stdfilter = regval;
/* Flush the filter entry into physical RAM */
arch_clean_dcache((uintptr_t)stdfilter, (uintptr_t)stdfilter + 4);
mcan_dev_unlock(priv);
return ndx;
}
}
mcan_dev_unlock(priv);
return -EAGAIN;
}
#endif
/****************************************************************************
* Name: mcan_del_stdfilter
*
* Description:
* Remove an address filter for a standard 28 bit address.
*
* Input Parameters:
* priv - An instance of the MCAN driver state structure.
* ndx - The filter index previously returned by the mcan_add_stdfilter().
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise a negated errno value is
* returned to indicate the nature of the error.
*
****************************************************************************/
#ifndef CONFIG_CAN_EXTID
static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx)
{
FAR const struct sam_config_s *config;
FAR uint32_t *stdfilter;
int word;
int bit;
DEBUGASSERT(priv != NULL && priv->config != NULL);
config = priv->config;
DEBUGASSERT(ndx < config->nstdfilters);
/* Get exclusive excess to the MCAN hardware */
mcan_dev_lock(priv);
/* Deactivate the filter */
stdfilter = config->msgram.stdfilters + ndx;
*stdfilter = 0;
/* Release the filter */
word = ndx >> 5;
bit = ndx & 0x1f;
priv->stdfilters[word] &= ~(1 << bit);
mcan_dev_unlock(priv);
return OK;
}
#endif
/****************************************************************************
* Name: mcan_reset
*
@ -1753,9 +2000,99 @@ static void mcan_txint(FAR struct can_dev_s *dev, bool enable)
static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg)
{
FAR struct sam_mcan_s *priv;
int ret = -ENOTTY;
canvdbg("cmd=%04x arg=%lu\n", cmd, arg);
DEBUGASSERT(dev && dev->cd_priv);
priv = dev->cd_priv;
/* Handle the command */
switch (cmd)
{
#ifdef CONFIG_CAN_EXTID
/* CANIOC_ADD_EXTFILTER:
* Description: Add an address filter for a extended 28 bit
* address.
* Argument: A reference to struct canioc_extfilter_s
* Returned Value: A non-negative filter ID is returned on success.
* Otherwise -1 (ERROR) is returned with the errno
* variable set to indicate the nature of the error.
*/
case CANIOC_ADD_EXTFILTER:
{
FAR struct canioc_extfilter_s *extfilter =
(FAR struct canioc_extfilter_s *)arg;
ret = mcan_add_extfilter(priv, extfilter->xf_id, extfilter->xf_mask);
}
break;
/* CANIOC_DEL_EXTFILTER:
* Description: Remove an address filter for a standard 28 bit address.
* Argument: The filter index previously returned by the
* CANIOC_ADD_EXTFILTER command
* Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
* is returned with the errno variable set to indicate the
* nature of the error.
*/
case CANIOC_DEL_EXTFILTER:
{
DEBUGASSERT(arg <= priv->config->nextfilters);
ret = mcan_del_extfilter(priv, (int)arg);
}
break;
#else
/* CANIOC_ADD_STDFILTER:
* Description: Add an address filter for a standard 11 bit
* address.
* Argument: A reference to struct canioc_stdfilter_s
* Returned Value: A non-negative filter ID is returned on success.
* Otherwise -1 (ERROR) is returned with the errno
* variable set to indicate the nature of the error.
*/
case CANIOC_ADD_STDFILTER:
{
FAR struct canioc_stdfilter_s *stdfilter =
(FAR struct canioc_stdfilter_s *)arg;
ret = mcan_add_stdfilter(priv, stdfilter->sf_id);
}
break;
/* CANIOC_DEL_STDFILTER:
* Description: Remove an address filter for a standard 11 bit address.
* Argument: The filter index previously returned by the
* CANIOC_ADD_STDFILTER command
* Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
* is returned with the errno variable set to indicate the
* nature of the error.
*/
case CANIOC_DEL_STDFILTER:
{
DEBUGASSERT(arg <= priv->config->nstdfilters);
ret = mcan_del_stdfilter(priv, (int)arg);
}
break;
#endif
/* Unsupported/unrecognized command */
default:
candbg("ERROR: Unrecognized command: %04x\n", cmd);
break;
}
/* No CAN ioctls are supported */
return -ENOTTY;
return ret;
}
/****************************************************************************