linuxdebug/drivers/sst/sst_common.c

189 lines
5.4 KiB
C
Raw Normal View History

2024-07-16 15:50:57 +02:00
#include "sst_internal.h"
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/random.h>
#include <linux/slab.h>
static sst_info_t *cur_sst_info = NULL;
static char an_answer[] = "You shall ask a question!\n";
char *sst_questions[SST_MAX_QUESTIONS] = {
"What is the answer to the Ultimate Question of Life, The Universe, and Everything?",
"What do you get if you multiply six by nine?"
};
EXPORT_SYMBOL(sst_questions);
char *sst_answers[SST_MAX_ANSWERS] = {
"42!\n",
"Six by nine. Forty two.\n",
"Flash!, a-ah. Savior of the Universe. Flash!, a-ah.\n"
};
EXPORT_SYMBOL(sst_answers);
sst_info_t* get_sst_info(void) {
return cur_sst_info;
}
EXPORT_SYMBOL(get_sst_info);
static int control_thread_work(void *data) {
sst_info_t *info = (sst_info_t*)data;
int err, i;
#if 0
int sleep = 0;
#endif
size_t len_answer = 0, len_question = 0;
char *question = NULL, *answer = NULL, *my_answer = NULL;
sst_debug("Using data at 0x%lx\n", (uintptr_t)info);
while(1) {
wait_event_interruptible(info->wait, !is_empty(&info->questions));
if (kthread_should_stop()) {
break;
}
err = sst_consume_question(info, &question);
if (err) {
pr_err("Questions was empty!\n");
continue;
} else if (question == NULL) {
pr_err("Question is NULL although ret value is 0.\n");
continue;
} else {
printk("Received msg at 0x%lx\n", (uintptr_t)question);
sst_debug("Received msg '%s' at 0x%lx\n", question, (uintptr_t)question);
}
len_question = strlen(question);
if (len_question > 2 && (question[len_question - 1] == '?' ||
(question[len_question - 1] == '\n' && question[len_question - 2] == '?'))) {
my_answer = sst_answers[0];
for (i = 0; i < SST_MAX_QUESTIONS; i++) {
if (strcmp(question, sst_questions[i]) == 0) {
my_answer = sst_answers[i];
break;
}
}
} else {
my_answer = an_answer;
}
len_answer = strlen(my_answer) + 1;
answer = kmalloc(len_answer, GFP_KERNEL);
if (!answer) {
pr_err("Cannot allocate memory for answer!\n");
kfree(question);
continue;
}
snprintf(answer, len_answer, "%s", my_answer);
if (sst_produce_answer(info, answer)) {
pr_err("Answers is full!\n");
kfree(answer);
} else {
sst_debug("The universe has an answer at 0x%lx for you!\n", (uintptr_t)answer);
}
#if 0
sleep = get_random_u8() % 90;
sst_debug("Randomly sleeping for %d secs. ZzzzZZzz\n", sleep);
ssleep(sleep);
#endif
kfree(question);
}
return 0;
}
int sst_init(void) {
cur_sst_info = kmalloc(sizeof(*cur_sst_info), GFP_KERNEL);
if (!cur_sst_info) {
return -ENOMEM;
}
spin_lock_init(&cur_sst_info->lock_questions);
spin_lock_init(&cur_sst_info->lock_answers);
sema_init(&cur_sst_info->answers_rdy, 0);
init_waitqueue_head(&cur_sst_info->wait);
init_bbuffer(&cur_sst_info->answers);
init_bbuffer(&cur_sst_info->questions);
sst_debug("Allocated private data for the universe at [0x%lx,0x%lx]\n", (uintptr_t)cur_sst_info, (uintptr_t)((uintptr_t)cur_sst_info + sizeof(*cur_sst_info)));
cur_sst_info->thread = kthread_create(control_thread_work, get_sst_info(), "sst-worker-%d", 1);
if (IS_ERR(cur_sst_info->thread)) {
kfree(cur_sst_info);
return -EFAULT;
}
wake_up_process(cur_sst_info->thread);
sst_debug("Created and started control thread (%d)\n", cur_sst_info->thread->pid);
return 0;
}
EXPORT_SYMBOL(sst_init);
void sst_destroy(void) {
sst_debug("Waiting for control thread (%d) to terminate...\n", cur_sst_info->thread->pid);
kthread_stop(cur_sst_info->thread);
sst_debug("Control thread (%d) terminated.\n", cur_sst_info->thread->pid);
kfree(cur_sst_info);
sst_debug("Freed private data for the universe at 0x%lx\n", (uintptr_t)cur_sst_info);
};
EXPORT_SYMBOL(sst_destroy);
int sst_produce_question(sst_info_t *info, char *value) {
int err = 0;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
spin_lock_bh(&info->lock_questions);
err = produce(&info->questions, value);
spin_unlock_bh(&info->lock_questions);
if (!err) {
wake_up_interruptible(&info->wait);
}
return err;
}
EXPORT_SYMBOL(sst_produce_question);
int sst_produce_answer(sst_info_t *info, char *value) {
int err = 0;
unsigned long flags;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
spin_lock_irqsave(&info->lock_answers, flags);
err = produce(&info->answers, value);
spin_unlock_irqrestore(&info->lock_answers, flags);
up(&info->answers_rdy);
return err;
}
EXPORT_SYMBOL(sst_produce_answer);
int sst_consume_question(sst_info_t *info, char **value) {
int err = 0;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
spin_lock_bh(&info->lock_questions);
err = consume(&info->questions, value);
spin_unlock_bh(&info->lock_questions);
return err;
}
EXPORT_SYMBOL(sst_consume_question);
int sst_consume_answer(sst_info_t *info, char **value) {
int err = 0;
unsigned long flags;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
if (down_trylock(&info->answers_rdy)) {
sst_debug("Sry. No answer for you!\n");
return -2;
}
spin_lock_irqsave(&info->lock_answers, flags);
err = consume(&info->answers, value);
spin_unlock_irqrestore(&info->lock_answers, flags);
return err;
}
EXPORT_SYMBOL(sst_consume_answer);