From 04f0e6ebd1a2ca3a1f1a356e9a07ef1797ef1b7c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 14 May 2016 23:42:22 +0530 Subject: [PATCH] greybus: fw-management: Add ioctl to initiate mode-switch Once the interface firmware is loaded successfully to a module, userspace can ask it to mode switch to the newly loaded firmware. This patch provides a new ioctl to initiate mode switch. Userspace can initiate a mode switch if it has previously loaded the interface firmware successfully, otherwise the firmware core rejects it. Also, once the mode-switch is initiated, disallow any more interactions from the userspace. Signed-off-by: Viresh Kumar Tested-by: Karthik Ravi Shankar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/fw-management.c | 20 ++++++++++++++++++++ drivers/staging/greybus/greybus_firmware.h | 1 + 2 files changed, 21 insertions(+) diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c index 2db5a11c5a1d..7c2226ab5d5c 100644 --- a/drivers/staging/greybus/fw-management.c +++ b/drivers/staging/greybus/fw-management.c @@ -34,6 +34,8 @@ struct fw_mgmt { unsigned int timeout_jiffies; /* Interface Firmware specific fields */ + bool mode_switch_started; + bool intf_fw_loaded; u8 intf_fw_request_id; u8 intf_fw_status; u16 intf_fw_major; @@ -123,6 +125,7 @@ static int fw_mgmt_load_and_validate_operation(struct fw_mgmt *fw_mgmt, } fw_mgmt->intf_fw_request_id = ret; + fw_mgmt->intf_fw_loaded = false; request.request_id = ret; ret = gb_operation_sync(fw_mgmt->connection, @@ -183,6 +186,8 @@ static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op) dev_err(fw_mgmt->parent, "failed to validate interface firmware, status:%02x\n", fw_mgmt->intf_fw_status); + else + fw_mgmt->intf_fw_loaded = true; complete(&fw_mgmt->completion); @@ -329,6 +334,10 @@ static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd, unsigned int timeout; int ret; + /* Reject any operations after mode-switch has started */ + if (fw_mgmt->mode_switch_started) + return -EBUSY; + switch (cmd) { case FW_MGMT_IOC_GET_INTF_FW: ret = fw_mgmt_interface_fw_version_operation(fw_mgmt, &fw_info); @@ -407,6 +416,17 @@ static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd, fw_mgmt->timeout_jiffies = msecs_to_jiffies(timeout); + return 0; + case FW_MGMT_IOC_MODE_SWITCH: + if (!fw_mgmt->intf_fw_loaded) { + dev_err(fw_mgmt->parent, + "Firmware not loaded for mode-switch\n"); + return -EPERM; + } + + fw_mgmt->mode_switch_started = true; + + /* FIXME: Initiate mode-switch from here */ return 0; default: return -ENOTTY; diff --git a/drivers/staging/greybus/greybus_firmware.h b/drivers/staging/greybus/greybus_firmware.h index 9c5ad75438ae..4e194f21d475 100644 --- a/drivers/staging/greybus/greybus_firmware.h +++ b/drivers/staging/greybus/greybus_firmware.h @@ -79,6 +79,7 @@ struct fw_mgmt_ioc_backend_fw_update { #define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate) #define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update) #define FW_MGMT_IOC_SET_TIMEOUT_MS _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int) +#define FW_MGMT_IOC_MODE_SWITCH _IO(FW_MGMT_IOCTL_BASE, 5) #endif /* __GREYBUS_FIRMWARE_USER_H */ -- 2.39.5