-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom wrapper over kthread, fixes MEI commands during kthread_stop
Thanks to @qzed for figuring out that trying to call mei_cldev_send inside of a thread after kthread_stop has been called will always result in -EINTR being returned.
- Loading branch information
Showing
5 changed files
with
187 additions
and
25 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,4 @@ ipts-objs += main.o | |
ipts-objs += mei.o | ||
ipts-objs += receiver.o | ||
ipts-objs += resources.o | ||
ipts-objs += thread.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
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,89 @@ | ||
// 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/completion.h> | ||
#include <linux/err.h> | ||
#include <linux/kthread.h> | ||
#include <linux/mutex.h> | ||
|
||
#include "thread.h" | ||
|
||
bool ipts_thread_should_stop(struct ipts_thread *thread) | ||
{ | ||
bool ret = false; | ||
|
||
if (!thread) | ||
return false; | ||
|
||
mutex_lock(&thread->lock); | ||
ret = thread->should_stop; | ||
mutex_unlock(&thread->lock); | ||
|
||
return ret; | ||
} | ||
|
||
static int ipts_thread_runner(void *data) | ||
{ | ||
int ret = 0; | ||
struct ipts_thread *thread = data; | ||
|
||
if (!thread) | ||
return -EFAULT; | ||
|
||
if (!thread->threadfn) | ||
return -EFAULT; | ||
|
||
ret = thread->threadfn(thread); | ||
complete_all(&thread->done); | ||
|
||
return ret; | ||
} | ||
|
||
int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), | ||
void *data, const char *name) | ||
{ | ||
if (!thread) | ||
return -EFAULT; | ||
|
||
if (!threadfn) | ||
return -EFAULT; | ||
|
||
mutex_init(&thread->lock); | ||
init_completion(&thread->done); | ||
|
||
thread->data = data; | ||
thread->should_stop = false; | ||
thread->threadfn = threadfn; | ||
|
||
thread->thread = kthread_run(ipts_thread_runner, thread, name); | ||
return PTR_ERR_OR_ZERO(thread->thread); | ||
} | ||
|
||
int ipts_thread_stop(struct ipts_thread *thread) | ||
{ | ||
int ret = 0; | ||
|
||
if (!thread) | ||
return -EFAULT; | ||
|
||
if (!thread->thread) | ||
return 0; | ||
|
||
mutex_lock(&thread->lock); | ||
thread->should_stop = true; | ||
mutex_unlock(&thread->lock); | ||
|
||
wait_for_completion(&thread->done); | ||
ret = kthread_stop(thread->thread); | ||
|
||
thread->thread = NULL; | ||
thread->data = NULL; | ||
thread->threadfn = NULL; | ||
|
||
return ret; | ||
} |
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,62 @@ | ||
/* 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_THREAD_H | ||
#define IPTS_THREAD_H | ||
|
||
#include <linux/completion.h> | ||
#include <linux/mutex.h> | ||
#include <linux/sched.h> | ||
|
||
/* | ||
* This wrapper over kthread is neccessary, because calling kthread_stop makes it impossible | ||
* to issue MEI commands from that thread while it shuts itself down. By using a custom | ||
* boolean variable and a completion object, we can call kthread_stop only when the thread | ||
* already finished all of its work and has returned. | ||
*/ | ||
struct ipts_thread { | ||
struct task_struct *thread; | ||
|
||
bool should_stop; | ||
|
||
struct mutex lock; | ||
struct completion done; | ||
|
||
void *data; | ||
int (*threadfn)(struct ipts_thread *thread); | ||
}; | ||
|
||
/* | ||
* ipts_thread_should_stop() - Returns true if the thread is asked to terminate. | ||
* @thread: The current thread. | ||
* | ||
* Returns: true if the thread should stop, false if not. | ||
*/ | ||
bool ipts_thread_should_stop(struct ipts_thread *thread); | ||
|
||
/* | ||
* ipts_thread_start() - Starts an IPTS thread. | ||
* @thread: The thread to initialize and start. | ||
* @threadfn: The function to execute. | ||
* @data: An argument that will be passed to threadfn. | ||
* @name: The name of the new thread. | ||
* | ||
* Returns: 0 on success, <0 on error. | ||
*/ | ||
int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), | ||
void *data, const char name[]); | ||
|
||
/* | ||
* ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. | ||
* @thread: The thread that should stop. | ||
* | ||
* Returns: The return value of the thread function. | ||
*/ | ||
int ipts_thread_stop(struct ipts_thread *thread); | ||
|
||
#endif /* IPTS_THREAD_H */ |