0004-ipts.patch 42 KB

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