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 if (copy_from_user(compat_effect, buffer, 80 sizeof(struct ff_effect_compat))) 81 return -EFAULT; 82 83 if (compat_effect->type == FF_PERIODIC && 84 compat_effect->u.periodic.waveform == FF_CUSTOM) 85 effect->u.periodic.custom_data = 86 compat_ptr(compat_effect->u.periodic.custom_data); 87 } else { 88 if (size != sizeof(struct ff_effect)) 89 return -EINVAL; 90 91 if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 92 return -EFAULT; 93 } 94 95 return 0; 96 } 97 98 int input_bits_to_string(char *buf, int buf_size, unsigned long bits, 99 bool skip_empty) 100 { 101 int len = 0; 102 103 if (in_compat_syscall()) { 104 u32 dword = bits >> 32; 105 if (dword || !skip_empty) 106 len += snprintf(buf, buf_size, "%x ", dword); 107 108 dword = bits & 0xffffffffUL; 109 if (dword || !skip_empty || len) 110 len += snprintf(buf + len, max(buf_size - len, 0), 111 "%x", dword); 112 } else { 113 if (bits || !skip_empty) 114 len += snprintf(buf, buf_size, "%lx", bits); 115 } 116 117 return len; 118 } 119 120 #else 121 122 int input_event_from_user(const char __user *buffer, 123 struct input_event *event) 124 { 125 if (copy_from_user(event, buffer, sizeof(struct input_event))) 126 return -EFAULT; 127 128 return 0; 129 } 130 131 int input_event_to_user(char __user *buffer, 132 const struct input_event *event) 133 { 134 if (copy_to_user(buffer, event, sizeof(struct input_event))) 135 return -EFAULT; 136 137 return 0; 138 } 139 140 int input_ff_effect_from_user(const char __user *buffer, size_t size, 141 struct ff_effect *effect) 142 { 143 if (size != sizeof(struct ff_effect)) 144 return -EINVAL; 145 146 if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 147 return -EFAULT; 148 149 return 0; 150 } 151 152 int input_bits_to_string(char *buf, int buf_size, unsigned long bits, 153 bool skip_empty) 154 { 155 return bits || !skip_empty ? 156 snprintf(buf, buf_size, "%lx", bits) : 0; 157 } 158 159 #endif /* CONFIG_COMPAT */ 160 161 EXPORT_SYMBOL_GPL(input_event_from_user); 162 EXPORT_SYMBOL_GPL(input_event_to_user); 163 EXPORT_SYMBOL_GPL(input_ff_effect_from_user); 164