Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: synaptics-rmi4 - forward upper mechanical buttons to PS/2 guest

On the latest series of ThinkPads, the button events for the TrackPoint
are reported through the touchpad itself as opposed to the TrackPoint
device. In order to report these buttons properly, we need to forward
them to the TrackPoint device and notify psmouse to send the button
presses/releases.

Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Benjamin Tissoires and committed by
Dmitry Torokhov
81dec809 bf3e8502

+95 -16
+13
drivers/input/rmi4/rmi_driver.h
··· 107 107 108 108 const char *rmi_f01_get_product_ID(struct rmi_function *fn); 109 109 110 + #ifdef CONFIG_RMI4_F03 111 + int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button, 112 + int value); 113 + void rmi_f03_commit_buttons(struct rmi_function *fn); 114 + #else 115 + static inline int rmi_f03_overwrite_button(struct rmi_function *fn, 116 + unsigned int button, int value) 117 + { 118 + return 0; 119 + } 120 + static inline void rmi_f03_commit_buttons(struct rmi_function *fn) {} 121 + #endif 122 + 110 123 #ifdef CONFIG_RMI4_F34 111 124 int rmi_f34_create_sysfs(struct rmi_device *rmi_dev); 112 125 void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
+38
drivers/input/rmi4/rmi_f03.c
··· 26 26 #define RMI_F03_BYTES_PER_DEVICE_SHIFT 4 27 27 #define RMI_F03_QUEUE_LENGTH 0x0F 28 28 29 + #define PSMOUSE_OOB_EXTRA_BTNS 0x01 30 + 29 31 struct f03_data { 30 32 struct rmi_function *fn; 31 33 32 34 struct serio *serio; 33 35 36 + unsigned int overwrite_buttons; 37 + 34 38 u8 device_count; 35 39 u8 rx_queue_length; 36 40 }; 41 + 42 + int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button, 43 + int value) 44 + { 45 + struct f03_data *f03 = dev_get_drvdata(&fn->dev); 46 + unsigned int bit; 47 + 48 + if (button < BTN_LEFT || button > BTN_MIDDLE) 49 + return -EINVAL; 50 + 51 + bit = BIT(button - BTN_LEFT); 52 + 53 + if (value) 54 + f03->overwrite_buttons |= bit; 55 + else 56 + f03->overwrite_buttons &= ~bit; 57 + 58 + return 0; 59 + } 60 + 61 + void rmi_f03_commit_buttons(struct rmi_function *fn) 62 + { 63 + struct f03_data *f03 = dev_get_drvdata(&fn->dev); 64 + struct serio *serio = f03->serio; 65 + 66 + serio_pause_rx(serio); 67 + if (serio->drv) { 68 + serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS, 69 + SERIO_OOB_DATA); 70 + serio->drv->interrupt(serio, f03->overwrite_buttons, 71 + SERIO_OOB_DATA); 72 + } 73 + serio_continue_rx(serio); 74 + } 37 75 38 76 static int rmi_f03_pt_write(struct serio *id, unsigned char val) 39 77 {
+44 -16
drivers/input/rmi4/rmi_f30.c
··· 48 48 + 1 \ 49 49 + 1) 50 50 51 + #define TRACKSTICK_RANGE_START 3 52 + #define TRACKSTICK_RANGE_END 6 53 + 51 54 struct rmi_f30_ctrl_data { 52 55 int address; 53 56 int length; ··· 79 76 u16 *gpioled_key_map; 80 77 81 78 struct input_dev *input; 79 + 80 + struct rmi_function *f03; 81 + bool trackstick_buttons; 82 82 }; 83 83 84 84 static int rmi_f30_read_control_parameters(struct rmi_function *fn, ··· 106 100 { 107 101 unsigned int reg_num = button >> 3; 108 102 unsigned int bit_num = button & 0x07; 103 + u16 key_code = f30->gpioled_key_map[button]; 109 104 bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num)); 110 105 111 - rmi_dbg(RMI_DEBUG_FN, &fn->dev, 112 - "%s: call input report key (0x%04x) value (0x%02x)", 113 - __func__, f30->gpioled_key_map[button], key_down); 106 + if (f30->trackstick_buttons && 107 + button >= TRACKSTICK_RANGE_START && 108 + button <= TRACKSTICK_RANGE_END) { 109 + rmi_f03_overwrite_button(f30->f03, key_code, key_down); 110 + } else { 111 + rmi_dbg(RMI_DEBUG_FN, &fn->dev, 112 + "%s: call input report key (0x%04x) value (0x%02x)", 113 + __func__, key_code, key_down); 114 114 115 - input_report_key(f30->input, f30->gpioled_key_map[button], key_down); 115 + input_report_key(f30->input, key_code, key_down); 116 + } 116 117 } 117 118 118 119 static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) ··· 151 138 } 152 139 } 153 140 154 - if (f30->has_gpio) 141 + if (f30->has_gpio) { 155 142 for (i = 0; i < f30->gpioled_count; i++) 156 143 if (f30->gpioled_key_map[i] != KEY_RESERVED) 157 144 rmi_f30_report_button(fn, f30, i); 145 + if (f30->trackstick_buttons) 146 + rmi_f03_commit_buttons(f30->f03); 147 + } 158 148 159 149 return 0; 160 150 } ··· 169 153 const struct rmi_device_platform_data *pdata = 170 154 rmi_get_platform_data(fn->rmi_dev); 171 155 int error; 156 + 157 + if (pdata->f30_data.trackstick_buttons) { 158 + /* Try [re-]establish link to F03. */ 159 + f30->f03 = rmi_find_function(fn->rmi_dev, 0x03); 160 + f30->trackstick_buttons = f30->f03 != NULL; 161 + } 172 162 173 163 if (pdata->f30_data.disable) { 174 164 drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask); ··· 225 203 rmi_get_platform_data(fn->rmi_dev); 226 204 struct input_dev *input = f30->input; 227 205 unsigned int button = BTN_LEFT; 206 + unsigned int trackstick_button = BTN_LEFT; 207 + bool button_mapped = false; 228 208 int i; 229 209 230 210 f30->gpioled_key_map = devm_kcalloc(&fn->dev, ··· 239 215 } 240 216 241 217 for (i = 0; i < f30->gpioled_count; i++) { 242 - if (rmi_f30_is_valid_button(i, f30->ctrl)) { 218 + if (!rmi_f30_is_valid_button(i, f30->ctrl)) 219 + continue; 220 + 221 + if (pdata->f30_data.trackstick_buttons && 222 + i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) { 223 + f30->gpioled_key_map[i] = trackstick_button++; 224 + } else if (!pdata->f30_data.buttonpad || !button_mapped) { 243 225 f30->gpioled_key_map[i] = button; 244 226 input_set_capability(input, EV_KEY, button++); 245 - 246 - /* 247 - * buttonpad might be given by 248 - * f30->has_mech_mouse_btns, but I am 249 - * not sure, so use only the pdata info 250 - */ 251 - if (pdata->f30_data.buttonpad) { 252 - __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 253 - break; 254 - } 227 + button_mapped = true; 255 228 } 256 229 } 257 230 258 231 input->keycode = f30->gpioled_key_map; 259 232 input->keycodesize = sizeof(f30->gpioled_key_map[0]); 260 233 input->keycodemax = f30->gpioled_count; 234 + 235 + /* 236 + * Buttonpad could be also inferred from f30->has_mech_mouse_btns, 237 + * but I am not sure, so use only the pdata info. 238 + */ 239 + if (pdata->f30_data.buttonpad) 240 + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 261 241 262 242 return 0; 263 243 }