Skip to content

Commit 783f424

Browse files
committed
Enable sysfs to send data from user to kernel
We wish to achieve full interactivity between user space and kernel space, which means we can manipulate the displaying status, restart and ending choice for the tic-tac-toe games between kernel theads from user space. We doing so by establish device attribute through "DEVICE_ATTR_RW()" so we can interact with kernel from user space by reading or writing contents into a file under sysfs.
1 parent baed53d commit 783f424

File tree

3 files changed

+122
-19
lines changed

3 files changed

+122
-19
lines changed

kmldrv-user.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
#include <fcntl.h>
12
#include <getopt.h>
23
#include <stdbool.h>
34
#include <stdio.h>
45
#include <stdlib.h>
56
#include <string.h>
7+
#include <termios.h>
68
#include <unistd.h>
79

810
#include "game.h"
911

1012
#define KMLDRV_STATUS_FILE "/sys/module/kmldrv/initstate"
1113
#define KMLDRV_DEVICE_FILE "/dev/kmldrv"
14+
#define KMLDRV_DEVICE_ATTR_FILE "/sys/class/kmldrv/kmldrv/kmldrv_state"
1215

1316
bool kmldrv_status_check(void)
1417
{
@@ -32,6 +35,21 @@ bool kmldrv_status_check(void)
3235
return true;
3336
}
3437

38+
static struct termios orig_termios;
39+
40+
static void disableRawMode(void)
41+
{
42+
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
43+
}
44+
45+
static void enableRawMode(void)
46+
{
47+
tcgetattr(STDIN_FILENO, &orig_termios);
48+
atexit(disableRawMode);
49+
struct termios raw = orig_termios;
50+
raw.c_lflag &= ~(ECHO | ICANON);
51+
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
52+
}
3553

3654
int main(int argc, char *argv[])
3755
{
@@ -63,13 +81,37 @@ int main(int argc, char *argv[])
6381
if (!kmldrv_status_check())
6482
exit(1);
6583

84+
enableRawMode();
85+
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
86+
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
87+
6688
FILE *device_ptr = fopen(KMLDRV_DEVICE_FILE, "r");
6789
char display_buf[DRAWBUFFER_SIZE];
90+
91+
int attr_fd = open(KMLDRV_DEVICE_ATTR_FILE, O_WRONLY);
92+
char input;
6893
while (fgets(display_buf, DRAWBUFFER_SIZE, device_ptr)) {
6994
printf("%s", display_buf);
95+
96+
if (read(STDIN_FILENO, &input, 1) == 1) {
97+
switch (input) {
98+
case 16:
99+
char buf[20];
100+
read(attr_fd, buf, 5);
101+
buf[0] = (buf[0] - '0') ? '0' : '1';
102+
write(attr_fd, buf, 5);
103+
break;
104+
case 17:
105+
break;
106+
}
107+
}
70108
}
71109

110+
disableRawMode();
111+
fcntl(STDIN_FILENO, F_SETFL, flags);
112+
72113
fclose(device_ptr);
114+
close(attr_fd);
73115

74116
return 0;
75117
}

scripts/pre-commit.hook

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ CPPCHECK_suppresses="--suppress=unmatchedSuppression \
44
--suppress=missingIncludeSystem -i ksort.mod.c --suppress=variableScope \
55
--suppress=unmatchedSuppression:simrupt.c \
66
--suppress=constParameterPointer:simrupt.c \
7-
--suppress=constParameterCallback:simrupt.c"
7+
--suppress=constParameterCallback:simrupt.c \
8+
--suppress=unusedFunction:simrupt.c"
89
CPPCHECK_OPTS="-I. --enable=all --error-exitcode=1 --force $CPPCHECK_suppresses ."
910

1011
RETURN=0

simrupt.c

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/kfifo.h>
99
#include <linux/module.h>
1010
#include <linux/slab.h>
11+
#include <linux/sysfs.h>
1112
#include <linux/version.h>
1213
#include <linux/workqueue.h>
1314

@@ -32,6 +33,42 @@ MODULE_DESCRIPTION("A device that simulates interrupts");
3233

3334
static int delay = 100; /* time (in ms) to generate an event */
3435

36+
/* Declare kernel module attribute for sysfs */
37+
38+
struct kmldrv_attr {
39+
char display;
40+
char restart;
41+
char end;
42+
rwlock_t lock;
43+
};
44+
45+
static struct kmldrv_attr attr_obj;
46+
47+
static ssize_t kmldrv_state_show(struct device *dev,
48+
struct device_attribute *attr,
49+
char *buf)
50+
{
51+
read_lock(&attr_obj.lock);
52+
int ret = snprintf(buf, 6, "%c %c %c\n", attr_obj.display, attr_obj.restart,
53+
attr_obj.end);
54+
read_unlock(&attr_obj.lock);
55+
return ret;
56+
}
57+
58+
static ssize_t kmldrv_state_store(struct device *dev,
59+
struct device_attribute *attr,
60+
const char *buf,
61+
size_t count)
62+
{
63+
write_lock(&attr_obj.lock);
64+
sscanf(buf, "%c %c %c", &(attr_obj.display), &(attr_obj.restart),
65+
&(attr_obj.end));
66+
write_unlock(&attr_obj.lock);
67+
return count;
68+
}
69+
70+
static DEVICE_ATTR_RW(kmldrv_state);
71+
3572
/* Data produced by the simulated device */
3673

3774
/* Timer to simulate a periodic IRQ */
@@ -135,16 +172,21 @@ static void drawboard_work_func(struct work_struct *w)
135172
pr_info("kmldrv: [CPU#%d] %s\n", cpu, __func__);
136173
put_cpu();
137174

175+
read_lock(&attr_obj.lock);
176+
if (attr_obj.display == '0') {
177+
read_unlock(&attr_obj.lock);
178+
return;
179+
}
180+
read_unlock(&attr_obj.lock);
181+
138182
mutex_lock(&producer_lock);
139183
draw_board(table);
140184
mutex_unlock(&producer_lock);
141185

142186
/* Store data to the kfifo buffer */
143-
// mutex_lock(&producer_lock);
144187
mutex_lock(&consumer_lock);
145188
produce_board();
146189
mutex_unlock(&consumer_lock);
147-
// mutex_unlock(&producer_lock);
148190

149191
wake_up_interruptible(&rx_wait);
150192
}
@@ -300,24 +342,28 @@ static void timer_handler(struct timer_list *__timer)
300342

301343
if (win == ' ') {
302344
ai_game();
303-
mod_timer(&timer, jiffies + msecs_to_jiffies(delay));
304345
} else {
305-
int cpu = get_cpu();
306-
pr_info("kmldrv: [CPU#%d] Drawing final board\n", cpu);
307-
put_cpu();
308-
309-
mutex_lock(&producer_lock);
310-
draw_board(table);
311-
mutex_unlock(&producer_lock);
312-
313-
/* Store data to the kfifo buffer */
314-
mutex_lock(&consumer_lock);
315-
produce_board();
316-
mutex_unlock(&consumer_lock);
317-
318-
wake_up_interruptible(&rx_wait);
346+
read_lock(&attr_obj.lock);
347+
if (attr_obj.display == '1') {
348+
int cpu = get_cpu();
349+
pr_info("kmldrv: [CPU#%d] Drawing final board\n", cpu);
350+
put_cpu();
351+
352+
mutex_lock(&producer_lock);
353+
draw_board(table);
354+
mutex_unlock(&producer_lock);
355+
356+
/* Store data to the kfifo buffer */
357+
mutex_lock(&consumer_lock);
358+
produce_board();
359+
mutex_unlock(&consumer_lock);
360+
361+
wake_up_interruptible(&rx_wait);
362+
}
363+
read_unlock(&attr_obj.lock);
319364

320365
pr_info("kmldrv: %c win!!!\n", win);
366+
memset(table, ' ', N_GRIDS); /* Reset the table so the game restart */
321367
}
322368
tv_end = ktime_get();
323369

@@ -326,6 +372,8 @@ static void timer_handler(struct timer_list *__timer)
326372
pr_info("kmldrv: [CPU#%d] %s in_irq: %llu usec\n", smp_processor_id(),
327373
__func__, (unsigned long long) nsecs >> 10);
328374

375+
mod_timer(&timer, jiffies + msecs_to_jiffies(delay));
376+
329377
local_irq_enable();
330378
}
331379

@@ -433,7 +481,14 @@ static int __init kmldrv_init(void)
433481
}
434482

435483
/* Register the device with sysfs */
436-
device_create(kmldrv_class, NULL, MKDEV(major, 0), NULL, DEV_NAME);
484+
struct device *kmldrv_dev =
485+
device_create(kmldrv_class, NULL, MKDEV(major, 0), NULL, DEV_NAME);
486+
487+
ret = device_create_file(kmldrv_dev, &dev_attr_kmldrv_state);
488+
if (ret < 0) {
489+
printk(KERN_ERR "failed to create sysfs file kmldrv_state\n");
490+
goto error_cdev;
491+
}
437492

438493
/* Allocate fast circular buffer */
439494
fast_buf.buf = vmalloc(PAGE_SIZE);
@@ -458,6 +513,11 @@ static int __init kmldrv_init(void)
458513
memset(table, ' ', N_GRIDS);
459514
turn = 'O';
460515
finish = 1;
516+
517+
attr_obj.display = '1';
518+
attr_obj.restart = '0';
519+
attr_obj.end = '0';
520+
rwlock_init(&attr_obj.lock);
461521
/* Setup the timer */
462522
timer_setup(&timer, timer_handler, 0);
463523
atomic_set(&open_cnt, 0);

0 commit comments

Comments
 (0)