0004-ipts.patch 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. From c0c0233e107398277401acbdc68263b75e4ec764 Mon Sep 17 00:00:00 2001
  2. From: Dorian Stoll <dorian.stoll@tmsp.io>
  3. Date: Thu, 30 Jul 2020 13:21:53 +0200
  4. Subject: [PATCH] misc: mei: Add missing IPTS device IDs
  5. Patchset: ipts
  6. ---
  7. drivers/misc/mei/hw-me-regs.h | 1 +
  8. drivers/misc/mei/pci-me.c | 1 +
  9. 2 files changed, 2 insertions(+)
  10. diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
  11. index 67bb6a25fd0a..d1cb94d3452e 100644
  12. --- a/drivers/misc/mei/hw-me-regs.h
  13. +++ b/drivers/misc/mei/hw-me-regs.h
  14. @@ -92,6 +92,7 @@
  15. #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */
  16. #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
  17. +#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */
  18. #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */
  19. #define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */
  20. diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
  21. index 3a45aaf002ac..55b8ee30a03c 100644
  22. --- a/drivers/misc/mei/pci-me.c
  23. +++ b/drivers/misc/mei/pci-me.c
  24. @@ -96,6 +96,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
  25. {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)},
  26. {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
  27. + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)},
  28. {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)},
  29. {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
  30. --
  31. 2.34.0
  32. From d8fe8086fc5c53e0b4d24dbbcc1bb926482a9a78 Mon Sep 17 00:00:00 2001
  33. From: Dorian Stoll <dorian.stoll@tmsp.io>
  34. Date: Thu, 6 Aug 2020 11:20:41 +0200
  35. Subject: [PATCH] misc: Add support for Intel Precise Touch & Stylus
  36. Based on linux-surface/intel-precise-touch@3f362c
  37. Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
  38. Patchset: ipts
  39. ---
  40. drivers/misc/Kconfig | 1 +
  41. drivers/misc/Makefile | 1 +
  42. drivers/misc/ipts/Kconfig | 17 ++
  43. drivers/misc/ipts/Makefile | 12 ++
  44. drivers/misc/ipts/context.h | 47 +++++
  45. drivers/misc/ipts/control.c | 113 +++++++++++
  46. drivers/misc/ipts/control.h | 24 +++
  47. drivers/misc/ipts/mei.c | 125 ++++++++++++
  48. drivers/misc/ipts/protocol.h | 347 ++++++++++++++++++++++++++++++++++
  49. drivers/misc/ipts/receiver.c | 224 ++++++++++++++++++++++
  50. drivers/misc/ipts/receiver.h | 16 ++
  51. drivers/misc/ipts/resources.c | 128 +++++++++++++
  52. drivers/misc/ipts/resources.h | 17 ++
  53. drivers/misc/ipts/uapi.c | 208 ++++++++++++++++++++
  54. drivers/misc/ipts/uapi.h | 47 +++++
  55. 15 files changed, 1327 insertions(+)
  56. create mode 100644 drivers/misc/ipts/Kconfig
  57. create mode 100644 drivers/misc/ipts/Makefile
  58. create mode 100644 drivers/misc/ipts/context.h
  59. create mode 100644 drivers/misc/ipts/control.c
  60. create mode 100644 drivers/misc/ipts/control.h
  61. create mode 100644 drivers/misc/ipts/mei.c
  62. create mode 100644 drivers/misc/ipts/protocol.h
  63. create mode 100644 drivers/misc/ipts/receiver.c
  64. create mode 100644 drivers/misc/ipts/receiver.h
  65. create mode 100644 drivers/misc/ipts/resources.c
  66. create mode 100644 drivers/misc/ipts/resources.h
  67. create mode 100644 drivers/misc/ipts/uapi.c
  68. create mode 100644 drivers/misc/ipts/uapi.h
  69. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
  70. index f4fb5c52b863..0e5a2fe6bffe 100644
  71. --- a/drivers/misc/Kconfig
  72. +++ b/drivers/misc/Kconfig
  73. @@ -464,4 +464,5 @@ source "drivers/misc/cardreader/Kconfig"
  74. source "drivers/misc/habanalabs/Kconfig"
  75. source "drivers/misc/uacce/Kconfig"
  76. source "drivers/misc/pvpanic/Kconfig"
  77. +source "drivers/misc/ipts/Kconfig"
  78. endmenu
  79. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
  80. index e92a56d4442f..7adce5540183 100644
  81. --- a/drivers/misc/Makefile
  82. +++ b/drivers/misc/Makefile
  83. @@ -57,3 +57,4 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/
  84. obj-$(CONFIG_UACCE) += uacce/
  85. obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
  86. obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
  87. +obj-$(CONFIG_MISC_IPTS) += ipts/
  88. diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
  89. new file mode 100644
  90. index 000000000000..83e2a930c396
  91. --- /dev/null
  92. +++ b/drivers/misc/ipts/Kconfig
  93. @@ -0,0 +1,17 @@
  94. +# SPDX-License-Identifier: GPL-2.0-or-later
  95. +
  96. +config MISC_IPTS
  97. + tristate "Intel Precise Touch & Stylus"
  98. + depends on INTEL_MEI
  99. + help
  100. + Say Y here if your system has a touchscreen using Intels
  101. + Precise Touch & Stylus (IPTS) technology.
  102. +
  103. + If unsure say N.
  104. +
  105. + To compile this driver as a module, choose M here: the
  106. + module will be called ipts.
  107. +
  108. + Building this driver alone will not give you a working touchscreen.
  109. + It only exposed a userspace API that can be used by a daemon to
  110. + receive and process data from the touchscreen hardware.
  111. diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
  112. new file mode 100644
  113. index 000000000000..8f58b9adbc94
  114. --- /dev/null
  115. +++ b/drivers/misc/ipts/Makefile
  116. @@ -0,0 +1,12 @@
  117. +# SPDX-License-Identifier: GPL-2.0-or-later
  118. +#
  119. +# Makefile for the IPTS touchscreen driver
  120. +#
  121. +
  122. +obj-$(CONFIG_MISC_IPTS) += ipts.o
  123. +ipts-objs := control.o
  124. +ipts-objs += mei.o
  125. +ipts-objs += receiver.o
  126. +ipts-objs += resources.o
  127. +ipts-objs += uapi.o
  128. +
  129. diff --git a/drivers/misc/ipts/context.h b/drivers/misc/ipts/context.h
  130. new file mode 100644
  131. index 000000000000..f4b06a2d3f72
  132. --- /dev/null
  133. +++ b/drivers/misc/ipts/context.h
  134. @@ -0,0 +1,47 @@
  135. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  136. +/*
  137. + * Copyright (c) 2016 Intel Corporation
  138. + * Copyright (c) 2020 Dorian Stoll
  139. + *
  140. + * Linux driver for Intel Precise Touch & Stylus
  141. + */
  142. +
  143. +#ifndef _IPTS_CONTEXT_H_
  144. +#define _IPTS_CONTEXT_H_
  145. +
  146. +#include <linux/cdev.h>
  147. +#include <linux/device.h>
  148. +#include <linux/mei_cl_bus.h>
  149. +#include <linux/types.h>
  150. +
  151. +#include "protocol.h"
  152. +
  153. +enum ipts_host_status {
  154. + IPTS_HOST_STATUS_STARTING,
  155. + IPTS_HOST_STATUS_STARTED,
  156. + IPTS_HOST_STATUS_STOPPING,
  157. + IPTS_HOST_STATUS_STOPPED,
  158. +};
  159. +
  160. +struct ipts_buffer_info {
  161. + u8 *address;
  162. + dma_addr_t dma_address;
  163. +};
  164. +
  165. +struct ipts_context {
  166. + struct mei_cl_device *cldev;
  167. + struct device *dev;
  168. +
  169. + bool restart;
  170. + enum ipts_host_status status;
  171. + struct ipts_get_device_info_rsp device_info;
  172. +
  173. + struct ipts_buffer_info data[IPTS_BUFFERS];
  174. + struct ipts_buffer_info doorbell;
  175. +
  176. + struct ipts_buffer_info feedback[IPTS_BUFFERS];
  177. + struct ipts_buffer_info workqueue;
  178. + struct ipts_buffer_info host2me;
  179. +};
  180. +
  181. +#endif /* _IPTS_CONTEXT_H_ */
  182. diff --git a/drivers/misc/ipts/control.c b/drivers/misc/ipts/control.c
  183. new file mode 100644
  184. index 000000000000..a1d1f97a13d7
  185. --- /dev/null
  186. +++ b/drivers/misc/ipts/control.c
  187. @@ -0,0 +1,113 @@
  188. +// SPDX-License-Identifier: GPL-2.0-or-later
  189. +/*
  190. + * Copyright (c) 2016 Intel Corporation
  191. + * Copyright (c) 2020 Dorian Stoll
  192. + *
  193. + * Linux driver for Intel Precise Touch & Stylus
  194. + */
  195. +
  196. +#include <linux/mei_cl_bus.h>
  197. +
  198. +#include "context.h"
  199. +#include "protocol.h"
  200. +#include "resources.h"
  201. +#include "uapi.h"
  202. +
  203. +int ipts_control_send(struct ipts_context *ipts, u32 code, void *payload,
  204. + size_t size)
  205. +{
  206. + int ret;
  207. + struct ipts_command cmd;
  208. +
  209. + memset(&cmd, 0, sizeof(struct ipts_command));
  210. + cmd.code = code;
  211. +
  212. + if (payload && size > 0)
  213. + memcpy(&cmd.payload, payload, size);
  214. +
  215. + ret = mei_cldev_send(ipts->cldev, (u8 *)&cmd, sizeof(cmd.code) + size);
  216. + if (ret >= 0)
  217. + return 0;
  218. +
  219. + /*
  220. + * During shutdown the device might get pulled away from below our feet.
  221. + * Dont log an error in this case, because it will confuse people.
  222. + */
  223. + if (ret != -ENODEV || ipts->status != IPTS_HOST_STATUS_STOPPING)
  224. + dev_err(ipts->dev, "Error while sending: 0x%X:%d\n", code, ret);
  225. +
  226. + return ret;
  227. +}
  228. +
  229. +int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer)
  230. +{
  231. + struct ipts_feedback_cmd cmd;
  232. +
  233. + memset(&cmd, 0, sizeof(struct ipts_feedback_cmd));
  234. + cmd.buffer = buffer;
  235. +
  236. + return ipts_control_send(ipts, IPTS_CMD_FEEDBACK, &cmd,
  237. + sizeof(struct ipts_feedback_cmd));
  238. +}
  239. +
  240. +int ipts_control_set_feature(struct ipts_context *ipts, u8 report, u8 value)
  241. +{
  242. + struct ipts_feedback_buffer *feedback;
  243. +
  244. + memset(ipts->host2me.address, 0, ipts->device_info.feedback_size);
  245. + feedback = (struct ipts_feedback_buffer *)ipts->host2me.address;
  246. +
  247. + feedback->cmd_type = IPTS_FEEDBACK_CMD_TYPE_NONE;
  248. + feedback->data_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES;
  249. + feedback->buffer = IPTS_HOST2ME_BUFFER;
  250. + feedback->size = 2;
  251. + feedback->payload[0] = report;
  252. + feedback->payload[1] = value;
  253. +
  254. + return ipts_control_send_feedback(ipts, IPTS_HOST2ME_BUFFER);
  255. +}
  256. +
  257. +int ipts_control_start(struct ipts_context *ipts)
  258. +{
  259. + if (ipts->status != IPTS_HOST_STATUS_STOPPED)
  260. + return -EBUSY;
  261. +
  262. + dev_info(ipts->dev, "Starting IPTS\n");
  263. + ipts->status = IPTS_HOST_STATUS_STARTING;
  264. + ipts->restart = false;
  265. +
  266. + ipts_uapi_link(ipts);
  267. + return ipts_control_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0);
  268. +}
  269. +
  270. +int ipts_control_stop(struct ipts_context *ipts)
  271. +{
  272. + int ret;
  273. +
  274. + if (ipts->status == IPTS_HOST_STATUS_STOPPING)
  275. + return -EBUSY;
  276. +
  277. + if (ipts->status == IPTS_HOST_STATUS_STOPPED)
  278. + return -EBUSY;
  279. +
  280. + dev_info(ipts->dev, "Stopping IPTS\n");
  281. + ipts->status = IPTS_HOST_STATUS_STOPPING;
  282. +
  283. + ipts_uapi_unlink();
  284. + ipts_resources_free(ipts);
  285. +
  286. + ret = ipts_control_send_feedback(ipts, 0);
  287. + if (ret == -ENODEV)
  288. + ipts->status = IPTS_HOST_STATUS_STOPPED;
  289. +
  290. + return ret;
  291. +}
  292. +
  293. +int ipts_control_restart(struct ipts_context *ipts)
  294. +{
  295. + if (ipts->restart)
  296. + return -EBUSY;
  297. +
  298. + ipts->restart = true;
  299. + return ipts_control_stop(ipts);
  300. +}
  301. diff --git a/drivers/misc/ipts/control.h b/drivers/misc/ipts/control.h
  302. new file mode 100644
  303. index 000000000000..2c44e9e0e99f
  304. --- /dev/null
  305. +++ b/drivers/misc/ipts/control.h
  306. @@ -0,0 +1,24 @@
  307. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  308. +/*
  309. + * Copyright (c) 2016 Intel Corporation
  310. + * Copyright (c) 2020 Dorian Stoll
  311. + *
  312. + * Linux driver for Intel Precise Touch & Stylus
  313. + */
  314. +
  315. +#ifndef _IPTS_CONTROL_H_
  316. +#define _IPTS_CONTROL_H_
  317. +
  318. +#include <linux/types.h>
  319. +
  320. +#include "context.h"
  321. +
  322. +int ipts_control_send(struct ipts_context *ipts, u32 cmd, void *payload,
  323. + size_t size);
  324. +int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer);
  325. +int ipts_control_set_feature(struct ipts_context *ipts, u8 report, u8 value);
  326. +int ipts_control_start(struct ipts_context *ipts);
  327. +int ipts_control_restart(struct ipts_context *ipts);
  328. +int ipts_control_stop(struct ipts_context *ipts);
  329. +
  330. +#endif /* _IPTS_CONTROL_H_ */
  331. diff --git a/drivers/misc/ipts/mei.c b/drivers/misc/ipts/mei.c
  332. new file mode 100644
  333. index 000000000000..59ecf13e00d2
  334. --- /dev/null
  335. +++ b/drivers/misc/ipts/mei.c
  336. @@ -0,0 +1,125 @@
  337. +// SPDX-License-Identifier: GPL-2.0-or-later
  338. +/*
  339. + * Copyright (c) 2016 Intel Corporation
  340. + * Copyright (c) 2020 Dorian Stoll
  341. + *
  342. + * Linux driver for Intel Precise Touch & Stylus
  343. + */
  344. +
  345. +#include <linux/delay.h>
  346. +#include <linux/dma-mapping.h>
  347. +#include <linux/mei_cl_bus.h>
  348. +#include <linux/mod_devicetable.h>
  349. +#include <linux/module.h>
  350. +#include <linux/slab.h>
  351. +
  352. +#include "context.h"
  353. +#include "control.h"
  354. +#include "protocol.h"
  355. +#include "receiver.h"
  356. +#include "uapi.h"
  357. +
  358. +static int ipts_mei_set_dma_mask(struct mei_cl_device *cldev)
  359. +{
  360. + int ret;
  361. +
  362. + ret = dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64));
  363. + if (!ret)
  364. + return 0;
  365. +
  366. + return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32));
  367. +}
  368. +
  369. +static int ipts_mei_probe(struct mei_cl_device *cldev,
  370. + const struct mei_cl_device_id *id)
  371. +{
  372. + int ret;
  373. + struct ipts_context *ipts;
  374. +
  375. + if (ipts_mei_set_dma_mask(cldev)) {
  376. + dev_err(&cldev->dev, "Failed to set DMA mask for IPTS\n");
  377. + return -EFAULT;
  378. + }
  379. +
  380. + ret = mei_cldev_enable(cldev);
  381. + if (ret) {
  382. + dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret);
  383. + return ret;
  384. + }
  385. +
  386. + ipts = kzalloc(sizeof(*ipts), GFP_KERNEL);
  387. + if (!ipts) {
  388. + mei_cldev_disable(cldev);
  389. + return -ENOMEM;
  390. + }
  391. +
  392. + ipts->cldev = cldev;
  393. + ipts->dev = &cldev->dev;
  394. + ipts->status = IPTS_HOST_STATUS_STOPPED;
  395. +
  396. + mei_cldev_set_drvdata(cldev, ipts);
  397. + mei_cldev_register_rx_cb(cldev, ipts_receiver_callback);
  398. +
  399. + return ipts_control_start(ipts);
  400. +}
  401. +
  402. +static void ipts_mei_remove(struct mei_cl_device *cldev)
  403. +{
  404. + int i;
  405. + struct ipts_context *ipts = mei_cldev_get_drvdata(cldev);
  406. +
  407. + ipts_control_stop(ipts);
  408. +
  409. + for (i = 0; i < 20; i++) {
  410. + if (ipts->status == IPTS_HOST_STATUS_STOPPED)
  411. + break;
  412. +
  413. + msleep(25);
  414. + }
  415. +
  416. + mei_cldev_disable(cldev);
  417. + kfree(ipts);
  418. +}
  419. +
  420. +static struct mei_cl_device_id ipts_mei_device_id_table[] = {
  421. + { "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY },
  422. + {},
  423. +};
  424. +MODULE_DEVICE_TABLE(mei, ipts_mei_device_id_table);
  425. +
  426. +static struct mei_cl_driver ipts_mei_driver = {
  427. + .id_table = ipts_mei_device_id_table,
  428. + .name = "ipts",
  429. + .probe = ipts_mei_probe,
  430. + .remove = ipts_mei_remove,
  431. +};
  432. +
  433. +static int __init ipts_mei_init(void)
  434. +{
  435. + int ret;
  436. +
  437. + ret = ipts_uapi_init();
  438. + if (ret)
  439. + return ret;
  440. +
  441. + ret = mei_cldev_driver_register(&ipts_mei_driver);
  442. + if (ret) {
  443. + ipts_uapi_free();
  444. + return ret;
  445. + }
  446. +
  447. + return 0;
  448. +}
  449. +
  450. +static void __exit ipts_mei_exit(void)
  451. +{
  452. + mei_cldev_driver_unregister(&ipts_mei_driver);
  453. + ipts_uapi_free();
  454. +}
  455. +
  456. +MODULE_DESCRIPTION("IPTS touchscreen driver");
  457. +MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
  458. +MODULE_LICENSE("GPL");
  459. +
  460. +module_init(ipts_mei_init);
  461. +module_exit(ipts_mei_exit);
  462. diff --git a/drivers/misc/ipts/protocol.h b/drivers/misc/ipts/protocol.h
  463. new file mode 100644
  464. index 000000000000..c3458904a94d
  465. --- /dev/null
  466. +++ b/drivers/misc/ipts/protocol.h
  467. @@ -0,0 +1,347 @@
  468. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  469. +/*
  470. + * Copyright (c) 2016 Intel Corporation
  471. + * Copyright (c) 2020 Dorian Stoll
  472. + *
  473. + * Linux driver for Intel Precise Touch & Stylus
  474. + */
  475. +
  476. +#ifndef _IPTS_PROTOCOL_H_
  477. +#define _IPTS_PROTOCOL_H_
  478. +
  479. +#include <linux/types.h>
  480. +
  481. +/*
  482. + * The MEI client ID for IPTS functionality.
  483. + */
  484. +#define IPTS_MEI_UUID \
  485. + UUID_LE(0x3e8d0870, 0x271a, 0x4208, 0x8e, 0xb5, 0x9a, 0xcb, 0x94, \
  486. + 0x02, 0xae, 0x04)
  487. +
  488. +/*
  489. + * Queries the device for vendor specific information.
  490. + *
  491. + * The command must not contain any payload.
  492. + * The response will contain struct ipts_get_device_info_rsp as payload.
  493. + */
  494. +#define IPTS_CMD_GET_DEVICE_INFO 0x00000001
  495. +#define IPTS_RSP_GET_DEVICE_INFO 0x80000001
  496. +
  497. +/*
  498. + * Sets the mode that IPTS will operate in.
  499. + *
  500. + * The command must contain struct ipts_set_mode_cmd as payload.
  501. + * The response will not contain any payload.
  502. + */
  503. +#define IPTS_CMD_SET_MODE 0x00000002
  504. +#define IPTS_RSP_SET_MODE 0x80000002
  505. +
  506. +/*
  507. + * Configures the memory buffers that the ME will use
  508. + * for passing data to the host.
  509. + *
  510. + * The command must contain struct ipts_set_mem_window_cmd as payload.
  511. + * The response will not contain any payload.
  512. + */
  513. +#define IPTS_CMD_SET_MEM_WINDOW 0x00000003
  514. +#define IPTS_RSP_SET_MEM_WINDOW 0x80000003
  515. +
  516. +/*
  517. + * Signals that the host is ready to receive data to the ME.
  518. + *
  519. + * The command must not contain any payload.
  520. + * The response will not contain any payload.
  521. + */
  522. +#define IPTS_CMD_READY_FOR_DATA 0x00000005
  523. +#define IPTS_RSP_READY_FOR_DATA 0x80000005
  524. +
  525. +/*
  526. + * Signals that a buffer can be refilled to the ME.
  527. + *
  528. + * The command must contain struct ipts_feedback_cmd as payload.
  529. + * The response will not contain any payload.
  530. + */
  531. +#define IPTS_CMD_FEEDBACK 0x00000006
  532. +#define IPTS_RSP_FEEDBACK 0x80000006
  533. +
  534. +/*
  535. + * Resets the data flow from the ME to the hosts and
  536. + * clears the buffers that were set with SET_MEM_WINDOW.
  537. + *
  538. + * The command must not contain any payload.
  539. + * The response will not contain any payload.
  540. + */
  541. +#define IPTS_CMD_CLEAR_MEM_WINDOW 0x00000007
  542. +#define IPTS_RSP_CLEAR_MEM_WINDOW 0x80000007
  543. +
  544. +/*
  545. + * Instructs the ME to reset the touch sensor.
  546. + *
  547. + * The command must contain struct ipts_reset_sensor_cmd as payload.
  548. + * The response will not contain any payload.
  549. + */
  550. +#define IPTS_CMD_RESET_SENSOR 0x0000000B
  551. +#define IPTS_RSP_RESET_SENSOR 0x8000000B
  552. +
  553. +/**
  554. + * enum ipts_status - Possible status codes returned by IPTS commands.
  555. + * @IPTS_STATUS_SUCCESS: Operation completed successfully.
  556. + * @IPTS_STATUS_INVALID_PARAMS: Command contained a payload with invalid parameters.
  557. + * @IPTS_STATUS_ACCESS_DENIED: ME could not validate buffer addresses supplied by host.
  558. + * @IPTS_STATUS_CMD_SIZE_ERROR: Command contains an invalid payload.
  559. + * @IPTS_STATUS_NOT_READY: Buffer addresses have not been set.
  560. + * @IPTS_STATUS_REQUEST_OUTSTANDING: There is an outstanding command of the same type.
  561. + * The host must wait for a response before sending another
  562. + * command of the same type.
  563. + * @IPTS_STATUS_NO_SENSOR_FOUND: No sensor could be found. Either no sensor is connected, it
  564. + * has not been initialized yet, or the system is improperly
  565. + * configured.
  566. + * @IPTS_STATUS_OUT_OF_MEMORY: Not enough free memory for requested operation.
  567. + * @IPTS_STATUS_INTERNAL_ERROR: An unexpected error occurred.
  568. + * @IPTS_STATUS_SENSOR_DISABLED: The sensor has been disabled and must be reinitialized.
  569. + * @IPTS_STATUS_COMPAT_CHECK_FAIL: Compatibility revision check between sensor and ME failed.
  570. + * The host can ignore this error and attempt to continue.
  571. + * @IPTS_STATUS_SENSOR_EXPECTED_RESET: The sensor went through a reset initiated by ME or host.
  572. + * @IPTS_STATUS_SENSOR_UNEXPECTED_RESET: The sensor went through an unexpected reset.
  573. + * @IPTS_STATUS_RESET_FAILED: Requested sensor reset failed to complete.
  574. + * @IPTS_STATUS_TIMEOUT: The operation timed out.
  575. + * @IPTS_STATUS_TEST_MODE_FAIL: Test mode pattern did not match expected values.
  576. + * @IPTS_STATUS_SENSOR_FAIL_FATAL: The sensor reported a fatal error during reset sequence.
  577. + * Further progress is not possible.
  578. + * @IPTS_STATUS_SENSOR_FAIL_NONFATAL: The sensor reported a fatal error during reset sequence.
  579. + * The host can attempt to continue.
  580. + * @IPTS_STATUS_INVALID_DEVICE_CAPS: The device reported invalid capabilities.
  581. + * @IPTS_STATUS_QUIESCE_IO_IN_PROGRESS: Command cannot be completed until Quiesce IO is done.
  582. + */
  583. +enum ipts_status {
  584. + IPTS_STATUS_SUCCESS = 0,
  585. + IPTS_STATUS_INVALID_PARAMS = 1,
  586. + IPTS_STATUS_ACCESS_DENIED = 2,
  587. + IPTS_STATUS_CMD_SIZE_ERROR = 3,
  588. + IPTS_STATUS_NOT_READY = 4,
  589. + IPTS_STATUS_REQUEST_OUTSTANDING = 5,
  590. + IPTS_STATUS_NO_SENSOR_FOUND = 6,
  591. + IPTS_STATUS_OUT_OF_MEMORY = 7,
  592. + IPTS_STATUS_INTERNAL_ERROR = 8,
  593. + IPTS_STATUS_SENSOR_DISABLED = 9,
  594. + IPTS_STATUS_COMPAT_CHECK_FAIL = 10,
  595. + IPTS_STATUS_SENSOR_EXPECTED_RESET = 11,
  596. + IPTS_STATUS_SENSOR_UNEXPECTED_RESET = 12,
  597. + IPTS_STATUS_RESET_FAILED = 13,
  598. + IPTS_STATUS_TIMEOUT = 14,
  599. + IPTS_STATUS_TEST_MODE_FAIL = 15,
  600. + IPTS_STATUS_SENSOR_FAIL_FATAL = 16,
  601. + IPTS_STATUS_SENSOR_FAIL_NONFATAL = 17,
  602. + IPTS_STATUS_INVALID_DEVICE_CAPS = 18,
  603. + IPTS_STATUS_QUIESCE_IO_IN_PROGRESS = 19,
  604. +};
  605. +
  606. +/*
  607. + * The amount of buffers that is used for IPTS
  608. + */
  609. +#define IPTS_BUFFERS 16
  610. +
  611. +/*
  612. + * The special buffer ID that is used for direct host2me feedback.
  613. + */
  614. +#define IPTS_HOST2ME_BUFFER IPTS_BUFFERS
  615. +
  616. +/**
  617. + * enum ipts_mode - Operation mode for IPTS hardware
  618. + * @IPTS_MODE_SINGLETOUCH: Fallback that supports only one finger and no stylus.
  619. + * The data is received as a HID report with ID 64.
  620. + * @IPTS_MODE_MULTITOUCH: The "proper" operation mode for IPTS. It will return
  621. + * stylus data as well as capacitive heatmap touch data.
  622. + * This data needs to be processed in userspace.
  623. + */
  624. +enum ipts_mode {
  625. + IPTS_MODE_SINGLETOUCH = 0,
  626. + IPTS_MODE_MULTITOUCH = 1,
  627. +};
  628. +
  629. +/**
  630. + * struct ipts_set_mode_cmd - Payload for the SET_MODE command.
  631. + * @mode: The mode that IPTS should operate in.
  632. + */
  633. +struct ipts_set_mode_cmd {
  634. + enum ipts_mode mode;
  635. + u8 reserved[12];
  636. +} __packed;
  637. +
  638. +#define IPTS_WORKQUEUE_SIZE 8192
  639. +#define IPTS_WORKQUEUE_ITEM_SIZE 16
  640. +
  641. +/**
  642. + * struct ipts_set_mem_window_cmd - Payload for the SET_MEM_WINDOW command.
  643. + * @data_buffer_addr_lower: Lower 32 bits of the data buffer addresses.
  644. + * @data_buffer_addr_upper: Upper 32 bits of the data buffer addresses.
  645. + * @workqueue_addr_lower: Lower 32 bits of the workqueue buffer address.
  646. + * @workqueue_addr_upper: Upper 32 bits of the workqueue buffer address.
  647. + * @doorbell_addr_lower: Lower 32 bits of the doorbell buffer address.
  648. + * @doorbell_addr_upper: Upper 32 bits of the doorbell buffer address.
  649. + * @feedback_buffer_addr_lower: Lower 32 bits of the feedback buffer addresses.
  650. + * @feedback_buffer_addr_upper: Upper 32 bits of the feedback buffer addresses.
  651. + * @host2me_addr_lower: Lower 32 bits of the host2me buffer address.
  652. + * @host2me_addr_upper: Upper 32 bits of the host2me buffer address.
  653. + * @workqueue_item_size: Magic value. (IPTS_WORKQUEUE_ITEM_SIZE)
  654. + * @workqueue_size: Magic value. (IPTS_WORKQUEUE_SIZE)
  655. + *
  656. + * The data buffers are buffers that get filled with touch data by the ME.
  657. + * The doorbell buffer is a u32 that gets incremented by the ME once a data
  658. + * buffer has been filled with new data.
  659. + *
  660. + * The other buffers are required for using GuC submission with binary
  661. + * firmware. Since support for GuC submission has been dropped from i915,
  662. + * they are not used anymore, but they need to be allocated and passed,
  663. + * otherwise the hardware will refuse to start.
  664. + */
  665. +struct ipts_set_mem_window_cmd {
  666. + u32 data_buffer_addr_lower[IPTS_BUFFERS];
  667. + u32 data_buffer_addr_upper[IPTS_BUFFERS];
  668. + u32 workqueue_addr_lower;
  669. + u32 workqueue_addr_upper;
  670. + u32 doorbell_addr_lower;
  671. + u32 doorbell_addr_upper;
  672. + u32 feedback_buffer_addr_lower[IPTS_BUFFERS];
  673. + u32 feedback_buffer_addr_upper[IPTS_BUFFERS];
  674. + u32 host2me_addr_lower;
  675. + u32 host2me_addr_upper;
  676. + u32 host2me_size;
  677. + u8 reserved1;
  678. + u8 workqueue_item_size;
  679. + u16 workqueue_size;
  680. + u8 reserved[32];
  681. +} __packed;
  682. +
  683. +/**
  684. + * struct ipts_feedback_cmd - Payload for the FEEDBACK command.
  685. + * @buffer: The buffer that the ME should refill.
  686. + */
  687. +struct ipts_feedback_cmd {
  688. + u32 buffer;
  689. + u8 reserved[12];
  690. +} __packed;
  691. +
  692. +/**
  693. + * enum ipts_feedback_cmd_type - Commands that can be executed on the sensor through feedback.
  694. + */
  695. +enum ipts_feedback_cmd_type {
  696. + IPTS_FEEDBACK_CMD_TYPE_NONE = 0,
  697. + IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET = 1,
  698. + IPTS_FEEDBACK_CMD_TYPE_GOTO_ARMED = 2,
  699. + IPTS_FEEDBACK_CMD_TYPE_GOTO_SENSING = 3,
  700. + IPTS_FEEDBACK_CMD_TYPE_GOTO_SLEEP = 4,
  701. + IPTS_FEEDBACK_CMD_TYPE_GOTO_DOZE = 5,
  702. + IPTS_FEEDBACK_CMD_TYPE_HARD_RESET = 6,
  703. +};
  704. +
  705. +/**
  706. + * enum ipts_feedback_data_type - Describes the data that a feedback buffer contains.
  707. + * @IPTS_FEEDBACK_DATA_TYPE_VENDOR: The buffer contains vendor specific feedback.
  708. + * @IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES: The buffer contains a HID set features command.
  709. + * @IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES: The buffer contains a HID get features command.
  710. + * @IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT: The buffer contains a HID output report.
  711. + * @IPTS_FEEDBACK_DATA_TYPE_STORE_DATA: The buffer contains calibration data for the sensor.
  712. + */
  713. +enum ipts_feedback_data_type {
  714. + IPTS_FEEDBACK_DATA_TYPE_VENDOR = 0,
  715. + IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES = 1,
  716. + IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES = 2,
  717. + IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT = 3,
  718. + IPTS_FEEDBACK_DATA_TYPE_STORE_DATA = 4,
  719. +};
  720. +
  721. +/**
  722. + * struct ipts_feedback_buffer - The contents of an IPTS feedback buffer.
  723. + * @cmd_type: A command that should be executed on the sensor.
  724. + * @size: The size of the payload to be written.
  725. + * @buffer: The ID of the buffer that contains this feedback data.
  726. + * @protocol: The protocol version of the EDS.
  727. + * @data_type: The type of payload that the buffer contains.
  728. + * @spi_offset: The offset at which to write the payload data.
  729. + * @payload: Payload for the feedback command, or 0 if no payload is sent.
  730. + */
  731. +struct ipts_feedback_buffer {
  732. + enum ipts_feedback_cmd_type cmd_type;
  733. + u32 size;
  734. + u32 buffer;
  735. + u32 protocol;
  736. + enum ipts_feedback_data_type data_type;
  737. + u32 spi_offset;
  738. + u8 reserved[40];
  739. + u8 payload[];
  740. +} __packed;
  741. +
  742. +/**
  743. + * enum ipts_reset_type - Possible ways of resetting the touch sensor
  744. + * @IPTS_RESET_TYPE_HARD: Perform hardware reset using GPIO pin.
  745. + * @IPTS_RESET_TYPE_SOFT: Perform software reset using SPI interface.
  746. + */
  747. +enum ipts_reset_type {
  748. + IPTS_RESET_TYPE_HARD = 0,
  749. + IPTS_RESET_TYPE_SOFT = 1,
  750. +};
  751. +
  752. +/**
  753. + * struct ipts_reset_sensor_cmd - Payload for the RESET_SENSOR command.
  754. + * @type: What type of reset should be performed.
  755. + */
  756. +struct ipts_reset_sensor_cmd {
  757. + enum ipts_reset_type type;
  758. + u8 reserved[4];
  759. +} __packed;
  760. +
  761. +/**
  762. + * struct ipts_command - A message sent from the host to the ME.
  763. + * @code: The message code describing the command. (see IPTS_CMD_*)
  764. + * @payload: Payload for the command, or 0 if no payload is required.
  765. + */
  766. +struct ipts_command {
  767. + u32 code;
  768. + u8 payload[320];
  769. +} __packed;
  770. +
  771. +/**
  772. + * struct ipts_device_info - Payload for the GET_DEVICE_INFO response.
  773. + * @vendor_id: Vendor ID of the touch sensor.
  774. + * @device_id: Device ID of the touch sensor.
  775. + * @hw_rev: Hardware revision of the touch sensor.
  776. + * @fw_rev: Firmware revision of the touch sensor.
  777. + * @data_size: Required size of one data buffer.
  778. + * @feedback_size: Required size of one feedback buffer.
  779. + * @mode: Current operation mode of IPTS.
  780. + * @max_contacts: The amount of concurrent touches supported by the sensor.
  781. + */
  782. +struct ipts_get_device_info_rsp {
  783. + u16 vendor_id;
  784. + u16 device_id;
  785. + u32 hw_rev;
  786. + u32 fw_rev;
  787. + u32 data_size;
  788. + u32 feedback_size;
  789. + enum ipts_mode mode;
  790. + u8 max_contacts;
  791. + u8 reserved[19];
  792. +} __packed;
  793. +
  794. +/**
  795. + * struct ipts_feedback_rsp - Payload for the FEEDBACK response.
  796. + * @buffer: The buffer that has received feedback.
  797. + */
  798. +struct ipts_feedback_rsp {
  799. + u32 buffer;
  800. +} __packed;
  801. +
  802. +/**
  803. + * struct ipts_response - A message sent from the ME to the host.
  804. + * @code: The message code describing the response. (see IPTS_RSP_*)
  805. + * @status: The status code returned by the command.
  806. + * @payload: Payload returned by the command.
  807. + */
  808. +struct ipts_response {
  809. + u32 code;
  810. + enum ipts_status status;
  811. + u8 payload[80];
  812. +} __packed;
  813. +
  814. +#endif /* _IPTS_PROTOCOL_H_ */
  815. diff --git a/drivers/misc/ipts/receiver.c b/drivers/misc/ipts/receiver.c
  816. new file mode 100644
  817. index 000000000000..23dca13c2139
  818. --- /dev/null
  819. +++ b/drivers/misc/ipts/receiver.c
  820. @@ -0,0 +1,224 @@
  821. +// SPDX-License-Identifier: GPL-2.0-or-later
  822. +/*
  823. + * Copyright (c) 2016 Intel Corporation
  824. + * Copyright (c) 2020 Dorian Stoll
  825. + *
  826. + * Linux driver for Intel Precise Touch & Stylus
  827. + */
  828. +
  829. +#include <linux/mei_cl_bus.h>
  830. +#include <linux/moduleparam.h>
  831. +#include <linux/types.h>
  832. +
  833. +#include "context.h"
  834. +#include "control.h"
  835. +#include "protocol.h"
  836. +#include "resources.h"
  837. +
  838. +/*
  839. + * Temporary parameter to guard gen7 multitouch mode.
  840. + * Remove once gen7 has stable iptsd support.
  841. + */
  842. +static bool gen7mt;
  843. +module_param(gen7mt, bool, 0644);
  844. +
  845. +static int ipts_receiver_handle_get_device_info(struct ipts_context *ipts,
  846. + struct ipts_response *rsp)
  847. +{
  848. + struct ipts_set_mode_cmd cmd;
  849. +
  850. + memcpy(&ipts->device_info, rsp->payload,
  851. + sizeof(struct ipts_get_device_info_rsp));
  852. +
  853. + memset(&cmd, 0, sizeof(struct ipts_set_mode_cmd));
  854. + cmd.mode = IPTS_MODE_MULTITOUCH;
  855. +
  856. + return ipts_control_send(ipts, IPTS_CMD_SET_MODE, &cmd,
  857. + sizeof(struct ipts_set_mode_cmd));
  858. +}
  859. +
  860. +static int ipts_receiver_handle_set_mode(struct ipts_context *ipts)
  861. +{
  862. + int i, ret;
  863. + struct ipts_set_mem_window_cmd cmd;
  864. +
  865. + ret = ipts_resources_alloc(ipts);
  866. + if (ret) {
  867. + dev_err(ipts->dev, "Failed to allocate resources\n");
  868. + return ret;
  869. + }
  870. +
  871. + memset(&cmd, 0, sizeof(struct ipts_set_mem_window_cmd));
  872. +
  873. + for (i = 0; i < IPTS_BUFFERS; i++) {
  874. + cmd.data_buffer_addr_lower[i] =
  875. + lower_32_bits(ipts->data[i].dma_address);
  876. +
  877. + cmd.data_buffer_addr_upper[i] =
  878. + upper_32_bits(ipts->data[i].dma_address);
  879. +
  880. + cmd.feedback_buffer_addr_lower[i] =
  881. + lower_32_bits(ipts->feedback[i].dma_address);
  882. +
  883. + cmd.feedback_buffer_addr_upper[i] =
  884. + upper_32_bits(ipts->feedback[i].dma_address);
  885. + }
  886. +
  887. + cmd.workqueue_addr_lower = lower_32_bits(ipts->workqueue.dma_address);
  888. + cmd.workqueue_addr_upper = upper_32_bits(ipts->workqueue.dma_address);
  889. +
  890. + cmd.doorbell_addr_lower = lower_32_bits(ipts->doorbell.dma_address);
  891. + cmd.doorbell_addr_upper = upper_32_bits(ipts->doorbell.dma_address);
  892. +
  893. + cmd.host2me_addr_lower = lower_32_bits(ipts->host2me.dma_address);
  894. + cmd.host2me_addr_upper = upper_32_bits(ipts->host2me.dma_address);
  895. +
  896. + cmd.workqueue_size = IPTS_WORKQUEUE_SIZE;
  897. + cmd.workqueue_item_size = IPTS_WORKQUEUE_ITEM_SIZE;
  898. +
  899. + return ipts_control_send(ipts, IPTS_CMD_SET_MEM_WINDOW, &cmd,
  900. + sizeof(struct ipts_set_mem_window_cmd));
  901. +}
  902. +
  903. +static int ipts_receiver_handle_set_mem_window(struct ipts_context *ipts)
  904. +{
  905. + int ret;
  906. +
  907. + dev_info(ipts->dev, "Device %04hX:%04hX ready\n",
  908. + ipts->device_info.vendor_id, ipts->device_info.device_id);
  909. + ipts->status = IPTS_HOST_STATUS_STARTED;
  910. +
  911. + ret = ipts_control_send(ipts, IPTS_CMD_READY_FOR_DATA, NULL, 0);
  912. + if (ret)
  913. + return ret;
  914. +
  915. + if (!gen7mt)
  916. + return 0;
  917. +
  918. + return ipts_control_set_feature(ipts, 0x5, 0x1);
  919. +}
  920. +
  921. +static int ipts_receiver_handle_feedback(struct ipts_context *ipts,
  922. + struct ipts_response *rsp)
  923. +{
  924. + struct ipts_feedback_rsp feedback;
  925. +
  926. + if (ipts->status != IPTS_HOST_STATUS_STOPPING)
  927. + return 0;
  928. +
  929. + memcpy(&feedback, rsp->payload, sizeof(feedback));
  930. +
  931. + if (feedback.buffer < IPTS_BUFFERS - 1)
  932. + return ipts_control_send_feedback(ipts, feedback.buffer + 1);
  933. +
  934. + return ipts_control_send(ipts, IPTS_CMD_CLEAR_MEM_WINDOW, NULL, 0);
  935. +}
  936. +
  937. +static int ipts_receiver_handle_clear_mem_window(struct ipts_context *ipts)
  938. +{
  939. + ipts->status = IPTS_HOST_STATUS_STOPPED;
  940. +
  941. + if (ipts->restart)
  942. + return ipts_control_start(ipts);
  943. +
  944. + return 0;
  945. +}
  946. +
  947. +static bool ipts_receiver_sensor_was_reset(u32 status)
  948. +{
  949. + return status == IPTS_STATUS_SENSOR_EXPECTED_RESET ||
  950. + status == IPTS_STATUS_SENSOR_UNEXPECTED_RESET;
  951. +}
  952. +
  953. +static bool ipts_receiver_handle_error(struct ipts_context *ipts,
  954. + struct ipts_response *rsp)
  955. +{
  956. + bool error;
  957. +
  958. + switch (rsp->status) {
  959. + case IPTS_STATUS_SUCCESS:
  960. + case IPTS_STATUS_COMPAT_CHECK_FAIL:
  961. + error = false;
  962. + break;
  963. + case IPTS_STATUS_INVALID_PARAMS:
  964. + error = rsp->code != IPTS_RSP_FEEDBACK;
  965. + break;
  966. + case IPTS_STATUS_SENSOR_DISABLED:
  967. + error = ipts->status != IPTS_HOST_STATUS_STOPPING;
  968. + break;
  969. + default:
  970. + error = true;
  971. + break;
  972. + }
  973. +
  974. + if (!error)
  975. + return false;
  976. +
  977. + dev_err(ipts->dev, "Command 0x%08x failed: %d\n", rsp->code,
  978. + rsp->status);
  979. +
  980. + if (ipts_receiver_sensor_was_reset(rsp->status)) {
  981. + dev_err(ipts->dev, "Sensor was reset\n");
  982. +
  983. + if (ipts_control_restart(ipts))
  984. + dev_err(ipts->dev, "Failed to restart IPTS\n");
  985. + }
  986. +
  987. + return true;
  988. +}
  989. +
  990. +static void ipts_receiver_handle_response(struct ipts_context *ipts,
  991. + struct ipts_response *rsp)
  992. +{
  993. + int ret;
  994. +
  995. + if (ipts_receiver_handle_error(ipts, rsp))
  996. + return;
  997. +
  998. + switch (rsp->code) {
  999. + case IPTS_RSP_GET_DEVICE_INFO:
  1000. + ret = ipts_receiver_handle_get_device_info(ipts, rsp);
  1001. + break;
  1002. + case IPTS_RSP_SET_MODE:
  1003. + ret = ipts_receiver_handle_set_mode(ipts);
  1004. + break;
  1005. + case IPTS_RSP_SET_MEM_WINDOW:
  1006. + ret = ipts_receiver_handle_set_mem_window(ipts);
  1007. + break;
  1008. + case IPTS_RSP_FEEDBACK:
  1009. + ret = ipts_receiver_handle_feedback(ipts, rsp);
  1010. + break;
  1011. + case IPTS_RSP_CLEAR_MEM_WINDOW:
  1012. + ret = ipts_receiver_handle_clear_mem_window(ipts);
  1013. + break;
  1014. + default:
  1015. + ret = 0;
  1016. + break;
  1017. + }
  1018. +
  1019. + if (!ret)
  1020. + return;
  1021. +
  1022. + dev_err(ipts->dev, "Error while handling response 0x%08x: %d\n",
  1023. + rsp->code, ret);
  1024. +
  1025. + if (ipts_control_stop(ipts))
  1026. + dev_err(ipts->dev, "Failed to stop IPTS\n");
  1027. +}
  1028. +
  1029. +void ipts_receiver_callback(struct mei_cl_device *cldev)
  1030. +{
  1031. + int ret;
  1032. + struct ipts_response rsp;
  1033. + struct ipts_context *ipts;
  1034. +
  1035. + ipts = mei_cldev_get_drvdata(cldev);
  1036. +
  1037. + ret = mei_cldev_recv(cldev, (u8 *)&rsp, sizeof(struct ipts_response));
  1038. + if (ret <= 0) {
  1039. + dev_err(ipts->dev, "Error while reading response: %d\n", ret);
  1040. + return;
  1041. + }
  1042. +
  1043. + ipts_receiver_handle_response(ipts, &rsp);
  1044. +}
  1045. diff --git a/drivers/misc/ipts/receiver.h b/drivers/misc/ipts/receiver.h
  1046. new file mode 100644
  1047. index 000000000000..7f075afa7ef8
  1048. --- /dev/null
  1049. +++ b/drivers/misc/ipts/receiver.h
  1050. @@ -0,0 +1,16 @@
  1051. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1052. +/*
  1053. + * Copyright (c) 2016 Intel Corporation
  1054. + * Copyright (c) 2020 Dorian Stoll
  1055. + *
  1056. + * Linux driver for Intel Precise Touch & Stylus
  1057. + */
  1058. +
  1059. +#ifndef _IPTS_RECEIVER_H_
  1060. +#define _IPTS_RECEIVER_H_
  1061. +
  1062. +#include <linux/mei_cl_bus.h>
  1063. +
  1064. +void ipts_receiver_callback(struct mei_cl_device *cldev);
  1065. +
  1066. +#endif /* _IPTS_RECEIVER_H_ */
  1067. diff --git a/drivers/misc/ipts/resources.c b/drivers/misc/ipts/resources.c
  1068. new file mode 100644
  1069. index 000000000000..8e3a2409e438
  1070. --- /dev/null
  1071. +++ b/drivers/misc/ipts/resources.c
  1072. @@ -0,0 +1,128 @@
  1073. +// SPDX-License-Identifier: GPL-2.0-or-later
  1074. +/*
  1075. + * Copyright (c) 2016 Intel Corporation
  1076. + * Copyright (c) 2020 Dorian Stoll
  1077. + *
  1078. + * Linux driver for Intel Precise Touch & Stylus
  1079. + */
  1080. +
  1081. +#include <linux/dma-mapping.h>
  1082. +
  1083. +#include "context.h"
  1084. +
  1085. +void ipts_resources_free(struct ipts_context *ipts)
  1086. +{
  1087. + int i;
  1088. + struct ipts_buffer_info *buffers;
  1089. +
  1090. + u32 data_buffer_size = ipts->device_info.data_size;
  1091. + u32 feedback_buffer_size = ipts->device_info.feedback_size;
  1092. +
  1093. + buffers = ipts->data;
  1094. + for (i = 0; i < IPTS_BUFFERS; i++) {
  1095. + if (!buffers[i].address)
  1096. + continue;
  1097. +
  1098. + dma_free_coherent(ipts->dev, data_buffer_size,
  1099. + buffers[i].address, buffers[i].dma_address);
  1100. +
  1101. + buffers[i].address = NULL;
  1102. + buffers[i].dma_address = 0;
  1103. + }
  1104. +
  1105. + buffers = ipts->feedback;
  1106. + for (i = 0; i < IPTS_BUFFERS; i++) {
  1107. + if (!buffers[i].address)
  1108. + continue;
  1109. +
  1110. + dma_free_coherent(ipts->dev, feedback_buffer_size,
  1111. + buffers[i].address, buffers[i].dma_address);
  1112. +
  1113. + buffers[i].address = NULL;
  1114. + buffers[i].dma_address = 0;
  1115. + }
  1116. +
  1117. + if (ipts->doorbell.address) {
  1118. + dma_free_coherent(ipts->dev, sizeof(u32),
  1119. + ipts->doorbell.address,
  1120. + ipts->doorbell.dma_address);
  1121. +
  1122. + ipts->doorbell.address = NULL;
  1123. + ipts->doorbell.dma_address = 0;
  1124. + }
  1125. +
  1126. + if (ipts->workqueue.address) {
  1127. + dma_free_coherent(ipts->dev, sizeof(u32),
  1128. + ipts->workqueue.address,
  1129. + ipts->workqueue.dma_address);
  1130. +
  1131. + ipts->workqueue.address = NULL;
  1132. + ipts->workqueue.dma_address = 0;
  1133. + }
  1134. +
  1135. + if (ipts->host2me.address) {
  1136. + dma_free_coherent(ipts->dev, feedback_buffer_size,
  1137. + ipts->host2me.address,
  1138. + ipts->host2me.dma_address);
  1139. +
  1140. + ipts->host2me.address = NULL;
  1141. + ipts->host2me.dma_address = 0;
  1142. + }
  1143. +}
  1144. +
  1145. +int ipts_resources_alloc(struct ipts_context *ipts)
  1146. +{
  1147. + int i;
  1148. + struct ipts_buffer_info *buffers;
  1149. +
  1150. + u32 data_buffer_size = ipts->device_info.data_size;
  1151. + u32 feedback_buffer_size = ipts->device_info.feedback_size;
  1152. +
  1153. + buffers = ipts->data;
  1154. + for (i = 0; i < IPTS_BUFFERS; i++) {
  1155. + buffers[i].address =
  1156. + dma_alloc_coherent(ipts->dev, data_buffer_size,
  1157. + &buffers[i].dma_address, GFP_KERNEL);
  1158. +
  1159. + if (!buffers[i].address)
  1160. + goto release_resources;
  1161. + }
  1162. +
  1163. + buffers = ipts->feedback;
  1164. + for (i = 0; i < IPTS_BUFFERS; i++) {
  1165. + buffers[i].address =
  1166. + dma_alloc_coherent(ipts->dev, feedback_buffer_size,
  1167. + &buffers[i].dma_address, GFP_KERNEL);
  1168. +
  1169. + if (!buffers[i].address)
  1170. + goto release_resources;
  1171. + }
  1172. +
  1173. + ipts->doorbell.address =
  1174. + dma_alloc_coherent(ipts->dev, sizeof(u32),
  1175. + &ipts->doorbell.dma_address, GFP_KERNEL);
  1176. +
  1177. + if (!ipts->doorbell.address)
  1178. + goto release_resources;
  1179. +
  1180. + ipts->workqueue.address =
  1181. + dma_alloc_coherent(ipts->dev, sizeof(u32),
  1182. + &ipts->workqueue.dma_address, GFP_KERNEL);
  1183. +
  1184. + if (!ipts->workqueue.address)
  1185. + goto release_resources;
  1186. +
  1187. + ipts->host2me.address =
  1188. + dma_alloc_coherent(ipts->dev, feedback_buffer_size,
  1189. + &ipts->host2me.dma_address, GFP_KERNEL);
  1190. +
  1191. + if (!ipts->workqueue.address)
  1192. + goto release_resources;
  1193. +
  1194. + return 0;
  1195. +
  1196. +release_resources:
  1197. +
  1198. + ipts_resources_free(ipts);
  1199. + return -ENOMEM;
  1200. +}
  1201. diff --git a/drivers/misc/ipts/resources.h b/drivers/misc/ipts/resources.h
  1202. new file mode 100644
  1203. index 000000000000..fdac0eee9156
  1204. --- /dev/null
  1205. +++ b/drivers/misc/ipts/resources.h
  1206. @@ -0,0 +1,17 @@
  1207. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1208. +/*
  1209. + * Copyright (c) 2016 Intel Corporation
  1210. + * Copyright (c) 2020 Dorian Stoll
  1211. + *
  1212. + * Linux driver for Intel Precise Touch & Stylus
  1213. + */
  1214. +
  1215. +#ifndef _IPTS_RESOURCES_H_
  1216. +#define _IPTS_RESOURCES_H_
  1217. +
  1218. +#include "context.h"
  1219. +
  1220. +int ipts_resources_alloc(struct ipts_context *ipts);
  1221. +void ipts_resources_free(struct ipts_context *ipts);
  1222. +
  1223. +#endif /* _IPTS_RESOURCES_H_ */
  1224. diff --git a/drivers/misc/ipts/uapi.c b/drivers/misc/ipts/uapi.c
  1225. new file mode 100644
  1226. index 000000000000..598f0710ad64
  1227. --- /dev/null
  1228. +++ b/drivers/misc/ipts/uapi.c
  1229. @@ -0,0 +1,208 @@
  1230. +// SPDX-License-Identifier: GPL-2.0-or-later
  1231. +/*
  1232. + * Copyright (c) 2016 Intel Corporation
  1233. + * Copyright (c) 2020 Dorian Stoll
  1234. + *
  1235. + * Linux driver for Intel Precise Touch & Stylus
  1236. + */
  1237. +
  1238. +#include <linux/cdev.h>
  1239. +#include <linux/delay.h>
  1240. +#include <linux/device.h>
  1241. +#include <linux/fs.h>
  1242. +#include <linux/types.h>
  1243. +#include <linux/uaccess.h>
  1244. +
  1245. +#include "context.h"
  1246. +#include "control.h"
  1247. +#include "protocol.h"
  1248. +#include "uapi.h"
  1249. +
  1250. +struct ipts_uapi uapi;
  1251. +
  1252. +static ssize_t ipts_uapi_read(struct file *file, char __user *buf, size_t count,
  1253. + loff_t *offset)
  1254. +{
  1255. + int buffer;
  1256. + int maxbytes;
  1257. + struct ipts_context *ipts = uapi.ipts;
  1258. +
  1259. + buffer = MINOR(file->f_path.dentry->d_inode->i_rdev);
  1260. +
  1261. + if (!ipts || ipts->status != IPTS_HOST_STATUS_STARTED)
  1262. + return -ENODEV;
  1263. +
  1264. + maxbytes = ipts->device_info.data_size - *offset;
  1265. + if (maxbytes <= 0 || count > maxbytes)
  1266. + return -EINVAL;
  1267. +
  1268. + if (copy_to_user(buf, ipts->data[buffer].address + *offset, count))
  1269. + return -EFAULT;
  1270. +
  1271. + return count;
  1272. +}
  1273. +
  1274. +static long ipts_uapi_ioctl_get_device_ready(struct ipts_context *ipts,
  1275. + unsigned long arg)
  1276. +{
  1277. + void __user *buffer = (void __user *)arg;
  1278. + u8 ready = 0;
  1279. +
  1280. + if (ipts)
  1281. + ready = ipts->status == IPTS_HOST_STATUS_STARTED;
  1282. +
  1283. + if (copy_to_user(buffer, &ready, sizeof(u8)))
  1284. + return -EFAULT;
  1285. +
  1286. + return 0;
  1287. +}
  1288. +
  1289. +static long ipts_uapi_ioctl_get_device_info(struct ipts_context *ipts,
  1290. + unsigned long arg)
  1291. +{
  1292. + struct ipts_device_info info;
  1293. + void __user *buffer = (void __user *)arg;
  1294. +
  1295. + if (!ipts || ipts->status != IPTS_HOST_STATUS_STARTED)
  1296. + return -ENODEV;
  1297. +
  1298. + info.vendor = ipts->device_info.vendor_id;
  1299. + info.product = ipts->device_info.device_id;
  1300. + info.version = ipts->device_info.fw_rev;
  1301. + info.buffer_size = ipts->device_info.data_size;
  1302. + info.max_contacts = ipts->device_info.max_contacts;
  1303. +
  1304. + if (copy_to_user(buffer, &info, sizeof(struct ipts_device_info)))
  1305. + return -EFAULT;
  1306. +
  1307. + return 0;
  1308. +}
  1309. +
  1310. +static long ipts_uapi_ioctl_get_doorbell(struct ipts_context *ipts,
  1311. + unsigned long arg)
  1312. +{
  1313. + void __user *buffer = (void __user *)arg;
  1314. +
  1315. + if (!ipts || ipts->status != IPTS_HOST_STATUS_STARTED)
  1316. + return -ENODEV;
  1317. +
  1318. + if (copy_to_user(buffer, ipts->doorbell.address, sizeof(u32)))
  1319. + return -EFAULT;
  1320. +
  1321. + return 0;
  1322. +}
  1323. +
  1324. +static long ipts_uapi_ioctl_send_feedback(struct ipts_context *ipts,
  1325. + struct file *file)
  1326. +{
  1327. + int ret;
  1328. + u32 buffer;
  1329. +
  1330. + if (!ipts || ipts->status != IPTS_HOST_STATUS_STARTED)
  1331. + return -ENODEV;
  1332. +
  1333. + buffer = MINOR(file->f_path.dentry->d_inode->i_rdev);
  1334. +
  1335. + ret = ipts_control_send_feedback(ipts, buffer);
  1336. + if (ret)
  1337. + return -EFAULT;
  1338. +
  1339. + return 0;
  1340. +}
  1341. +
  1342. +static long ipts_uapi_ioctl_send_reset(struct ipts_context *ipts)
  1343. +{
  1344. + int ret;
  1345. + struct ipts_reset_sensor_cmd cmd;
  1346. +
  1347. + if (!ipts || ipts->status != IPTS_HOST_STATUS_STARTED)
  1348. + return -ENODEV;
  1349. +
  1350. + memset(&cmd, 0, sizeof(struct ipts_reset_sensor_cmd));
  1351. + cmd.type = IPTS_RESET_TYPE_SOFT;
  1352. +
  1353. + ret = ipts_control_send(ipts, IPTS_CMD_RESET_SENSOR, &cmd,
  1354. + sizeof(struct ipts_reset_sensor_cmd));
  1355. +
  1356. + if (ret)
  1357. + return -EFAULT;
  1358. +
  1359. + return 0;
  1360. +}
  1361. +
  1362. +static long ipts_uapi_ioctl(struct file *file, unsigned int cmd,
  1363. + unsigned long arg)
  1364. +{
  1365. + struct ipts_context *ipts = uapi.ipts;
  1366. +
  1367. + switch (cmd) {
  1368. + case IPTS_IOCTL_GET_DEVICE_READY:
  1369. + return ipts_uapi_ioctl_get_device_ready(ipts, arg);
  1370. + case IPTS_IOCTL_GET_DEVICE_INFO:
  1371. + return ipts_uapi_ioctl_get_device_info(ipts, arg);
  1372. + case IPTS_IOCTL_GET_DOORBELL:
  1373. + return ipts_uapi_ioctl_get_doorbell(ipts, arg);
  1374. + case IPTS_IOCTL_SEND_FEEDBACK:
  1375. + return ipts_uapi_ioctl_send_feedback(ipts, file);
  1376. + case IPTS_IOCTL_SEND_RESET:
  1377. + return ipts_uapi_ioctl_send_reset(ipts);
  1378. + default:
  1379. + return -ENOTTY;
  1380. + }
  1381. +}
  1382. +
  1383. +static const struct file_operations ipts_uapi_fops = {
  1384. + .owner = THIS_MODULE,
  1385. + .read = ipts_uapi_read,
  1386. + .unlocked_ioctl = ipts_uapi_ioctl,
  1387. +#ifdef CONFIG_COMPAT
  1388. + .compat_ioctl = ipts_uapi_ioctl,
  1389. +#endif
  1390. +};
  1391. +
  1392. +void ipts_uapi_link(struct ipts_context *ipts)
  1393. +{
  1394. + uapi.ipts = ipts;
  1395. +}
  1396. +
  1397. +void ipts_uapi_unlink(void)
  1398. +{
  1399. + uapi.ipts = NULL;
  1400. +}
  1401. +
  1402. +int ipts_uapi_init(void)
  1403. +{
  1404. + int i, major;
  1405. +
  1406. + alloc_chrdev_region(&uapi.dev, 0, IPTS_BUFFERS, "ipts");
  1407. + uapi.class = class_create(THIS_MODULE, "ipts");
  1408. +
  1409. + major = MAJOR(uapi.dev);
  1410. +
  1411. + cdev_init(&uapi.cdev, &ipts_uapi_fops);
  1412. + uapi.cdev.owner = THIS_MODULE;
  1413. + cdev_add(&uapi.cdev, MKDEV(major, 0), IPTS_BUFFERS);
  1414. +
  1415. + for (i = 0; i < IPTS_BUFFERS; i++) {
  1416. + device_create(uapi.class, NULL, MKDEV(major, i), NULL,
  1417. + "ipts/%d", i);
  1418. + }
  1419. +
  1420. + return 0;
  1421. +}
  1422. +
  1423. +void ipts_uapi_free(void)
  1424. +{
  1425. + int i;
  1426. + int major;
  1427. +
  1428. + major = MAJOR(uapi.dev);
  1429. +
  1430. + for (i = 0; i < IPTS_BUFFERS; i++)
  1431. + device_destroy(uapi.class, MKDEV(major, i));
  1432. +
  1433. + cdev_del(&uapi.cdev);
  1434. +
  1435. + unregister_chrdev_region(MKDEV(major, 0), MINORMASK);
  1436. + class_destroy(uapi.class);
  1437. +}
  1438. diff --git a/drivers/misc/ipts/uapi.h b/drivers/misc/ipts/uapi.h
  1439. new file mode 100644
  1440. index 000000000000..53fb86a88f97
  1441. --- /dev/null
  1442. +++ b/drivers/misc/ipts/uapi.h
  1443. @@ -0,0 +1,47 @@
  1444. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1445. +/*
  1446. + * Copyright (c) 2016 Intel Corporation
  1447. + * Copyright (c) 2020 Dorian Stoll
  1448. + *
  1449. + * Linux driver for Intel Precise Touch & Stylus
  1450. + */
  1451. +
  1452. +#ifndef _IPTS_UAPI_H_
  1453. +#define _IPTS_UAPI_H_
  1454. +
  1455. +#include <linux/types.h>
  1456. +
  1457. +#include "context.h"
  1458. +
  1459. +struct ipts_uapi {
  1460. + dev_t dev;
  1461. + struct class *class;
  1462. + struct cdev cdev;
  1463. +
  1464. + struct ipts_context *ipts;
  1465. +};
  1466. +
  1467. +struct ipts_device_info {
  1468. + __u16 vendor;
  1469. + __u16 product;
  1470. + __u32 version;
  1471. + __u32 buffer_size;
  1472. + __u8 max_contacts;
  1473. +
  1474. + /* For future expansion */
  1475. + __u8 reserved[19];
  1476. +};
  1477. +
  1478. +#define IPTS_IOCTL_GET_DEVICE_READY _IOR(0x86, 0x01, __u8)
  1479. +#define IPTS_IOCTL_GET_DEVICE_INFO _IOR(0x86, 0x02, struct ipts_device_info)
  1480. +#define IPTS_IOCTL_GET_DOORBELL _IOR(0x86, 0x03, __u32)
  1481. +#define IPTS_IOCTL_SEND_FEEDBACK _IO(0x86, 0x04)
  1482. +#define IPTS_IOCTL_SEND_RESET _IO(0x86, 0x05)
  1483. +
  1484. +void ipts_uapi_link(struct ipts_context *ipts);
  1485. +void ipts_uapi_unlink(void);
  1486. +
  1487. +int ipts_uapi_init(void);
  1488. +void ipts_uapi_free(void);
  1489. +
  1490. +#endif /* _IPTS_UAPI_H_ */
  1491. --
  1492. 2.34.0