-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtsukutsuku.c
196 lines (162 loc) · 4.61 KB
/
tsukutsuku.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL v2");
#define MINOR_BASE 0
#define MINOR_NUMBER 1
static struct class * tsukutsuku_mod_class;
static struct cdev tsukutsuku_mod_cdev;
static dev_t dev;
typedef struct _automaton_state {
char *msg;
int msg_len;
int n;
int *transition;
int *transition_prob;
} automaton_state;
static char m0[] = "ジー...";
static int t0[] = { 1 };
static int tp0[] = { 100 };
static char m1[] = "ツクツク";
static int t1[] = { 1, 2 };
static int tp1[] = { 35, 65 };
static char m2[] = "ボーシ!";
static int t2[] = { 3 };
static int tp2[] = { 100 };
static char m3[] = "ツクツクボーシ!";
static int t3[] = { 3, 4 };
static int tp3[] = { 90, 10 };
static char m4[] = "ウイヨース!";
static int t4[] = { 4, 0 };
static int tp4[] = { 80, 20 };
static automaton_state tsukutsuku_automaton[] = {
{
.msg = m0,
.msg_len = sizeof(m0),
.n = sizeof(t0),
.transition = t0,
.transition_prob = tp0,
},
{
.msg = m1,
.msg_len = sizeof(m1),
.n = sizeof(t1),
.transition = t1,
.transition_prob = tp1,
},
{
.msg = m2,
.msg_len = sizeof(m2),
.n = sizeof(t2),
.transition = t2,
.transition_prob = tp2,
},
{
.msg = m3,
.msg_len = sizeof(m3),
.n = sizeof(t3),
.transition = t3,
.transition_prob = tp3,
},
{
.msg = m4,
.msg_len = sizeof(m4),
.n = sizeof(t4),
.transition = t4,
.transition_prob = tp4,
},
};
static int current_state_num = 0;
static ssize_t read_tsukutsuku(struct file *file, char __user *buf, size_t size, loff_t *offset) {
automaton_state current_state = tsukutsuku_automaton[current_state_num];
char *buffer = current_state.msg;
size_t chunk = min(current_state.msg_len, size);
unsigned int random, prob;
int i, prob_sum;
if (chunk <= 0 || size <= 0) {
return 0;
}
if (copy_to_user(buf, buffer, chunk)) {
return -EFAULT;
}
get_random_bytes(&random, sizeof(random));
prob = random % 100;
prob_sum = 0;
for (i = 0; i < current_state.n; i ++) {
prob_sum += current_state.transition_prob[i];
if (prob < prob_sum) {
break;
}
}
current_state_num = current_state.transition[i]; // update state
return chunk;
}
static struct file_operations tsukutsuku_mod_drv_fops = {
.owner = THIS_MODULE,
.open = NULL,
.release = NULL,
.read = read_tsukutsuku,
.write = NULL,
};
static int __init tsukutsuku_mod_init(void)
{
int result;
struct device *tsukutsuku_mod_dev = NULL;
pr_info("tsukutsuku_mod: init function start\n");
/* Major/Minor番号を動的に確保し/proc/devicesへ登録 */
result = alloc_chrdev_region(&dev, MINOR_BASE, MINOR_NUMBER, "tsukutsuku_mod");
if(result){
pr_err("tsukutsuku_mod: error, alloc_chrdev_region = %d\n", result);
goto MMNUMBER_ERR;
}
/* モジュールのクラスを/sys/class/へ登録 */
tsukutsuku_mod_class = class_create(THIS_MODULE, "tsukutsuku_mod");
if(IS_ERR(tsukutsuku_mod_class)){
result = PTR_ERR(tsukutsuku_mod_class);
pr_err("tsukutsuku_mod: error, class_create = %d\n", result);
goto CLASS_ERR;
}
/* キャラクタデバイス構造体(cdev構造体)の初期化およびfopsの設定 */
cdev_init(&tsukutsuku_mod_cdev, &tsukutsuku_mod_drv_fops);
/* キャラクタデバイス構造体の登録 */
result = cdev_add(&tsukutsuku_mod_cdev, dev, MINOR_NUMBER);
if(result){
pr_err("tsukutsuku_mod: error, cdev_add = %d\n", result);
goto CDEV_ERR;
}
/* デバイスノードの作成.作成したノードは/dev以下からアクセス可能 */
tsukutsuku_mod_dev = device_create(tsukutsuku_mod_class, NULL, dev, NULL, "tsukutsuku");
if(IS_ERR(tsukutsuku_mod_dev)){
result = PTR_ERR(tsukutsuku_mod_dev);
pr_err("tsukutsuku_mod: error, device_create = %d\n", result);
goto DEV_ERR;
}
pr_info("tsukutsuku_mod: init function end\n");
return result;
DEV_ERR:
cdev_del(&tsukutsuku_mod_cdev);
CDEV_ERR:
class_destroy(tsukutsuku_mod_class);
CLASS_ERR:
unregister_chrdev_region(dev, MINOR_NUMBER);
MMNUMBER_ERR:
return result;
}
static void __exit tsukutsuku_mod_exit(void)
{
pr_info("tsukutsuku_mod: exit function start\n");
/* デバイスノードの削除 */
device_destroy(tsukutsuku_mod_class, dev);
/* キャラクタデバイスをKernelから削除 */
cdev_del(&tsukutsuku_mod_cdev);
/* デバイスのクラス登録を解除 */
class_destroy(tsukutsuku_mod_class);
/* デバイスが使用していたメジャー番号の登録を解除 */
unregister_chrdev_region(dev, MINOR_NUMBER);
pr_info("tsukutsuku_mod: exit function end\n");
}
module_init(tsukutsuku_mod_init);
module_exit(tsukutsuku_mod_exit);