0003-ipts.patch 36 KB

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