/** * scu_ipc_ioctl - control ioctls for the SCU * @fp: file handle of the SCU device * @cmd: ioctl coce * @arg: pointer to user passed structure * * Support the I/O and firmware flashing interfaces of the SCU */ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int ret; struct scu_ipc_data data; void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_RAWIO)) return -EPERM; if (cmd == INTE_SCU_IPC_FW_UPDATE) { u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); if (fwbuf == NULL) return -ENOMEM; if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { kfree(fwbuf); return -EFAULT; } ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE); kfree(fwbuf); return ret; } else { if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) return -EFAULT; ret = scu_reg_access(cmd, &data); if (ret < 0) return ret; if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) return -EFAULT; return 0; } }
/** * scu_ipc_ioctl - control ioctls for the SCU * @fp: file handle of the SCU device * @cmd: ioctl coce * @arg: pointer to user passed structure * * Support the I/O and firmware flashing interfaces of the SCU */ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int ret; struct scu_ipc_data data; void __user *argp = (void __user *)arg; if (!capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) return -EFAULT; ret = scu_reg_access(cmd, &data); if (ret < 0) return ret; if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) return -EFAULT; return 0; }
/** * scu_ipc_ioctl - control ioctls for the SCU * @fp: file handle of the SCU device * @cmd: ioctl coce * @arg: pointer to user passed structure * * Support the I/O and firmware flashing interfaces of the SCU */ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int ret = -EINVAL; struct scu_ipc_data data; void __user *argp = (void __user *)arg; int platform; /* Only IOCTL cmd allowed to pass through without capability check */ /* is getting fw version info, all others need to check to prevent */ /* arbitrary access to all sort of bit of the hardware exposed here*/ if (cmd != INTEL_SCU_IPC_FW_REVISION_GET && !capable(CAP_SYS_RAWIO)) return -EPERM; platform = intel_mid_identify_cpu(); switch (cmd) { case INTEL_SCU_IPC_READ_FBMODE_FROM_OSNIB: { u8 fb_mode; ret = intel_scu_ipc_read_osnib_fb_mode(&fb_mode); if (ret < 0) { pr_err("read fb_mode from ipc failed!!\n"); return ret; } ret = copy_to_user(argp, &fb_mode, 1); break; } case INTEL_SCU_IPC_WRITE_FBMODE_TO_OSNIB: { u8 fb_mode; ret = copy_from_user(&fb_mode, (u8 *)arg, 1); if (ret < 0) { pr_err("copy fb_mode from user failed!!\n"); return ret; } ret = intel_scu_ipc_write_osnib_fb_mode(fb_mode); break; } case INTEL_SCU_IPC_READ_BOS_FROM_OSNIB: { u8 resync_reason; ret = intel_scu_ipc_read_osnib_bos(&resync_reason); if (ret < 0) return ret; ret = copy_to_user(argp, &resync_reason, 1); break; } case INTEL_SCU_IPC_WRITE_BOS_TO_OSNIB: { u8 data; ret = copy_from_user(&data, (u8 *)arg, 1); if (ret < 0) { pr_err("copy from user failed!!\n"); return ret; } ret = intel_scu_ipc_write_osnib_bos(data); break; } case INTEL_SCU_IPC_READ_RR_FROM_OSNIB: { u8 reboot_reason; ret = intel_scu_ipc_read_osnib_rr(&reboot_reason); if (ret < 0) return ret; ret = copy_to_user(argp, &reboot_reason, 1); break; } case INTEL_SCU_IPC_WRITE_RR_TO_OSNIB: { u8 data; ret = copy_from_user(&data, (u8 *)arg, 1); if (ret < 0) { pr_err("copy from user failed!!\n"); return ret; } ret = intel_scu_ipc_write_osnib_rr(data); break; } case INTEL_SCU_IPC_WRITE_ALARM_FLAG_TO_OSNIB: { u8 flag, data; ret = copy_from_user(&flag, (u8 *)arg, 1); if (ret < 0) { pr_err("copy from user failed!!\n"); return ret; } ret = intel_scu_ipc_read_osnib(&data, 1, OSNIB_ALARM_OFFSET); if (ret < 0) return ret; if (flag) data = data | 0x1; /* set alarm flag */ else data = data & 0xFE; /* clear alarm flag */ ret = intel_scu_ipc_write_osnib(&data, 1, OSNIB_ALARM_OFFSET); break; } case INTEL_SCU_IPC_READ_VBATTCRIT: { u32 value; pr_debug("cmd = INTEL_SCU_IPC_READ_VBATTCRIT"); ret = intel_scu_ipc_read_mip((u8 *)&value, 4, 0x318, 1); if (ret < 0) return ret; pr_debug("VBATTCRIT VALUE = %x\n", value); ret = copy_to_user(argp, &value, 4); break; } case INTEL_SCU_IPC_FW_REVISION_GET: { struct scu_ipc_version version; if (copy_from_user(&version, argp, sizeof(u32))) return -EFAULT; if (version.count > 16) return -EINVAL; ret = intel_scu_ipc_command(IPCMSG_FW_REVISION, 0, NULL, 0, (u32 *)version.data, 4); if (ret < 0) return ret; if (copy_to_user(argp + sizeof(u32), version.data, version.count)) ret = -EFAULT; break; } case INTEL_SCU_IPC_OSC_CLK_CNTL: { struct osc_clk_t osc_clk; if (copy_from_user(&osc_clk, argp, sizeof(struct osc_clk_t))) return -EFAULT; ret = intel_scu_ipc_osc_clk(osc_clk.id, osc_clk.khz); if (ret) pr_err("%s: failed to set osc clk\n", __func__); break; } case INTEL_SCU_IPC_READ_BYTE_IN_OSNIB: { struct osnib_data read_data; ret = copy_from_user(&read_data, (u8 *)arg, sizeof(struct scu_ipc_data)); if (ret < 0) { pr_err("copy from user failed!!\n"); return ret; } if ((read_data.offset-OSNIB_OFFSET) >= 32) return -EINVAL; ret = intel_scu_ipc_read_osnib_byte(read_data.offset, &read_data.data); if (ret < 0) return ret; ret = copy_to_user(argp, &read_data, sizeof(struct scu_ipc_data)); break; } case INTEL_SCU_IPC_WRITE_BYTE_IN_OSNIB: { struct osnib_data write_data; ret = copy_from_user(&write_data, (u8 *)arg, sizeof(struct scu_ipc_data)); if (ret < 0) { pr_err("copy from user failed!!\n"); return ret; } if ((write_data.offset-OSNIB_OFFSET) >= 32) return -EINVAL; ret = intel_scu_ipc_write_osnib_byte(write_data.offset, write_data.data); if (ret < 0) return ret; break; } default: if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) return -EFAULT; ret = scu_reg_access(cmd, &data); if (ret < 0) return ret; if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) return -EFAULT; return 0; } return ret; }