//@return, 0:operate successfully // > 0: the length of memory size ioctl has accessed, // error otherwise. static long gt1x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { u32 value = 0; s32 ret = 0; //the initial value must be 0 u8 *data = NULL; GTP_DEBUG("IOCTL CMD:%x", cmd); GTP_DEBUG("command:%d, length:%d, rw:%s", _IOC_NR(cmd), _IOC_SIZE(cmd), (_IOC_DIR(cmd) & _IOC_READ) ? "read" : (_IOC_DIR(cmd) & _IOC_WRITE) ? "write" : "-"); if (_IOC_DIR(cmd)) { s32 err = -1; s32 data_length = _IOC_SIZE(cmd); data = (u8 *) kzalloc(data_length, GFP_KERNEL); memset(data, 0, data_length); if (_IOC_DIR(cmd) & _IOC_WRITE) { err = copy_from_user(data, (void __user *)arg, data_length); if (err) { GTP_DEBUG("Can't access the memory."); kfree(data); return -1; } } } else { value = (u32) arg; } switch (cmd & NEGLECT_SIZE_MASK) { case IO_GET_VERISON: if ((u8 __user *) arg) { ret = copy_to_user(((u8 __user *) arg), IO_VERSION, sizeof(IO_VERSION)); if (!ret) { ret = sizeof(IO_VERSION); } GTP_INFO("%s", IO_VERSION); } break; case IO_IIC_READ: ret = io_iic_read(data, (void __user *)arg); break; case IO_IIC_WRITE: ret = io_iic_write(data); break; case IO_RESET_GUITAR: gt1x_reset_guitar(); break; case IO_DISABLE_IRQ: gt1x_irq_disable(); #if GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_OFF); #endif break; case IO_ENABLE_IRQ: gt1x_irq_enable(); #if GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_ON); #endif break; //print a string to syc log messages between application and kernel. case IO_PRINT: if (data) GTP_INFO("%s", (char *)data); break; #if GTP_GESTURE_WAKEUP case GESTURE_ENABLE_TOTALLY: GTP_DEBUG("ENABLE_GESTURE_TOTALLY"); gesture_enabled = (is_all_dead(gestures_flag, sizeof(gestures_flag)) ? 0 : 1); break; case GESTURE_DISABLE_TOTALLY: GTP_DEBUG("DISABLE_GESTURE_TOTALLY"); gesture_enabled = 0; break; case GESTURE_ENABLE_PARTLY: SETBIT(gestures_flag, (u8) value); gesture_enabled = 1; GTP_DEBUG("ENABLE_GESTURE_PARTLY, gesture = 0x%02X, gesture_enabled = %d", value, gesture_enabled); break; case GESTURE_DISABLE_PARTLY: ret = QUERYBIT(gestures_flag, (u8) value); if (!ret) { break; } CLEARBIT(gestures_flag, (u8) value); if (is_all_dead(gestures_flag, sizeof(gestures_flag))) { gesture_enabled = 0; } GTP_DEBUG("DISABLE_GESTURE_PARTLY, gesture = 0x%02X, gesture_enabled = %d", value, gesture_enabled); break; case GESTURE_DATA_OBTAIN: GTP_DEBUG("OBTAIN_GESTURE_DATA"); mutex_lock(&gesture_data_mutex); if (gesture_data.data[1] > GESTURE_MAX_POINT_COUNT) { gesture_data.data[1] = GESTURE_MAX_POINT_COUNT; } if (gesture_data.data[3] > 80) { gesture_data.data[3] = 80; } ret = copy_to_user(((u8 __user *) arg), &gesture_data.data, 4 + gesture_data.data[1] * 4 + gesture_data.data[3]); mutex_unlock(&gesture_data_mutex); if (ret) { GTP_ERROR("ERROR when copy gesture data to user."); ret = ERROR_MEM; } else { ret = 4 + gesture_data.data[1] * 4 + gesture_data.data[3]; } break; case GESTURE_DATA_ERASE: GTP_DEBUG("ERASE_GESTURE_DATA"); gesture_clear_wakeup_data(); break; #endif // GTP_GESTURE_WAKEUP #if GTP_HOTKNOT case HOTKNOT_LOAD_HOTKNOT: ret = hotknot_load_hotknot_subsystem(); break; case HOTKNOT_LOAD_AUTHENTICATION: #if GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_ON); #endif ret = hotknot_load_authentication_subsystem(); break; case HOTKNOT_RECOVERY_MAIN: ret = hotknot_recovery_main_system(); break; #if HOTKNOT_BLOCK_RW case HOTKNOT_DEVICES_PAIRED: hotknot_paired_flag = 0; force_wake_flag = 0; block_enable = 1; ret = hotknot_block_rw(HN_DEVICE_PAIRED, (s32) value); break; case HOTKNOT_MASTER_SEND: ret = hotknot_block_rw(HN_MASTER_SEND, (s32) value); if (!ret) ret = got_hotknot_extra_state; break; case HOTKNOT_SLAVE_RECEIVE: ret = hotknot_block_rw(HN_SLAVE_RECEIVED, (s32) value); if (!ret) ret = got_hotknot_extra_state; break; case HOTKNOT_MASTER_DEPARTED: ret = hotknot_block_rw(HN_MASTER_DEPARTED, (s32) value); break; case HOTKNOT_SLAVE_DEPARTED: ret = hotknot_block_rw(HN_SLAVE_DEPARTED, (s32) value); break; case HOTKNOT_WAKEUP_BLOCK: hotknot_wakeup_block(); break; #endif //HOTKNOT_BLOCK_RW #endif //GTP_HOTKNOT default: GTP_INFO("Unknown cmd."); ret = -1; break; } if (data != NULL) { kfree(data); } return ret; }
/*@return, 0:operate successfully / > 0: the length of memory size ioctl has accessed, / error otherwise.*/ static long gt1x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { u32 value = 0; s32 ret = 0; /*the initial value must be 0*/ u8 *data = NULL; static struct ratelimit_state ratelimit = { .lock = __RAW_SPIN_LOCK_UNLOCKED(ratelimit.lock), .interval = HZ/2, .burst = 1, .begin = 1, }; GTP_DEBUG("IOCTL CMD:%x", cmd); /*GTP_DEBUG("command:%d, length:%d, rw:%s", _IOC_NR(cmd), _IOC_SIZE(cmd), (_IOC_DIR(cmd) & _IOC_READ) ? "read" : (_IOC_DIR(cmd) & _IOC_WRITE) ? "write" : "-");*/ if (_IOC_DIR(cmd)) { s32 err = -1; s32 data_length = _IOC_SIZE(cmd); data = kzalloc(data_length, GFP_KERNEL); memset(data, 0, data_length); if (_IOC_DIR(cmd) & _IOC_WRITE) { err = copy_from_user(data, (void __user *)arg, data_length); if (err) { GTP_DEBUG("Can't access the memory."); kfree(data); return -1; } } } else { value = (u32) arg; } switch (cmd & NEGLECT_SIZE_MASK) { case IO_GET_VERSION: if ((u8 __user *) arg) { ret = copy_to_user(((u8 __user *) arg), IO_VERSION, sizeof(IO_VERSION)); if (!ret) ret = sizeof(IO_VERSION); GTP_INFO("%s", IO_VERSION); } break; case IO_IIC_READ: if (1 == gt1x_is_tpd_halt()) { if (__ratelimit(&ratelimit)) GTP_ERROR("touch is suspended."); break; } ret = io_iic_read(data, (void __user *)arg); break; case IO_IIC_WRITE: if (1 == gt1x_is_tpd_halt()) { if (__ratelimit(&ratelimit)) GTP_ERROR("touch is suspended."); break; } ret = io_iic_write(data); break; case IO_RESET_GUITAR: gt1x_reset_guitar(); break; case IO_DISABLE_IRQ: gt1x_irq_disable(); #ifdef CONFIG_GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_OFF); #endif break; case IO_ENABLE_IRQ: gt1x_irq_enable(); #ifdef CONFIG_GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_ON); #endif break; /*print a string to syc log messages between application and kernel.*/ case IO_PRINT: if (data) GTP_INFO("%s", (char *)data); break; #ifdef CONFIG_GTP_GESTURE_WAKEUP case GESTURE_ENABLE_TOTALLY: GTP_DEBUG("ENABLE_GESTURE_TOTALLY"); gesture_enabled = (is_all_dead(gestures_flag, sizeof(gestures_flag)) ? 0 : 1); break; case GESTURE_DISABLE_TOTALLY: GTP_DEBUG("DISABLE_GESTURE_TOTALLY"); gesture_enabled = 0; break; case GESTURE_ENABLE_PARTLY: SETBIT(gestures_flag, (u8) value); gesture_enabled = 1; GTP_DEBUG("ENABLE_GESTURE_PARTLY, gesture = 0x%02X, gesture_enabled = %d", value, gesture_enabled); break; case GESTURE_DISABLE_PARTLY: ret = QUERYBIT(gestures_flag, (u8) value); if (!ret) break; CLEARBIT(gestures_flag, (u8) value); if (is_all_dead(gestures_flag, sizeof(gestures_flag))) gesture_enabled = 0; GTP_DEBUG("DISABLE_GESTURE_PARTLY, gesture = 0x%02X, gesture_enabled = %d", value, gesture_enabled); break; case GESTURE_DATA_OBTAIN: GTP_DEBUG("OBTAIN_GESTURE_DATA"); mutex_lock(&gesture_data_mutex); if (gesture_data.data[1] > GESTURE_MAX_POINT_COUNT) gesture_data.data[1] = GESTURE_MAX_POINT_COUNT; if (gesture_data.data[3] > 80) gesture_data.data[3] = 80; ret = copy_to_user(((u8 __user *) arg), &gesture_data.data, 4 + gesture_data.data[1] * 4 + gesture_data.data[3]); mutex_unlock(&gesture_data_mutex); if (ret) { GTP_ERROR("ERROR when copy gesture data to user."); ret = ERROR_MEM; } else { ret = 4 + gesture_data.data[1] * 4 + gesture_data.data[3]; } break; case GESTURE_DATA_ERASE: GTP_DEBUG("ERASE_GESTURE_DATA"); gesture_clear_wakeup_data(); break; #endif /*CONFIG_GTP_GESTURE_WAKEUP*/ #ifdef CONFIG_GTP_HOTKNOT case HOTKNOT_LOAD_HOTKNOT: ret = hotknot_load_hotknot_subsystem(); break; case HOTKNOT_LOAD_AUTHENTICATION: if (1 == gt1x_is_tpd_halt()) { GTP_ERROR("touch is suspended."); break; } #ifdef CONFIG_GTP_ESD_PROTECT gt1x_esd_switch(SWITCH_ON); #endif ret = hotknot_load_authentication_subsystem(); break; case HOTKNOT_RECOVERY_MAIN: if (1 == gt1x_is_tpd_halt()) { GTP_ERROR("touch is suspended."); break; } ret = hotknot_recovery_main_system(); break; #ifdef CONFIG_HOTKNOT_BLOCK_RW case HOTKNOT_DEVICES_PAIRED: hotknot_paired_flag = 0; force_wake_flag = 0; block_enable = 1; ret = hotknot_block_rw(HN_DEVICE_PAIRED, (s32) value); break; case HOTKNOT_MASTER_SEND: ret = hotknot_block_rw(HN_MASTER_SEND, (s32) value); if (!ret) ret = got_hotknot_extra_state; break; case HOTKNOT_SLAVE_RECEIVE: ret = hotknot_block_rw(HN_SLAVE_RECEIVED, (s32) value); if (!ret) ret = got_hotknot_extra_state; break; case HOTKNOT_MASTER_DEPARTED: ret = hotknot_block_rw(HN_MASTER_DEPARTED, (s32) value); break; case HOTKNOT_SLAVE_DEPARTED: ret = hotknot_block_rw(HN_SLAVE_DEPARTED, (s32) value); break; case HOTKNOT_WAKEUP_BLOCK: hotknot_wakeup_block(); break; #endif /*CONFIG_HOTKNOT_BLOCK_RW*/ #endif /*CONFIG_GTP_HOTKNOT*/ default: GTP_INFO("Unknown cmd."); ret = -1; break; } if (data != NULL) kfree(data); return ret; } #ifdef CONFIG_GTP_HOTKNOT #ifdef CONFIG_COMPAT static long gt1x_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; void __user *arg32 = NULL; GTP_DEBUG("gt1x_compat_ioctl cmd = %x, arg: 0x%lx\n", cmd, arg); arg32 = compat_ptr(arg); if (!file->f_op || !file->f_op->unlocked_ioctl) return -ENOTTY; /*GTP_DEBUG("gt1x_compat_ioctl arg: 0x%lx, arg32: 0x%p\n",arg, arg32);*/ switch (cmd & NEGLECT_SIZE_MASK) { case COMPAT_IO_GET_VERSION: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_GET_VERSION\n");*/ if (arg32 == NULL) { GTP_ERROR("invalid argument."); return -EINVAL; } ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_IIC_READ: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_IIC_READ\n");*/ if (arg32 == NULL) { GTP_ERROR("invalid argument."); return -EINVAL; } ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_IIC_WRITE: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_IIC_WRITE\n");*/ if (arg32 == NULL) { GTP_ERROR("invalid argument."); return -EINVAL; } ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_RESET_GUITAR: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_RESET_GUITAR\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_DISABLE_IRQ: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_DISABLE_IRQ\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_ENABLE_IRQ: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_ENABLE_IRQ\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_IO_PRINT: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_IO_PRINT\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_ENABLE_TOTALLY: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_ENABLE_TOTALLY\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_DISABLE_TOTALLY: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_DISABLE_TOTALLY\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_ENABLE_PARTLY: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_ENABLE_PARTLY\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_DISABLE_PARTLY: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_DISABLE_PARTLY\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_DATA_OBTAIN: if (arg32 == NULL) { GTP_ERROR("invalid argument."); return -EINVAL; } /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_DATA_OBTAIN\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_GESTURE_DATA_ERASE: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_GESTURE_DATA_ERASE\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_LOAD_HOTKNOT: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_LOAD_HOTKNOT\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_LOAD_AUTHENTICATION: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_LOAD_AUTHENTICATION\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_RECOVERY_MAIN: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_RECOVERY_MAIN\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_DEVICES_PAIRED: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_DEVICES_PAIRED\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_MASTER_SEND: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_MASTER_SEND\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_SLAVE_RECEIVE: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_SLAVE_RECEIVE\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_MASTER_DEPARTED: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_MASTER_DEPARTED\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_SLAVE_DEPARTED: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_SLAVE_DEPARTED\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; case COMPAT_HOTKNOT_WAKEUP_BLOCK: /*GTP_DEBUG("gt1x_compat_ioctl COMPAT_HOTKNOT_WAKEUP_BLOCK\n");*/ ret = file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); break; default: GTP_INFO("Unknown cmd."); ret = -1; break; } return ret; }