[PATCH 3/9] VC04_SERVICES: Add compat ioctl handler for "create service"

Michael Zoran mzoran at crowfest.net
Wed Jan 18 07:04:47 PST 2017


Add compat handler for "create service" ioctl and move
parts in common with the regular ioctl to vchiq_ioctl_create_service

Signed-off-by: Michael Zoran <mzoran at crowfest.net>
---
 .../vc04_services/interface/vchiq_arm/vchiq_arm.c  | 180 +++++++++++++--------
 1 file changed, 112 insertions(+), 68 deletions(-)

diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index 9ade2f63606b..e26949247f91 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -503,6 +503,75 @@ vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
 				   &context, total_size);
 }
 
+static long
+vchiq_ioctl_create_service(VCHIQ_INSTANCE_T instance,
+			   VCHIQ_CREATE_SERVICE_T *args,
+			   VCHIQ_STATUS_T *status)
+{
+	VCHIQ_SERVICE_T *service = NULL;
+	USER_SERVICE_T *user_service = NULL;
+	void *userdata;
+	int srvstate;
+
+	user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
+	if (!user_service)
+		return -ENOMEM;
+
+	if (args->is_open) {
+		if (!instance->connected) {
+			kfree(user_service);
+			return -ENOTCONN;
+		}
+		srvstate = VCHIQ_SRVSTATE_OPENING;
+	} else {
+		srvstate =
+			 instance->connected ?
+			 VCHIQ_SRVSTATE_LISTENING :
+			 VCHIQ_SRVSTATE_HIDDEN;
+	}
+
+	userdata = args->params.userdata;
+	args->params.callback = service_callback;
+	args->params.userdata = user_service;
+
+	service = vchiq_add_service_internal(
+			instance->state,
+			&args->params, srvstate,
+			instance, user_service_free);
+
+	if (!service) {
+		kfree(user_service);
+		return -EEXIST;
+	}
+
+	user_service->service = service;
+	user_service->userdata = userdata;
+	user_service->instance = instance;
+	user_service->is_vchi = (args->is_vchi != 0);
+	user_service->dequeue_pending = 0;
+	user_service->close_pending = 0;
+	user_service->message_available_pos =
+		instance->completion_remove - 1;
+	user_service->msg_insert = 0;
+	user_service->msg_remove = 0;
+	sema_init(&user_service->insert_event, 0);
+	sema_init(&user_service->remove_event, 0);
+	sema_init(&user_service->close_event, 0);
+
+	if (args->is_open) {
+		*status = vchiq_open_service_internal(service, instance->pid);
+
+		if (*status != VCHIQ_SUCCESS) {
+			vchiq_remove_service(service->handle);
+			return (*status == VCHIQ_RETRY) ? -EINTR : -EIO;
+		}
+	}
+
+	args->handle = service->handle;
+
+	return 0;
+}
+
 /****************************************************************************
 *
 *   vchiq_ioctl
@@ -575,85 +644,25 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 	case VCHIQ_IOC_CREATE_SERVICE: {
 		VCHIQ_CREATE_SERVICE_T args;
-		USER_SERVICE_T *user_service = NULL;
-		void *userdata;
-		int srvstate;
 
 		if (copy_from_user
 			 (&args, (const void __user *)arg,
-			  sizeof(args)) != 0) {
+			  sizeof(args))) {
 			ret = -EFAULT;
 			break;
 		}
 
-		user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
-		if (!user_service) {
-			ret = -ENOMEM;
-			break;
-		}
-
-		if (args.is_open) {
-			if (!instance->connected) {
-				ret = -ENOTCONN;
-				kfree(user_service);
-				break;
-			}
-			srvstate = VCHIQ_SRVSTATE_OPENING;
-		} else {
-			srvstate =
-				 instance->connected ?
-				 VCHIQ_SRVSTATE_LISTENING :
-				 VCHIQ_SRVSTATE_HIDDEN;
-		}
-
-		userdata = args.params.userdata;
-		args.params.callback = service_callback;
-		args.params.userdata = user_service;
-		service = vchiq_add_service_internal(
-				instance->state,
-				&args.params, srvstate,
-				instance, user_service_free);
-
-		if (service != NULL) {
-			user_service->service = service;
-			user_service->userdata = userdata;
-			user_service->instance = instance;
-			user_service->is_vchi = (args.is_vchi != 0);
-			user_service->dequeue_pending = 0;
-			user_service->close_pending = 0;
-			user_service->message_available_pos =
-				instance->completion_remove - 1;
-			user_service->msg_insert = 0;
-			user_service->msg_remove = 0;
-			sema_init(&user_service->insert_event, 0);
-			sema_init(&user_service->remove_event, 0);
-			sema_init(&user_service->close_event, 0);
-
-			if (args.is_open) {
-				status = vchiq_open_service_internal
-					(service, instance->pid);
-				if (status != VCHIQ_SUCCESS) {
-					vchiq_remove_service(service->handle);
-					service = NULL;
-					ret = (status == VCHIQ_RETRY) ?
-						-EINTR : -EIO;
-					break;
-				}
-			}
+		ret = vchiq_ioctl_create_service(instance, &args, &status);
 
+		if (ret >= 0) {
 			if (copy_to_user((void __user *)
-				&(((VCHIQ_CREATE_SERVICE_T __user *)
-					arg)->handle),
-				(const void *)&service->handle,
-				sizeof(service->handle)) != 0) {
+					&(((VCHIQ_CREATE_SERVICE_T __user *)
+						arg)->handle),
+					(const void *)&args.handle,
+					sizeof(args.handle))) {
 				ret = -EFAULT;
-				vchiq_remove_service(service->handle);
+				vchiq_remove_service(args.handle);
 			}
-
-			service = NULL;
-		} else {
-			ret = -EEXIST;
-			kfree(user_service);
 		}
 	} break;
 
@@ -1229,6 +1238,39 @@ vchiq_ioctl_compat_internal(
 			ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
 
 	switch (cmd) {
+	case VCHIQ_IOC_CREATE_SERVICE32: {
+		struct vchiq_create_service32 args32;
+		VCHIQ_CREATE_SERVICE_T args;
+
+		if (copy_from_user
+			 (&args32, (const void __user *)arg,
+			  sizeof(args32))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		args.params.fourcc	= args32.params.fourcc;
+		args.params.callback	= compat_ptr(args32.params.callback);
+		args.params.userdata	= compat_ptr(args32.params.userdata);
+		args.params.version	= args32.params.version;
+		args.params.version_min = args32.params.version_min;
+		args.is_open		= args32.is_open;
+		args.is_vchi		= args32.is_vchi;
+
+		ret = vchiq_ioctl_create_service(instance, &args, &status);
+
+		if (ret >= 0) {
+			if (copy_to_user((void __user *)
+					&(((struct vchiq_create_service32 __user *)
+						arg)->handle),
+					(const void *)&args.handle,
+					sizeof(args.handle))) {
+				ret = -EFAULT;
+				vchiq_remove_service(args.handle);
+			}
+		}
+	} break;
+
 	default:
 		ret = -ENOTTY;
 		break;
@@ -1269,6 +1311,8 @@ static long
 vchiq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	switch (cmd) {
+	case VCHIQ_IOC_CREATE_SERVICE32:
+		return vchiq_ioctl_compat_internal(file, cmd, arg);
 	default:
 		return vchiq_ioctl(file, cmd, arg);
 	}
-- 
2.11.0




More information about the linux-rpi-kernel mailing list