[PATCH 22/22] xlink-core: factorize xlink_ioctl function by creating sub-functions for each ioctl command
From: mgross
Date: Tue Dec 01 2020 - 17:38:37 EST
From: Seamus Kelly <seamus.kelly@xxxxxxxxx>
Refactor the too large IOCTL function to call helper functions.
Reviewed-by: Mark Gross <mgross@xxxxxxxxxxxxxxx>
Signed-off-by: Seamus Kelly <seamus.kelly@xxxxxxxxx>
---
drivers/misc/xlink-core/Makefile | 2 +-
drivers/misc/xlink-core/xlink-core.c | 625 ++++++--------------------
drivers/misc/xlink-core/xlink-core.h | 24 +
drivers/misc/xlink-core/xlink-defs.h | 2 +-
drivers/misc/xlink-core/xlink-ioctl.c | 584 ++++++++++++++++++++++++
drivers/misc/xlink-core/xlink-ioctl.h | 36 ++
6 files changed, 773 insertions(+), 500 deletions(-)
create mode 100644 drivers/misc/xlink-core/xlink-core.h
create mode 100644 drivers/misc/xlink-core/xlink-ioctl.c
create mode 100644 drivers/misc/xlink-core/xlink-ioctl.h
diff --git a/drivers/misc/xlink-core/Makefile b/drivers/misc/xlink-core/Makefile
index 6e604c0b8962..2f64703301d6 100644
--- a/drivers/misc/xlink-core/Makefile
+++ b/drivers/misc/xlink-core/Makefile
@@ -2,4 +2,4 @@
# Makefile for KeemBay xlink Linux driver
#
obj-$(CONFIG_XLINK_CORE) += xlink.o
-xlink-objs += xlink-core.o xlink-multiplexer.o xlink-dispatcher.o xlink-platform.o
+xlink-objs += xlink-core.o xlink-multiplexer.o xlink-dispatcher.o xlink-platform.o xlink-ioctl.o
diff --git a/drivers/misc/xlink-core/xlink-core.c b/drivers/misc/xlink-core/xlink-core.c
index 63f65def8aa9..ed2b37085851 100644
--- a/drivers/misc/xlink-core/xlink-core.c
+++ b/drivers/misc/xlink-core/xlink-core.c
@@ -20,9 +20,11 @@
#endif
#include "xlink-defs.h"
+#include "xlink-core.h"
#include "xlink-dispatcher.h"
#include "xlink-multiplexer.h"
#include "xlink-platform.h"
+#include "xlink-ioctl.h"
// xlink version number
#define XLINK_VERSION_MAJOR 0
@@ -52,25 +54,7 @@ static struct class *dev_class;
static struct cdev xlink_cdev;
static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-static enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
- u16 chan, u8 const *pmessage,
- u32 size);
-static enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
- u16 chan, u8 const *message,
- u32 size);
-static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
- u16 chan, u8 const *message,
- u32 size, u32 user_flag);
-static enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
- u32 *event_list,
- u32 num_events,
- xlink_device_event_cb event_notif_fn);
-static enum xlink_error do_xlink_register_device_event(struct xlink_handle *handle,
- u32 *event_list,
- u32 num_events,
- xlink_device_event_cb event_notif_fn,
- u32 user_flag);
static struct mutex dev_event_lock;
static const struct file_operations fops = {
@@ -105,9 +89,6 @@ struct event_info {
xlink_device_event_cb event_notif_fn;
};
-static u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
-#define NUM_REG_EVENTS 4
-
// sysfs attribute functions
static ssize_t event0_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -342,427 +323,84 @@ static int kmb_xlink_remove(struct platform_device *pdev)
* IOCTL function for User Space access to xlink kernel functions
*
*/
+int ioctl_connect(unsigned long arg);
static long xlink_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct xlink_handle devh = {0};
- struct xlinkopenchannel op = {0};
- struct xlinkwritedata wr = {0};
- struct xlinkreaddata rd = {0};
- struct xlinkreadtobuffer rdtobuf = {0};
- struct xlinkconnect con = {0};
- struct xlinkrelease rel = {0};
- struct xlinkstartvpu startvpu = {0};
- struct xlinkcallback cb = {0};
- struct xlinkgetdevicename devn = {0};
- struct xlinkgetdevicelist devl = {0};
- struct xlinkgetdevicestatus devs = {0};
- struct xlinkbootdevice boot = {0};
- struct xlinkresetdevice res = {0};
- struct xlinkdevmode devm = {0};
- struct xlinkregdevevent regdevevent = {0};
- u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
- char name[XLINK_MAX_DEVICE_NAME_SIZE];
- int interface = NULL_INTERFACE;
- u32 device_status = 0;
- u32 num_devices = 0;
- u32 device_mode = 0;
- u32 num_events = 0;
- char filename[64];
- u32 *ev_list;
- u8 reladdr;
- u8 *rdaddr;
- u32 size;
int rc;
switch (cmd) {
case XL_CONNECT:
- if (copy_from_user(&con, (void __user *)arg,
- sizeof(struct xlinkconnect)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)con.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_connect(&devh);
- if (rc == X_LINK_SUCCESS) {
- if (copy_to_user((void __user *)con.handle,
- &devh, sizeof(struct xlink_handle)))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)con.return_code, (void *)&rc,
- sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_connect(arg);
break;
case XL_OPEN_CHANNEL:
- if (copy_from_user(&op, (void __user *)arg,
- sizeof(struct xlinkopenchannel)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)op.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_open_channel(&devh, op.chan, op.mode, op.data_size,
- op.timeout);
- if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_open_channel(arg);
break;
case XL_DATA_READY_CALLBACK:
- if (copy_from_user(&cb, (void __user *)arg,
- sizeof(struct xlinkcallback)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)cb.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
- rc = xlink_data_available_event(&devh, cb.chan, cb.callback);
- if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_data_ready_callback(arg);
break;
case XL_DATA_CONSUMED_CALLBACK:
- if (copy_from_user(&cb, (void __user *)arg,
- sizeof(struct xlinkcallback)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)cb.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
- rc = xlink_data_consumed_event(&devh, cb.chan, cb.callback);
- if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_data_consumed_callback(arg);
break;
case XL_READ_DATA:
- if (copy_from_user(&rd, (void __user *)arg,
- sizeof(struct xlinkreaddata)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)rd.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_read_data(&devh, rd.chan, &rdaddr, &size);
- if (!rc) {
- interface = get_interface_from_sw_device_id(devh.sw_device_id);
- if (interface == IPC_INTERFACE) {
- if (copy_to_user((void __user *)rd.pmessage, (void *)&rdaddr,
- sizeof(u32)))
- return -EFAULT;
- } else {
- if (copy_to_user((void __user *)rd.pmessage, (void *)rdaddr,
- size))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)rd.size, (void *)&size, sizeof(size)))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)rd.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_read_data(arg);
break;
case XL_READ_TO_BUFFER:
- if (copy_from_user(&rdtobuf, (void __user *)arg,
- sizeof(struct xlinkreadtobuffer)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
- (u8 *)volbuf, &size);
- if (!rc) {
- if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
- size))
- return -EFAULT;
- if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
- sizeof(size)))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)rdtobuf.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_read_to_buffer(arg);
break;
case XL_WRITE_DATA:
- if (copy_from_user(&wr, (void __user *)arg,
- sizeof(struct xlinkwritedata)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)wr.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (wr.size <= XLINK_MAX_DATA_SIZE) {
- rc = xlink_write_data_user(&devh, wr.chan, wr.pmessage,
- wr.size);
- if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
- sizeof(rc)))
- return -EFAULT;
- } else {
- return -EFAULT;
- }
+ rc = ioctl_write_data(arg);
break;
case XL_WRITE_VOLATILE:
- if (copy_from_user(&wr, (void __user *)arg,
- sizeof(struct xlinkwritedata)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)wr.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (wr.size <= XLINK_MAX_BUF_SIZE) {
- if (copy_from_user(volbuf, (void __user *)wr.pmessage,
- wr.size))
- return -EFAULT;
- rc = xlink_write_volatile_user(&devh, wr.chan, volbuf,
- wr.size);
- if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
- sizeof(rc)))
- return -EFAULT;
- } else {
- return -EFAULT;
- }
+ rc = ioctl_write_volatile_data(arg);
break;
case XL_WRITE_CONTROL_DATA:
- if (copy_from_user(&wr, (void __user *)arg,
- sizeof(struct xlinkwritedata)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)wr.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (wr.size <= XLINK_MAX_CONTROL_DATA_SIZE) {
- if (copy_from_user(volbuf, (void __user *)wr.pmessage,
- wr.size))
- return -EFAULT;
- rc = xlink_write_control_data(&devh, wr.chan, volbuf,
- wr.size);
- if (copy_to_user((void __user *)wr.return_code,
- (void *)&rc, sizeof(rc)))
- return -EFAULT;
- } else {
- return -EFAULT;
- }
+ rc = ioctl_write_control_data(arg);
break;
case XL_RELEASE_DATA:
- if (copy_from_user(&rel, (void __user *)arg,
- sizeof(struct xlinkrelease)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)rel.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (rel.addr) {
- if (get_user(reladdr, (u32 __user *const)rel.addr))
- return -EFAULT;
- rc = xlink_release_data(&devh, rel.chan,
- (u8 *)&reladdr);
- } else {
- rc = xlink_release_data(&devh, rel.chan, NULL);
- }
- if (copy_to_user((void __user *)rel.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_release_data(arg);
break;
case XL_CLOSE_CHANNEL:
- if (copy_from_user(&op, (void __user *)arg,
- sizeof(struct xlinkopenchannel)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)op.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_close_channel(&devh, op.chan);
- if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_close_channel(arg);
break;
case XL_START_VPU:
- if (copy_from_user(&startvpu, (void __user *)arg,
- sizeof(struct xlinkstartvpu)))
- return -EFAULT;
- if (startvpu.namesize > sizeof(filename))
- return -EINVAL;
- memset(filename, 0, sizeof(filename));
- if (copy_from_user(filename, (void __user *)startvpu.filename,
- startvpu.namesize))
- return -EFAULT;
- rc = xlink_start_vpu(filename);
- if (copy_to_user((void __user *)startvpu.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_start_vpu(arg);
break;
case XL_STOP_VPU:
- rc = xlink_stop_vpu();
+ rc = ioctl_stop_vpu();
break;
case XL_RESET_VPU:
- rc = xlink_stop_vpu();
+ rc = ioctl_stop_vpu();
break;
case XL_DISCONNECT:
- if (copy_from_user(&con, (void __user *)arg,
- sizeof(struct xlinkconnect)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)con.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_disconnect(&devh);
- if (copy_to_user((void __user *)con.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_disconnect(arg);
break;
case XL_GET_DEVICE_NAME:
- if (copy_from_user(&devn, (void __user *)arg,
- sizeof(struct xlinkgetdevicename)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)devn.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
- rc = xlink_get_device_name(&devh, name, devn.name_size);
- if (!rc) {
- if (copy_to_user((void __user *)devn.name, (void *)name,
- devn.name_size))
- return -EFAULT;
- }
- } else {
- rc = X_LINK_ERROR;
- }
- if (copy_to_user((void __user *)devn.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_get_device_name(arg);
break;
case XL_GET_DEVICE_LIST:
- if (copy_from_user(&devl, (void __user *)arg,
- sizeof(struct xlinkgetdevicelist)))
- return -EFAULT;
- rc = xlink_get_device_list(sw_device_id_list, &num_devices);
- if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
- /* TODO: this next copy is dangerous! we have no idea
- * how large the devl.sw_device_id_list buffer is
- * provided by the user. if num_devices is too large,
- * the copy will overflow the buffer.
- */
- if (copy_to_user((void __user *)devl.sw_device_id_list,
- (void *)sw_device_id_list,
- (sizeof(*sw_device_id_list)
- * num_devices)))
- return -EFAULT;
- if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
- (sizeof(num_devices))))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)devl.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_get_device_list(arg);
break;
case XL_GET_DEVICE_STATUS:
- if (copy_from_user(&devs, (void __user *)arg,
- sizeof(struct xlinkgetdevicestatus)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)devs.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_get_device_status(&devh, &device_status);
- if (!rc) {
- if (copy_to_user((void __user *)devs.device_status,
- (void *)&device_status,
- sizeof(device_status)))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)devs.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_get_device_status(arg);
break;
case XL_BOOT_DEVICE:
- if (copy_from_user(&boot, (void __user *)arg,
- sizeof(struct xlinkbootdevice)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)boot.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (boot.binary_name_size > sizeof(filename))
- return -EINVAL;
- memset(filename, 0, sizeof(filename));
- if (copy_from_user(filename, (void __user *)boot.binary_name,
- boot.binary_name_size))
- return -EFAULT;
- rc = xlink_boot_device(&devh, filename);
- if (copy_to_user((void __user *)boot.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_boot_device(arg);
break;
case XL_RESET_DEVICE:
- if (copy_from_user(&res, (void __user *)arg,
- sizeof(struct xlinkresetdevice)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)res.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_reset_device(&devh);
- if (copy_to_user((void __user *)res.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_reset_device(arg);
break;
case XL_GET_DEVICE_MODE:
- if (copy_from_user(&devm, (void __user *)arg,
- sizeof(struct xlinkdevmode)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)devm.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- rc = xlink_get_device_mode(&devh, &device_mode);
- if (!rc) {
- if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
- sizeof(device_mode)))
- return -EFAULT;
- }
- if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_get_device_mode(arg);
break;
case XL_SET_DEVICE_MODE:
- if (copy_from_user(&devm, (void __user *)arg,
- sizeof(struct xlinkdevmode)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)devm.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
- sizeof(device_mode)))
- return -EFAULT;
- rc = xlink_set_device_mode(&devh, device_mode);
- if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_set_device_mode(arg);
break;
case XL_REGISTER_DEV_EVENT:
- if (copy_from_user(®devevent, (void __user *)arg,
- sizeof(struct xlinkregdevevent)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)regdevevent.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- num_events = regdevevent.num_events;
- if (num_events > 0 && num_events <= NUM_REG_EVENTS) {
- ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
- if (ev_list) {
- if (copy_from_user(ev_list,
- (void __user *)regdevevent.event_list,
- (num_events * sizeof(u32)))) {
- kfree(ev_list);
- return -EFAULT;
- }
- rc = xlink_register_device_event_user(&devh,
- ev_list,
- num_events,
- NULL);
- kfree(ev_list);
- } else {
- rc = X_LINK_ERROR;
- }
- } else {
- rc = X_LINK_ERROR;
- }
- if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_register_device_event(arg);
break;
case XL_UNREGISTER_DEV_EVENT:
- if (copy_from_user(®devevent, (void __user *)arg,
- sizeof(struct xlinkregdevevent)))
- return -EFAULT;
- if (copy_from_user(&devh, (void __user *)regdevevent.handle,
- sizeof(struct xlink_handle)))
- return -EFAULT;
- num_events = regdevevent.num_events;
- if (num_events <= NUM_REG_EVENTS) {
- ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
- if (copy_from_user(ev_list,
- (void __user *)regdevevent.event_list,
- (num_events * sizeof(u32)))) {
- kfree(ev_list);
- return -EFAULT;
- }
- rc = xlink_unregister_device_event(&devh, ev_list, num_events);
- kfree(ev_list);
- } else {
- rc = X_LINK_ERROR;
- }
- if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
- return -EFAULT;
+ rc = ioctl_unregister_device_event(arg);
break;
}
if (rc)
@@ -997,13 +635,16 @@ enum xlink_error xlink_close_channel(struct xlink_handle *handle,
}
EXPORT_SYMBOL(xlink_close_channel);
-enum xlink_error xlink_write_data(struct xlink_handle *handle,
- u16 chan, u8 const *pmessage, u32 size)
+static enum xlink_error do_xlink_write_data(struct xlink_handle *handle,
+ u16 chan, u8 const *pmessage,
+ u32 size, u32 user_flag)
{
struct xlink_event *event;
struct xlink_link *link;
enum xlink_error rc;
int event_queued = 0;
+ dma_addr_t paddr = 0;
+ u32 addr;
if (!xlink || !handle)
return X_LINK_ERROR;
@@ -1019,88 +660,75 @@ enum xlink_error xlink_write_data(struct xlink_handle *handle,
chan, size, 0);
if (!event)
return X_LINK_ERROR;
+ event->user_data = user_flag;
if (chan < XLINK_IPC_MAX_CHANNELS &&
event->interface == IPC_INTERFACE) {
/* only passing message address across IPC interface */
- event->data = &pmessage;
+ if (user_flag) {
+ if (get_user(addr, (u32 __user *)pmessage)) {
+ xlink_destroy_event(event);
+ return X_LINK_ERROR;
+ }
+ event->data = &addr;
+ } else {
+ event->data = &pmessage;
+ }
rc = xlink_multiplexer_tx(event, &event_queued);
xlink_destroy_event(event);
} else {
- event->data = (u8 *)pmessage;
- event->paddr = 0;
+ if (user_flag) {
+ event->data = xlink_platform_allocate(&xlink->pdev->dev, &paddr,
+ size,
+ XLINK_PACKET_ALIGNMENT,
+ XLINK_NORMAL_MEMORY);
+ if (!event->data) {
+ xlink_destroy_event(event);
+ return X_LINK_ERROR;
+ }
+ if (copy_from_user(event->data, (void __user *)pmessage, size)) {
+ xlink_platform_deallocate(&xlink->pdev->dev,
+ event->data, paddr, size,
+ XLINK_PACKET_ALIGNMENT,
+ XLINK_NORMAL_MEMORY);
+ xlink_destroy_event(event);
+ return X_LINK_ERROR;
+ }
+ event->paddr = paddr;
+ } else {
+ event->data = (u8 *)pmessage;
+ event->paddr = 0;
+ }
rc = xlink_multiplexer_tx(event, &event_queued);
- if (!event_queued)
+ if (!event_queued) {
+ if (user_flag) {
+ xlink_platform_deallocate(&xlink->pdev->dev,
+ event->data, paddr, size,
+ XLINK_PACKET_ALIGNMENT,
+ XLINK_NORMAL_MEMORY);
+ }
xlink_destroy_event(event);
+ }
}
return rc;
}
-EXPORT_SYMBOL(xlink_write_data);
-static enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
- u16 chan, u8 const *pmessage,
- u32 size)
+enum xlink_error xlink_write_data(struct xlink_handle *handle,
+ u16 chan, u8 const *pmessage, u32 size)
{
- struct xlink_event *event;
- struct xlink_link *link;
- enum xlink_error rc;
- int event_queued = 0;
- dma_addr_t paddr = 0;
- u32 addr;
-
- if (!xlink || !handle)
- return X_LINK_ERROR;
-
- if (size > XLINK_MAX_DATA_SIZE)
- return X_LINK_ERROR;
+ enum xlink_error rc = 0;
- link = get_link_by_sw_device_id(handle->sw_device_id);
- if (!link)
- return X_LINK_ERROR;
+ rc = do_xlink_write_data(handle, chan, pmessage, size, 0);
+ return rc;
+}
+EXPORT_SYMBOL(xlink_write_data);
- event = xlink_create_event(link->id, XLINK_WRITE_REQ, &link->handle,
- chan, size, 0);
- if (!event)
- return X_LINK_ERROR;
- event->user_data = 1;
+enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
+ u16 chan, u8 const *pmessage, u32 size)
+{
+ enum xlink_error rc = 0;
- if (chan < XLINK_IPC_MAX_CHANNELS &&
- event->interface == IPC_INTERFACE) {
- /* only passing message address across IPC interface */
- if (get_user(addr, (u32 __user *)pmessage)) {
- xlink_destroy_event(event);
- return X_LINK_ERROR;
- }
- event->data = &addr;
- rc = xlink_multiplexer_tx(event, &event_queued);
- xlink_destroy_event(event);
- } else {
- event->data = xlink_platform_allocate(&xlink->pdev->dev, &paddr,
- size,
- XLINK_PACKET_ALIGNMENT,
- XLINK_NORMAL_MEMORY);
- if (!event->data) {
- xlink_destroy_event(event);
- return X_LINK_ERROR;
- }
- if (copy_from_user(event->data, (void __user *)pmessage, size)) {
- xlink_platform_deallocate(&xlink->pdev->dev,
- event->data, paddr, size,
- XLINK_PACKET_ALIGNMENT,
- XLINK_NORMAL_MEMORY);
- xlink_destroy_event(event);
- return X_LINK_ERROR;
- }
- event->paddr = paddr;
- rc = xlink_multiplexer_tx(event, &event_queued);
- if (!event_queued) {
- xlink_platform_deallocate(&xlink->pdev->dev,
- event->data, paddr, size,
- XLINK_PACKET_ALIGNMENT,
- XLINK_NORMAL_MEMORY);
- xlink_destroy_event(event);
- }
- }
+ rc = do_xlink_write_data(handle, chan, pmessage, size, 1);
return rc;
}
@@ -1131,25 +759,6 @@ enum xlink_error xlink_write_control_data(struct xlink_handle *handle,
return rc;
}
EXPORT_SYMBOL(xlink_write_control_data);
-static enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
- u16 chan, u8 const *message,
- u32 size)
-{
- enum xlink_error rc = 0;
-
- rc = do_xlink_write_volatile(handle, chan, message, size, 1);
- return rc;
-}
-
-enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
- u16 chan, u8 const *message, u32 size)
-{
- enum xlink_error rc = 0;
-
- rc = do_xlink_write_volatile(handle, chan, message, size, 0);
- return rc;
-}
-EXPORT_SYMBOL(xlink_write_volatile);
static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
u16 chan, u8 const *message,
@@ -1196,6 +805,26 @@ static enum xlink_error do_xlink_write_volatile(struct xlink_handle *handle,
return rc;
}
+enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
+ u16 chan, u8 const *message,
+ u32 size)
+{
+ enum xlink_error rc = 0;
+
+ rc = do_xlink_write_volatile(handle, chan, message, size, 1);
+ return rc;
+}
+
+enum xlink_error xlink_write_volatile(struct xlink_handle *handle,
+ u16 chan, u8 const *message, u32 size)
+{
+ enum xlink_error rc = 0;
+
+ rc = do_xlink_write_volatile(handle, chan, message, size, 0);
+ return rc;
+}
+EXPORT_SYMBOL(xlink_write_volatile);
+
enum xlink_error xlink_read_data(struct xlink_handle *handle,
u16 chan, u8 **pmessage, u32 *size)
{
@@ -1531,29 +1160,6 @@ static bool event_registered(u32 sw_dev_id, u32 event)
return false;
}
-static enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
- u32 *event_list, u32 num_events,
- xlink_device_event_cb event_notif_fn)
-{
- enum xlink_error rc;
-
- rc = do_xlink_register_device_event(handle, event_list, num_events,
- event_notif_fn, 1);
- return rc;
-}
-
-enum xlink_error xlink_register_device_event(struct xlink_handle *handle,
- u32 *event_list, u32 num_events,
- xlink_device_event_cb event_notif_fn)
-{
- enum xlink_error rc;
-
- rc = do_xlink_register_device_event(handle, event_list, num_events,
- event_notif_fn, 0);
- return rc;
-}
-EXPORT_SYMBOL(xlink_register_device_event);
-
static enum xlink_error do_xlink_register_device_event(struct xlink_handle *handle,
u32 *event_list,
u32 num_events,
@@ -1599,6 +1205,29 @@ static enum xlink_error do_xlink_register_device_event(struct xlink_handle *hand
return X_LINK_SUCCESS;
}
+enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
+ u32 *event_list, u32 num_events,
+ xlink_device_event_cb event_notif_fn)
+{
+ enum xlink_error rc;
+
+ rc = do_xlink_register_device_event(handle, event_list, num_events,
+ event_notif_fn, 1);
+ return rc;
+}
+
+enum xlink_error xlink_register_device_event(struct xlink_handle *handle,
+ u32 *event_list, u32 num_events,
+ xlink_device_event_cb event_notif_fn)
+{
+ enum xlink_error rc;
+
+ rc = do_xlink_register_device_event(handle, event_list, num_events,
+ event_notif_fn, 0);
+ return rc;
+}
+EXPORT_SYMBOL(xlink_register_device_event);
+
enum xlink_error xlink_unregister_device_event(struct xlink_handle *handle,
u32 *event_list,
u32 num_events)
diff --git a/drivers/misc/xlink-core/xlink-core.h b/drivers/misc/xlink-core/xlink-core.h
new file mode 100644
index 000000000000..c3d100a75c44
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-core.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * xlink core header file.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+
+#ifndef XLINK_CORE_H_
+#define XLINK_CORE_H_
+#include "xlink-defs.h"
+
+#define NUM_REG_EVENTS 4
+
+enum xlink_error xlink_write_data_user(struct xlink_handle *handle,
+ u16 chan, u8 const *pmessage,
+ u32 size);
+enum xlink_error xlink_register_device_event_user(struct xlink_handle *handle,
+ u32 *event_list, u32 num_events,
+ xlink_device_event_cb event_notif_fn);
+enum xlink_error xlink_write_volatile_user(struct xlink_handle *handle,
+ u16 chan, u8 const *message,
+ u32 size);
+#endif /* XLINK_CORE_H_ */
diff --git a/drivers/misc/xlink-core/xlink-defs.h b/drivers/misc/xlink-core/xlink-defs.h
index df686e5185c5..81aa3bfffcd3 100644
--- a/drivers/misc/xlink-core/xlink-defs.h
+++ b/drivers/misc/xlink-core/xlink-defs.h
@@ -35,7 +35,7 @@
#define CONTROL_CHANNEL_TIMEOUT_MS 0U // wait indefinitely
#define SIGXLNK 44 // signal XLink uses for callback signalling
-#define UNUSED(x) (void)(x)
+#define UNUSED(x) ((void)(x))
// the end of the IPC channel range (starting at zero)
#define XLINK_IPC_MAX_CHANNELS 1024
diff --git a/drivers/misc/xlink-core/xlink-ioctl.c b/drivers/misc/xlink-core/xlink-ioctl.c
new file mode 100644
index 000000000000..9c1a8c896945
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-ioctl.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * xlink Core Driver.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+
+#include "xlink-defs.h"
+#include "xlink-core.h"
+#include "xlink-ioctl.h"
+
+#define CHANNEL_SET_USER_BIT(chan) ((chan) |= (1 << 15))
+
+int ioctl_connect(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkconnect con = {0};
+ int rc = 0;
+
+ if (copy_from_user(&con, (void __user *)arg,
+ sizeof(struct xlinkconnect)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)con.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_connect(&devh);
+ if (rc == X_LINK_SUCCESS) {
+ if (copy_to_user((void __user *)con.handle,
+ &devh, sizeof(struct xlink_handle)))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)con.return_code, (void *)&rc,
+ sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_open_channel(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkopenchannel op = {0};
+ int rc = 0;
+
+ if (copy_from_user(&op, (void __user *)arg,
+ sizeof(struct xlinkopenchannel)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)op.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_open_channel(&devh, op.chan, op.mode, op.data_size,
+ op.timeout);
+ if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_read_data(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkreaddata rd = {0};
+ int rc = 0;
+ u8 *rdaddr;
+ u32 size;
+ int interface;
+
+ if (copy_from_user(&rd, (void __user *)arg,
+ sizeof(struct xlinkreaddata)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)rd.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_read_data(&devh, rd.chan, &rdaddr, &size);
+ if (!rc) {
+ interface = get_interface_from_sw_device_id(devh.sw_device_id);
+ if (interface == IPC_INTERFACE) {
+ if (copy_to_user((void __user *)rd.pmessage, (void *)&rdaddr,
+ sizeof(u32)))
+ return -EFAULT;
+ } else {
+ if (copy_to_user((void __user *)rd.pmessage, (void *)rdaddr,
+ size))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)rd.size, (void *)&size, sizeof(size)))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)rd.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_read_to_buffer(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkreadtobuffer rdtobuf = {0};
+ int rc = 0;
+ u32 size;
+ u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
+ if (copy_from_user(&rdtobuf, (void __user *)arg,
+ sizeof(struct xlinkreadtobuffer)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)rdtobuf.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_read_data_to_buffer(&devh, rdtobuf.chan,
+ (u8 *)volbuf, &size);
+ if (!rc) {
+ if (copy_to_user((void __user *)rdtobuf.pmessage, (void *)volbuf,
+ size))
+ return -EFAULT;
+ if (copy_to_user((void __user *)rdtobuf.size, (void *)&size,
+ sizeof(size)))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)rdtobuf.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_write_data(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkwritedata wr = {0};
+ int rc = 0;
+
+ if (copy_from_user(&wr, (void __user *)arg,
+ sizeof(struct xlinkwritedata)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)wr.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (wr.size <= XLINK_MAX_DATA_SIZE) {
+ rc = xlink_write_data_user(&devh, wr.chan, wr.pmessage,
+ wr.size);
+ if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
+ sizeof(rc)))
+ return -EFAULT;
+ } else {
+ return -EFAULT;
+ }
+ return rc;
+}
+
+int ioctl_write_control_data(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkwritedata wr = {0};
+ u8 volbuf[XLINK_MAX_BUF_SIZE];
+ int rc = 0;
+
+ if (copy_from_user(&wr, (void __user *)arg,
+ sizeof(struct xlinkwritedata)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)wr.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (wr.size <= XLINK_MAX_CONTROL_DATA_SIZE) {
+ if (copy_from_user(volbuf, (void __user *)wr.pmessage,
+ wr.size))
+ return -EFAULT;
+ rc = xlink_write_control_data(&devh, wr.chan, volbuf,
+ wr.size);
+ if (copy_to_user((void __user *)wr.return_code,
+ (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ } else {
+ return -EFAULT;
+ }
+ return rc;
+}
+
+int ioctl_write_volatile_data(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkwritedata wr = {0};
+ int rc = 0;
+ u8 volbuf[XLINK_MAX_BUF_SIZE]; // buffer for volatile transactions
+
+ if (copy_from_user(&wr, (void __user *)arg,
+ sizeof(struct xlinkwritedata)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)wr.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (wr.size <= XLINK_MAX_BUF_SIZE) {
+ if (copy_from_user(volbuf, (void __user *)wr.pmessage,
+ wr.size))
+ return -EFAULT;
+ rc = xlink_write_volatile_user(&devh, wr.chan, volbuf,
+ wr.size);
+ if (copy_to_user((void __user *)wr.return_code, (void *)&rc,
+ sizeof(rc)))
+ return -EFAULT;
+ } else {
+ return -EFAULT;
+ }
+ return rc;
+}
+
+int ioctl_release_data(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkrelease rel = {0};
+ int rc = 0;
+ u8 reladdr;
+
+ if (copy_from_user(&rel, (void __user *)arg,
+ sizeof(struct xlinkrelease)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)rel.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (rel.addr) {
+ if (get_user(reladdr, (u32 __user *const)rel.addr))
+ return -EFAULT;
+ rc = xlink_release_data(&devh, rel.chan,
+ (u8 *)&reladdr);
+ } else {
+ rc = xlink_release_data(&devh, rel.chan, NULL);
+ }
+ if (copy_to_user((void __user *)rel.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_close_channel(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkopenchannel op = {0};
+ int rc = 0;
+
+ if (copy_from_user(&op, (void __user *)arg,
+ sizeof(struct xlinkopenchannel)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)op.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_close_channel(&devh, op.chan);
+ if (copy_to_user((void __user *)op.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_start_vpu(unsigned long arg)
+{
+ struct xlinkstartvpu startvpu = {0};
+ char filename[64];
+ int rc = 0;
+
+ if (copy_from_user(&startvpu, (void __user *)arg,
+ sizeof(struct xlinkstartvpu)))
+ return -EFAULT;
+ if (startvpu.namesize > sizeof(filename))
+ return -EINVAL;
+ memset(filename, 0, sizeof(filename));
+ if (copy_from_user(filename, (void __user *)startvpu.filename,
+ startvpu.namesize))
+ return -EFAULT;
+ rc = xlink_start_vpu(filename);
+ if (copy_to_user((void __user *)startvpu.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_stop_vpu(void)
+{
+ int rc = 0;
+
+ rc = xlink_stop_vpu();
+ return rc;
+}
+
+int ioctl_disconnect(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkconnect con = {0};
+ int rc = 0;
+
+ if (copy_from_user(&con, (void __user *)arg,
+ sizeof(struct xlinkconnect)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)con.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_disconnect(&devh);
+ if (copy_to_user((void __user *)con.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_get_device_name(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkgetdevicename devn = {0};
+ char name[XLINK_MAX_DEVICE_NAME_SIZE];
+ int rc = 0;
+
+ if (copy_from_user(&devn, (void __user *)arg,
+ sizeof(struct xlinkgetdevicename)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)devn.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (devn.name_size <= XLINK_MAX_DEVICE_NAME_SIZE) {
+ rc = xlink_get_device_name(&devh, name, devn.name_size);
+ if (!rc) {
+ if (copy_to_user((void __user *)devn.name, (void *)name,
+ devn.name_size))
+ return -EFAULT;
+ }
+ } else {
+ rc = X_LINK_ERROR;
+ }
+ if (copy_to_user((void __user *)devn.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_get_device_list(unsigned long arg)
+{
+ struct xlinkgetdevicelist devl = {0};
+ u32 sw_device_id_list[XLINK_MAX_DEVICE_LIST_SIZE];
+ u32 num_devices = 0;
+ int rc = 0;
+
+ if (copy_from_user(&devl, (void __user *)arg,
+ sizeof(struct xlinkgetdevicelist)))
+ return -EFAULT;
+ rc = xlink_get_device_list(sw_device_id_list, &num_devices);
+ if (!rc && num_devices <= XLINK_MAX_DEVICE_LIST_SIZE) {
+ /* TODO: this next copy is dangerous! we have no idea
+ * how large the devl.sw_device_id_list buffer is
+ * provided by the user. if num_devices is too large,
+ * the copy will overflow the buffer.
+ */
+ if (copy_to_user((void __user *)devl.sw_device_id_list,
+ (void *)sw_device_id_list,
+ (sizeof(*sw_device_id_list)
+ * num_devices)))
+ return -EFAULT;
+ if (copy_to_user((void __user *)devl.num_devices, (void *)&num_devices,
+ (sizeof(num_devices))))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)devl.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_get_device_status(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkgetdevicestatus devs = {0};
+ u32 device_status = 0;
+ int rc = 0;
+
+ if (copy_from_user(&devs, (void __user *)arg,
+ sizeof(struct xlinkgetdevicestatus)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)devs.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_get_device_status(&devh, &device_status);
+ if (!rc) {
+ if (copy_to_user((void __user *)devs.device_status,
+ (void *)&device_status,
+ sizeof(device_status)))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)devs.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_boot_device(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkbootdevice boot = {0};
+ char filename[64];
+ int rc = 0;
+
+ if (copy_from_user(&boot, (void __user *)arg,
+ sizeof(struct xlinkbootdevice)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)boot.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (boot.binary_name_size > sizeof(filename))
+ return -EINVAL;
+ memset(filename, 0, sizeof(filename));
+ if (copy_from_user(filename, (void __user *)boot.binary_name,
+ boot.binary_name_size))
+ return -EFAULT;
+ rc = xlink_boot_device(&devh, filename);
+ if (copy_to_user((void __user *)boot.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_reset_device(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkresetdevice res = {0};
+ int rc = 0;
+
+ if (copy_from_user(&res, (void __user *)arg,
+ sizeof(struct xlinkresetdevice)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)res.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_reset_device(&devh);
+ if (copy_to_user((void __user *)res.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_get_device_mode(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkdevmode devm = {0};
+ u32 device_mode = 0;
+ int rc = 0;
+
+ if (copy_from_user(&devm, (void __user *)arg,
+ sizeof(struct xlinkdevmode)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)devm.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ rc = xlink_get_device_mode(&devh, &device_mode);
+ if (!rc) {
+ if (copy_to_user((void __user *)devm.device_mode, (void *)&device_mode,
+ sizeof(device_mode)))
+ return -EFAULT;
+ }
+ if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_set_device_mode(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkdevmode devm = {0};
+ u32 device_mode = 0;
+ int rc = 0;
+
+ if (copy_from_user(&devm, (void __user *)arg,
+ sizeof(struct xlinkdevmode)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)devm.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ if (copy_from_user(&device_mode, (void __user *)devm.device_mode,
+ sizeof(device_mode)))
+ return -EFAULT;
+ rc = xlink_set_device_mode(&devh, device_mode);
+ if (copy_to_user((void __user *)devm.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_register_device_event(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkregdevevent regdevevent = {0};
+ u32 num_events = 0;
+ u32 *ev_list;
+ int rc = 0;
+
+ if (copy_from_user(®devevent, (void __user *)arg,
+ sizeof(struct xlinkregdevevent)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)regdevevent.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ num_events = regdevevent.num_events;
+ if (num_events > 0 && num_events <= NUM_REG_EVENTS) {
+ ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
+ if (ev_list) {
+ if (copy_from_user(ev_list,
+ (void __user *)regdevevent.event_list,
+ (num_events * sizeof(u32)))) {
+ kfree(ev_list);
+ return -EFAULT;
+ }
+ rc = xlink_register_device_event_user(&devh,
+ ev_list,
+ num_events,
+ NULL);
+ kfree(ev_list);
+ } else {
+ rc = X_LINK_ERROR;
+ }
+ } else {
+ rc = X_LINK_ERROR;
+ }
+ if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_unregister_device_event(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkregdevevent regdevevent = {0};
+ u32 num_events = 0;
+ u32 *ev_list;
+ int rc = 0;
+
+ if (copy_from_user(®devevent, (void __user *)arg,
+ sizeof(struct xlinkregdevevent)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)regdevevent.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ num_events = regdevevent.num_events;
+ if (num_events <= NUM_REG_EVENTS) {
+ ev_list = kzalloc((num_events * sizeof(u32)), GFP_KERNEL);
+ if (copy_from_user(ev_list,
+ (void __user *)regdevevent.event_list,
+ (num_events * sizeof(u32)))) {
+ kfree(ev_list);
+ return -EFAULT;
+ }
+ rc = xlink_unregister_device_event(&devh, ev_list, num_events);
+ kfree(ev_list);
+ } else {
+ rc = X_LINK_ERROR;
+ }
+ if (copy_to_user((void __user *)regdevevent.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_data_ready_callback(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkcallback cb = {0};
+ int rc = 0;
+
+ if (copy_from_user(&cb, (void __user *)arg,
+ sizeof(struct xlinkcallback)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)cb.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
+ rc = xlink_data_available_event(&devh, cb.chan, cb.callback);
+ if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
+
+int ioctl_data_consumed_callback(unsigned long arg)
+{
+ struct xlink_handle devh = {0};
+ struct xlinkcallback cb = {0};
+ int rc = 0;
+
+ if (copy_from_user(&cb, (void __user *)arg,
+ sizeof(struct xlinkcallback)))
+ return -EFAULT;
+ if (copy_from_user(&devh, (void __user *)cb.handle,
+ sizeof(struct xlink_handle)))
+ return -EFAULT;
+ CHANNEL_SET_USER_BIT(cb.chan); // set MSbit for user space call
+ rc = xlink_data_consumed_event(&devh, cb.chan, cb.callback);
+ if (copy_to_user((void __user *)cb.return_code, (void *)&rc, sizeof(rc)))
+ return -EFAULT;
+ return rc;
+}
diff --git a/drivers/misc/xlink-core/xlink-ioctl.h b/drivers/misc/xlink-core/xlink-ioctl.h
new file mode 100644
index 000000000000..7818b676d488
--- /dev/null
+++ b/drivers/misc/xlink-core/xlink-ioctl.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * xlink ioctl header files.
+ *
+ * Copyright (C) 2018-2019 Intel Corporation
+ *
+ */
+
+#ifndef XLINK_IOCTL_H_
+#define XLINK_IOCTL_H_
+
+int ioctl_connect(unsigned long arg);
+int ioctl_open_channel(unsigned long arg);
+int ioctl_read_data(unsigned long arg);
+int ioctl_read_to_buffer(unsigned long arg);
+int ioctl_write_data(unsigned long arg);
+int ioctl_write_control_data(unsigned long arg);
+int ioctl_write_volatile_data(unsigned long arg);
+int ioctl_release_data(unsigned long arg);
+int ioctl_close_channel(unsigned long arg);
+int ioctl_start_vpu(unsigned long arg);
+int ioctl_stop_vpu(void);
+int ioctl_disconnect(unsigned long arg);
+int ioctl_get_device_name(unsigned long arg);
+int ioctl_get_device_list(unsigned long arg);
+int ioctl_get_device_status(unsigned long arg);
+int ioctl_boot_device(unsigned long arg);
+int ioctl_reset_device(unsigned long arg);
+int ioctl_get_device_mode(unsigned long arg);
+int ioctl_set_device_mode(unsigned long arg);
+int ioctl_register_device_event(unsigned long arg);
+int ioctl_unregister_device_event(unsigned long arg);
+int ioctl_data_ready_callback(unsigned long arg);
+int ioctl_data_consumed_callback(unsigned long arg);
+
+#endif /* XLINK_IOCTL_H_ */
--
2.17.1