18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015-2016 Red Hat 48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/serio.h> 108c2ecf20Sopenharmony_ci#include <linux/notifier.h> 118c2ecf20Sopenharmony_ci#include "rmi_driver.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define RMI_F03_RX_DATA_OFB 0x01 148c2ecf20Sopenharmony_ci#define RMI_F03_OB_SIZE 2 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define RMI_F03_OB_OFFSET 2 178c2ecf20Sopenharmony_ci#define RMI_F03_OB_DATA_OFFSET 1 188c2ecf20Sopenharmony_ci#define RMI_F03_OB_FLAG_TIMEOUT BIT(6) 198c2ecf20Sopenharmony_ci#define RMI_F03_OB_FLAG_PARITY BIT(7) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define RMI_F03_DEVICE_COUNT 0x07 228c2ecf20Sopenharmony_ci#define RMI_F03_BYTES_PER_DEVICE 0x07 238c2ecf20Sopenharmony_ci#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4 248c2ecf20Sopenharmony_ci#define RMI_F03_QUEUE_LENGTH 0x0F 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define PSMOUSE_OOB_EXTRA_BTNS 0x01 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct f03_data { 298c2ecf20Sopenharmony_ci struct rmi_function *fn; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci struct serio *serio; 328c2ecf20Sopenharmony_ci bool serio_registered; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci unsigned int overwrite_buttons; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci u8 device_count; 378c2ecf20Sopenharmony_ci u8 rx_queue_length; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciint rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button, 418c2ecf20Sopenharmony_ci int value) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct f03_data *f03 = dev_get_drvdata(&fn->dev); 448c2ecf20Sopenharmony_ci unsigned int bit; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (button < BTN_LEFT || button > BTN_MIDDLE) 478c2ecf20Sopenharmony_ci return -EINVAL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci bit = BIT(button - BTN_LEFT); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (value) 528c2ecf20Sopenharmony_ci f03->overwrite_buttons |= bit; 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci f03->overwrite_buttons &= ~bit; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid rmi_f03_commit_buttons(struct rmi_function *fn) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct f03_data *f03 = dev_get_drvdata(&fn->dev); 628c2ecf20Sopenharmony_ci struct serio *serio = f03->serio; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci serio_pause_rx(serio); 658c2ecf20Sopenharmony_ci if (serio->drv) { 668c2ecf20Sopenharmony_ci serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS, 678c2ecf20Sopenharmony_ci SERIO_OOB_DATA); 688c2ecf20Sopenharmony_ci serio->drv->interrupt(serio, f03->overwrite_buttons, 698c2ecf20Sopenharmony_ci SERIO_OOB_DATA); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci serio_continue_rx(serio); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int rmi_f03_pt_write(struct serio *id, unsigned char val) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct f03_data *f03 = id->port_data; 778c2ecf20Sopenharmony_ci int error; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev, 808c2ecf20Sopenharmony_ci "%s: Wrote %.2hhx to PS/2 passthrough address", 818c2ecf20Sopenharmony_ci __func__, val); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val); 848c2ecf20Sopenharmony_ci if (error) { 858c2ecf20Sopenharmony_ci dev_err(&f03->fn->dev, 868c2ecf20Sopenharmony_ci "%s: Failed to write to F03 TX register (%d).\n", 878c2ecf20Sopenharmony_ci __func__, error); 888c2ecf20Sopenharmony_ci return error; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int rmi_f03_initialize(struct f03_data *f03) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct rmi_function *fn = f03->fn; 978c2ecf20Sopenharmony_ci struct device *dev = &fn->dev; 988c2ecf20Sopenharmony_ci int error; 998c2ecf20Sopenharmony_ci u8 bytes_per_device; 1008c2ecf20Sopenharmony_ci u8 query1; 1018c2ecf20Sopenharmony_ci u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE]; 1028c2ecf20Sopenharmony_ci size_t query2_len; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1); 1058c2ecf20Sopenharmony_ci if (error) { 1068c2ecf20Sopenharmony_ci dev_err(dev, "Failed to read query register (%d).\n", error); 1078c2ecf20Sopenharmony_ci return error; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci f03->device_count = query1 & RMI_F03_DEVICE_COUNT; 1118c2ecf20Sopenharmony_ci bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) & 1128c2ecf20Sopenharmony_ci RMI_F03_BYTES_PER_DEVICE; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci query2_len = f03->device_count * bytes_per_device; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * The first generation of image sensors don't have a second part to 1188c2ecf20Sopenharmony_ci * their f03 query, as such we have to set some of these values manually 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (query2_len < 1) { 1218c2ecf20Sopenharmony_ci f03->device_count = 1; 1228c2ecf20Sopenharmony_ci f03->rx_queue_length = 7; 1238c2ecf20Sopenharmony_ci } else { 1248c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1, 1258c2ecf20Sopenharmony_ci query2, query2_len); 1268c2ecf20Sopenharmony_ci if (error) { 1278c2ecf20Sopenharmony_ci dev_err(dev, 1288c2ecf20Sopenharmony_ci "Failed to read second set of query registers (%d).\n", 1298c2ecf20Sopenharmony_ci error); 1308c2ecf20Sopenharmony_ci return error; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int rmi_f03_pt_open(struct serio *serio) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct f03_data *f03 = serio->port_data; 1428c2ecf20Sopenharmony_ci struct rmi_function *fn = f03->fn; 1438c2ecf20Sopenharmony_ci const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; 1448c2ecf20Sopenharmony_ci const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET; 1458c2ecf20Sopenharmony_ci u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE]; 1468c2ecf20Sopenharmony_ci int error; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Consume any pending data. Some devices like to spam with 1508c2ecf20Sopenharmony_ci * 0xaa 0x00 announcements which may confuse us as we try to 1518c2ecf20Sopenharmony_ci * probe the device. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len); 1548c2ecf20Sopenharmony_ci if (!error) 1558c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, 1568c2ecf20Sopenharmony_ci "%s: Consumed %*ph (%d) from PS2 guest\n", 1578c2ecf20Sopenharmony_ci __func__, ob_len, obs, ob_len); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic void rmi_f03_pt_close(struct serio *serio) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct f03_data *f03 = serio->port_data; 1658c2ecf20Sopenharmony_ci struct rmi_function *fn = f03->fn; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int rmi_f03_register_pt(struct f03_data *f03) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct serio *serio; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 1758c2ecf20Sopenharmony_ci if (!serio) 1768c2ecf20Sopenharmony_ci return -ENOMEM; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci serio->id.type = SERIO_PS_PSTHRU; 1798c2ecf20Sopenharmony_ci serio->write = rmi_f03_pt_write; 1808c2ecf20Sopenharmony_ci serio->open = rmi_f03_pt_open; 1818c2ecf20Sopenharmony_ci serio->close = rmi_f03_pt_close; 1828c2ecf20Sopenharmony_ci serio->port_data = f03; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci strlcpy(serio->name, "RMI4 PS/2 pass-through", sizeof(serio->name)); 1858c2ecf20Sopenharmony_ci snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", 1868c2ecf20Sopenharmony_ci dev_name(&f03->fn->dev)); 1878c2ecf20Sopenharmony_ci serio->dev.parent = &f03->fn->dev; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci f03->serio = serio; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci printk(KERN_INFO "serio: %s port at %s\n", 1928c2ecf20Sopenharmony_ci serio->name, dev_name(&f03->fn->dev)); 1938c2ecf20Sopenharmony_ci serio_register_port(serio); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int rmi_f03_probe(struct rmi_function *fn) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct device *dev = &fn->dev; 2018c2ecf20Sopenharmony_ci struct f03_data *f03; 2028c2ecf20Sopenharmony_ci int error; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL); 2058c2ecf20Sopenharmony_ci if (!f03) 2068c2ecf20Sopenharmony_ci return -ENOMEM; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci f03->fn = fn; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci error = rmi_f03_initialize(f03); 2118c2ecf20Sopenharmony_ci if (error < 0) 2128c2ecf20Sopenharmony_ci return error; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (f03->device_count != 1) 2158c2ecf20Sopenharmony_ci dev_warn(dev, "found %d devices on PS/2 passthrough", 2168c2ecf20Sopenharmony_ci f03->device_count); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci dev_set_drvdata(dev, f03); 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int rmi_f03_config(struct rmi_function *fn) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct f03_data *f03 = dev_get_drvdata(&fn->dev); 2258c2ecf20Sopenharmony_ci int error; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!f03->serio_registered) { 2288c2ecf20Sopenharmony_ci error = rmi_f03_register_pt(f03); 2298c2ecf20Sopenharmony_ci if (error) 2308c2ecf20Sopenharmony_ci return error; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci f03->serio_registered = true; 2338c2ecf20Sopenharmony_ci } else { 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * We must be re-configuring the sensor, just enable 2368c2ecf20Sopenharmony_ci * interrupts for this function. 2378c2ecf20Sopenharmony_ci */ 2388c2ecf20Sopenharmony_ci fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic irqreturn_t rmi_f03_attention(int irq, void *ctx) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct rmi_function *fn = ctx; 2478c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 2488c2ecf20Sopenharmony_ci struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); 2498c2ecf20Sopenharmony_ci struct f03_data *f03 = dev_get_drvdata(&fn->dev); 2508c2ecf20Sopenharmony_ci const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET; 2518c2ecf20Sopenharmony_ci const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; 2528c2ecf20Sopenharmony_ci u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE]; 2538c2ecf20Sopenharmony_ci u8 ob_status; 2548c2ecf20Sopenharmony_ci u8 ob_data; 2558c2ecf20Sopenharmony_ci unsigned int serio_flags; 2568c2ecf20Sopenharmony_ci int i; 2578c2ecf20Sopenharmony_ci int error; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (drvdata->attn_data.data) { 2608c2ecf20Sopenharmony_ci /* First grab the data passed by the transport device */ 2618c2ecf20Sopenharmony_ci if (drvdata->attn_data.size < ob_len) { 2628c2ecf20Sopenharmony_ci dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n"); 2638c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci memcpy(obs, drvdata->attn_data.data, ob_len); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci drvdata->attn_data.data += ob_len; 2698c2ecf20Sopenharmony_ci drvdata->attn_data.size -= ob_len; 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci /* Grab all of the data registers, and check them for data */ 2728c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len); 2738c2ecf20Sopenharmony_ci if (error) { 2748c2ecf20Sopenharmony_ci dev_err(&fn->dev, 2758c2ecf20Sopenharmony_ci "%s: Failed to read F03 output buffers: %d\n", 2768c2ecf20Sopenharmony_ci __func__, error); 2778c2ecf20Sopenharmony_ci serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); 2788c2ecf20Sopenharmony_ci return IRQ_RETVAL(error); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) { 2838c2ecf20Sopenharmony_ci ob_status = obs[i]; 2848c2ecf20Sopenharmony_ci ob_data = obs[i + RMI_F03_OB_DATA_OFFSET]; 2858c2ecf20Sopenharmony_ci serio_flags = 0; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!(ob_status & RMI_F03_RX_DATA_OFB)) 2888c2ecf20Sopenharmony_ci continue; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (ob_status & RMI_F03_OB_FLAG_TIMEOUT) 2918c2ecf20Sopenharmony_ci serio_flags |= SERIO_TIMEOUT; 2928c2ecf20Sopenharmony_ci if (ob_status & RMI_F03_OB_FLAG_PARITY) 2938c2ecf20Sopenharmony_ci serio_flags |= SERIO_PARITY; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, 2968c2ecf20Sopenharmony_ci "%s: Received %.2hhx from PS2 guest T: %c P: %c\n", 2978c2ecf20Sopenharmony_ci __func__, ob_data, 2988c2ecf20Sopenharmony_ci serio_flags & SERIO_TIMEOUT ? 'Y' : 'N', 2998c2ecf20Sopenharmony_ci serio_flags & SERIO_PARITY ? 'Y' : 'N'); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci serio_interrupt(f03->serio, ob_data, serio_flags); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void rmi_f03_remove(struct rmi_function *fn) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct f03_data *f03 = dev_get_drvdata(&fn->dev); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (f03->serio_registered) 3128c2ecf20Sopenharmony_ci serio_unregister_port(f03->serio); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistruct rmi_function_handler rmi_f03_handler = { 3168c2ecf20Sopenharmony_ci .driver = { 3178c2ecf20Sopenharmony_ci .name = "rmi4_f03", 3188c2ecf20Sopenharmony_ci }, 3198c2ecf20Sopenharmony_ci .func = 0x03, 3208c2ecf20Sopenharmony_ci .probe = rmi_f03_probe, 3218c2ecf20Sopenharmony_ci .config = rmi_f03_config, 3228c2ecf20Sopenharmony_ci .attention = rmi_f03_attention, 3238c2ecf20Sopenharmony_ci .remove = rmi_f03_remove, 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>"); 3278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RMI F03 module"); 3288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 329