/[packages]/backports/8/kernel/current/SOURCES/hid-Add-support-for-Intel-Precise-Touch-and-Stylus.patch
ViewVC logotype

Contents of /backports/8/kernel/current/SOURCES/hid-Add-support-for-Intel-Precise-Touch-and-Stylus.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1935597 - (show annotations) (download)
Tue Jan 24 10:18:02 2023 UTC (14 months, 4 weeks ago) by tmb
File size: 76280 byte(s)
- update to 6.1.8
  * drop merged patches
- hid: Add support for Intel Precise Touch and Stylus
- hid: Add support for Intel Touch Host Controller
- update defconfigs for Microsoft Surface devices
- enable more hid devices


1 From 3847479cdd29d61213ef6fbf9097c5655a134077 Mon Sep 17 00:00:00 2001
2 From: Dorian Stoll <dorian.stoll@tmsp.io>
3 Date: Sun, 11 Dec 2022 12:00:59 +0100
4 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus
5
6 Based on linux-surface/intel-precise-touch@1698639
7
8 Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
9 Patchset: ipts
10 ---
11 drivers/hid/Kconfig | 2 +
12 drivers/hid/Makefile | 2 +
13 drivers/hid/ipts/Kconfig | 14 +
14 drivers/hid/ipts/Makefile | 14 +
15 drivers/hid/ipts/cmd.c | 62 +++++
16 drivers/hid/ipts/cmd.h | 61 ++++
17 drivers/hid/ipts/context.h | 48 ++++
18 drivers/hid/ipts/control.c | 495 +++++++++++++++++++++++++++++++++
19 drivers/hid/ipts/control.h | 127 +++++++++
20 drivers/hid/ipts/desc.h | 81 ++++++
21 drivers/hid/ipts/hid.c | 348 +++++++++++++++++++++++
22 drivers/hid/ipts/hid.h | 22 ++
23 drivers/hid/ipts/main.c | 127 +++++++++
24 drivers/hid/ipts/mei.c | 189 +++++++++++++
25 drivers/hid/ipts/mei.h | 67 +++++
26 drivers/hid/ipts/receiver.c | 249 +++++++++++++++++
27 drivers/hid/ipts/receiver.h | 17 ++
28 drivers/hid/ipts/resources.c | 108 +++++++
29 drivers/hid/ipts/resources.h | 39 +++
30 drivers/hid/ipts/spec-data.h | 100 +++++++
31 drivers/hid/ipts/spec-device.h | 285 +++++++++++++++++++
32 drivers/hid/ipts/spec-hid.h | 35 +++
33 drivers/hid/ipts/thread.c | 85 ++++++
34 drivers/hid/ipts/thread.h | 60 ++++
35 24 files changed, 2637 insertions(+)
36 create mode 100644 drivers/hid/ipts/Kconfig
37 create mode 100644 drivers/hid/ipts/Makefile
38 create mode 100644 drivers/hid/ipts/cmd.c
39 create mode 100644 drivers/hid/ipts/cmd.h
40 create mode 100644 drivers/hid/ipts/context.h
41 create mode 100644 drivers/hid/ipts/control.c
42 create mode 100644 drivers/hid/ipts/control.h
43 create mode 100644 drivers/hid/ipts/desc.h
44 create mode 100644 drivers/hid/ipts/hid.c
45 create mode 100644 drivers/hid/ipts/hid.h
46 create mode 100644 drivers/hid/ipts/main.c
47 create mode 100644 drivers/hid/ipts/mei.c
48 create mode 100644 drivers/hid/ipts/mei.h
49 create mode 100644 drivers/hid/ipts/receiver.c
50 create mode 100644 drivers/hid/ipts/receiver.h
51 create mode 100644 drivers/hid/ipts/resources.c
52 create mode 100644 drivers/hid/ipts/resources.h
53 create mode 100644 drivers/hid/ipts/spec-data.h
54 create mode 100644 drivers/hid/ipts/spec-device.h
55 create mode 100644 drivers/hid/ipts/spec-hid.h
56 create mode 100644 drivers/hid/ipts/thread.c
57 create mode 100644 drivers/hid/ipts/thread.h
58
59 diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
60 index 185a077d59cdd..1523ccdf73b51 100644
61 --- a/drivers/hid/Kconfig
62 +++ b/drivers/hid/Kconfig
63 @@ -1290,4 +1290,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
64
65 source "drivers/hid/surface-hid/Kconfig"
66
67 +source "drivers/hid/ipts/Kconfig"
68 +
69 endmenu
70 diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
71 index e8014c1a2f8b6..e48300bcea9be 100644
72 --- a/drivers/hid/Makefile
73 +++ b/drivers/hid/Makefile
74 @@ -164,3 +164,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
75 obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
76
77 obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/
78 +
79 +obj-$(CONFIG_HID_IPTS) += ipts/
80 diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig
81 new file mode 100644
82 index 0000000000000..297401bd388dd
83 --- /dev/null
84 +++ b/drivers/hid/ipts/Kconfig
85 @@ -0,0 +1,14 @@
86 +# SPDX-License-Identifier: GPL-2.0-or-later
87 +
88 +config HID_IPTS
89 + tristate "Intel Precise Touch & Stylus"
90 + depends on INTEL_MEI
91 + depends on HID
92 + help
93 + Say Y here if your system has a touchscreen using Intels
94 + Precise Touch & Stylus (IPTS) technology.
95 +
96 + If unsure say N.
97 +
98 + To compile this driver as a module, choose M here: the
99 + module will be called ipts.
100 diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile
101 new file mode 100644
102 index 0000000000000..0fe655bccdc0f
103 --- /dev/null
104 +++ b/drivers/hid/ipts/Makefile
105 @@ -0,0 +1,14 @@
106 +# SPDX-License-Identifier: GPL-2.0-or-later
107 +#
108 +# Makefile for the IPTS touchscreen driver
109 +#
110 +
111 +obj-$(CONFIG_HID_IPTS) += ipts.o
112 +ipts-objs := cmd.o
113 +ipts-objs += control.o
114 +ipts-objs += hid.o
115 +ipts-objs += main.o
116 +ipts-objs += mei.o
117 +ipts-objs += receiver.o
118 +ipts-objs += resources.o
119 +ipts-objs += thread.o
120 diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c
121 new file mode 100644
122 index 0000000000000..df93c4c95e021
123 --- /dev/null
124 +++ b/drivers/hid/ipts/cmd.c
125 @@ -0,0 +1,62 @@
126 +// SPDX-License-Identifier: GPL-2.0-or-later
127 +/*
128 + * Copyright (c) 2016 Intel Corporation
129 + * Copyright (c) 2020-2023 Dorian Stoll
130 + *
131 + * Linux driver for Intel Precise Touch & Stylus
132 + */
133 +
134 +#include <linux/errno.h>
135 +#include <linux/types.h>
136 +
137 +#include "cmd.h"
138 +#include "context.h"
139 +#include "mei.h"
140 +#include "spec-device.h"
141 +
142 +int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code,
143 + struct ipts_response *rsp, u64 timeout)
144 +{
145 + int ret = 0;
146 +
147 + if (!ipts)
148 + return -EFAULT;
149 +
150 + if (!rsp)
151 + return -EFAULT;
152 +
153 + /*
154 + * In a response, the command code will have the most significant bit flipped to 1.
155 + * If code is passed to ipts_mei_recv as is, no messages will be recevied.
156 + */
157 + ret = ipts_mei_recv(&ipts->mei, code | IPTS_RSP_BIT, rsp, timeout);
158 + if (ret < 0)
159 + return ret;
160 +
161 + dev_dbg(ipts->dev, "Received 0x%02X with status 0x%02X\n", code, rsp->status);
162 +
163 + /*
164 + * Some devices will always return this error.
165 + * It is allowed to ignore it and to try continuing.
166 + */
167 + if (rsp->status == IPTS_STATUS_COMPAT_CHECK_FAIL)
168 + rsp->status = IPTS_STATUS_SUCCESS;
169 +
170 + return 0;
171 +}
172 +
173 +int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size)
174 +{
175 + struct ipts_command cmd = { 0 };
176 +
177 + if (!ipts)
178 + return -EFAULT;
179 +
180 + cmd.cmd = code;
181 +
182 + if (data && size > 0)
183 + memcpy(cmd.payload, data, size);
184 +
185 + dev_dbg(ipts->dev, "Sending 0x%02X with %ld bytes payload\n", code, size);
186 + return ipts_mei_send(&ipts->mei, &cmd, sizeof(cmd.cmd) + size);
187 +}
188 diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h
189 new file mode 100644
190 index 0000000000000..e94e5491d6fe5
191 --- /dev/null
192 +++ b/drivers/hid/ipts/cmd.h
193 @@ -0,0 +1,61 @@
194 +/* SPDX-License-Identifier: GPL-2.0-or-later */
195 +/*
196 + * Copyright (c) 2016 Intel Corporation
197 + * Copyright (c) 2020-2023 Dorian Stoll
198 + *
199 + * Linux driver for Intel Precise Touch & Stylus
200 + */
201 +
202 +#ifndef IPTS_CMD_H
203 +#define IPTS_CMD_H
204 +
205 +#include <linux/types.h>
206 +
207 +#include "context.h"
208 +#include "spec-device.h"
209 +
210 +/*
211 + * The default timeout for receiving responses
212 + */
213 +#define IPTS_CMD_DEFAULT_TIMEOUT 1000
214 +
215 +/*
216 + * ipts_cmd_recv_timeout() - Receives a response to a command.
217 + * @ipts: The IPTS driver context.
218 + * @code: The type of the command / response.
219 + * @rsp: The address that the received response will be copied to.
220 + * @timeout: How many milliseconds the function will wait at most.
221 + *
222 + * A negative timeout means to wait forever.
223 + *
224 + * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received.
225 +*/
226 +int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code,
227 + struct ipts_response *rsp, u64 timeout);
228 +
229 +/*
230 + * ipts_cmd_recv() - Receives a response to a command.
231 + * @ipts: The IPTS driver context.
232 + * @code: The type of the command / response.
233 + * @rsp: The address that the received response will be copied to.
234 + *
235 + * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received.
236 +*/
237 +static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code,
238 + struct ipts_response *rsp)
239 +{
240 + return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT);
241 +}
242 +
243 +/*
244 + * ipts_cmd_send() - Executes a command on the device.
245 + * @ipts: The IPTS driver context.
246 + * @code: The type of the command to execute.
247 + * @data: The payload containing parameters for the command.
248 + * @size: The size of the payload.
249 + *
250 + * Returns: 0 on success, <0 on error.
251 +*/
252 +int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size);
253 +
254 +#endif /* IPTS_CMD_H */
255 diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h
256 new file mode 100644
257 index 0000000000000..3b3ebe3407a25
258 --- /dev/null
259 +++ b/drivers/hid/ipts/context.h
260 @@ -0,0 +1,48 @@
261 +/* SPDX-License-Identifier: GPL-2.0-or-later */
262 +/*
263 + * Copyright (c) 2016 Intel Corporation
264 + * Copyright (c) 2020-2023 Dorian Stoll
265 + *
266 + * Linux driver for Intel Precise Touch & Stylus
267 + */
268 +
269 +#ifndef IPTS_CONTEXT_H
270 +#define IPTS_CONTEXT_H
271 +
272 +#include <linux/completion.h>
273 +#include <linux/device.h>
274 +#include <linux/hid.h>
275 +#include <linux/mei_cl_bus.h>
276 +#include <linux/mutex.h>
277 +#include <linux/sched.h>
278 +#include <linux/types.h>
279 +
280 +#include "mei.h"
281 +#include "resources.h"
282 +#include "spec-device.h"
283 +#include "thread.h"
284 +
285 +struct ipts_context {
286 + struct device *dev;
287 + struct ipts_mei mei;
288 +
289 + enum ipts_mode mode;
290 +
291 + struct mutex feature_lock;
292 + struct completion feature_event;
293 +
294 + /*
295 + * These are not inside of struct ipts_resources
296 + * because they don't own the memory they point to.
297 + */
298 + struct ipts_buffer feature_report;
299 + struct ipts_buffer descriptor;
300 +
301 + struct hid_device *hid;
302 + struct ipts_device_info info;
303 + struct ipts_resources resources;
304 +
305 + struct ipts_thread receiver_loop;
306 +};
307 +
308 +#endif /* IPTS_CONTEXT_H */
309 diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c
310 new file mode 100644
311 index 0000000000000..79623f852c7be
312 --- /dev/null
313 +++ b/drivers/hid/ipts/control.c
314 @@ -0,0 +1,495 @@
315 +// SPDX-License-Identifier: GPL-2.0-or-later
316 +/*
317 + * Copyright (c) 2016 Intel Corporation
318 + * Copyright (c) 2020-2023 Dorian Stoll
319 + *
320 + * Linux driver for Intel Precise Touch & Stylus
321 + */
322 +
323 +#include <linux/delay.h>
324 +#include <linux/dev_printk.h>
325 +#include <linux/errno.h>
326 +#include <linux/kernel.h>
327 +#include <linux/kthread.h>
328 +#include <linux/types.h>
329 +
330 +#include "cmd.h"
331 +#include "context.h"
332 +#include "control.h"
333 +#include "desc.h"
334 +#include "hid.h"
335 +#include "receiver.h"
336 +#include "resources.h"
337 +#include "spec-data.h"
338 +#include "spec-device.h"
339 +
340 +static int ipts_control_get_device_info(struct ipts_context *ipts, struct ipts_device_info *info)
341 +{
342 + int ret = 0;
343 + struct ipts_response rsp = { 0 };
344 +
345 + if (!ipts)
346 + return -EFAULT;
347 +
348 + if (!info)
349 + return -EFAULT;
350 +
351 + ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0);
352 + if (ret) {
353 + dev_err(ipts->dev, "GET_DEVICE_INFO: send failed: %d\n", ret);
354 + return ret;
355 + }
356 +
357 + ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DEVICE_INFO, &rsp);
358 + if (ret) {
359 + dev_err(ipts->dev, "GET_DEVICE_INFO: recv failed: %d\n", ret);
360 + return ret;
361 + }
362 +
363 + if (rsp.status != IPTS_STATUS_SUCCESS) {
364 + dev_err(ipts->dev, "GET_DEVICE_INFO: cmd failed: %d\n", rsp.status);
365 + return -EBADR;
366 + }
367 +
368 + memcpy(info, rsp.payload, sizeof(*info));
369 + return 0;
370 +}
371 +
372 +static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode)
373 +{
374 + int ret = 0;
375 + struct ipts_set_mode cmd = { 0 };
376 + struct ipts_response rsp = { 0 };
377 +
378 + if (!ipts)
379 + return -EFAULT;
380 +
381 + cmd.mode = mode;
382 +
383 + ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MODE, &cmd, sizeof(cmd));
384 + if (ret) {
385 + dev_err(ipts->dev, "SET_MODE: send failed: %d\n", ret);
386 + return ret;
387 + }
388 +
389 + ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MODE, &rsp);
390 + if (ret) {
391 + dev_err(ipts->dev, "SET_MODE: recv failed: %d\n", ret);
392 + return ret;
393 + }
394 +
395 + if (rsp.status != IPTS_STATUS_SUCCESS) {
396 + dev_err(ipts->dev, "SET_MODE: cmd failed: %d\n", rsp.status);
397 + return -EBADR;
398 + }
399 +
400 + return 0;
401 +}
402 +
403 +static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res)
404 +{
405 + int ret = 0;
406 + struct ipts_mem_window cmd = { 0 };
407 + struct ipts_response rsp = { 0 };
408 +
409 + if (!ipts)
410 + return -EFAULT;
411 +
412 + if (!res)
413 + return -EFAULT;
414 +
415 + for (int i = 0; i < IPTS_BUFFERS; i++) {
416 + cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address);
417 + cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address);
418 + cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address);
419 + cmd.feedback_addr_upper[i] = upper_32_bits(res->feedback[i].dma_address);
420 + }
421 +
422 + cmd.workqueue_addr_lower = lower_32_bits(res->workqueue.dma_address);
423 + cmd.workqueue_addr_upper = upper_32_bits(res->workqueue.dma_address);
424 +
425 + cmd.doorbell_addr_lower = lower_32_bits(res->doorbell.dma_address);
426 + cmd.doorbell_addr_upper = upper_32_bits(res->doorbell.dma_address);
427 +
428 + cmd.hid2me_addr_lower = lower_32_bits(res->hid2me.dma_address);
429 + cmd.hid2me_addr_upper = upper_32_bits(res->hid2me.dma_address);
430 +
431 + cmd.workqueue_size = IPTS_WORKQUEUE_SIZE;
432 + cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE;
433 +
434 + ret = ipts_cmd_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd, sizeof(cmd));
435 + if (ret) {
436 + dev_err(ipts->dev, "SET_MEM_WINDOW: send failed: %d\n", ret);
437 + return ret;
438 + }
439 +
440 + ret = ipts_cmd_recv(ipts, IPTS_CMD_SET_MEM_WINDOW, &rsp);
441 + if (ret) {
442 + dev_err(ipts->dev, "SET_MEM_WINDOW: recv failed: %d\n", ret);
443 + return ret;
444 + }
445 +
446 + if (rsp.status != IPTS_STATUS_SUCCESS) {
447 + dev_err(ipts->dev, "SET_MEM_WINDOW: cmd failed: %d\n", rsp.status);
448 + return -EBADR;
449 + }
450 +
451 + return 0;
452 +}
453 +
454 +static int ipts_control_get_descriptor(struct ipts_context *ipts)
455 +{
456 + int ret = 0;
457 + struct ipts_data_header *header = NULL;
458 + struct ipts_get_descriptor cmd = { 0 };
459 + struct ipts_response rsp = { 0 };
460 +
461 + if (!ipts)
462 + return -EFAULT;
463 +
464 + if (!ipts->resources.descriptor.address)
465 + return -EFAULT;
466 +
467 + memset(ipts->resources.descriptor.address, 0, ipts->resources.descriptor.size);
468 +
469 + cmd.addr_lower = lower_32_bits(ipts->resources.descriptor.dma_address);
470 + cmd.addr_upper = upper_32_bits(ipts->resources.descriptor.dma_address);
471 + cmd.magic = 8;
472 +
473 + ret = ipts_cmd_send(ipts, IPTS_CMD_GET_DESCRIPTOR, &cmd, sizeof(cmd));
474 + if (ret) {
475 + dev_err(ipts->dev, "GET_DESCRIPTOR: send failed: %d\n", ret);
476 + return ret;
477 + }
478 +
479 + ret = ipts_cmd_recv(ipts, IPTS_CMD_GET_DESCRIPTOR, &rsp);
480 + if (ret) {
481 + dev_err(ipts->dev, "GET_DESCRIPTOR: recv failed: %d\n", ret);
482 + return ret;
483 + }
484 +
485 + if (rsp.status != IPTS_STATUS_SUCCESS) {
486 + dev_err(ipts->dev, "GET_DESCRIPTOR: cmd failed: %d\n", rsp.status);
487 + return -EBADR;
488 + }
489 +
490 + header = (struct ipts_data_header *)ipts->resources.descriptor.address;
491 +
492 + if (header->type == IPTS_DATA_TYPE_DESCRIPTOR) {
493 + ipts->descriptor.address = &header->data[8];
494 + ipts->descriptor.size = header->size - 8;
495 +
496 + return 0;
497 + }
498 +
499 + return -ENODATA;
500 +}
501 +
502 +int ipts_control_request_flush(struct ipts_context *ipts)
503 +{
504 + int ret = 0;
505 + struct ipts_quiesce_io cmd = { 0 };
506 +
507 + if (!ipts)
508 + return -EFAULT;
509 +
510 + ret = ipts_cmd_send(ipts, IPTS_CMD_QUIESCE_IO, &cmd, sizeof(cmd));
511 + if (ret)
512 + dev_err(ipts->dev, "QUIESCE_IO: send failed: %d\n", ret);
513 +
514 + return ret;
515 +}
516 +
517 +int ipts_control_wait_flush(struct ipts_context *ipts)
518 +{
519 + int ret = 0;
520 + struct ipts_response rsp = { 0 };
521 +
522 + if (!ipts)
523 + return -EFAULT;
524 +
525 + ret = ipts_cmd_recv(ipts, IPTS_CMD_QUIESCE_IO, &rsp);
526 + if (ret) {
527 + dev_err(ipts->dev, "QUIESCE_IO: recv failed: %d\n", ret);
528 + return ret;
529 + }
530 +
531 + if (rsp.status == IPTS_STATUS_TIMEOUT)
532 + return -EAGAIN;
533 +
534 + if (rsp.status != IPTS_STATUS_SUCCESS) {
535 + dev_err(ipts->dev, "QUIESCE_IO: cmd failed: %d\n", rsp.status);
536 + return -EBADR;
537 + }
538 +
539 + return 0;
540 +}
541 +
542 +int ipts_control_request_data(struct ipts_context *ipts)
543 +{
544 + int ret = 0;
545 +
546 + if (!ipts)
547 + return -EFAULT;
548 +
549 + ret = ipts_cmd_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0);
550 + if (ret)
551 + dev_err(ipts->dev, "READY_FOR_DATA: send failed: %d\n", ret);
552 +
553 + return ret;
554 +}
555 +
556 +int ipts_control_wait_data(struct ipts_context *ipts, bool shutdown)
557 +{
558 + int ret = 0;
559 + struct ipts_response rsp = { 0 };
560 +
561 + if (!ipts)
562 + return -EFAULT;
563 +
564 + if (!shutdown)
565 + ret = ipts_cmd_recv_timeout(ipts, IPTS_CMD_READY_FOR_DATA, &rsp, 0);
566 + else
567 + ret = ipts_cmd_recv(ipts, IPTS_CMD_READY_FOR_DATA, &rsp);
568 +
569 + if (ret) {
570 + if (ret != -EAGAIN)
571 + dev_err(ipts->dev, "READY_FOR_DATA: recv failed: %d\n", ret);
572 +
573 + return ret;
574 + }
575 +
576 + /*
577 + * During shutdown, it is possible that the sensor has already been disabled.
578 + */
579 + if (rsp.status == IPTS_STATUS_SENSOR_DISABLED)
580 + return 0;
581 +
582 + if (rsp.status == IPTS_STATUS_TIMEOUT)
583 + return -EAGAIN;
584 +
585 + if (rsp.status != IPTS_STATUS_SUCCESS) {
586 + dev_err(ipts->dev, "READY_FOR_DATA: cmd failed: %d\n", rsp.status);
587 + return -EBADR;
588 + }
589 +
590 + return 0;
591 +}
592 +
593 +int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer)
594 +{
595 + int ret = 0;
596 + struct ipts_feedback cmd = { 0 };
597 + struct ipts_response rsp = { 0 };
598 +
599 + if (!ipts)
600 + return -EFAULT;
601 +
602 + cmd.buffer = buffer;
603 +
604 + ret = ipts_cmd_send(ipts, IPTS_CMD_FEEDBACK, &cmd, sizeof(cmd));
605 + if (ret) {
606 + dev_err(ipts->dev, "FEEDBACK: send failed: %d\n", ret);
607 + return ret;
608 + }
609 +
610 + ret = ipts_cmd_recv(ipts, IPTS_CMD_FEEDBACK, &rsp);
611 + if (ret) {
612 + dev_err(ipts->dev, "FEEDBACK: recv failed: %d\n", ret);
613 + return ret;
614 + }
615 +
616 + /*
617 + * We don't know what feedback data looks like so we are sending zeros.
618 + * See also ipts_control_refill_buffer.
619 + */
620 + if (rsp.status == IPTS_STATUS_INVALID_PARAMS)
621 + return 0;
622 +
623 + if (rsp.status != IPTS_STATUS_SUCCESS) {
624 + dev_err(ipts->dev, "FEEDBACK: cmd failed: %d\n", rsp.status);
625 + return -EBADR;
626 + }
627 +
628 + return 0;
629 +}
630 +
631 +int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd,
632 + enum ipts_feedback_data_type type, void *data, size_t size)
633 +{
634 + struct ipts_feedback_header *header = NULL;
635 +
636 + if (!ipts)
637 + return -EFAULT;
638 +
639 + if (!ipts->resources.hid2me.address)
640 + return -EFAULT;
641 +
642 + memset(ipts->resources.hid2me.address, 0, ipts->resources.hid2me.size);
643 + header = (struct ipts_feedback_header *)ipts->resources.hid2me.address;
644 +
645 + header->cmd_type = cmd;
646 + header->data_type = type;
647 + header->size = size;
648 + header->buffer = IPTS_HID2ME_BUFFER;
649 +
650 + if (size + sizeof(*header) > ipts->resources.hid2me.size)
651 + return -EINVAL;
652 +
653 + if (data && size > 0)
654 + memcpy(header->payload, data, size);
655 +
656 + return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER);
657 +}
658 +
659 +static inline int ipts_control_reset_sensor(struct ipts_context *ipts)
660 +{
661 + return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET,
662 + IPTS_FEEDBACK_DATA_TYPE_VENDOR, NULL, 0);
663 +}
664 +
665 +int ipts_control_start(struct ipts_context *ipts)
666 +{
667 + int ret = 0;
668 + struct ipts_device_info info = { 0 };
669 +
670 + if (!ipts)
671 + return -EFAULT;
672 +
673 + dev_info(ipts->dev, "Starting IPTS\n");
674 +
675 + ret = ipts_control_get_device_info(ipts, &info);
676 + if (ret) {
677 + dev_err(ipts->dev, "Failed to get device info: %d\n", ret);
678 + return ret;
679 + }
680 +
681 + ipts->info = info;
682 +
683 + ret = ipts_resources_init(&ipts->resources, ipts->dev, info.data_size, info.feedback_size);
684 + if (ret) {
685 + dev_err(ipts->dev, "Failed to allocate buffers: %d", ret);
686 + return ret;
687 + }
688 +
689 + dev_info(ipts->dev, "IPTS EDS Version: %d\n", info.intf_eds);
690 +
691 + /*
692 + * Handle newer devices
693 + */
694 + if (info.intf_eds > 1) {
695 + /*
696 + * Fetching the descriptor will only work on newer devices.
697 + * For older devices, a fallback descriptor will be used.
698 + */
699 + ret = ipts_control_get_descriptor(ipts);
700 + if (ret) {
701 + dev_err(ipts->dev, "Failed to fetch HID descriptor: %d\n", ret);
702 + return ret;
703 + }
704 +
705 + /*
706 + * Newer devices can be directly initialized in doorbell mode.
707 + */
708 + ipts->mode = IPTS_MODE_DOORBELL;
709 + }
710 +
711 + ret = ipts_control_set_mode(ipts, ipts->mode);
712 + if (ret) {
713 + dev_err(ipts->dev, "Failed to set mode: %d\n", ret);
714 + return ret;
715 + }
716 +
717 + ret = ipts_control_set_mem_window(ipts, &ipts->resources);
718 + if (ret) {
719 + dev_err(ipts->dev, "Failed to set memory window: %d\n", ret);
720 + return ret;
721 + }
722 +
723 + ret = ipts_receiver_start(ipts);
724 + if (ret) {
725 + dev_err(ipts->dev, "Failed to start receiver: %d\n", ret);
726 + return ret;
727 + }
728 +
729 + ret = ipts_control_request_data(ipts);
730 + if (ret) {
731 + dev_err(ipts->dev, "Failed to request data: %d\n", ret);
732 + return ret;
733 + }
734 +
735 + ret = ipts_hid_init(ipts, info);
736 + if (ret) {
737 + dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret);
738 + return ret;
739 + }
740 +
741 + return 0;
742 +}
743 +
744 +static int _ipts_control_stop(struct ipts_context *ipts)
745 +{
746 + int ret = 0;
747 +
748 + if (!ipts)
749 + return -EFAULT;
750 +
751 + dev_info(ipts->dev, "Stopping IPTS\n");
752 +
753 + ret = ipts_receiver_stop(ipts);
754 + if (ret) {
755 + dev_err(ipts->dev, "Failed to stop receiver: %d\n", ret);
756 + return ret;
757 + }
758 +
759 + ret = ipts_control_reset_sensor(ipts);
760 + if (ret) {
761 + dev_err(ipts->dev, "Failed to reset sensor: %d\n", ret);
762 + return ret;
763 + }
764 +
765 + ret = ipts_resources_free(&ipts->resources);
766 + if (ret) {
767 + dev_err(ipts->dev, "Failed to free resources: %d\n", ret);
768 + return ret;
769 + }
770 +
771 + return 0;
772 +}
773 +
774 +int ipts_control_stop(struct ipts_context *ipts)
775 +{
776 + int ret = 0;
777 +
778 + ret = _ipts_control_stop(ipts);
779 + if (ret)
780 + return ret;
781 +
782 + ret = ipts_hid_free(ipts);
783 + if (ret) {
784 + dev_err(ipts->dev, "Failed to free HID device: %d\n", ret);
785 + return ret;
786 + }
787 +
788 + return 0;
789 +}
790 +
791 +int ipts_control_restart(struct ipts_context *ipts)
792 +{
793 + int ret = 0;
794 +
795 + ret = _ipts_control_stop(ipts);
796 + if (ret)
797 + return ret;
798 +
799 + /*
800 + * Give the sensor some time to come back from resetting
801 + */
802 + msleep(1000);
803 +
804 + ret = ipts_control_start(ipts);
805 + if (ret)
806 + return ret;
807 +
808 + return 0;
809 +}
810 diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h
811 new file mode 100644
812 index 0000000000000..92b649d4ccbc8
813 --- /dev/null
814 +++ b/drivers/hid/ipts/control.h
815 @@ -0,0 +1,127 @@
816 +/* SPDX-License-Identifier: GPL-2.0-or-later */
817 +/*
818 + * Copyright (c) 2016 Intel Corporation
819 + * Copyright (c) 2020-2023 Dorian Stoll
820 + *
821 + * Linux driver for Intel Precise Touch & Stylus
822 + */
823 +
824 +#ifndef IPTS_CONTROL_H
825 +#define IPTS_CONTROL_H
826 +
827 +#include <linux/types.h>
828 +
829 +#include "context.h"
830 +#include "spec-data.h"
831 +#include "spec-device.h"
832 +
833 +/*
834 + * ipts_control_request_flush() - Stop the data flow.
835 + * @ipts: The IPTS driver context.
836 + *
837 + * Runs the command to stop the data flow on the device.
838 + * All outstanding data needs to be acknowledged using feedback before the command will return.
839 + *
840 + * Returns: 0 on success, <0 on error.
841 +*/
842 +int ipts_control_request_flush(struct ipts_context *ipts);
843 +
844 +/*
845 + * ipts_control_wait_flush() - Wait until data flow has been stopped.
846 + * @ipts: The IPTS driver context.
847 + *
848 + * Returns: 0 on success, <0 on error.
849 +*/
850 +int ipts_control_wait_flush(struct ipts_context *ipts);
851 +
852 +/*
853 + * ipts_control_wait_flush() - Notify the device that the driver can receive new data.
854 + * @ipts: The IPTS driver context.
855 + *
856 + * Returns: 0 on success, <0 on error.
857 +*/
858 +int ipts_control_request_data(struct ipts_context *ipts);
859 +
860 +/*
861 + * ipts_control_wait_data() - Wait until new data is available.
862 + * @ipts: The IPTS driver context.
863 + * @block: Whether to block execution until data is available.
864 + *
865 + * In doorbell mode, this function will never return while the data flow is active. Instead,
866 + * the doorbell will be incremented when new data is available.
867 + *
868 + * Returns: 0 on success, <0 on error, -EAGAIN if no data is available.
869 +*/
870 +int ipts_control_wait_data(struct ipts_context *ipts, bool block);
871 +
872 +/*
873 + * ipts_control_send_feedback() - Submits a feedback buffer to the device.
874 + * @ipts: The IPTS driver context.
875 + * @buffer: The ID of the buffer containing feedback data.
876 + *
877 + * Returns: 0 on success, <0 on error.
878 +*/
879 +int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer);
880 +
881 +/*
882 + * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback.
883 + * @ipts: The IPTS driver context.
884 + * @cmd: The command that will be run on the device.
885 + * @type: The type of the payload that is sent to the device.
886 + * @data: The payload of the feedback command.
887 + * @size: The size of the payload.
888 + *
889 + * HID2ME feedback is a special type of feedback, because it allows interfacing with
890 + * the HID API of the device at any moment, without requiring a buffer that has to
891 + * be acknowledged.
892 + *
893 + * Returns: 0 on success, <0 on error.
894 + */
895 +int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd,
896 + enum ipts_feedback_data_type type, void *data, size_t size);
897 +
898 +/*
899 + * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed.
900 + * @ipts: The IPTS driver context.
901 + * @buffer: The buffer that has been processed and can be refilled.
902 + *
903 + * Returns: 0 on success, <0 on error.
904 + */
905 +static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buffer)
906 +{
907 + /*
908 + * IPTS expects structured data in the feedback buffer matching the buffer that will be refilled.
909 + * We don't know what that data looks like, so we just keep the buffer empty.
910 + * This results in an INVALID_PARAMS error, but the buffer gets refilled without an issue.
911 + * Sending a minimal structure with the buffer ID fixes the error, but breaks refilling
912 + * the buffers on some devices.
913 + */
914 +
915 + return ipts_control_send_feedback(ipts, buffer);
916 +}
917 +
918 +/*
919 + * ipts_control_start() - Initialized the device and starts the data flow.
920 + * @ipts: The IPTS driver context.
921 + *
922 + * Returns: 0 on success, <0 on error.
923 + */
924 +int ipts_control_start(struct ipts_context *ipts);
925 +
926 +/*
927 + * ipts_control_stop() - Stops the data flow and resets the device.
928 + * @ipts: The IPTS driver context.
929 + *
930 + * Returns: 0 on success, <0 on error.
931 + */
932 +int ipts_control_stop(struct ipts_context *ipts);
933 +
934 +/*
935 + * ipts_control_restart() - Stops the device and starts it again.
936 + * @ipts: The IPTS driver context.
937 + *
938 + * Returns: 0 on success, <0 on error.
939 + */
940 +int ipts_control_restart(struct ipts_context *ipts);
941 +
942 +#endif /* IPTS_CONTROL_H */
943 diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h
944 new file mode 100644
945 index 0000000000000..c058974a03a1e
946 --- /dev/null
947 +++ b/drivers/hid/ipts/desc.h
948 @@ -0,0 +1,81 @@
949 +/* SPDX-License-Identifier: GPL-2.0-or-later */
950 +/*
951 + * Copyright (c) 2016 Intel Corporation
952 + * Copyright (c) 2022-2023 Dorian Stoll
953 + *
954 + * Linux driver for Intel Precise Touch & Stylus
955 + */
956 +
957 +#ifndef IPTS_DESC_H
958 +#define IPTS_DESC_H
959 +
960 +#include <linux/types.h>
961 +
962 +#define IPTS_HID_REPORT_SINGLETOUCH 64
963 +#define IPTS_HID_REPORT_DATA 65
964 +#define IPTS_HID_REPORT_SET_MODE 66
965 +
966 +#define IPTS_HID_REPORT_DATA_SIZE 7485
967 +
968 +/*
969 + * HID descriptor for singletouch data.
970 + * This descriptor should be present on all IPTS devices.
971 + */
972 +static const u8 ipts_singletouch_descriptor[] = {
973 + 0x05, 0x0D, /* Usage Page (Digitizer), */
974 + 0x09, 0x04, /* Usage (Touchscreen), */
975 + 0xA1, 0x01, /* Collection (Application), */
976 + 0x85, 0x40, /* Report ID (64), */
977 + 0x09, 0x42, /* Usage (Tip Switch), */
978 + 0x15, 0x00, /* Logical Minimum (0), */
979 + 0x25, 0x01, /* Logical Maximum (1), */
980 + 0x75, 0x01, /* Report Size (1), */
981 + 0x95, 0x01, /* Report Count (1), */
982 + 0x81, 0x02, /* Input (Variable), */
983 + 0x95, 0x07, /* Report Count (7), */
984 + 0x81, 0x03, /* Input (Constant, Variable), */
985 + 0x05, 0x01, /* Usage Page (Desktop), */
986 + 0x09, 0x30, /* Usage (X), */
987 + 0x75, 0x10, /* Report Size (16), */
988 + 0x95, 0x01, /* Report Count (1), */
989 + 0xA4, /* Push, */
990 + 0x55, 0x0E, /* Unit Exponent (14), */
991 + 0x65, 0x11, /* Unit (Centimeter), */
992 + 0x46, 0x76, 0x0B, /* Physical Maximum (2934), */
993 + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
994 + 0x81, 0x02, /* Input (Variable), */
995 + 0x09, 0x31, /* Usage (Y), */
996 + 0x46, 0x74, 0x06, /* Physical Maximum (1652), */
997 + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
998 + 0x81, 0x02, /* Input (Variable), */
999 + 0xB4, /* Pop, */
1000 + 0xC0, /* End Collection */
1001 +};
1002 +
1003 +/*
1004 + * Fallback HID descriptor for older devices that do not have
1005 + * the ability to query their HID descriptor.
1006 + */
1007 +static const u8 ipts_fallback_descriptor[] = {
1008 + 0x05, 0x0D, /* Usage Page (Digitizer), */
1009 + 0x09, 0x0F, /* Usage (Capacitive Hm Digitizer), */
1010 + 0xA1, 0x01, /* Collection (Application), */
1011 + 0x85, 0x41, /* Report ID (65), */
1012 + 0x09, 0x56, /* Usage (Scan Time), */
1013 + 0x95, 0x01, /* Report Count (1), */
1014 + 0x75, 0x10, /* Report Size (16), */
1015 + 0x81, 0x02, /* Input (Variable), */
1016 + 0x09, 0x61, /* Usage (Gesture Char Quality), */
1017 + 0x75, 0x08, /* Report Size (8), */
1018 + 0x96, 0x3D, 0x1D, /* Report Count (7485), */
1019 + 0x81, 0x03, /* Input (Constant, Variable), */
1020 + 0x85, 0x42, /* Report ID (66), */
1021 + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
1022 + 0x09, 0xC8, /* Usage (C8h), */
1023 + 0x75, 0x08, /* Report Size (8), */
1024 + 0x95, 0x01, /* Report Count (1), */
1025 + 0xB1, 0x02, /* Feature (Variable), */
1026 + 0xC0, /* End Collection, */
1027 +};
1028 +
1029 +#endif /* IPTS_DESC_H */
1030 diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c
1031 new file mode 100644
1032 index 0000000000000..6782394e8dde3
1033 --- /dev/null
1034 +++ b/drivers/hid/ipts/hid.c
1035 @@ -0,0 +1,348 @@
1036 +// SPDX-License-Identifier: GPL-2.0-or-later
1037 +/*
1038 + * Copyright (c) 2016 Intel Corporation
1039 + * Copyright (c) 2022-2023 Dorian Stoll
1040 + *
1041 + * Linux driver for Intel Precise Touch & Stylus
1042 + */
1043 +
1044 +#include <linux/completion.h>
1045 +#include <linux/gfp.h>
1046 +#include <linux/hid.h>
1047 +#include <linux/mutex.h>
1048 +#include <linux/slab.h>
1049 +#include <linux/types.h>
1050 +
1051 +#include "context.h"
1052 +#include "control.h"
1053 +#include "desc.h"
1054 +#include "hid.h"
1055 +#include "spec-data.h"
1056 +#include "spec-device.h"
1057 +#include "spec-hid.h"
1058 +
1059 +static int ipts_hid_start(struct hid_device *hid)
1060 +{
1061 + return 0;
1062 +}
1063 +
1064 +static void ipts_hid_stop(struct hid_device *hid)
1065 +{
1066 +}
1067 +
1068 +static int ipts_hid_switch_mode(struct ipts_context *ipts, enum ipts_mode mode)
1069 +{
1070 + if (!ipts)
1071 + return -EFAULT;
1072 +
1073 + if (ipts->mode == mode)
1074 + return 0;
1075 +
1076 + /*
1077 + * This is only allowed on older devices.
1078 + */
1079 + if (ipts->info.intf_eds > 1)
1080 + return 0;
1081 +
1082 + ipts->mode = mode;
1083 + return ipts_control_restart(ipts);
1084 +}
1085 +
1086 +static int ipts_hid_parse(struct hid_device *hid)
1087 +{
1088 + int ret = 0;
1089 + struct ipts_context *ipts = NULL;
1090 +
1091 + bool has_native_descriptor = false;
1092 +
1093 + u8 *buffer = NULL;
1094 + size_t size = 0;
1095 +
1096 + if (!hid)
1097 + return -ENODEV;
1098 +
1099 + ipts = hid->driver_data;
1100 +
1101 + if (!ipts)
1102 + return -EFAULT;
1103 +
1104 + size = sizeof(ipts_singletouch_descriptor);
1105 + has_native_descriptor = ipts->descriptor.address && ipts->descriptor.size > 0;
1106 +
1107 + if (has_native_descriptor)
1108 + size += ipts->descriptor.size;
1109 + else
1110 + size += sizeof(ipts_fallback_descriptor);
1111 +
1112 + buffer = kzalloc(size, GFP_KERNEL);
1113 + if (!buffer)
1114 + return -ENOMEM;
1115 +
1116 + memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor));
1117 +
1118 + if (has_native_descriptor) {
1119 + memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address,
1120 + ipts->descriptor.size);
1121 + } else {
1122 + memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor,
1123 + sizeof(ipts_fallback_descriptor));
1124 + }
1125 +
1126 + ret = hid_parse_report(hid, buffer, size);
1127 + kfree(buffer);
1128 +
1129 + if (ret) {
1130 + dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret);
1131 + return ret;
1132 + }
1133 +
1134 + return 0;
1135 +}
1136 +
1137 +static int ipts_hid_get_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf,
1138 + size_t size, enum ipts_feedback_data_type type)
1139 +{
1140 + int ret = 0;
1141 +
1142 + if (!ipts)
1143 + return -EFAULT;
1144 +
1145 + if (!buf)
1146 + return -EFAULT;
1147 +
1148 + mutex_lock(&ipts->feature_lock);
1149 +
1150 + memset(buf, 0, size);
1151 + buf[0] = reportnum;
1152 +
1153 + memset(&ipts->feature_report, 0, sizeof(ipts->feature_report));
1154 + reinit_completion(&ipts->feature_event);
1155 +
1156 + ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size);
1157 + if (ret) {
1158 + dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret);
1159 + goto out;
1160 + }
1161 +
1162 + ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000));
1163 + if (ret == 0) {
1164 + dev_warn(ipts->dev, "GET_FEATURES timed out!\n");
1165 + ret = -EIO;
1166 + goto out;
1167 + }
1168 +
1169 + if (!ipts->feature_report.address) {
1170 + ret = -EFAULT;
1171 + goto out;
1172 + }
1173 +
1174 + if (ipts->feature_report.size > size) {
1175 + ret = -ETOOSMALL;
1176 + goto out;
1177 + }
1178 +
1179 + ret = ipts->feature_report.size;
1180 + memcpy(buf, ipts->feature_report.address, ipts->feature_report.size);
1181 +
1182 +out:
1183 + mutex_unlock(&ipts->feature_lock);
1184 + return ret;
1185 +}
1186 +
1187 +static int ipts_hid_set_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf,
1188 + size_t size, enum ipts_feedback_data_type type)
1189 +{
1190 + int ret = 0;
1191 +
1192 + if (!ipts)
1193 + return -EFAULT;
1194 +
1195 + if (!buf)
1196 + return -EFAULT;
1197 +
1198 + buf[0] = reportnum;
1199 +
1200 + ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size);
1201 + if (ret)
1202 + dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret);
1203 +
1204 + return ret;
1205 +}
1206 +
1207 +static int ipts_hid_raw_request(struct hid_device *hid, unsigned char reportnum, __u8 *buf,
1208 + size_t size, unsigned char rtype, int reqtype)
1209 +{
1210 + int ret = 0;
1211 + struct ipts_context *ipts = NULL;
1212 +
1213 + enum ipts_feedback_data_type type = IPTS_FEEDBACK_DATA_TYPE_VENDOR;
1214 +
1215 + if (!hid)
1216 + return -ENODEV;
1217 +
1218 + ipts = hid->driver_data;
1219 +
1220 + if (!ipts)
1221 + return -EFAULT;
1222 +
1223 + if (!buf)
1224 + return -EFAULT;
1225 +
1226 + if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT)
1227 + type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT;
1228 + else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT)
1229 + type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES;
1230 + else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT)
1231 + type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES;
1232 + else
1233 + return -EIO;
1234 +
1235 + // Implemente mode switching report for older devices without native HID support
1236 + if (type == IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES && reportnum == IPTS_HID_REPORT_SET_MODE) {
1237 + ret = ipts_hid_switch_mode(ipts, buf[1]);
1238 + if (ret) {
1239 + dev_err(ipts->dev, "Failed to switch modes: %d\n", ret);
1240 + return ret;
1241 + }
1242 + }
1243 +
1244 + if (reqtype == HID_REQ_GET_REPORT)
1245 + return ipts_hid_get_feature(ipts, reportnum, buf, size, type);
1246 + else
1247 + return ipts_hid_set_feature(ipts, reportnum, buf, size, type);
1248 +}
1249 +
1250 +static int ipts_hid_output_report(struct hid_device *hid, __u8 *data, size_t size)
1251 +{
1252 + struct ipts_context *ipts = NULL;
1253 +
1254 + if (!hid)
1255 + return -ENODEV;
1256 +
1257 + ipts = hid->driver_data;
1258 +
1259 + return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE,
1260 + IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, data, size);
1261 +}
1262 +
1263 +static struct hid_ll_driver ipts_hid_driver = {
1264 + .start = ipts_hid_start,
1265 + .stop = ipts_hid_stop,
1266 + .open = ipts_hid_start,
1267 + .close = ipts_hid_stop,
1268 + .parse = ipts_hid_parse,
1269 + .raw_request = ipts_hid_raw_request,
1270 + .output_report = ipts_hid_output_report,
1271 +};
1272 +
1273 +int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer)
1274 +{
1275 + int ret = 0;
1276 + u8 *temp = NULL;
1277 + struct ipts_hid_header *frame = NULL;
1278 + struct ipts_data_header *header = NULL;
1279 +
1280 + if (!ipts)
1281 + return -EFAULT;
1282 +
1283 + if (!ipts->hid)
1284 + return -ENODEV;
1285 +
1286 + header = (struct ipts_data_header *)ipts->resources.data[buffer].address;
1287 +
1288 + if (!header)
1289 + return -EFAULT;
1290 +
1291 + if (header->size == 0)
1292 + return 0;
1293 +
1294 + if (header->type == IPTS_DATA_TYPE_HID)
1295 + return hid_input_report(ipts->hid, HID_INPUT_REPORT, header->data, header->size, 1);
1296 +
1297 + if (header->type == IPTS_DATA_TYPE_GET_FEATURES) {
1298 + ipts->feature_report.address = header->data;
1299 + ipts->feature_report.size = header->size;
1300 +
1301 + complete_all(&ipts->feature_event);
1302 + return 0;
1303 + }
1304 +
1305 + if (header->type != IPTS_DATA_TYPE_FRAME)
1306 + return 0;
1307 +
1308 + if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE)
1309 + return -ERANGE;
1310 +
1311 + temp = kzalloc(IPTS_HID_REPORT_DATA_SIZE, GFP_KERNEL);
1312 + if (!temp)
1313 + return -ENOMEM;
1314 +
1315 + /*
1316 + * Synthesize a HID report matching the devices that natively send HID reports
1317 + */
1318 + temp[0] = IPTS_HID_REPORT_DATA;
1319 +
1320 + frame = (struct ipts_hid_header *)&temp[3];
1321 + frame->type = IPTS_HID_FRAME_TYPE_RAW;
1322 + frame->size = header->size + sizeof(*frame);
1323 +
1324 + memcpy(frame->data, header->data, header->size);
1325 +
1326 + ret = hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1);
1327 + kfree(temp);
1328 +
1329 + return ret;
1330 +}
1331 +
1332 +int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info)
1333 +{
1334 + int ret = 0;
1335 +
1336 + if (!ipts)
1337 + return -EFAULT;
1338 +
1339 + if (ipts->hid)
1340 + return 0;
1341 +
1342 + ipts->hid = hid_allocate_device();
1343 + if (IS_ERR(ipts->hid)) {
1344 + int err = PTR_ERR(ipts->hid);
1345 +
1346 + dev_err(ipts->dev, "Failed to allocate HID device: %d\n", err);
1347 + return err;
1348 + }
1349 +
1350 + ipts->hid->driver_data = ipts;
1351 + ipts->hid->dev.parent = ipts->dev;
1352 + ipts->hid->ll_driver = &ipts_hid_driver;
1353 +
1354 + ipts->hid->vendor = info.vendor;
1355 + ipts->hid->product = info.product;
1356 + ipts->hid->group = HID_GROUP_MULTITOUCH;
1357 +
1358 + snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor,
1359 + info.product);
1360 +
1361 + ret = hid_add_device(ipts->hid);
1362 + if (ret) {
1363 + dev_err(ipts->dev, "Failed to add HID device: %d\n", ret);
1364 + ipts_hid_free(ipts);
1365 + return ret;
1366 + }
1367 +
1368 + return 0;
1369 +}
1370 +
1371 +int ipts_hid_free(struct ipts_context *ipts)
1372 +{
1373 + if (!ipts)
1374 + return -EFAULT;
1375 +
1376 + if (!ipts->hid)
1377 + return 0;
1378 +
1379 + hid_destroy_device(ipts->hid);
1380 + ipts->hid = NULL;
1381 +
1382 + return 0;
1383 +}
1384 diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h
1385 new file mode 100644
1386 index 0000000000000..62bf3cd486081
1387 --- /dev/null
1388 +++ b/drivers/hid/ipts/hid.h
1389 @@ -0,0 +1,22 @@
1390 +/* SPDX-License-Identifier: GPL-2.0-or-later */
1391 +/*
1392 + * Copyright (c) 2016 Intel Corporation
1393 + * Copyright (c) 2022-2023 Dorian Stoll
1394 + *
1395 + * Linux driver for Intel Precise Touch & Stylus
1396 + */
1397 +
1398 +#ifndef IPTS_HID_H
1399 +#define IPTS_HID_H
1400 +
1401 +#include <linux/types.h>
1402 +
1403 +#include "context.h"
1404 +#include "spec-device.h"
1405 +
1406 +int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer);
1407 +
1408 +int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info);
1409 +int ipts_hid_free(struct ipts_context *ipts);
1410 +
1411 +#endif /* IPTS_HID_H */
1412 diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c
1413 new file mode 100644
1414 index 0000000000000..0f20c6c08c38c
1415 --- /dev/null
1416 +++ b/drivers/hid/ipts/main.c
1417 @@ -0,0 +1,127 @@
1418 +// SPDX-License-Identifier: GPL-2.0-or-later
1419 +/*
1420 + * Copyright (c) 2016 Intel Corporation
1421 + * Copyright (c) 2020-2023 Dorian Stoll
1422 + *
1423 + * Linux driver for Intel Precise Touch & Stylus
1424 + */
1425 +
1426 +#include <linux/completion.h>
1427 +#include <linux/delay.h>
1428 +#include <linux/device.h>
1429 +#include <linux/dma-mapping.h>
1430 +#include <linux/mei_cl_bus.h>
1431 +#include <linux/mod_devicetable.h>
1432 +#include <linux/module.h>
1433 +#include <linux/mutex.h>
1434 +#include <linux/slab.h>
1435 +#include <linux/stddef.h>
1436 +#include <linux/types.h>
1437 +
1438 +#include "context.h"
1439 +#include "control.h"
1440 +#include "mei.h"
1441 +#include "receiver.h"
1442 +#include "spec-device.h"
1443 +
1444 +/*
1445 + * The MEI client ID for IPTS functionality.
1446 + */
1447 +#define IPTS_ID UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
1448 +
1449 +static int ipts_set_dma_mask(struct mei_cl_device *cldev)
1450 +{
1451 + if (!cldev)
1452 + return -EFAULT;
1453 +
1454 + if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)))
1455 + return 0;
1456 +
1457 + return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32));
1458 +}
1459 +
1460 +static int ipts_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id)
1461 +{
1462 + int ret = 0;
1463 + struct ipts_context *ipts = NULL;
1464 +
1465 + if (!cldev)
1466 + return -EFAULT;
1467 +
1468 + ret = ipts_set_dma_mask(cldev);
1469 + if (ret) {
1470 + dev_err(&cldev->dev, "Failed to set DMA mask for IPTS: %d\n", ret);
1471 + return ret;
1472 + }
1473 +
1474 + ret = mei_cldev_enable(cldev);
1475 + if (ret) {
1476 + dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret);
1477 + return ret;
1478 + }
1479 +
1480 + ipts = devm_kzalloc(&cldev->dev, sizeof(*ipts), GFP_KERNEL);
1481 + if (!ipts) {
1482 + mei_cldev_disable(cldev);
1483 + return -ENOMEM;
1484 + }
1485 +
1486 + ret = ipts_mei_init(&ipts->mei, cldev);
1487 + if (ret) {
1488 + dev_err(&cldev->dev, "Failed to init MEI bus logic: %d\n", ret);
1489 + return ret;
1490 + }
1491 +
1492 + ipts->dev = &cldev->dev;
1493 + ipts->mode = IPTS_MODE_EVENT;
1494 +
1495 + mutex_init(&ipts->feature_lock);
1496 + init_completion(&ipts->feature_event);
1497 +
1498 + mei_cldev_set_drvdata(cldev, ipts);
1499 +
1500 + ret = ipts_control_start(ipts);
1501 + if (ret) {
1502 + dev_err(&cldev->dev, "Failed to start IPTS: %d\n", ret);
1503 + return ret;
1504 + }
1505 +
1506 + return 0;
1507 +}
1508 +
1509 +static void ipts_remove(struct mei_cl_device *cldev)
1510 +{
1511 + int ret = 0;
1512 + struct ipts_context *ipts = NULL;
1513 +
1514 + if (!cldev) {
1515 + pr_err("MEI device is NULL!");
1516 + return;
1517 + }
1518 +
1519 + ipts = mei_cldev_get_drvdata(cldev);
1520 +
1521 + ret = ipts_control_stop(ipts);
1522 + if (ret)
1523 + dev_err(&cldev->dev, "Failed to stop IPTS: %d\n", ret);
1524 +
1525 + mei_cldev_disable(cldev);
1526 +}
1527 +
1528 +static struct mei_cl_device_id ipts_device_id_table[] = {
1529 + { .uuid = IPTS_ID, .version = MEI_CL_VERSION_ANY },
1530 + {},
1531 +};
1532 +MODULE_DEVICE_TABLE(mei, ipts_device_id_table);
1533 +
1534 +static struct mei_cl_driver ipts_driver = {
1535 + .id_table = ipts_device_id_table,
1536 + .name = "ipts",
1537 + .probe = ipts_probe,
1538 + .remove = ipts_remove,
1539 +};
1540 +module_mei_cl_driver(ipts_driver);
1541 +
1542 +MODULE_DESCRIPTION("IPTS touchscreen driver");
1543 +MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
1544 +MODULE_LICENSE("GPL");
1545 diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c
1546 new file mode 100644
1547 index 0000000000000..26666fd99b0c7
1548 --- /dev/null
1549 +++ b/drivers/hid/ipts/mei.c
1550 @@ -0,0 +1,189 @@
1551 +// SPDX-License-Identifier: GPL-2.0-or-later
1552 +/*
1553 + * Copyright (c) 2016 Intel Corporation
1554 + * Copyright (c) 2023 Dorian Stoll
1555 + *
1556 + * Linux driver for Intel Precise Touch & Stylus
1557 + */
1558 +
1559 +#include <linux/device.h>
1560 +#include <linux/errno.h>
1561 +#include <linux/jiffies.h>
1562 +#include <linux/list.h>
1563 +#include <linux/mei_cl_bus.h>
1564 +#include <linux/printk.h>
1565 +#include <linux/rwsem.h>
1566 +#include <linux/types.h>
1567 +#include <linux/wait.h>
1568 +
1569 +#include "context.h"
1570 +#include "mei.h"
1571 +
1572 +static void locked_list_add(struct list_head *new, struct list_head *head,
1573 + struct rw_semaphore *lock)
1574 +{
1575 + down_write(lock);
1576 + list_add(new, head);
1577 + up_write(lock);
1578 +}
1579 +
1580 +static void locked_list_del(struct list_head *entry, struct rw_semaphore *lock)
1581 +{
1582 + down_write(lock);
1583 + list_del(entry);
1584 + up_write(lock);
1585 +}
1586 +
1587 +static void ipts_mei_incoming(struct mei_cl_device *cldev)
1588 +{
1589 + ssize_t ret = 0;
1590 + struct ipts_mei_message *entry = NULL;
1591 + struct ipts_context *ipts = NULL;
1592 +
1593 + if (!cldev) {
1594 + pr_err("MEI device is NULL!");
1595 + return;
1596 + }
1597 +
1598 + ipts = mei_cldev_get_drvdata(cldev);
1599 + if (!ipts) {
1600 + pr_err("IPTS driver context is NULL!");
1601 + return;
1602 + }
1603 +
1604 + entry = devm_kzalloc(ipts->dev, sizeof(*entry), GFP_KERNEL);
1605 + if (!entry)
1606 + return;
1607 +
1608 + INIT_LIST_HEAD(&entry->list);
1609 +
1610 + do {
1611 + ret = mei_cldev_recv(cldev, (u8 *)&entry->rsp, sizeof(entry->rsp));
1612 + } while (ret == -EINTR);
1613 +
1614 + if (ret < 0) {
1615 + dev_err(ipts->dev, "Error while reading response: %ld\n", ret);
1616 + return;
1617 + }
1618 +
1619 + if (ret == 0) {
1620 + dev_err(ipts->dev, "Received empty response\n");
1621 + return;
1622 + }
1623 +
1624 + locked_list_add(&entry->list, &ipts->mei.messages, &ipts->mei.message_lock);
1625 + wake_up_all(&ipts->mei.message_queue);
1626 +}
1627 +
1628 +static int ipts_mei_search(struct ipts_mei *mei, enum ipts_command_code code,
1629 + struct ipts_response *rsp)
1630 +{
1631 + struct ipts_mei_message *entry = NULL;
1632 +
1633 + if (!mei)
1634 + return -EFAULT;
1635 +
1636 + if (!rsp)
1637 + return -EFAULT;
1638 +
1639 + down_read(&mei->message_lock);
1640 +
1641 + /*
1642 + * Iterate over the list of received messages, and check if there is one
1643 + * matching the requested command code.
1644 + */
1645 + list_for_each_entry(entry, &mei->messages, list) {
1646 + if (entry->rsp.cmd == code)
1647 + break;
1648 + }
1649 +
1650 + up_read(&mei->message_lock);
1651 +
1652 + /*
1653 + * If entry is not the list head, this means that the loop above has been stopped early,
1654 + * and that we found a matching element. We drop the message from the list and return it.
1655 + */
1656 + if (!list_entry_is_head(entry, &mei->messages, list)) {
1657 + locked_list_del(&entry->list, &mei->message_lock);
1658 +
1659 + *rsp = entry->rsp;
1660 + devm_kfree(&mei->cldev->dev, entry);
1661 +
1662 + return 0;
1663 + }
1664 +
1665 + return -EAGAIN;
1666 +}
1667 +
1668 +int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp,
1669 + u64 timeout)
1670 +{
1671 + int ret = 0;
1672 +
1673 + if (!mei)
1674 + return -EFAULT;
1675 +
1676 + /*
1677 + * A timeout of 0 means check and return immideately.
1678 + */
1679 + if (timeout == 0)
1680 + return ipts_mei_search(mei, code, rsp);
1681 +
1682 + /*
1683 + * A timeout of less than 0 means to wait forever.
1684 + */
1685 + if (timeout < 0) {
1686 + wait_event(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0);
1687 + return 0;
1688 + }
1689 +
1690 + ret = wait_event_timeout(mei->message_queue, ipts_mei_search(mei, code, rsp) == 0,
1691 + msecs_to_jiffies(timeout));
1692 +
1693 + if (ret > 0)
1694 + return 0;
1695 +
1696 + return -EAGAIN;
1697 +}
1698 +
1699 +int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length)
1700 +{
1701 + int ret = 0;
1702 +
1703 + if (!mei)
1704 + return -EFAULT;
1705 +
1706 + if (!mei->cldev)
1707 + return -EFAULT;
1708 +
1709 + if (!data)
1710 + return -EFAULT;
1711 +
1712 + do {
1713 + ret = mei_cldev_send(mei->cldev, (u8 *)data, length);
1714 + } while (ret == -EINTR);
1715 +
1716 + if (ret < 0)
1717 + return ret;
1718 +
1719 + return 0;
1720 +}
1721 +
1722 +int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev)
1723 +{
1724 + if (!mei)
1725 + return -EFAULT;
1726 +
1727 + if (!cldev)
1728 + return -EFAULT;
1729 +
1730 + mei->cldev = cldev;
1731 +
1732 + INIT_LIST_HEAD(&mei->messages);
1733 + init_waitqueue_head(&mei->message_queue);
1734 + init_rwsem(&mei->message_lock);
1735 +
1736 + mei_cldev_register_rx_cb(cldev, ipts_mei_incoming);
1737 +
1738 + return 0;
1739 +}
1740 diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h
1741 new file mode 100644
1742 index 0000000000000..eadacae54c400
1743 --- /dev/null
1744 +++ b/drivers/hid/ipts/mei.h
1745 @@ -0,0 +1,67 @@
1746 +/* SPDX-License-Identifier: GPL-2.0-or-later */
1747 +/*
1748 + * Copyright (c) 2016 Intel Corporation
1749 + * Copyright (c) 2023 Dorian Stoll
1750 + *
1751 + * Linux driver for Intel Precise Touch & Stylus
1752 + */
1753 +
1754 +#ifndef IPTS_MEI_H
1755 +#define IPTS_MEI_H
1756 +
1757 +#include <linux/list.h>
1758 +#include <linux/mei_cl_bus.h>
1759 +#include <linux/rwsem.h>
1760 +#include <linux/types.h>
1761 +#include <linux/wait.h>
1762 +
1763 +#include "spec-device.h"
1764 +
1765 +struct ipts_mei_message {
1766 + struct list_head list;
1767 + struct ipts_response rsp;
1768 +};
1769 +
1770 +struct ipts_mei {
1771 + struct mei_cl_device *cldev;
1772 +
1773 + struct list_head messages;
1774 +
1775 + wait_queue_head_t message_queue;
1776 + struct rw_semaphore message_lock;
1777 +};
1778 +
1779 +/*
1780 + * ipts_mei_recv() - Receive data from a MEI device.
1781 + * @mei: The IPTS MEI device context.
1782 + * @code: The IPTS command code to look for.
1783 + * @rsp: The address that the received data will be copied to.
1784 + * @timeout: How many milliseconds the function will wait at most.
1785 + *
1786 + * A negative timeout means to wait forever.
1787 + *
1788 + * Returns: 0 on success, <0 on error, -EAGAIN if no response has been received.
1789 + */
1790 +int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp,
1791 + u64 timeout);
1792 +
1793 +/*
1794 + * ipts_mei_send() - Send data to a MEI device.
1795 + * @ipts: The IPTS MEI device context.
1796 + * @data: The data to send.
1797 + * @size: The size of the data.
1798 + *
1799 + * Returns: 0 on success, <0 on error.
1800 + */
1801 +int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length);
1802 +
1803 +/*
1804 + * ipts_mei_init() - Initialize the MEI device context.
1805 + * @mei: The MEI device context to initialize.
1806 + * @cldev: The MEI device the context will be bound to.
1807 + *
1808 + * Returns: 0 on success, <0 on error.
1809 + */
1810 +int ipts_mei_init(struct ipts_mei *mei, struct mei_cl_device *cldev);
1811 +
1812 +#endif /* IPTS_MEI_H */
1813 diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c
1814 new file mode 100644
1815 index 0000000000000..77234f9e0e178
1816 --- /dev/null
1817 +++ b/drivers/hid/ipts/receiver.c
1818 @@ -0,0 +1,249 @@
1819 +// SPDX-License-Identifier: GPL-2.0-or-later
1820 +/*
1821 + * Copyright (c) 2016 Intel Corporation
1822 + * Copyright (c) 2020-2023 Dorian Stoll
1823 + *
1824 + * Linux driver for Intel Precise Touch & Stylus
1825 + */
1826 +
1827 +#include <linux/delay.h>
1828 +#include <linux/err.h>
1829 +#include <linux/kthread.h>
1830 +#include <linux/time64.h>
1831 +#include <linux/timekeeping.h>
1832 +#include <linux/types.h>
1833 +
1834 +#include "cmd.h"
1835 +#include "context.h"
1836 +#include "control.h"
1837 +#include "hid.h"
1838 +#include "resources.h"
1839 +#include "spec-device.h"
1840 +#include "thread.h"
1841 +
1842 +static void ipts_receiver_next_doorbell(struct ipts_context *ipts)
1843 +{
1844 + u32 *doorbell = (u32 *)ipts->resources.doorbell.address;
1845 + *doorbell = *doorbell + 1;
1846 +}
1847 +
1848 +static u32 ipts_receiver_current_doorbell(struct ipts_context *ipts)
1849 +{
1850 + u32 *doorbell = (u32 *)ipts->resources.doorbell.address;
1851 + return *doorbell;
1852 +}
1853 +
1854 +static void ipts_receiver_backoff(time64_t last, u32 n)
1855 +{
1856 + /*
1857 + * If the last change was less than n seconds ago,
1858 + * sleep for a shorter period so that new data can be
1859 + * processed quickly. If there was no change for more than
1860 + * n seconds, sleep longer to avoid wasting CPU cycles.
1861 + */
1862 + if (last + n > ktime_get_seconds())
1863 + msleep(20);
1864 + else
1865 + msleep(200);
1866 +}
1867 +
1868 +static int ipts_receiver_event_loop(struct ipts_thread *thread)
1869 +{
1870 + int ret = 0;
1871 + u32 buffer = 0;
1872 +
1873 + struct ipts_context *ipts = NULL;
1874 + time64_t last = ktime_get_seconds();
1875 +
1876 + if (!thread)
1877 + return -EFAULT;
1878 +
1879 + ipts = thread->data;
1880 +
1881 + if (!ipts)
1882 + return -EFAULT;
1883 +
1884 + dev_info(ipts->dev, "IPTS running in event mode\n");
1885 +
1886 + while (!ipts_thread_should_stop(thread)) {
1887 + for (int i = 0; i < IPTS_BUFFERS; i++) {
1888 + ret = ipts_control_wait_data(ipts, false);
1889 + if (ret == -EAGAIN)
1890 + break;
1891 +
1892 + if (ret) {
1893 + dev_err(ipts->dev, "Failed to wait for data: %d\n", ret);
1894 + continue;
1895 + }
1896 +
1897 + buffer = ipts_receiver_current_doorbell(ipts) % IPTS_BUFFERS;
1898 + ipts_receiver_next_doorbell(ipts);
1899 +
1900 + ret = ipts_hid_input_data(ipts, buffer);
1901 + if (ret)
1902 + dev_err(ipts->dev, "Failed to process buffer: %d\n", ret);
1903 +
1904 + ret = ipts_control_refill_buffer(ipts, buffer);
1905 + if (ret)
1906 + dev_err(ipts->dev, "Failed to send feedback: %d\n", ret);
1907 +
1908 + ret = ipts_control_request_data(ipts);
1909 + if (ret)
1910 + dev_err(ipts->dev, "Failed to request data: %d\n", ret);
1911 +
1912 + last = ktime_get_seconds();
1913 + }
1914 +
1915 + ipts_receiver_backoff(last, 5);
1916 + }
1917 +
1918 + ret = ipts_control_request_flush(ipts);
1919 + if (ret) {
1920 + dev_err(ipts->dev, "Failed to request flush: %d\n", ret);
1921 + return ret;
1922 + }
1923 +
1924 + ret = ipts_control_wait_data(ipts, true);
1925 + if (ret) {
1926 + dev_err(ipts->dev, "Failed to wait for data: %d\n", ret);
1927 +
1928 + if (ret != -EAGAIN)
1929 + return ret;
1930 + else
1931 + return 0;
1932 + }
1933 +
1934 + ret = ipts_control_wait_flush(ipts);
1935 + if (ret) {
1936 + dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret);
1937 +
1938 + if (ret != -EAGAIN)
1939 + return ret;
1940 + else
1941 + return 0;
1942 + }
1943 +
1944 + return 0;
1945 +}
1946 +
1947 +static int ipts_receiver_doorbell_loop(struct ipts_thread *thread)
1948 +{
1949 + int ret = 0;
1950 + u32 buffer = 0;
1951 +
1952 + u32 doorbell = 0;
1953 + u32 lastdb = 0;
1954 +
1955 + struct ipts_context *ipts = NULL;
1956 + time64_t last = ktime_get_seconds();
1957 +
1958 + if (!thread)
1959 + return -EFAULT;
1960 +
1961 + ipts = thread->data;
1962 +
1963 + if (!ipts)
1964 + return -EFAULT;
1965 +
1966 + dev_info(ipts->dev, "IPTS running in doorbell mode\n");
1967 +
1968 + while (true) {
1969 + if (ipts_thread_should_stop(thread)) {
1970 + ret = ipts_control_request_flush(ipts);
1971 + if (ret) {
1972 + dev_err(ipts->dev, "Failed to request flush: %d\n", ret);
1973 + return ret;
1974 + }
1975 + }
1976 +
1977 + doorbell = ipts_receiver_current_doorbell(ipts);
1978 +
1979 + /*
1980 + * After filling up one of the data buffers, IPTS will increment
1981 + * the doorbell. The value of the doorbell stands for the *next*
1982 + * buffer that IPTS is going to fill.
1983 + */
1984 + while (lastdb != doorbell) {
1985 + buffer = lastdb % IPTS_BUFFERS;
1986 +
1987 + ret = ipts_hid_input_data(ipts, buffer);
1988 + if (ret)
1989 + dev_err(ipts->dev, "Failed to process buffer: %d\n", ret);
1990 +
1991 + ret = ipts_control_refill_buffer(ipts, buffer);
1992 + if (ret)
1993 + dev_err(ipts->dev, "Failed to send feedback: %d\n", ret);
1994 +
1995 + last = ktime_get_seconds();
1996 + lastdb++;
1997 + }
1998 +
1999 + if (ipts_thread_should_stop(thread))
2000 + break;
2001 +
2002 + ipts_receiver_backoff(last, 5);
2003 + }
2004 +
2005 + ret = ipts_control_wait_data(ipts, true);
2006 + if (ret) {
2007 + dev_err(ipts->dev, "Failed to wait for data: %d\n", ret);
2008 +
2009 + if (ret != -EAGAIN)
2010 + return ret;
2011 + else
2012 + return 0;
2013 + }
2014 +
2015 + ret = ipts_control_wait_flush(ipts);
2016 + if (ret) {
2017 + dev_err(ipts->dev, "Failed to wait for flush: %d\n", ret);
2018 +
2019 + if (ret != -EAGAIN)
2020 + return ret;
2021 + else
2022 + return 0;
2023 + }
2024 +
2025 + return 0;
2026 +}
2027 +
2028 +int ipts_receiver_start(struct ipts_context *ipts)
2029 +{
2030 + int ret = 0;
2031 +
2032 + if (!ipts)
2033 + return -EFAULT;
2034 +
2035 + if (ipts->mode == IPTS_MODE_EVENT) {
2036 + ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts,
2037 + "ipts_event");
2038 + } else if (ipts->mode == IPTS_MODE_DOORBELL) {
2039 + ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_doorbell_loop, ipts,
2040 + "ipts_doorbell");
2041 + } else {
2042 + ret = -EINVAL;
2043 + }
2044 +
2045 + if (ret) {
2046 + dev_err(ipts->dev, "Failed to start receiver loop: %d\n", ret);
2047 + return ret;
2048 + }
2049 +
2050 + return 0;
2051 +}
2052 +
2053 +int ipts_receiver_stop(struct ipts_context *ipts)
2054 +{
2055 + int ret = 0;
2056 +
2057 + if (!ipts)
2058 + return -EFAULT;
2059 +
2060 + ret = ipts_thread_stop(&ipts->receiver_loop);
2061 + if (ret) {
2062 + dev_err(ipts->dev, "Failed to stop receiver loop: %d\n", ret);
2063 + return ret;
2064 + }
2065 +
2066 + return 0;
2067 +}
2068 diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h
2069 new file mode 100644
2070 index 0000000000000..96070f34fbcaa
2071 --- /dev/null
2072 +++ b/drivers/hid/ipts/receiver.h
2073 @@ -0,0 +1,17 @@
2074 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2075 +/*
2076 + * Copyright (c) 2016 Intel Corporation
2077 + * Copyright (c) 2020-2023 Dorian Stoll
2078 + *
2079 + * Linux driver for Intel Precise Touch & Stylus
2080 + */
2081 +
2082 +#ifndef IPTS_RECEIVER_H
2083 +#define IPTS_RECEIVER_H
2084 +
2085 +#include "context.h"
2086 +
2087 +int ipts_receiver_start(struct ipts_context *ipts);
2088 +int ipts_receiver_stop(struct ipts_context *ipts);
2089 +
2090 +#endif /* IPTS_RECEIVER_H */
2091 diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c
2092 new file mode 100644
2093 index 0000000000000..80ba5885bb55d
2094 --- /dev/null
2095 +++ b/drivers/hid/ipts/resources.c
2096 @@ -0,0 +1,108 @@
2097 +// SPDX-License-Identifier: GPL-2.0-or-later
2098 +/*
2099 + * Copyright (c) 2016 Intel Corporation
2100 + * Copyright (c) 2020-2023 Dorian Stoll
2101 + *
2102 + * Linux driver for Intel Precise Touch & Stylus
2103 + */
2104 +
2105 +#include <linux/dma-mapping.h>
2106 +#include <linux/types.h>
2107 +
2108 +#include "resources.h"
2109 +#include "spec-device.h"
2110 +
2111 +static int ipts_resources_alloc_buffer(struct ipts_buffer *buffer, struct device *dev, size_t size)
2112 +{
2113 + if (!buffer)
2114 + return -EFAULT;
2115 +
2116 + if (buffer->address)
2117 + return 0;
2118 +
2119 + buffer->address = dma_alloc_coherent(dev, size, &buffer->dma_address, GFP_KERNEL);
2120 +
2121 + if (!buffer->address)
2122 + return -ENOMEM;
2123 +
2124 + buffer->size = size;
2125 + buffer->device = dev;
2126 +
2127 + return 0;
2128 +}
2129 +
2130 +static void ipts_resources_free_buffer(struct ipts_buffer *buffer)
2131 +{
2132 + if (!buffer->address)
2133 + return;
2134 +
2135 + dma_free_coherent(buffer->device, buffer->size, buffer->address, buffer->dma_address);
2136 +
2137 + buffer->address = NULL;
2138 + buffer->size = 0;
2139 +
2140 + buffer->dma_address = 0;
2141 + buffer->device = NULL;
2142 +}
2143 +
2144 +int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs)
2145 +{
2146 + int ret = 0;
2147 +
2148 + if (!res)
2149 + return -EFAULT;
2150 +
2151 + for (int i = 0; i < IPTS_BUFFERS; i++) {
2152 + ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds);
2153 + if (ret)
2154 + goto err;
2155 + }
2156 +
2157 + for (int i = 0; i < IPTS_BUFFERS; i++) {
2158 + ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs);
2159 + if (ret)
2160 + goto err;
2161 + }
2162 +
2163 + ret = ipts_resources_alloc_buffer(&res->doorbell, dev, sizeof(u32));
2164 + if (ret)
2165 + goto err;
2166 +
2167 + ret = ipts_resources_alloc_buffer(&res->workqueue, dev, sizeof(u32));
2168 + if (ret)
2169 + goto err;
2170 +
2171 + ret = ipts_resources_alloc_buffer(&res->hid2me, dev, fs);
2172 + if (ret)
2173 + goto err;
2174 +
2175 + ret = ipts_resources_alloc_buffer(&res->descriptor, dev, ds + 8);
2176 + if (ret)
2177 + goto err;
2178 +
2179 + return 0;
2180 +
2181 +err:
2182 +
2183 + ipts_resources_free(res);
2184 + return ret;
2185 +}
2186 +
2187 +int ipts_resources_free(struct ipts_resources *res)
2188 +{
2189 + if (!res)
2190 + return -EFAULT;
2191 +
2192 + for (int i = 0; i < IPTS_BUFFERS; i++)
2193 + ipts_resources_free_buffer(&res->data[i]);
2194 +
2195 + for (int i = 0; i < IPTS_BUFFERS; i++)
2196 + ipts_resources_free_buffer(&res->feedback[i]);
2197 +
2198 + ipts_resources_free_buffer(&res->doorbell);
2199 + ipts_resources_free_buffer(&res->workqueue);
2200 + ipts_resources_free_buffer(&res->hid2me);
2201 + ipts_resources_free_buffer(&res->descriptor);
2202 +
2203 + return 0;
2204 +}
2205 diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h
2206 new file mode 100644
2207 index 0000000000000..6cbb24a8a0543
2208 --- /dev/null
2209 +++ b/drivers/hid/ipts/resources.h
2210 @@ -0,0 +1,39 @@
2211 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2212 +/*
2213 + * Copyright (c) 2016 Intel Corporation
2214 + * Copyright (c) 2020-2023 Dorian Stoll
2215 + *
2216 + * Linux driver for Intel Precise Touch & Stylus
2217 + */
2218 +
2219 +#ifndef IPTS_RESOURCES_H
2220 +#define IPTS_RESOURCES_H
2221 +
2222 +#include <linux/device.h>
2223 +#include <linux/types.h>
2224 +
2225 +#include "spec-device.h"
2226 +
2227 +struct ipts_buffer {
2228 + u8 *address;
2229 + size_t size;
2230 +
2231 + dma_addr_t dma_address;
2232 + struct device *device;
2233 +};
2234 +
2235 +struct ipts_resources {
2236 + struct ipts_buffer data[IPTS_BUFFERS];
2237 + struct ipts_buffer feedback[IPTS_BUFFERS];
2238 +
2239 + struct ipts_buffer doorbell;
2240 + struct ipts_buffer workqueue;
2241 + struct ipts_buffer hid2me;
2242 +
2243 + struct ipts_buffer descriptor;
2244 +};
2245 +
2246 +int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs);
2247 +int ipts_resources_free(struct ipts_resources *res);
2248 +
2249 +#endif /* IPTS_RESOURCES_H */
2250 diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h
2251 new file mode 100644
2252 index 0000000000000..e8dd98895a7ee
2253 --- /dev/null
2254 +++ b/drivers/hid/ipts/spec-data.h
2255 @@ -0,0 +1,100 @@
2256 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2257 +/*
2258 + * Copyright (c) 2016 Intel Corporation
2259 + * Copyright (c) 2020-2023 Dorian Stoll
2260 + *
2261 + * Linux driver for Intel Precise Touch & Stylus
2262 + */
2263 +
2264 +#ifndef IPTS_SPEC_DATA_H
2265 +#define IPTS_SPEC_DATA_H
2266 +
2267 +#include <linux/build_bug.h>
2268 +#include <linux/types.h>
2269 +
2270 +/**
2271 + * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback.
2272 + */
2273 +enum ipts_feedback_cmd_type {
2274 + IPTS_FEEDBACK_CMD_TYPE_NONE = 0,
2275 + IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1,
2276 + IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2,
2277 + IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3,
2278 + IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4,
2279 + IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5,
2280 + IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6,
2281 +};
2282 +
2283 +/**
2284 + * enum ipts_feedback_data_type - Defines what data a feedback buffer contains.
2285 + * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback.
2286 + * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features report.
2287 + * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features report.
2288 + * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report.
2289 + * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor.
2290 + */
2291 +enum ipts_feedback_data_type {
2292 + IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0,
2293 + IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1,
2294 + IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2,
2295 + IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3,
2296 + IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4,
2297 +};
2298 +
2299 +/**
2300 + * struct ipts_feedback_header - Header that is prefixed to the data in a feedback buffer.
2301 + * @cmd_type: A command that should be executed on the sensor.
2302 + * @size: The size of the payload to be written.
2303 + * @buffer: The ID of the buffer that contains this feedback data.
2304 + * @protocol: The protocol version of the EDS.
2305 + * @data_type: The type of data that the buffer contains.
2306 + * @spi_offset: The offset at which to write the payload data to the sensor.
2307 + * @payload: Payload for the feedback command, or 0 if no payload is sent.
2308 + */
2309 +struct ipts_feedback_header {
2310 + enum ipts_feedback_cmd_type cmd_type;
2311 + u32 size;
2312 + u32 buffer;
2313 + u32 protocol;
2314 + enum ipts_feedback_data_type data_type;
2315 + u32 spi_offset;
2316 + u8 reserved[40];
2317 + u8 payload[];
2318 +} __packed;
2319 +
2320 +static_assert(sizeof(struct ipts_feedback_header) == 64);
2321 +
2322 +/**
2323 + * enum ipts_data_type - Defines what type of data a buffer contains.
2324 + * @IPTS_DATA_TYPE_FRAME: Raw data frame.
2325 + * @IPTS_DATA_TYPE_ERROR: Error data.
2326 + * @IPTS_DATA_TYPE_VENDOR: Vendor specific data.
2327 + * @IPTS_DATA_TYPE_HID: A HID report.
2328 + * @IPTS_DATA_TYPE_GET_FEATURES: The response to a GET_FEATURES HID2ME command.
2329 + */
2330 +enum ipts_data_type {
2331 + IPTS_DATA_TYPE_FRAME = 0x00,
2332 + IPTS_DATA_TYPE_ERROR = 0x01,
2333 + IPTS_DATA_TYPE_VENDOR = 0x02,
2334 + IPTS_DATA_TYPE_HID = 0x03,
2335 + IPTS_DATA_TYPE_GET_FEATURES = 0x04,
2336 + IPTS_DATA_TYPE_DESCRIPTOR = 0x05,
2337 +};
2338 +
2339 +/**
2340 + * struct ipts_data_header - Header that is prefixed to the data in a data buffer.
2341 + * @type: What data the buffer contains.
2342 + * @size: How much data the buffer contains.
2343 + * @buffer: Which buffer the data is in.
2344 + */
2345 +struct ipts_data_header {
2346 + enum ipts_data_type type;
2347 + u32 size;
2348 + u32 buffer;
2349 + u8 reserved[52];
2350 + u8 data[];
2351 +} __packed;
2352 +
2353 +static_assert(sizeof(struct ipts_data_header) == 64);
2354 +
2355 +#endif /* IPTS_SPEC_DATA_H */
2356 diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h
2357 new file mode 100644
2358 index 0000000000000..e8a9117709daf
2359 --- /dev/null
2360 +++ b/drivers/hid/ipts/spec-device.h
2361 @@ -0,0 +1,285 @@
2362 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2363 +/*
2364 + * Copyright (c) 2016 Intel Corporation
2365 + * Copyright (c) 2020-2023 Dorian Stoll
2366 + *
2367 + * Linux driver for Intel Precise Touch & Stylus
2368 + */
2369 +
2370 +#ifndef IPTS_SPEC_DEVICE_H
2371 +#define IPTS_SPEC_DEVICE_H
2372 +
2373 +#include <linux/build_bug.h>
2374 +#include <linux/types.h>
2375 +
2376 +/*
2377 + * The amount of buffers that IPTS can use for data transfer.
2378 + */
2379 +#define IPTS_BUFFERS 16
2380 +
2381 +/*
2382 + * The buffer ID that is used for HID2ME feedback
2383 + */
2384 +#define IPTS_HID2ME_BUFFER IPTS_BUFFERS
2385 +
2386 +/**
2387 + * enum ipts_command - Commands that can be sent to the IPTS hardware.
2388 + * @IPTS_CMD_GET_DEVICE_INFO: Retrieves vendor information from the device.
2389 + * @IPTS_CMD_SET_MODE: Changes the mode that the device will operate in.
2390 + * @IPTS_CMD_SET_MEM_WINDOW: Configures memory buffers for passing data between device and driver.
2391 + * @IPTS_CMD_QUIESCE_IO: Stops the data flow from the device to the driver.
2392 + * @IPTS_CMD_READY_FOR_DATA: Informs the device that the driver is ready to receive data.
2393 + * @IPTS_CMD_FEEDBACK: Informs the device that a buffer was processed and can be refilled.
2394 + * @IPTS_CMD_CLEAR_MEM_WINDOW: Stops the data flow and clears the buffer addresses on the device.
2395 + * @IPTS_CMD_RESET_SENSOR: Resets the sensor to its default state.
2396 + * @IPTS_CMD_GET_DESCRIPTOR: Retrieves the HID descriptor of the device.
2397 + */
2398 +enum ipts_command_code {
2399 + IPTS_CMD_GET_DEVICE_INFO = 0x01,
2400 + IPTS_CMD_SET_MODE = 0x02,
2401 + IPTS_CMD_SET_MEM_WINDOW = 0x03,
2402 + IPTS_CMD_QUIESCE_IO = 0x04,
2403 + IPTS_CMD_READY_FOR_DATA = 0x05,
2404 + IPTS_CMD_FEEDBACK = 0x06,
2405 + IPTS_CMD_CLEAR_MEM_WINDOW = 0x07,
2406 + IPTS_CMD_RESET_SENSOR = 0x0B,
2407 + IPTS_CMD_GET_DESCRIPTOR = 0x0F,
2408 +};
2409 +
2410 +/**
2411 + * enum ipts_status - Possible status codes returned by the IPTS device.
2412 + * @IPTS_STATUS_SUCCESS: Operation completed successfully.
2413 + * @IPTS_STATUS_INVALID_PARAMS: Command contained an invalid payload.
2414 + * @IPTS_STATUS_ACCESS_DENIED: ME could not validate a buffer address.
2415 + * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload.
2416 + * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set.
2417 + * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type.
2418 + * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found.
2419 + * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation.
2420 + * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred.
2421 + * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized.
2422 + * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed.
2423 + * The host can ignore this error and attempt to continue.
2424 + * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by the driver.
2425 + * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset.
2426 + * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete.
2427 + * @IPTS_STATUS_TIMEOUT: The operation timed out.
2428 + * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values.
2429 + * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported an error during reset sequence.
2430 + * Further progress is not possible.
2431 + * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported an error during reset sequence.
2432 + * The driver can attempt to continue.
2433 + * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities.
2434 + * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done.
2435 + */
2436 +enum ipts_status {
2437 + IPTS_STATUS_SUCCESS = 0x00,
2438 + IPTS_STATUS_INVALID_PARAMS = 0x01,
2439 + IPTS_STATUS_ACCESS_DENIED = 0x02,
2440 + IPTS_STATUS_CMD_SIZE_ERROR = 0x03,
2441 + IPTS_STATUS_NOT_READY = 0x04,
2442 + IPTS_STATUS_REQUEST_OUTSTANDING = 0x05,
2443 + IPTS_STATUS_NO_SENSOR_FOUND = 0x06,
2444 + IPTS_STATUS_OUT_OF_MEMORY = 0x07,
2445 + IPTS_STATUS_INTERNAL_ERROR = 0x08,
2446 + IPTS_STATUS_SENSOR_DISABLED = 0x09,
2447 + IPTS_STATUS_COMPAT_CHECK_FAIL = 0x0A,
2448 + IPTS_STATUS_SENSOR_EXPECTED_RESET = 0x0B,
2449 + IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 0x0C,
2450 + IPTS_STATUS_RESET_FAILED = 0x0D,
2451 + IPTS_STATUS_TIMEOUT = 0x0E,
2452 + IPTS_STATUS_TEST_MODE_FAIL = 0x0F,
2453 + IPTS_STATUS_SENSOR_FAIL_FATAL = 0x10,
2454 + IPTS_STATUS_SENSOR_FAIL_NONFATAL = 0x11,
2455 + IPTS_STATUS_INVALID_DEVICE_CAPS = 0x12,
2456 + IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 0x13,
2457 +};
2458 +
2459 +/**
2460 + * struct ipts_command - Message that is sent to the device for calling a command.
2461 + * @cmd: The command that will be called.
2462 + * @payload: Payload containing parameters for the called command.
2463 + */
2464 +struct ipts_command {
2465 + enum ipts_command_code cmd;
2466 + u8 payload[320];
2467 +} __packed;
2468 +
2469 +static_assert(sizeof(struct ipts_command) == 324);
2470 +
2471 +/**
2472 + * enum ipts_mode - Configures what data the device produces and how its sent.
2473 + * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled.
2474 + * Older device will return singletouch data in this mode.
2475 + * @IPTS_MODE_DOORBELL: The device will notify the driver by incrementing the doorbell value.
2476 + * Older devices will return multitouch data in this mode.
2477 + */
2478 +enum ipts_mode {
2479 + IPTS_MODE_EVENT = 0x00,
2480 + IPTS_MODE_DOORBELL = 0x01,
2481 +};
2482 +
2483 +/**
2484 + * struct ipts_set_mode - Payload for the SET_MODE command.
2485 + * @mode: Changes the mode that IPTS will operate in.
2486 + */
2487 +struct ipts_set_mode {
2488 + enum ipts_mode mode;
2489 + u8 reserved[12];
2490 +} __packed;
2491 +
2492 +static_assert(sizeof(struct ipts_set_mode) == 16);
2493 +
2494 +#define IPTS_WORKQUEUE_SIZE 8192
2495 +#define IPTS_WORKQUEUE_ITEM_SIZE 16
2496 +
2497 +/**
2498 + * struct ipts_mem_window - Payload for the SET_MEM_WINDOW command.
2499 + * @data_addr_lower: Lower 32 bits of the data buffer addresses.
2500 + * @data_addr_upper: Upper 32 bits of the data buffer addresses.
2501 + * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address.
2502 + * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address.
2503 + * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address.
2504 + * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address.
2505 + * @feedbackaddr_lower: Lower 32 bits of the feedback buffer addresses.
2506 + * @feedbackaddr_upper: Upper 32 bits of the feedback buffer addresses.
2507 + * @hid2me_addr_lower: Lower 32 bits of the hid2me buffer address.
2508 + * @hid2me_addr_upper: Upper 32 bits of the hid2me buffer address.
2509 + * @hid2me_size: Size of the hid2me feedback buffer.
2510 + * @workqueue_item_size: Magic value. Must be 16.
2511 + * @workqueue_size: Magic value. Must be 8192.
2512 + *
2513 + * The workqueue related items in this struct are required for using
2514 + * GuC submission with binary processing firmware. Since this driver does
2515 + * not use GuC submission and instead exports raw data to userspace, these
2516 + * items are not actually used, but they need to be allocated and passed
2517 + * to the device, otherwise initialization will fail.
2518 + */
2519 +struct ipts_mem_window {
2520 + u32 data_addr_lower[IPTS_BUFFERS];
2521 + u32 data_addr_upper[IPTS_BUFFERS];
2522 + u32 workqueue_addr_lower;
2523 + u32 workqueue_addr_upper;
2524 + u32 doorbell_addr_lower;
2525 + u32 doorbell_addr_upper;
2526 + u32 feedback_addr_lower[IPTS_BUFFERS];
2527 + u32 feedback_addr_upper[IPTS_BUFFERS];
2528 + u32 hid2me_addr_lower;
2529 + u32 hid2me_addr_upper;
2530 + u32 hid2me_size;
2531 + u8 reserved1;
2532 + u8 workqueue_item_size;
2533 + u16 workqueue_size;
2534 + u8 reserved[32];
2535 +} __packed;
2536 +
2537 +static_assert(sizeof(struct ipts_mem_window) == 320);
2538 +
2539 +/**
2540 + * struct ipts_quiesce_io - Payload for the QUIESCE_IO command.
2541 + */
2542 +struct ipts_quiesce_io {
2543 + u8 reserved[12];
2544 +} __packed;
2545 +
2546 +static_assert(sizeof(struct ipts_quiesce_io) == 12);
2547 +
2548 +/**
2549 + * struct ipts_feedback - Payload for the FEEDBACK command.
2550 + * @buffer: The buffer that the device should refill.
2551 + */
2552 +struct ipts_feedback {
2553 + u32 buffer;
2554 + u8 reserved[12];
2555 +} __packed;
2556 +
2557 +static_assert(sizeof(struct ipts_feedback) == 16);
2558 +
2559 +/**
2560 + * enum ipts_reset_type - Possible ways of resetting the device.
2561 + * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin.
2562 + * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI command.
2563 + */
2564 +enum ipts_reset_type {
2565 + IPTS_RESET_TYPE_HARD = 0x00,
2566 + IPTS_RESET_TYPE_SOFT = 0x01,
2567 +};
2568 +
2569 +/**
2570 + * struct ipts_reset - Payload for the RESET_SENSOR command.
2571 + * @type: How the device should get reset.
2572 + */
2573 +struct ipts_reset_sensor {
2574 + enum ipts_reset_type type;
2575 + u8 reserved[4];
2576 +} __packed;
2577 +
2578 +static_assert(sizeof(struct ipts_reset_sensor) == 8);
2579 +
2580 +/**
2581 + * struct ipts_get_descriptor - Payload for the GET_DESCRIPTOR command.
2582 + * @addr_lower: The lower 32 bits of the descriptor buffer address.
2583 + * @addr_upper: The upper 32 bits of the descriptor buffer address.
2584 + * @magic: A magic value. Must be 8.
2585 + */
2586 +struct ipts_get_descriptor {
2587 + u32 addr_lower;
2588 + u32 addr_upper;
2589 + u32 magic;
2590 + u8 reserved[12];
2591 +} __packed;
2592 +
2593 +static_assert(sizeof(struct ipts_get_descriptor) == 24);
2594 +
2595 +/*
2596 + * The type of a response is indicated by a
2597 + * command code, with the most significant bit flipped to 1.
2598 + */
2599 +#define IPTS_RSP_BIT BIT(31)
2600 +
2601 +/**
2602 + * struct ipts_response - Data returned from the device in response to a command.
2603 + * @cmd: The command that this response answers (IPTS_RSP_BIT will be 1).
2604 + * @status: The return code of the command.
2605 + * @payload: The data that was produced by the command.
2606 + */
2607 +struct ipts_response {
2608 + enum ipts_command_code cmd;
2609 + enum ipts_status status;
2610 + u8 payload[80];
2611 +} __packed;
2612 +
2613 +static_assert(sizeof(struct ipts_response) == 88);
2614 +
2615 +/**
2616 + * struct ipts_device_info - Vendor information of the IPTS device.
2617 + * @vendor: Vendor ID of this device.
2618 + * @product: Product ID of this device.
2619 + * @hw_version: Hardware revision of this device.
2620 + * @fw_version: Firmware revision of this device.
2621 + * @data_size: Requested size for a data buffer.
2622 + * @feedback_size: Requested size for a feedback buffer.
2623 + * @mode: Mode that the device currently operates in.
2624 + * @max_contacts: Maximum amount of concurrent touches the sensor can process.
2625 + */
2626 +struct ipts_device_info {
2627 + u16 vendor;
2628 + u16 product;
2629 + u32 hw_version;
2630 + u32 fw_version;
2631 + u32 data_size;
2632 + u32 feedback_size;
2633 + enum ipts_mode mode;
2634 + u8 max_contacts;
2635 + u8 reserved1[3];
2636 + u8 sensor_min_eds;
2637 + u8 sensor_maj_eds;
2638 + u8 me_min_eds;
2639 + u8 me_maj_eds;
2640 + u8 intf_eds;
2641 + u8 reserved2[11];
2642 +} __packed;
2643 +
2644 +static_assert(sizeof(struct ipts_device_info) == 44);
2645 +
2646 +#endif /* IPTS_SPEC_DEVICE_H */
2647 diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h
2648 new file mode 100644
2649 index 0000000000000..ea70f29ff00cb
2650 --- /dev/null
2651 +++ b/drivers/hid/ipts/spec-hid.h
2652 @@ -0,0 +1,35 @@
2653 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2654 +/*
2655 + * Copyright (c) 2016 Intel Corporation
2656 + * Copyright (c) 2020-2023 Dorian Stoll
2657 + *
2658 + * Linux driver for Intel Precise Touch & Stylus
2659 + */
2660 +
2661 +#ifndef IPTS_SPEC_HID_H
2662 +#define IPTS_SPEC_HID_H
2663 +
2664 +#include <linux/build_bug.h>
2665 +#include <linux/types.h>
2666 +
2667 +/*
2668 + * Made-up type for passing raw IPTS data in a HID report.
2669 + */
2670 +#define IPTS_HID_FRAME_TYPE_RAW 0xEE
2671 +
2672 +/**
2673 + * struct ipts_hid_frame - Header that is prefixed to raw IPTS data wrapped in a HID report.
2674 + * @size: Size of the data inside the report, including this header.
2675 + * @type: What type of data does this report contain.
2676 + */
2677 +struct ipts_hid_header {
2678 + u32 size;
2679 + u8 reserved1;
2680 + u8 type;
2681 + u8 reserved2;
2682 + u8 data[];
2683 +} __packed;
2684 +
2685 +static_assert(sizeof(struct ipts_hid_header) == 7);
2686 +
2687 +#endif /* IPTS_SPEC_HID_H */
2688 diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c
2689 new file mode 100644
2690 index 0000000000000..8b46f775c1070
2691 --- /dev/null
2692 +++ b/drivers/hid/ipts/thread.c
2693 @@ -0,0 +1,85 @@
2694 +// SPDX-License-Identifier: GPL-2.0-or-later
2695 +/*
2696 + * Copyright (c) 2016 Intel Corporation
2697 + * Copyright (c) 2023 Dorian Stoll
2698 + *
2699 + * Linux driver for Intel Precise Touch & Stylus
2700 + */
2701 +
2702 +#include <linux/completion.h>
2703 +#include <linux/err.h>
2704 +#include <linux/kthread.h>
2705 +#include <linux/mutex.h>
2706 +
2707 +#include "thread.h"
2708 +
2709 +bool ipts_thread_should_stop(struct ipts_thread *thread)
2710 +{
2711 + if (!thread)
2712 + return false;
2713 +
2714 + return READ_ONCE(thread->should_stop);
2715 +}
2716 +
2717 +static int ipts_thread_runner(void *data)
2718 +{
2719 + int ret = 0;
2720 + struct ipts_thread *thread = data;
2721 +
2722 + if (!thread)
2723 + return -EFAULT;
2724 +
2725 + if (!thread->threadfn)
2726 + return -EFAULT;
2727 +
2728 + ret = thread->threadfn(thread);
2729 + complete_all(&thread->done);
2730 +
2731 + return ret;
2732 +}
2733 +
2734 +int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread),
2735 + void *data, const char *name)
2736 +{
2737 + if (!thread)
2738 + return -EFAULT;
2739 +
2740 + if (!threadfn)
2741 + return -EFAULT;
2742 +
2743 + init_completion(&thread->done);
2744 +
2745 + thread->data = data;
2746 + thread->should_stop = false;
2747 + thread->threadfn = threadfn;
2748 +
2749 + thread->thread = kthread_run(ipts_thread_runner, thread, name);
2750 + return PTR_ERR_OR_ZERO(thread->thread);
2751 +}
2752 +
2753 +int ipts_thread_stop(struct ipts_thread *thread)
2754 +{
2755 + int ret = 0;
2756 +
2757 + if (!thread)
2758 + return -EFAULT;
2759 +
2760 + if (!thread->thread)
2761 + return 0;
2762 +
2763 + WRITE_ONCE(thread->should_stop, true);
2764 +
2765 + /*
2766 + * Make sure that the write has gone through before waiting.
2767 + */
2768 + wmb();
2769 +
2770 + wait_for_completion(&thread->done);
2771 + ret = kthread_stop(thread->thread);
2772 +
2773 + thread->thread = NULL;
2774 + thread->data = NULL;
2775 + thread->threadfn = NULL;
2776 +
2777 + return ret;
2778 +}
2779 diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h
2780 new file mode 100644
2781 index 0000000000000..dd2299fa0f63b
2782 --- /dev/null
2783 +++ b/drivers/hid/ipts/thread.h
2784 @@ -0,0 +1,60 @@
2785 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2786 +/*
2787 + * Copyright (c) 2016 Intel Corporation
2788 + * Copyright (c) 2023 Dorian Stoll
2789 + *
2790 + * Linux driver for Intel Precise Touch & Stylus
2791 + */
2792 +
2793 +#ifndef IPTS_THREAD_H
2794 +#define IPTS_THREAD_H
2795 +
2796 +#include <linux/completion.h>
2797 +#include <linux/mutex.h>
2798 +#include <linux/sched.h>
2799 +
2800 +/*
2801 + * This wrapper over kthread is neccessary, because calling kthread_stop makes it impossible
2802 + * to issue MEI commands from that thread while it shuts itself down. By using a custom
2803 + * boolean variable and a completion object, we can call kthread_stop only when the thread
2804 + * already finished all of its work and has returned.
2805 +*/
2806 +struct ipts_thread {
2807 + struct task_struct *thread;
2808 +
2809 + bool should_stop;
2810 + struct completion done;
2811 +
2812 + void *data;
2813 + int (*threadfn)(struct ipts_thread *thread);
2814 +};
2815 +
2816 +/*
2817 + * ipts_thread_should_stop() - Returns true if the thread is asked to terminate.
2818 + * @thread: The current thread.
2819 + *
2820 + * Returns: true if the thread should stop, false if not.
2821 + */
2822 +bool ipts_thread_should_stop(struct ipts_thread *thread);
2823 +
2824 +/*
2825 + * ipts_thread_start() - Starts an IPTS thread.
2826 + * @thread: The thread to initialize and start.
2827 + * @threadfn: The function to execute.
2828 + * @data: An argument that will be passed to threadfn.
2829 + * @name: The name of the new thread.
2830 + *
2831 + * Returns: 0 on success, <0 on error.
2832 + */
2833 +int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread),
2834 + void *data, const char name[]);
2835 +
2836 +/*
2837 + * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished.
2838 + * @thread: The thread that should stop.
2839 + *
2840 + * Returns: The return value of the thread function.
2841 + */
2842 +int ipts_thread_stop(struct ipts_thread *thread);
2843 +
2844 +#endif /* IPTS_THREAD_H */

  ViewVC Help
Powered by ViewVC 1.1.30