Files
vrpmdv-yocto-recipes/recipes-vrpmdv/recipes-base/vrpmdv-mon-datafile/save/vrpmdv-mon-datafile-before-DMA-Change.c
Markus Lehr 454ae2f46e added vrpmdv-rtservice, vrpmdv-mon-datafile,
vrpmdv-monitoring-controler, vrpmdv-mon-tty
2024-06-21 08:51:47 +02:00

707 lines
19 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) STMicroelectronics 2019 - All Rights Reserved
* Author: Jean-Philippe Romain <jean-philippe.romain@st.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/rpmsg.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/miscdevice.h>
#include <linux/eventfd.h>
#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/types.h>
#define RPMSG_SDB_DRIVER_VERSION "1.0"
/*
* Static global variables
*/
static const char rpmsg_sdb_driver_name[] = "vrpmdv-mon-datafile";
static int LastBufferId;
struct rpmsg_sdb_ioctl_set_efd {
int bufferId, eventfd;
};
struct rpmsg_sdb_ioctl_get_data_size {
int bufferId;
uint32_t size;
};
/* ioctl numbers */
/* _IOW means userland is writing and kernel is reading */
/* _IOR means userland is reading and kernel is writing */
/* _IOWR means userland and kernel can both read and write */
#define RPMSG_SDB_IOCTL_SET_EFD _IOW('R', 0x00, struct rpmsg_sdb_ioctl_set_efd *)
#define RPMSG_SDB_IOCTL_GET_DATA_SIZE _IOWR('R', 0x01, struct rpmsg_sdb_ioctl_get_data_size *)
struct sdb_buf_t {
int index; /* index of buffer */
size_t size; /* buffer size */
size_t writing_size; /* size of data written by copro */
dma_addr_t paddr; /* physical address*/
void *vaddr; /* virtual address */
void *uaddr; /* mapped address for userland */
struct eventfd_ctx *efd_ctx; /* eventfd context */
struct list_head buflist; /* reference in the buffers list */
};
struct rpmsg_sdb_t {
struct mutex mutex; /* mutex to protect the ioctls */
struct miscdevice mdev; /* misc device ref */
struct rpmsg_device *rpdev; /* handle rpmsg device */
struct list_head buffer_list; /* buffer instances list */
};
struct device *rpmsg_sdb_dev;
struct vRCMDeviceData {
uint32_t packageNo; //current package Number
uint32_t packageCount; //complete package Number
uint32_t dataQuantity; //number of uint32_t in data
uint32_t data[]; //the data
};
static int rpmsg_sdb_format_txbuf_string(struct sdb_buf_t *buffer, char *bufinfo_str, size_t bufinfo_str_size)
{
pr_info("rpmsg_sdb(%s): Buffer index:%d, addr:%08x, size:%08x\n",
__func__,
buffer->index,
buffer->paddr,
buffer->size);
return snprintf(bufinfo_str, bufinfo_str_size, "B%dA%08xL%08x", buffer->index, buffer->paddr, buffer->size);
}
static long rpmsg_sdb_decode_rxbuf_string(char *rxbuf_str, int *buffer_id, size_t *size)
{
int ret = 0;
char *sub_str;
long bsize;
long bufid;
const char delimiter[2] = {'L','\0'};
//__u32* data = (__u32*) rxbuf_str;
struct vRCMDeviceData* pdata = (struct vRCMDeviceData*) rxbuf_str;
//pr_info("rpmsg_sdb(%s): rxbuf_str:%s\n", __func__, rxbuf_str);
pr_info("rpmsg_sdb(%s): packageno:%d\n", __func__, pdata->packageNo);
pr_info("rpmsg_sdb(%s): packageCount:%d\n", __func__, pdata->packageCount);
pr_info("rpmsg_sdb(%s): dataquantity:%d\n", __func__, pdata->dataQuantity);
pr_info("rpmsg_sdb(%s): data:%d\n", __func__, (pdata->data)[0]);
// pr_info("rpmsg_sdb(%s): rxbuf_str:%d\n", __func__, data[0]);
// pr_info("rpmsg_sdb(%s): rxbuf_str:%d\n", __func__, data[1]);
// pr_info("rpmsg_sdb(%s): rxbuf_str:%d\n", __func__, data[2]);
/* Get first part containing the buffer id */
// sub_str = strsep(&rxbuf_str, delimiter);
// // pr_info("rpmsg_sdb(%s): sub_str:%s\n", __func__, sub_str);
// /* Save Buffer id and size: template BxLyyyyyyyy*/
// ret = kstrtol(&sub_str[1], 10, &bufid);
// if (ret < 0) {
// // pr_info("rpmsg_sdb(ERROR): Extract of buffer id failed(%d)", ret);
// goto out;
// }
// ret = kstrtol(&rxbuf_str[2], 16, &bsize);
// if (ret < 0) {
// // pr_info("rpmsg_sdb(ERROR): Extract of buffer size failed(%d)", ret);
// goto out;
// }
// *size = (size_t)bsize;
// *buffer_id = (int)bufid;
// out:
return ret;
}
static int rpmsg_sdb_send_buf_info(struct rpmsg_sdb_t *rpmsg_sdb, struct sdb_buf_t *buffer)
{
int count = 0, ret = 0;
const unsigned char *tbuf;
char mybuf[32];
int msg_size;
struct rpmsg_device *_rpdev;
pr_info("rpmsg_sdb(%s): start rpmsg_sdb_send_buf_info\n", __func__);
_rpdev = rpmsg_sdb->rpdev;
msg_size = rpmsg_get_mtu(_rpdev->ept);
pr_info("rpmsg_sdb(%s): checked msg site:%d\n", __func__, msg_size);
if (msg_size < 0)
return msg_size;
pr_info("rpmsg_sdb(%s): Call rpmsg_sdb_format_txbuf_string\n", __func__);
count = rpmsg_sdb_format_txbuf_string(buffer, mybuf, 32);
tbuf = &mybuf[0];
do {
/* send a message to our remote processor */
pr_info("rpmsg_sdb(%s): send a message to our remote processor\n", __func__);
ret = rpmsg_send(_rpdev->ept, (void *)tbuf,
count > msg_size ? msg_size : count);
if (ret) {
dev_err(&_rpdev->dev, "rpmsg_send failed: %d\n", ret);
pr_info("rpmsg_sdb(%s): error by send a message to our remote processor\n", __func__);
return ret;
}
else {
pr_info("rpmsg_sdb(%s): send succesfully a message to our remote processor\n", __func__);
}
if (count > msg_size) {
count -= msg_size;
tbuf += msg_size;
} else {
count = 0;
}
} while (count > 0);
return count;
}
static int rpmsg_sdb_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned long vsize = vma->vm_end - vma->vm_start;
unsigned long size = PAGE_ALIGN(vsize);
unsigned long NumPages = size >> PAGE_SHIFT;
unsigned long align = get_order(size);
pgprot_t prot = pgprot_noncached(vma->vm_page_prot);
struct rpmsg_sdb_t *_rpmsg_sdb;
struct sdb_buf_t *_buffer;
pr_info("rpmsg_sdb(%s): start rpmsg_sdb_mmap\n", __func__);
if (align > CONFIG_CMA_ALIGNMENT)
align = CONFIG_CMA_ALIGNMENT;
if (rpmsg_sdb_dev == NULL)
return -ENOMEM;
pr_info("rpmsg_sdb(%s): start rpmsg_sdb_mmap - coherent_dma_mask\n", __func__);
rpmsg_sdb_dev->coherent_dma_mask = DMA_BIT_MASK(32);
rpmsg_sdb_dev->dma_mask = &rpmsg_sdb_dev->coherent_dma_mask;
_rpmsg_sdb = container_of(file->private_data, struct rpmsg_sdb_t,
mdev);
/* Field the last buffer entry which is the last one created */
if (!list_empty(&_rpmsg_sdb->buffer_list)) {
pr_info("rpmsg_sdb(%s): start rpmsg_sdb_mmap - bufferlist not empty\n", __func__);
_buffer = list_last_entry(&_rpmsg_sdb->buffer_list,
struct sdb_buf_t, buflist);
_buffer->uaddr = NULL;
_buffer->size = NumPages * PAGE_SIZE;
_buffer->writing_size = -1;
_buffer->vaddr = dma_alloc_coherent(rpmsg_sdb_dev,
_buffer->size,
&_buffer->paddr,
GFP_KERNEL);
if (!_buffer->vaddr) {
pr_info("rpmsg_sdb(ERROR): Memory allocation issue\n");
return -ENOMEM;
}
pr_info("rpmsg_sdb(%s): dma_alloc_coherent done - paddr[%d]:%x - vaddr[%d]:%p\n",
__func__,
_buffer->index,
_buffer->paddr,
_buffer->index,
_buffer->vaddr);
/* Get address for userland */
if (remap_pfn_range(vma, vma->vm_start,
(_buffer->paddr >> PAGE_SHIFT) + vma->vm_pgoff,
size, prot)) {
pr_info("rpmsg_sdb(%s): remap_pfn_range could not be done\n");
return -EAGAIN;
}
_buffer->uaddr = (void *)vma->vm_start;
pr_info("rpmsg_sdb(%s): _buffer->uaddr = %p\n", __func__, _buffer->uaddr);
/* Send information to remote proc */
pr_info("rpmsg_sdb(%s): Send information to remote proc\n", __func__);
rpmsg_sdb_send_buf_info(_rpmsg_sdb, _buffer);
} else {
dev_err(rpmsg_sdb_dev, "No existing buffer entry exist in the list !!!");
pr_debug("rpmsg_sdb(%s): No existing buffer entry exist in the list !!!\n", __func__);
return -EINVAL;
}
/* Increment for number of requested buffer */
LastBufferId++;
return 0;
}
/**
* rpmsg_sdb_open - Open Session
*
* @inode: inode struct
* @file: file struct
*
* Return:
* 0 - Success
* Non-zero - Failure
*/
static int rpmsg_sdb_open(struct inode *inode, struct file *file)
{
struct rpmsg_sdb_t *_rpmsg_sdb;
_rpmsg_sdb = container_of(file->private_data, struct rpmsg_sdb_t,
mdev);
/* Initialize the buffer list*/
pr_debug("rpmsg_sdb(%s): Init bufferlist", __func__);
pr_info("rpmsg_sdb(%s): start Init bufferlist", __func__);
INIT_LIST_HEAD(&_rpmsg_sdb->buffer_list);
pr_info("rpmsg_sdb(%s): success Init bufferlist", __func__);
mutex_init(&_rpmsg_sdb->mutex);
return 0;
}
/**
* rpmsg_sdb_close - Close Session
*
* @inode: inode struct
* @file: file struct
*
* Return:
* 0 - Success
* Non-zero - Failure
*/
static int rpmsg_sdb_close(struct inode *inode, struct file *file)
{
struct rpmsg_sdb_t *_rpmsg_sdb;
struct sdb_buf_t *pos, *next;
_rpmsg_sdb = container_of(file->private_data, struct rpmsg_sdb_t,
mdev);
list_for_each_entry_safe(pos, next, &_rpmsg_sdb->buffer_list, buflist) {
/* Free the CMA allocation */
pr_info("rpmsg_sdb(%s): Free the CMA allocation 3", __func__);
dma_free_coherent(rpmsg_sdb_dev, pos->size, pos->vaddr, pos->paddr);
/* Remove the buffer from the list */
list_del(&pos->buflist);
/* Free the buffer */
kfree(pos);
}
pr_info("rpmsg_sdb(%s): Free the CMA allocation 4 - done", __func__);
/* Reset LastBufferId */
LastBufferId = 0;
return 0;
}
/**
* rpmsg_sdb_ioctl - IOCTL
*
* @session: ibmvmc_file_session struct
* @cmd: cmd field
* @arg: Argument field
*
* Return:
* 0 - Success
* Non-zero - Failure
*/
static long rpmsg_sdb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int idx = 0;
struct rpmsg_sdb_t *_rpmsg_sdb;
struct sdb_buf_t *buffer, *lastbuffer;
struct list_head *pos;
struct sdb_buf_t *datastructureptr = NULL;
struct rpmsg_sdb_ioctl_set_efd q_set_efd;
struct rpmsg_sdb_ioctl_get_data_size q_get_dat_size;
void __user *argp = (void __user *)arg;
_rpmsg_sdb = container_of(file->private_data, struct rpmsg_sdb_t,
mdev);
switch (cmd) {
case RPMSG_SDB_IOCTL_SET_EFD:
mutex_lock(&_rpmsg_sdb->mutex);
/* Get index from the last buffer in the list */
pr_info("mon-datafile: set EFD\n");
if (!list_empty(&_rpmsg_sdb->buffer_list)) {
lastbuffer = list_last_entry(&_rpmsg_sdb->buffer_list, struct sdb_buf_t, buflist);
idx = lastbuffer->index;
/* Check last index was properly initiated*/
if (lastbuffer->vaddr == NULL) {
// pr_err("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_SET_EFD - previous buffer was not allocated\n");
pr_info("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_SET_EFD - previous buffer was not allocated\n");
mutex_unlock(&_rpmsg_sdb->mutex);
return -EBADE;
}
/* increment this index for the next buffer creation*/
idx++;
}
if (copy_from_user(&q_set_efd, (struct rpmsg_sdb_ioctl_set_efd *)argp,
sizeof(struct rpmsg_sdb_ioctl_set_efd))) {
// pr_err("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_SET_EFD - copy from user failed\n");
pr_info("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_SET_EFD - copy from user failed\n");
mutex_unlock(&_rpmsg_sdb->mutex);
return -EFAULT;
}
/* create a new buffer which will be added in the buffer list */
buffer = kmalloc(sizeof(struct sdb_buf_t), GFP_KERNEL);
buffer->index = idx;
buffer->vaddr = NULL;
buffer->efd_ctx = eventfd_ctx_fdget(q_set_efd.eventfd);
list_add_tail(&buffer->buflist, &_rpmsg_sdb->buffer_list);
pr_info("rpmsg_sdb(SUCCES): RPMSG_SDB_IOCTL_SET_EFD \n");
mutex_unlock(&_rpmsg_sdb->mutex);
break;
case RPMSG_SDB_IOCTL_GET_DATA_SIZE:
pr_info("mon-datafile: get datasize\n");
if (copy_from_user(&q_get_dat_size, (struct rpmsg_sdb_ioctl_get_data_size *)argp,
sizeof(struct rpmsg_sdb_ioctl_get_data_size))) {
pr_err("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_GET_DATA_SIZE - copy from user failed\n");
return -EFAULT;
}
/* Get the index of the requested buffer and then look-up in the buffer list*/
idx = q_get_dat_size.bufferId;
list_for_each(pos, &_rpmsg_sdb->buffer_list)
{
datastructureptr = list_entry(pos, struct sdb_buf_t, buflist);
if (datastructureptr->index == idx) {
/* Get the writing size*/
q_get_dat_size.size = datastructureptr->writing_size;
break;
}
}
if (copy_to_user((struct rpmsg_sdb_ioctl_get_data_size *)argp, &q_get_dat_size,
sizeof(struct rpmsg_sdb_ioctl_get_data_size))) {
pr_err("rpmsg_sdb(ERROR): RPMSG_SDB_IOCTL_GET_DATA_SIZE - copy to user failed\n");
return -EFAULT;
}
/* Reset the writing size*/
datastructureptr->writing_size = -1;
break;
default:
return -EINVAL;
}
return 0;
}
static const struct file_operations rpmsg_sdb_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = rpmsg_sdb_ioctl,
.mmap = rpmsg_sdb_mmap,
.open = rpmsg_sdb_open,
.release = rpmsg_sdb_close,
};
static int rpmsg_sdb_drv_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
int ret = 0;
int buffer_id = 0;
size_t buffer_size;
char *rpmsg_RxBuf;
struct list_head *pos;
struct sdb_buf_t *datastructureptr = NULL;
//pr_info("mon-datafile: receive msg from Copro: %s, len:%d\n", __func__, len);
// struct rpmsg_sdb_t {
// struct mutex mutex; /* mutex to protect the ioctls */
// struct miscdevice mdev; /* misc device ref */
// struct rpmsg_device *rpdev; /* handle rpmsg device */
// struct list_head buffer_list; /* buffer instances list */
// };
rpmsg_RxBuf = (char *)kmalloc(len+1, GFP_KERNEL);
memcpy(rpmsg_RxBuf, data, len);
rpmsg_RxBuf[len] = 0;
// ret = rpmsg_sdb_decode_rxbuf_string(rpmsg_RxBuf, &buffer_id, &buffer_size);
// if (ret < 0)
// goto out;
// if (buffer_id > LastBufferId) {
// ret = -EINVAL;
// goto out;
// }
struct vRCMDeviceData* pdata = (struct vRCMDeviceData*) rpmsg_RxBuf;
//pr_info("rpmsg_sdb(%s): rxbuf_str:%s\n", __func__, rxbuf_str);
// pr_info("rpmsg_sdb(%s): packageno:%d\n", __func__, pdata->packageNo);
// pr_info("rpmsg_sdb(%s): packageCount:%d\n", __func__, pdata->packageCount);
// pr_info("rpmsg_sdb(%s): dataquantity:%d\n", __func__, pdata->dataQuantity);
// pr_info("rpmsg_sdb(%s): data:%d\n", __func__, (pdata->data)[0]);
struct rpmsg_sdb_t *drv = dev_get_drvdata(&rpdev->dev);
if (len == 0) {
dev_err(rpmsg_sdb_dev, "(%s) Empty lenght requested\n", __func__);
return -EINVAL;
}
if (drv == NULL) {
dev_err(rpmsg_sdb_dev, "(%s) no driver found\n", __func__);
return -EINVAL;
}
//copy data to structure
//1. get buffer
// struct vRCMDeviceData* pdata = (struct vRCMDeviceData*) kmalloc(len+1, GFP_KERNEL);
// memcpy(pdata, data, len);
// if (ret < 0)
// goto out;
// if (buffer_id > LastBufferId) {
// ret = -EINVAL;
// goto out;
// }
/**
rpmsg_RxBuf = (char *)kmalloc(len+1, GFP_KERNEL);
memcpy(rpmsg_RxBuf, data, len);
rpmsg_RxBuf[len] = 0;
ret = rpmsg_sdb_decode_rxbuf_string(rpmsg_RxBuf, &buffer_id, &buffer_size);
kfree(rpmsg_RxBuf);
if (ret < 0)
goto out;
if (buffer_id > LastBufferId) {
ret = -EINVAL;
goto out;
}
*/
/* Signal to User space application */
list_for_each(pos, &drv->buffer_list)
{
datastructureptr = list_entry(pos, struct sdb_buf_t, buflist);
/**
* struct vRCMDeviceData {
uint32_t packageNo; //current package Number
uint32_t packageCount; //complete package Number
uint32_t dataQuantity; //number of uint32_t in data
uint32_t data[]; //the data
};
*/
//copy data to buffer
// struct sdb_buf_t {
// int index; /* index of buffer */
// size_t size; /* buffer size */
// size_t writing_size; /* size of data written by copro */
// dma_addr_t paddr; /* physical address*/
// void *vaddr; /* virtual address */
// void *uaddr; /* mapped address for userland */
// struct eventfd_ctx *efd_ctx; /* eventfd context */
// struct list_head buflist; /* reference in the buffers list */
// };
//get the buffer as array of struct vRCMDeviceData
struct vRCMDeviceData* vrBuff = (struct vRCMDeviceData*) (datastructureptr->vaddr);
struct vRCMDeviceData* startAdress = &(vrBuff[pdata->packageNo]);
// pr_info("rpmsg_sdb(%s): startAdress:%d\n", __func__, startAdress);
if (virt_addr_valid(startAdress)) {
// pr_info("rpmsg_sdb(%s): startAdress:%d is valid\n", __func__, startAdress);
memcpy(startAdress, rpmsg_RxBuf, len);
}
else {
pr_info("rpmsg_sdb(%s): startAdress[%d]:%p is invalid!!\n", __func__, startAdress);
}
// if (datastructureptr->index == buffer_id) {
// datastructureptr->writing_size = buffer_size;
// if (datastructureptr->writing_size > datastructureptr->size) {
// dev_err(rpmsg_sdb_dev, "(%s) Writing size is bigger than buffer size\n", __func__);
// ret = -EINVAL;
// goto out;
// }
if ((pdata != NULL) && (pdata->packageNo == pdata->packageCount)) {
pr_info("rpmsg_sdb(%s): signal bufferfull!\n", __func__);
eventfd_signal(datastructureptr->efd_ctx, 1);
break;
}
}
/* Signal to User space application */
/** list_for_each(pos, &drv->buffer_list)
{
datastructureptr = list_entry(pos, struct sdb_buf_t, buflist);
if (datastructureptr->index == buffer_id) {
datastructureptr->writing_size = buffer_size;
if (datastructureptr->writing_size > datastructureptr->size) {
dev_err(rpmsg_sdb_dev, "(%s) Writing size is bigger than buffer size\n", __func__);
ret = -EINVAL;
goto out;
}
eventfd_signal(datastructureptr->efd_ctx, 1);
break;
}
}
*/
out:
kfree(rpmsg_RxBuf);
kfree(pdata);
return ret;
}
static int rpmsg_sdb_drv_probe(struct rpmsg_device *rpdev)
{
int ret = 0;
struct device *dev = &rpdev->dev;
struct rpmsg_sdb_t *rpmsg_sdb;
pr_info("mon-datafile: registering started\n");
rpmsg_sdb = devm_kzalloc(dev, sizeof(*rpmsg_sdb), GFP_KERNEL);
if (!rpmsg_sdb)
return -ENOMEM;
mutex_init(&rpmsg_sdb->mutex);
rpmsg_sdb->rpdev = rpdev;
rpmsg_sdb->mdev.name = "mon-datafile";//"rpmsg-sdb";
rpmsg_sdb->mdev.minor = MISC_DYNAMIC_MINOR;
rpmsg_sdb->mdev.fops = &rpmsg_sdb_fops;
pr_info("mon-datafile: Set Driver data\n");
dev_set_drvdata(&rpdev->dev, rpmsg_sdb);
/* Register misc device */
ret = misc_register(&rpmsg_sdb->mdev);
if (ret) {
dev_err(dev, "Failed to register device\n");
pr_info("mon-datafile: Failed to register device\n");
goto err_out;
}
rpmsg_sdb_dev = rpmsg_sdb->mdev.this_device;
//pr_info("rpmsg_sdb: Failed to register device\n");
dev_info(dev, "%s probed\n", rpmsg_sdb_driver_name);
err_out:
return ret;
}
static void rpmsg_sdb_drv_remove(struct rpmsg_device *rpmsgdev)
{
struct rpmsg_sdb_t *drv = dev_get_drvdata(&rpmsgdev->dev);
misc_deregister(&drv->mdev);
}
static struct rpmsg_device_id rpmsg_driver_sdb_id_table[] = {
{ .name = "vrpmdv-mon-datafile" },
{ },
};
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sdb_id_table);
//static struct rpmsg_driver rpmsg_sdb_rmpsg_drv = {
static struct rpmsg_driver vrpmdv_monitoring_data = {
.drv.name = KBUILD_MODNAME,
.drv.owner = THIS_MODULE,
.id_table = rpmsg_driver_sdb_id_table,
.probe = rpmsg_sdb_drv_probe,
.callback = rpmsg_sdb_drv_cb,
.remove = rpmsg_sdb_drv_remove,
};
module_rpmsg_driver(vrpmdv_monitoring_data);
// static int __init rpmsg_sdb_drv_init(void)
// {
// int ret = 0;
// /* Register rpmsg device */
// ret = register_rpmsg_driver(&rpmsg_sdb_rmpsg_drv);
// if (ret) {
// pr_err("rpmsg_sdb(ERROR): Failed to register device\n");
// return ret;
// }
// pr_info("rpmsg_sdb: Init done\n");
// return ret;
// }
// static void __exit rpmsg_sdb_drv_exit(void)
// {
// unregister_rpmsg_driver(&rpmsg_sdb_rmpsg_drv);
// pr_info("rpmsg_sdb: Exit\n");
// }
// module_init(rpmsg_sdb_drv_init);
// module_exit(rpmsg_sdb_drv_exit);
MODULE_AUTHOR("Markus Lehr <markus@malehr.de>");
MODULE_DESCRIPTION("shared data buffer over RPMSG");
MODULE_VERSION(RPMSG_SDB_DRIVER_VERSION);
MODULE_LICENSE("GPL v2");