Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HID based IPTS and ITHC support #132

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1336,4 +1336,8 @@ source "drivers/hid/amd-sfh-hid/Kconfig"

source "drivers/hid/surface-hid/Kconfig"

source "drivers/hid/ipts/Kconfig"

source "drivers/hid/ithc/Kconfig"

endmenu
3 changes: 3 additions & 0 deletions drivers/hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,6 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/

obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/

obj-$(CONFIG_HID_IPTS) += ipts/
obj-$(CONFIG_HID_ITHC) += ithc/
7 changes: 2 additions & 5 deletions drivers/misc/ipts/Kconfig → drivers/hid/ipts/Kconfig
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later

config MISC_IPTS
config HID_IPTS
tristate "Intel Precise Touch & Stylus"
depends on INTEL_MEI
depends on HID
help
Say Y here if your system has a touchscreen using Intels
Precise Touch & Stylus (IPTS) technology.
Expand All @@ -11,7 +12,3 @@ config MISC_IPTS

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.
8 changes: 4 additions & 4 deletions drivers/misc/ipts/Makefile → drivers/hid/ipts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# Makefile for the IPTS touchscreen driver
#

obj-$(CONFIG_MISC_IPTS) += ipts.o
ipts-objs := control.o
obj-$(CONFIG_HID_IPTS) += ipts.o
ipts-objs := cmd.o
ipts-objs += control.o
ipts-objs += hid.o
ipts-objs += mei.o
ipts-objs += receiver.o
ipts-objs += resources.o
ipts-objs += uapi.o

144 changes: 144 additions & 0 deletions drivers/hid/ipts/cmd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2020-2022 Dorian Stoll
*
* Linux driver for Intel Precise Touch & Stylus
*/

#include <linux/errno.h>
#include <linux/types.h>

#include "context.h"
#include "spec-device.h"

static int ipts_cmd_get_errno(struct ipts_response rsp, enum ipts_status expect)
{
if (rsp.status == IPTS_STATUS_SUCCESS)
return 0;

/*
* If a status code was expected, dont produce an error.
*/
if (rsp.status == expect)
return 0;

/*
* Some devices will always return this error. It is allowed
* to ignore it and to try continuing.
*/
if (rsp.status == IPTS_STATUS_COMPAT_CHECK_FAIL)
return 0;

/*
* Return something, this is not going to be checked.
* Any error will just cause the driver to stop.
*/
return -EINVAL;
}

static int _ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, void *data,
size_t size, bool block, enum ipts_status expect)
{
int ret;
struct ipts_response rsp = { 0 };

if (!ipts)
return -EFAULT;

if (size > sizeof(rsp.payload))
return -EINVAL;

if (block)
ret = mei_cldev_recv(ipts->cldev, (u8 *)&rsp, sizeof(rsp));
else
ret = mei_cldev_recv_nonblock(ipts->cldev, (u8 *)&rsp, sizeof(rsp));

if (ret == -EAGAIN)
return ret;

if (ret <= 0) {
dev_err(ipts->dev, "Error while reading response: %d\n", ret);
return ret;
}

/*
* In a response, the command code will have the most significant bit
* flipped to 1. We check for this and then set the bit to 0.
*/
if ((rsp.cmd & IPTS_RSP_BIT) == 0) {
dev_err(ipts->dev, "Invalid command code received: 0x%02X\n", rsp.cmd);
return -EINVAL;
}

rsp.cmd = rsp.cmd & ~(IPTS_RSP_BIT);
if (rsp.cmd != code) {
dev_err(ipts->dev, "Received response to wrong command: 0x%02X\n", rsp.cmd);
return -EINVAL;
}

ret = ipts_cmd_get_errno(rsp, expect);
if (ret) {
dev_err(ipts->dev, "Command 0x%02X failed: 0x%02X\n", rsp.cmd, rsp.status);
return ret;
}

if (data && size > 0)
memcpy(data, rsp.payload, size);

return 0;
}

int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size)
{
int ret;
struct ipts_command cmd = { 0 };

if (!ipts)
return -EFAULT;

cmd.cmd = code;

if (data && size > 0)
memcpy(cmd.payload, data, size);

ret = mei_cldev_send(ipts->cldev, (u8 *)&cmd, sizeof(cmd.cmd) + size);
if (ret >= 0)
return 0;

dev_err(ipts->dev, "Error while sending: 0x%02X:%d\n", code, ret);
return ret;
}

int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size)
{
return _ipts_cmd_recv(ipts, code, data, size, true, IPTS_STATUS_SUCCESS);
}

int ipts_cmd_recv_nonblock(struct ipts_context *ipts, enum ipts_command_code code, void *data,
size_t size)
{
return _ipts_cmd_recv(ipts, code, data, size, false, IPTS_STATUS_SUCCESS);
}

int ipts_cmd_recv_expect(struct ipts_context *ipts, enum ipts_command_code code, void *data,
size_t size, enum ipts_status expect)
{
return _ipts_cmd_recv(ipts, code, data, size, true, expect);
}

int ipts_cmd_run(struct ipts_context *ipts, enum ipts_command_code code, void *in, size_t insize,
void *out, size_t outsize)
{
int ret;

ret = ipts_cmd_send(ipts, code, in, insize);
if (ret)
return ret;

ret = ipts_cmd_recv(ipts, code, out, outsize);
if (ret)
return ret;

return 0;
}
51 changes: 51 additions & 0 deletions drivers/hid/ipts/cmd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (c) 2016 Intel Corporation
* Copyright (c) 2020-2022 Dorian Stoll
*
* Linux driver for Intel Precise Touch & Stylus
*/

#ifndef IPTS_CMD_H
#define IPTS_CMD_H

#include <linux/types.h>

#include "context.h"
#include "spec-device.h"

/*
* Executes the specified command with the given payload on the device.
*/
int ipts_cmd_send(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size);

/*
* Receives the response to the given command and copies the payload to the given buffer.
* This function will block until a message has been received.
*/
int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_code code, void *data, size_t size);

/*
* Receives the response to the given command and copies the payload to the given buffer.
* This function will not block. If no data is available, -EAGAIN will be returned.
*/
int ipts_cmd_recv_nonblock(struct ipts_context *ipts, enum ipts_command_code code, void *data,
size_t size);

/*
* Receives the response to the given command and copies the payload to the given buffer.
* This function will block until a message has been received.
* If the command finished with the expected status code, no error will be produced.
*/
int ipts_cmd_recv_expect(struct ipts_context *ipts, enum ipts_command_code code, void *data,
size_t size, enum ipts_status expect);

/*
* Executes the specified command with the given payload on the device. Then
* receives the response to the command and copies the payload to the given buffer.
* This function will block until the command has been completed.
*/
int ipts_cmd_run(struct ipts_context *ipts, enum ipts_command_code code, void *in, size_t insize,
void *out, size_t outsize);

#endif /* IPTS_CMD_H */
47 changes: 47 additions & 0 deletions drivers/hid/ipts/context.h
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-2022 Dorian Stoll
*
* Linux driver for Intel Precise Touch & Stylus
*/

#ifndef IPTS_CONTEXT_H
#define IPTS_CONTEXT_H

#include <linux/completion.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/mei_cl_bus.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/types.h>

#include "resources.h"
#include "spec-device.h"

struct ipts_context {
struct device *dev;
struct mei_cl_device *cldev;

enum ipts_mode mode;

struct mutex feature_lock;
struct completion feature_event;

/*
* These are not inside of struct ipts_resources
* because they don't own the memory they point to.
*/
struct ipts_buffer feature_report;
struct ipts_buffer descriptor;

struct hid_device *hid;
struct ipts_device_info info;
struct ipts_resources resources;

struct task_struct *event_loop;
struct task_struct *doorbell_loop;
};

#endif /* IPTS_CONTEXT_H */
Loading