318 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HID driver for ELO usb touchscreen 4000/45004 *5 * Copyright (c) 2013 Jiri Slaby6 *7 * Data parsing taken from elousb driver by Vojtech Pavlik.8 */9 10#include <linux/hid.h>11#include <linux/input.h>12#include <linux/module.h>13#include <linux/usb.h>14#include <linux/workqueue.h>15 16#include "hid-ids.h"17 18#define ELO_PERIODIC_READ_INTERVAL HZ19#define ELO_SMARTSET_CMD_TIMEOUT 2000 /* msec */20 21/* Elo SmartSet commands */22#define ELO_FLUSH_SMARTSET_RESPONSES 0x02 /* Flush all pending smartset responses */23#define ELO_SEND_SMARTSET_COMMAND 0x05 /* Send a smartset command */24#define ELO_GET_SMARTSET_RESPONSE 0x06 /* Get a smartset response */25#define ELO_DIAG 0x64 /* Diagnostics command */26#define ELO_SMARTSET_PACKET_SIZE 827 28struct elo_priv {29 struct usb_device *usbdev;30 struct delayed_work work;31 unsigned char buffer[ELO_SMARTSET_PACKET_SIZE];32};33 34static struct workqueue_struct *wq;35static bool use_fw_quirk = true;36module_param(use_fw_quirk, bool, S_IRUGO);37MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");38 39static int elo_input_configured(struct hid_device *hdev,40 struct hid_input *hidinput)41{42 struct input_dev *input = hidinput->input;43 44 /*45 * ELO devices have one Button usage in GenDesk field, which makes46 * hid-input map it to BTN_LEFT; that confuses userspace, which then47 * considers the device to be a mouse/touchpad instead of touchscreen.48 */49 clear_bit(BTN_LEFT, input->keybit);50 set_bit(BTN_TOUCH, input->keybit);51 set_bit(ABS_PRESSURE, input->absbit);52 input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);53 54 return 0;55}56 57static void elo_process_data(struct input_dev *input, const u8 *data, int size)58{59 int press;60 61 input_report_abs(input, ABS_X, (data[3] << 8) | data[2]);62 input_report_abs(input, ABS_Y, (data[5] << 8) | data[4]);63 64 press = 0;65 if (data[1] & 0x80)66 press = (data[7] << 8) | data[6];67 input_report_abs(input, ABS_PRESSURE, press);68 69 if (data[1] & 0x03) {70 input_report_key(input, BTN_TOUCH, 1);71 input_sync(input);72 }73 74 if (data[1] & 0x04)75 input_report_key(input, BTN_TOUCH, 0);76 77 input_sync(input);78}79 80static int elo_raw_event(struct hid_device *hdev, struct hid_report *report,81 u8 *data, int size)82{83 struct hid_input *hidinput;84 85 if (!(hdev->claimed & HID_CLAIMED_INPUT) || list_empty(&hdev->inputs))86 return 0;87 88 hidinput = list_first_entry(&hdev->inputs, struct hid_input, list);89 90 switch (report->id) {91 case 0:92 if (data[0] == 'T') { /* Mandatory ELO packet marker */93 elo_process_data(hidinput->input, data, size);94 return 1;95 }96 break;97 default: /* unknown report */98 /* Unknown report type; pass upstream */99 hid_info(hdev, "unknown report type %d\n", report->id);100 break;101 }102 103 return 0;104}105 106static int elo_smartset_send_get(struct usb_device *dev, u8 command,107 void *data)108{109 unsigned int pipe;110 u8 dir;111 112 if (command == ELO_SEND_SMARTSET_COMMAND) {113 pipe = usb_sndctrlpipe(dev, 0);114 dir = USB_DIR_OUT;115 } else if (command == ELO_GET_SMARTSET_RESPONSE) {116 pipe = usb_rcvctrlpipe(dev, 0);117 dir = USB_DIR_IN;118 } else119 return -EINVAL;120 121 return usb_control_msg(dev, pipe, command,122 dir | USB_TYPE_VENDOR | USB_RECIP_DEVICE,123 0, 0, data, ELO_SMARTSET_PACKET_SIZE,124 ELO_SMARTSET_CMD_TIMEOUT);125}126 127static int elo_flush_smartset_responses(struct usb_device *dev)128{129 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),130 ELO_FLUSH_SMARTSET_RESPONSES,131 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,132 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);133}134 135static void elo_work(struct work_struct *work)136{137 struct elo_priv *priv = container_of(work, struct elo_priv, work.work);138 struct usb_device *dev = priv->usbdev;139 unsigned char *buffer = priv->buffer;140 int ret;141 142 ret = elo_flush_smartset_responses(dev);143 if (ret < 0) {144 dev_err(&dev->dev, "initial FLUSH_SMARTSET_RESPONSES failed, error %d\n",145 ret);146 goto fail;147 }148 149 /* send Diagnostics command */150 *buffer = ELO_DIAG;151 ret = elo_smartset_send_get(dev, ELO_SEND_SMARTSET_COMMAND, buffer);152 if (ret < 0) {153 dev_err(&dev->dev, "send Diagnostics Command failed, error %d\n",154 ret);155 goto fail;156 }157 158 /* get the result */159 ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE, buffer);160 if (ret < 0) {161 dev_err(&dev->dev, "get Diagnostics Command response failed, error %d\n",162 ret);163 goto fail;164 }165 166 /* read the ack */167 if (*buffer != 'A') {168 ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE,169 buffer);170 if (ret < 0) {171 dev_err(&dev->dev, "get acknowledge response failed, error %d\n",172 ret);173 goto fail;174 }175 }176 177fail:178 ret = elo_flush_smartset_responses(dev);179 if (ret < 0)180 dev_err(&dev->dev, "final FLUSH_SMARTSET_RESPONSES failed, error %d\n",181 ret);182 queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);183}184 185/*186 * Not all Elo devices need the periodic HID descriptor reads.187 * Only firmware version M needs this.188 */189static bool elo_broken_firmware(struct usb_device *dev)190{191 struct usb_device *hub = dev->parent;192 struct usb_device *child = NULL;193 u16 fw_lvl = le16_to_cpu(dev->descriptor.bcdDevice);194 u16 child_vid, child_pid;195 int i;196 197 if (!use_fw_quirk)198 return false;199 if (fw_lvl != 0x10d)200 return false;201 202 /* iterate sibling devices of the touch controller */203 usb_hub_for_each_child(hub, i, child) {204 child_vid = le16_to_cpu(child->descriptor.idVendor);205 child_pid = le16_to_cpu(child->descriptor.idProduct);206 207 /*208 * If one of the devices below is present attached as a sibling of 209 * the touch controller then this is a newer IBM 4820 monitor that 210 * does not need the IBM-requested workaround if fw level is211 * 0x010d - aka 'M'.212 * No other HW can have this combination.213 */214 if (child_vid==0x04b3) {215 switch (child_pid) {216 case 0x4676: /* 4820 21x Video */217 case 0x4677: /* 4820 51x Video */218 case 0x4678: /* 4820 2Lx Video */219 case 0x4679: /* 4820 5Lx Video */220 return false;221 }222 }223 }224 return true;225}226 227static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)228{229 struct elo_priv *priv;230 int ret;231 232 if (!hid_is_usb(hdev))233 return -EINVAL;234 235 priv = kzalloc(sizeof(*priv), GFP_KERNEL);236 if (!priv)237 return -ENOMEM;238 239 INIT_DELAYED_WORK(&priv->work, elo_work);240 priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));241 242 hid_set_drvdata(hdev, priv);243 244 ret = hid_parse(hdev);245 if (ret) {246 hid_err(hdev, "parse failed\n");247 goto err_free;248 }249 250 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);251 if (ret) {252 hid_err(hdev, "hw start failed\n");253 goto err_free;254 }255 256 if (elo_broken_firmware(priv->usbdev)) {257 hid_info(hdev, "broken firmware found, installing workaround\n");258 queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);259 }260 261 return 0;262err_free:263 kfree(priv);264 return ret;265}266 267static void elo_remove(struct hid_device *hdev)268{269 struct elo_priv *priv = hid_get_drvdata(hdev);270 271 hid_hw_stop(hdev);272 cancel_delayed_work_sync(&priv->work);273 kfree(priv);274}275 276static const struct hid_device_id elo_devices[] = {277 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009), },278 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030), },279 { }280};281MODULE_DEVICE_TABLE(hid, elo_devices);282 283static struct hid_driver elo_driver = {284 .name = "elo",285 .id_table = elo_devices,286 .probe = elo_probe,287 .remove = elo_remove,288 .raw_event = elo_raw_event,289 .input_configured = elo_input_configured,290};291 292static int __init elo_driver_init(void)293{294 int ret;295 296 wq = create_singlethread_workqueue("elousb");297 if (!wq)298 return -ENOMEM;299 300 ret = hid_register_driver(&elo_driver);301 if (ret)302 destroy_workqueue(wq);303 304 return ret;305}306module_init(elo_driver_init);307 308static void __exit elo_driver_exit(void)309{310 hid_unregister_driver(&elo_driver);311 destroy_workqueue(wq);312}313module_exit(elo_driver_exit);314 315MODULE_AUTHOR("Jiri Slaby <jslaby@suse.cz>");316MODULE_DESCRIPTION("HID driver for ELO usb touchscreen 4000/4500");317MODULE_LICENSE("GPL");318