-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
misc: Add support for Intel Precise Touch & Stylus
Based on linux-surface/intel-precise-touch@3f362c Signed-off-by: Dorian Stoll <[email protected]> Patchset: ipts
- Loading branch information
Showing
15 changed files
with
1,328 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
config MISC_IPTS | ||
tristate "Intel Precise Touch & Stylus" | ||
depends on INTEL_MEI | ||
help | ||
Say Y here if your system has a touchscreen using Intels | ||
Precise Touch & Stylus (IPTS) technology. | ||
|
||
If unsure say N. | ||
|
||
To compile this driver as a module, choose M here: the | ||
module will be called ipts. | ||
|
||
Building this driver alone will not give you a working touchscreen. | ||
It only exposed a userspace API that can be used by a daemon to | ||
receive and process data from the touchscreen hardware. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# SPDX-License-Identifier: GPL-2.0-or-later | ||
# | ||
# Makefile for the IPTS touchscreen driver | ||
# | ||
|
||
obj-$(CONFIG_MISC_IPTS) += ipts.o | ||
ipts-objs := control.o | ||
ipts-objs += mei.o | ||
ipts-objs += receiver.o | ||
ipts-objs += resources.o | ||
ipts-objs += uapi.o | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
/* | ||
* Copyright (c) 2016 Intel Corporation | ||
* Copyright (c) 2020 Dorian Stoll | ||
* | ||
* Linux driver for Intel Precise Touch & Stylus | ||
*/ | ||
|
||
#ifndef _IPTS_CONTEXT_H_ | ||
#define _IPTS_CONTEXT_H_ | ||
|
||
#include <linux/cdev.h> | ||
#include <linux/device.h> | ||
#include <linux/mei_cl_bus.h> | ||
#include <linux/types.h> | ||
|
||
#include "protocol.h" | ||
|
||
enum ipts_host_status { | ||
IPTS_HOST_STATUS_STARTING, | ||
IPTS_HOST_STATUS_STARTED, | ||
IPTS_HOST_STATUS_STOPPING, | ||
IPTS_HOST_STATUS_STOPPED, | ||
}; | ||
|
||
struct ipts_buffer_info { | ||
u8 *address; | ||
dma_addr_t dma_address; | ||
}; | ||
|
||
struct ipts_context { | ||
struct mei_cl_device *cldev; | ||
struct device *dev; | ||
|
||
bool restart; | ||
enum ipts_host_status status; | ||
struct ipts_get_device_info_rsp device_info; | ||
|
||
struct ipts_buffer_info data[IPTS_BUFFERS]; | ||
struct ipts_buffer_info doorbell; | ||
|
||
struct ipts_buffer_info feedback[IPTS_BUFFERS]; | ||
struct ipts_buffer_info workqueue; | ||
struct ipts_buffer_info host2me; | ||
}; | ||
|
||
#endif /* _IPTS_CONTEXT_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Copyright (c) 2016 Intel Corporation | ||
* Copyright (c) 2020 Dorian Stoll | ||
* | ||
* Linux driver for Intel Precise Touch & Stylus | ||
*/ | ||
|
||
#include <linux/mei_cl_bus.h> | ||
|
||
#include "context.h" | ||
#include "protocol.h" | ||
#include "resources.h" | ||
#include "uapi.h" | ||
|
||
int ipts_control_send(struct ipts_context *ipts, u32 code, void *payload, | ||
size_t size) | ||
{ | ||
int ret; | ||
struct ipts_command cmd; | ||
|
||
memset(&cmd, 0, sizeof(struct ipts_command)); | ||
cmd.code = code; | ||
|
||
if (payload && size > 0) | ||
memcpy(&cmd.payload, payload, size); | ||
|
||
ret = mei_cldev_send(ipts->cldev, (u8 *)&cmd, sizeof(cmd.code) + size); | ||
if (ret >= 0) | ||
return 0; | ||
|
||
/* | ||
* During shutdown the device might get pulled away from below our feet. | ||
* Dont log an error in this case, because it will confuse people. | ||
*/ | ||
if (ret != -ENODEV || ipts->status != IPTS_HOST_STATUS_STOPPING) | ||
dev_err(ipts->dev, "Error while sending: 0x%X:%d\n", code, ret); | ||
|
||
return ret; | ||
} | ||
|
||
int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer) | ||
{ | ||
struct ipts_feedback_cmd cmd; | ||
|
||
memset(&cmd, 0, sizeof(struct ipts_feedback_cmd)); | ||
cmd.buffer = buffer; | ||
|
||
return ipts_control_send(ipts, IPTS_CMD_FEEDBACK, &cmd, | ||
sizeof(struct ipts_feedback_cmd)); | ||
} | ||
|
||
int ipts_control_set_feature(struct ipts_context *ipts, u8 report, u8 value) | ||
{ | ||
struct ipts_feedback_buffer *feedback; | ||
|
||
memset(ipts->host2me.address, 0, ipts->device_info.feedback_size); | ||
feedback = (struct ipts_feedback_buffer *)ipts->host2me.address; | ||
|
||
feedback->cmd_type = IPTS_FEEDBACK_CMD_TYPE_NONE; | ||
feedback->data_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; | ||
feedback->buffer = IPTS_HOST2ME_BUFFER; | ||
feedback->size = 2; | ||
feedback->payload[0] = report; | ||
feedback->payload[1] = value; | ||
|
||
return ipts_control_send_feedback(ipts, IPTS_HOST2ME_BUFFER); | ||
} | ||
|
||
int ipts_control_start(struct ipts_context *ipts) | ||
{ | ||
if (ipts->status != IPTS_HOST_STATUS_STOPPED) | ||
return -EBUSY; | ||
|
||
dev_info(ipts->dev, "Starting IPTS\n"); | ||
ipts->status = IPTS_HOST_STATUS_STARTING; | ||
ipts->restart = false; | ||
|
||
ipts_uapi_link(ipts); | ||
return ipts_control_send(ipts, IPTS_CMD_GET_DEVICE_INFO, NULL, 0); | ||
} | ||
|
||
int ipts_control_stop(struct ipts_context *ipts) | ||
{ | ||
int ret; | ||
|
||
if (ipts->status == IPTS_HOST_STATUS_STOPPING) | ||
return -EBUSY; | ||
|
||
if (ipts->status == IPTS_HOST_STATUS_STOPPED) | ||
return -EBUSY; | ||
|
||
dev_info(ipts->dev, "Stopping IPTS\n"); | ||
ipts->status = IPTS_HOST_STATUS_STOPPING; | ||
|
||
ipts_uapi_unlink(); | ||
ipts_resources_free(ipts); | ||
|
||
ret = ipts_control_send_feedback(ipts, 0); | ||
if (ret == -ENODEV) | ||
ipts->status = IPTS_HOST_STATUS_STOPPED; | ||
|
||
return ret; | ||
} | ||
|
||
int ipts_control_restart(struct ipts_context *ipts) | ||
{ | ||
if (ipts->restart) | ||
return -EBUSY; | ||
|
||
ipts->restart = true; | ||
return ipts_control_stop(ipts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
/* | ||
* Copyright (c) 2016 Intel Corporation | ||
* Copyright (c) 2020 Dorian Stoll | ||
* | ||
* Linux driver for Intel Precise Touch & Stylus | ||
*/ | ||
|
||
#ifndef _IPTS_CONTROL_H_ | ||
#define _IPTS_CONTROL_H_ | ||
|
||
#include <linux/types.h> | ||
|
||
#include "context.h" | ||
|
||
int ipts_control_send(struct ipts_context *ipts, u32 cmd, void *payload, | ||
size_t size); | ||
int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); | ||
int ipts_control_set_feature(struct ipts_context *ipts, u8 report, u8 value); | ||
int ipts_control_start(struct ipts_context *ipts); | ||
int ipts_control_restart(struct ipts_context *ipts); | ||
int ipts_control_stop(struct ipts_context *ipts); | ||
|
||
#endif /* _IPTS_CONTROL_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Copyright (c) 2016 Intel Corporation | ||
* Copyright (c) 2020 Dorian Stoll | ||
* | ||
* Linux driver for Intel Precise Touch & Stylus | ||
*/ | ||
|
||
#include <linux/delay.h> | ||
#include <linux/dma-mapping.h> | ||
#include <linux/mei_cl_bus.h> | ||
#include <linux/mod_devicetable.h> | ||
#include <linux/module.h> | ||
#include <linux/slab.h> | ||
|
||
#include "context.h" | ||
#include "control.h" | ||
#include "protocol.h" | ||
#include "receiver.h" | ||
#include "uapi.h" | ||
|
||
static int ipts_mei_set_dma_mask(struct mei_cl_device *cldev) | ||
{ | ||
int ret; | ||
|
||
ret = dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64)); | ||
if (!ret) | ||
return 0; | ||
|
||
return dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(32)); | ||
} | ||
|
||
static int ipts_mei_probe(struct mei_cl_device *cldev, | ||
const struct mei_cl_device_id *id) | ||
{ | ||
int ret; | ||
struct ipts_context *ipts; | ||
|
||
if (ipts_mei_set_dma_mask(cldev)) { | ||
dev_err(&cldev->dev, "Failed to set DMA mask for IPTS\n"); | ||
return -EFAULT; | ||
} | ||
|
||
ret = mei_cldev_enable(cldev); | ||
if (ret) { | ||
dev_err(&cldev->dev, "Failed to enable MEI device: %d\n", ret); | ||
return ret; | ||
} | ||
|
||
ipts = kzalloc(sizeof(*ipts), GFP_KERNEL); | ||
if (!ipts) { | ||
mei_cldev_disable(cldev); | ||
return -ENOMEM; | ||
} | ||
|
||
ipts->cldev = cldev; | ||
ipts->dev = &cldev->dev; | ||
ipts->status = IPTS_HOST_STATUS_STOPPED; | ||
|
||
mei_cldev_set_drvdata(cldev, ipts); | ||
mei_cldev_register_rx_cb(cldev, ipts_receiver_callback); | ||
|
||
return ipts_control_start(ipts); | ||
} | ||
|
||
static void ipts_mei_remove(struct mei_cl_device *cldev) | ||
{ | ||
int i; | ||
struct ipts_context *ipts = mei_cldev_get_drvdata(cldev); | ||
|
||
ipts_control_stop(ipts); | ||
|
||
for (i = 0; i < 20; i++) { | ||
if (ipts->status == IPTS_HOST_STATUS_STOPPED) | ||
break; | ||
|
||
msleep(25); | ||
} | ||
|
||
mei_cldev_disable(cldev); | ||
kfree(ipts); | ||
} | ||
|
||
static struct mei_cl_device_id ipts_mei_device_id_table[] = { | ||
{ "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY }, | ||
{}, | ||
}; | ||
MODULE_DEVICE_TABLE(mei, ipts_mei_device_id_table); | ||
|
||
static struct mei_cl_driver ipts_mei_driver = { | ||
.id_table = ipts_mei_device_id_table, | ||
.name = "ipts", | ||
.probe = ipts_mei_probe, | ||
.remove = ipts_mei_remove, | ||
}; | ||
|
||
static int __init ipts_mei_init(void) | ||
{ | ||
int ret; | ||
|
||
ret = ipts_uapi_init(); | ||
if (ret) | ||
return ret; | ||
|
||
ret = mei_cldev_driver_register(&ipts_mei_driver); | ||
if (ret) { | ||
ipts_uapi_free(); | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static void __exit ipts_mei_exit(void) | ||
{ | ||
mei_cldev_driver_unregister(&ipts_mei_driver); | ||
ipts_uapi_free(); | ||
} | ||
|
||
MODULE_DESCRIPTION("IPTS touchscreen driver"); | ||
MODULE_AUTHOR("Dorian Stoll <[email protected]>"); | ||
MODULE_LICENSE("GPL"); | ||
|
||
module_init(ipts_mei_init); | ||
module_exit(ipts_mei_exit); |
Oops, something went wrong.