1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 32bit compatibility wrappers for the input subsystem. 4 * 5 * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik 6 */ 7 8 #include <linux/export.h> 9 #include <linux/sprintf.h> 10 #include <linux/uaccess.h> 11 #include "input-compat.h" 12 13 #ifdef CONFIG_COMPAT 14 15 int input_event_from_user(const char __user *buffer, 16 struct input_event *event) 17 { 18 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 19 struct input_event_compat compat_event; 20 21 if (copy_from_user(&compat_event, buffer, 22 sizeof(struct input_event_compat))) 23 return -EFAULT; 24 25 event->input_event_sec = compat_event.sec; 26 event->input_event_usec = compat_event.usec; 27 event->type = compat_event.type; 28 event->code = compat_event.code; 29 event->value = compat_event.value; 30 31 } else { 32 if (copy_from_user(event, buffer, sizeof(struct input_event))) 33 return -EFAULT; 34 } 35 36 return 0; 37 } 38 39 int input_event_to_user(char __user *buffer, 40 const struct input_event *event) 41 { 42 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 43 struct input_event_compat compat_event; 44 45 compat_event.sec = event->input_event_sec; 46 compat_event.usec = event->input_event_usec; 47 compat_event.type = event->type; 48 compat_event.code = event->code; 49 compat_event.value = event->value; 50 51 if (copy_to_user(buffer, &compat_event, 52 sizeof(struct input_event_compat))) 53 return -EFAULT; 54 55 } else { 56 if (copy_to_user(buffer, event, sizeof(struct input_event))) 57 return -EFAULT; 58 } 59 60 return 0; 61 } 62 63 int input_ff_effect_from_user(const char __user *buffer, size_t size, 64 struct ff_effect *effect) 65 { 66 if (in_compat_syscall()) { 67 struct ff_effect_compat *compat_effect; 68 69 if (size != sizeof(struct ff_effect_compat)) 70 return -EINVAL; 71 72 /* 73 * It so happens that the pointer which needs to be changed 74 * is the last field in the structure, so we can retrieve the 75 * whole thing and replace just the pointer. 76 */ 77 compat_effect = (struct ff_effect_compat *)effect; 78 79 memset(effect, 0, sizeof(*effect)); 80 81 if (copy_from_user(compat_effect, buffer, 82 sizeof(struct ff_effect_compat))) 83 return -EFAULT; 84 85 if (compat_effect->type == FF_PERIODIC && 86 compat_effect->u.periodic.waveform == FF_CUSTOM) 87 effect->u.periodic.custom_data = 88 compat_ptr(compat_effect->u.periodic.custom_data); 89 } else { 90 if (size != sizeof(struct ff_effect)) 91 return -EINVAL; 92 93 if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 94 return -EFAULT; 95 } 96 97 return 0; 98 } 99 100 int input_bits_to_string(char *buf, int buf_size, unsigned long bits, 101 bool skip_empty) 102 { 103 int len = 0; 104 105 if (in_compat_syscall()) { 106 u32 dword = bits >> 32; 107 if (dword || !skip_empty) 108 len += snprintf(buf, buf_size, "%x ", dword); 109 110 dword = bits & 0xffffffffUL; 111 if (dword || !skip_empty || len) 112 len += snprintf(buf + len, max(buf_size - len, 0), 113 "%x", dword); 114 } else { 115 if (bits || !skip_empty) 116 len += snprintf(buf, buf_size, "%lx", bits); 117 } 118 119 return len; 120 } 121 122 #else 123 124 int input_event_from_user(const char __user *buffer, 125 struct input_event *event) 126 { 127 if (copy_from_user(event, buffer, sizeof(struct input_event))) 128 return -EFAULT; 129 130 return 0; 131 } 132 133 int input_event_to_user(char __user *buffer, 134 const struct input_event *event) 135 { 136 if (copy_to_user(buffer, event, sizeof(struct input_event))) 137 return -EFAULT; 138 139 return 0; 140 } 141 142 int input_ff_effect_from_user(const char __user *buffer, size_t size, 143 struct ff_effect *effect) 144 { 145 if (size != sizeof(struct ff_effect)) 146 return -EINVAL; 147 148 if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 149 return -EFAULT; 150 151 return 0; 152 } 153 154 int input_bits_to_string(char *buf, int buf_size, unsigned long bits, 155 bool skip_empty) 156 { 157 return bits || !skip_empty ? 158 snprintf(buf, buf_size, "%lx", bits) : 0; 159 } 160 161 #endif /* CONFIG_COMPAT */ 162 163 EXPORT_SYMBOL_GPL(input_event_from_user); 164 EXPORT_SYMBOL_GPL(input_event_to_user); 165 EXPORT_SYMBOL_GPL(input_ff_effect_from_user); 166