blob: 401eba2bc5cf4a40f87182723c628d0dd3ba3748 [file]
/****************************************************************************
* drivers/ipcc/ipcc_register.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/ipcc.h>
#include <nuttx/kmalloc.h>
#include <nuttx/circbuf.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include "ipcc_priv.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Device naming ************************************************************/
#define DEVNAME_FMT "/dev/ipcc%d"
#define DEVNAME_FMTLEN (9 + 3 + 1)
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_ipcc_fops =
{
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
.unlink = ipcc_unlink,
#endif /* CONFIG_DISABLE_PSEUDOFS_OPERATIONS */
.open = ipcc_open,
.close = ipcc_close,
.poll = ipcc_poll,
.read = ipcc_read,
.write = ipcc_write,
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipcc_cleanup
*
* Description:
* Cleans up resources allocated by ipcc_register()
*
* Input Parameters:
* priv - ipcc driver instance to clean up
*
* Returned Value:
* None
*
* Assumptions/Limitations:
* This function should be called only when ipcc_register is run with
* success and all resources in driver instance are properly allocated.
*
****************************************************************************/
void ipcc_cleanup(FAR struct ipcc_driver_s *priv)
{
#ifdef CONFIG_IPCC_BUFFERED
circbuf_uninit(&priv->ipcc->rxbuf);
circbuf_uninit(&priv->ipcc->txbuf);
#endif
nxsem_destroy(&priv->rxsem);
nxsem_destroy(&priv->txsem);
priv->ipcc->ops.cleanup(priv->ipcc);
nxmutex_destroy(&priv->lock);
kmm_free(priv);
}
/****************************************************************************
* Name: ipcc_register
*
* Description:
* Create and register the IPCC character driver.
*
* IPCC is a simple character driver that supports inter processor
* communication.
*
* Input Parameters:
* ipcc - An instance of the lower half IPCC driver
* chan - IPCC channel. This will be used ad IPCC minor number.
* IPPC will be registered as /dev/ipccN where N is the minor number.
* buflen - Length of tx and rx buffers, 0 for unbuffered communication.
*
* Returned Value:
* OK if the driver was successfully registered, or negated errno on
* failure.
*
* Assumptions/Limitations:
* ipcc is already allocated and initialized by architecture code.
*
****************************************************************************/
#ifdef CONFIG_IPCC_BUFFERED
int ipcc_register(FAR struct ipcc_lower_s *ipcc, size_t rxbuflen,
size_t txbuflen)
#else
int ipcc_register(FAR struct ipcc_lower_s *ipcc)
#endif
{
FAR struct ipcc_driver_s *priv;
char devname[DEVNAME_FMTLEN];
int ret;
/* Allocate a IPCC character device structure */
if ((priv = kmm_zalloc(sizeof(*priv))) == NULL)
{
return -ENOMEM;
}
/* Link upper and lower driver together */
priv->ipcc = ipcc;
ipcc->upper = priv;
#ifdef CONFIG_IPCC_BUFFERED
/* allocate buffers for reading and writing data to IPCC memory */
if (rxbuflen)
{
if ((ret = circbuf_init(&priv->ipcc->rxbuf, NULL, rxbuflen)))
{
goto error;
}
}
if (txbuflen)
{
if ((ret = circbuf_init(&priv->ipcc->txbuf, NULL, txbuflen)))
{
goto error;
}
}
#endif /* CONFIG_IPCC_BUFFERED */
/* Create the character device name */
snprintf(devname, sizeof(devname), DEVNAME_FMT, ipcc->chan);
if ((ret = register_driver(devname, &g_ipcc_fops, 0666, priv)))
{
goto error;
}
/* nxsem_init can't really fail us if we provide it with valid params */
nxmutex_init(&priv->lock);
nxsem_init(&priv->rxsem, 0, 0);
nxsem_init(&priv->txsem, 0, 1);
return OK;
error:
ipcc_cleanup(priv);
return ret;
}