diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | pix_driver.c | 258 | ||||
-rw-r--r-- | relay_control.c | 95 |
3 files changed, 360 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..152671c --- /dev/null +++ b/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | obj-m := relay_control.o | ||
2 | |||
3 | all: | ||
4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | ||
5 | |||
6 | clean: | ||
7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean | ||
diff --git a/pix_driver.c b/pix_driver.c new file mode 100644 index 0000000..10d3d21 --- /dev/null +++ b/pix_driver.c | |||
@@ -0,0 +1,258 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/kthread.h> | ||
4 | #include <linux/delay.h> | ||
5 | #include <linux/gpio.h> | ||
6 | |||
7 | MODULE_LICENSE("GPL"); | ||
8 | |||
9 | /* GPIO */ | ||
10 | |||
11 | #define A1 17 // 0 | ||
12 | #define A2 18 // 1 | ||
13 | #define A3 27 // 2 | ||
14 | #define OE 22 // 3 | ||
15 | #define LE 23 // 4 | ||
16 | #define SDI 24 // 5 | ||
17 | #define CLK 25 // 6 | ||
18 | |||
19 | #define LINES 8 | ||
20 | #define PER_LINE 12 | ||
21 | |||
22 | static u8 pix_screen[LINES][PER_LINE] = { | ||
23 | { | ||
24 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
25 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
26 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
27 | }, | ||
28 | { | ||
29 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
30 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
31 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
32 | }, | ||
33 | { | ||
34 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
35 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
36 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
37 | }, | ||
38 | { | ||
39 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
40 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
41 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
42 | }, | ||
43 | { | ||
44 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
45 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
46 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
47 | }, | ||
48 | { | ||
49 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
50 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
51 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
52 | }, | ||
53 | { | ||
54 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
55 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
56 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
57 | }, | ||
58 | { | ||
59 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
60 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
61 | 0b00000000,0b00000000,0b00000000,0b00000000, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | void pix_line(u8 row){ | ||
66 | gpio_set_value(A1, !(row & 0b00000001)); | ||
67 | gpio_set_value(A2, !(row & 0b00000010)); | ||
68 | gpio_set_value(A3, !(row & 0b00000100)); | ||
69 | } | ||
70 | |||
71 | void pix_dot(int x, int y, int r, int g, int b) { | ||
72 | uint8_t l,p,t; | ||
73 | |||
74 | if(y % 2){ | ||
75 | x = (x + 16); | ||
76 | } | ||
77 | y = (y / 2) - ((y / 2) % 1); | ||
78 | |||
79 | l = x / 8; | ||
80 | p = 7 - x % 8; | ||
81 | t = pix_screen[y][l]; | ||
82 | |||
83 | //printf("line:%i, l:%i, p:%i, t:%i\n", y,l,p,t); | ||
84 | |||
85 | if(r) { | ||
86 | t |= 1 << p; | ||
87 | }else{ | ||
88 | t &= ~(1 << p); | ||
89 | } | ||
90 | pix_screen[y][l] = t; | ||
91 | |||
92 | l = x / 8 + 4; | ||
93 | p = 7 - x % 8; | ||
94 | t = pix_screen[y][l]; | ||
95 | if(g) { | ||
96 | t |= 1 << p; | ||
97 | }else{ | ||
98 | t &= ~(1 << p); | ||
99 | } | ||
100 | pix_screen[y][l] = t; | ||
101 | |||
102 | l = x / 8 + 8; | ||
103 | p = 7 - x % 8; | ||
104 | t = pix_screen[y][l]; | ||
105 | if(b) { | ||
106 | t |= 1 << p; | ||
107 | }else{ | ||
108 | t &= ~(1 << p); | ||
109 | } | ||
110 | pix_screen[y][l] = t; | ||
111 | } | ||
112 | |||
113 | void pix_gpio_init(void){ | ||
114 | printk(KERN_INFO "PIX: starting gpio..."); | ||
115 | gpio_request(A1, "A1"); | ||
116 | gpio_request(A2, "A2"); | ||
117 | gpio_request(A3, "A3"); | ||
118 | |||
119 | gpio_request(OE, "OE"); | ||
120 | gpio_request(LE, "LE"); | ||
121 | gpio_request(SDI, "SDI"); | ||
122 | gpio_request(CLK, "CLK"); | ||
123 | |||
124 | gpio_direction_output(A1, 0); | ||
125 | gpio_direction_output(A2, 0); | ||
126 | gpio_direction_output(A3, 0); | ||
127 | |||
128 | gpio_direction_output(OE, 1); | ||
129 | gpio_direction_output(LE, 0); | ||
130 | gpio_direction_output(SDI, 0); | ||
131 | gpio_direction_output(CLK, 0); | ||
132 | printk(KERN_INFO "PIX: starting gpio done."); | ||
133 | } | ||
134 | |||
135 | void pix_gpio_exit(void){ | ||
136 | printk(KERN_INFO "PIX: stopping gpio..."); | ||
137 | gpio_free(A1); | ||
138 | gpio_free(A2); | ||
139 | gpio_free(A3); | ||
140 | |||
141 | gpio_free(OE); | ||
142 | gpio_free(LE); | ||
143 | gpio_free(SDI); | ||
144 | gpio_free(CLK); | ||
145 | printk(KERN_INFO "PIX: stopping gpio done."); | ||
146 | } | ||
147 | |||
148 | |||
149 | |||
150 | /* SYSFS */ | ||
151 | |||
152 | static struct kobject *pix_kobject; | ||
153 | |||
154 | static ssize_t set_pix(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { | ||
155 | u8 x = 0; | ||
156 | u8 y = 0; | ||
157 | u8 r = 0; | ||
158 | u8 g = 0; | ||
159 | u8 b = 0; | ||
160 | sscanf(buff, "%hhd %hhd %hhd %hhd %hhd", &x, &y, &r, &g, &b); | ||
161 | |||
162 | pix_dot(x,y,r,g,b); | ||
163 | // printk(KERN_INFO "PIX: %d %d %d %d %d", x,y,r,g,b); | ||
164 | |||
165 | return count; | ||
166 | } | ||
167 | |||
168 | static struct kobj_attribute pix_attribute =__ATTR(dot, (S_IWUSR | S_IRUGO), NULL, set_pix); | ||
169 | |||
170 | void pix_sysfs_init(void){ | ||
171 | printk(KERN_INFO "PIX: starting sysfs..."); | ||
172 | pix_kobject = kobject_create_and_add("pix", NULL); | ||
173 | if (sysfs_create_file(pix_kobject, &pix_attribute.attr)) { | ||
174 | pr_debug("failed to create pix sysfs!\n"); | ||
175 | } | ||
176 | printk(KERN_INFO "PIX: starting sysfs done."); | ||
177 | } | ||
178 | |||
179 | void pix_sysfs_exit(void){ | ||
180 | printk(KERN_INFO "PIX: stopping sysfs..."); | ||
181 | kobject_put(pix_kobject); | ||
182 | printk(KERN_INFO "PIX: stopping sysfs done."); | ||
183 | } | ||
184 | |||
185 | |||
186 | /* THREAD */ | ||
187 | |||
188 | #define THREAD_PRIORITY 45 | ||
189 | #define THREAD_NAME "pix" | ||
190 | |||
191 | struct task_struct *task; | ||
192 | |||
193 | int pix_thread(void *data){ | ||
194 | u8 line, pos, bit; | ||
195 | struct task_struct *TSK; | ||
196 | struct sched_param PARAM = { .sched_priority = MAX_RT_PRIO - 50 }; | ||
197 | //struct sched_param PARAM = { .sched_priority = DEFAULT_PRIO }; | ||
198 | TSK = current; | ||
199 | |||
200 | PARAM.sched_priority = THREAD_PRIORITY; | ||
201 | sched_setscheduler(TSK, SCHED_FIFO, &PARAM); | ||
202 | |||
203 | while(1) { | ||
204 | for(line = 0; line < LINES; line++) { | ||
205 | pix_line(line); | ||
206 | for(pos = 0; pos < PER_LINE; pos++) { | ||
207 | for (bit = 0; bit < 8; bit++) { | ||
208 | gpio_set_value(SDI, !!(pix_screen[line][pos] & (1 << (7 - bit)))); | ||
209 | gpio_set_value(CLK, 1); | ||
210 | gpio_set_value(CLK, 0); | ||
211 | } | ||
212 | } | ||
213 | gpio_set_value(LE, 1); | ||
214 | gpio_set_value(LE, 0); | ||
215 | gpio_set_value(OE, 0); | ||
216 | usleep_range(2000, 2000); | ||
217 | gpio_set_value(OE, 1); | ||
218 | } | ||
219 | if (kthread_should_stop()) break; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | void pix_thread_init(void){ | ||
225 | printk(KERN_INFO "PIX: starting thread..."); | ||
226 | task = kthread_run(pix_thread, NULL, THREAD_NAME); | ||
227 | printk(KERN_INFO "PIX: starting thread done."); | ||
228 | } | ||
229 | |||
230 | void pix_thread_exit(void){ | ||
231 | printk(KERN_INFO "PIX: stopping thread..."); | ||
232 | kthread_stop(task); | ||
233 | printk(KERN_INFO "PIX: stopping thread done."); | ||
234 | } | ||
235 | |||
236 | /* MODULE */ | ||
237 | |||
238 | static int __init pix_init(void){ | ||
239 | printk(KERN_INFO "PIX: staring..."); | ||
240 | pix_gpio_init(); | ||
241 | pix_thread_init(); | ||
242 | pix_sysfs_init(); | ||
243 | printk(KERN_INFO "PIX: staring done."); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static void __exit pix_exit(void){ | ||
248 | printk(KERN_INFO "PIX: stopping..."); | ||
249 | pix_sysfs_exit(); | ||
250 | pix_thread_exit(); | ||
251 | pix_gpio_exit(); | ||
252 | printk(KERN_INFO "PIX: stopping done."); | ||
253 | } | ||
254 | |||
255 | module_init(pix_init); | ||
256 | module_exit(pix_exit); | ||
257 | |||
258 | |||
diff --git a/relay_control.c b/relay_control.c new file mode 100644 index 0000000..7b0e59c --- /dev/null +++ b/relay_control.c | |||
@@ -0,0 +1,95 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/gpio.h> | ||
4 | #include <linux/string.h> | ||
5 | |||
6 | MODULE_LICENSE("GPL"); | ||
7 | |||
8 | #define RELAY_K1 18 | ||
9 | #define RELAY_K2 23 | ||
10 | #define RELAY_K3 24 | ||
11 | #define RELAY_K4 25 | ||
12 | |||
13 | #define NO_OFF 0 | ||
14 | #define NO_ON 1 | ||
15 | |||
16 | static struct kobject *relay_kobject; | ||
17 | |||
18 | static ssize_t set_relay(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { | ||
19 | int relay = 0; | ||
20 | u8 v = 0; | ||
21 | sscanf(buff, "%hhd", &v); | ||
22 | |||
23 | if (strcmp(attr->attr.name, "relay1") == 0) { | ||
24 | relay = RELAY_K1; | ||
25 | } else if (strcmp(attr->attr.name, "relay2") == 0) { | ||
26 | relay = RELAY_K2; | ||
27 | } else if (strcmp(attr->attr.name, "relay3") == 0) { | ||
28 | relay = RELAY_K3; | ||
29 | } else if (strcmp(attr->attr.name, "relay4") == 0) { | ||
30 | relay = RELAY_K4; | ||
31 | } | ||
32 | |||
33 | gpio_set_value(relay, (v == 0) ? NO_OFF : NO_ON); | ||
34 | return count; | ||
35 | } | ||
36 | |||
37 | static ssize_t get_relay(struct kobject *kobj, struct kobj_attribute *attr, char *buff) { | ||
38 | int relay = 0; | ||
39 | if (strcmp(attr->attr.name, "relay1") == 0) { | ||
40 | relay = RELAY_K1; | ||
41 | } else if (strcmp(attr->attr.name, "relay2") == 0) { | ||
42 | relay = RELAY_K2; | ||
43 | } else if (strcmp(attr->attr.name, "relay3") == 0) { | ||
44 | relay = RELAY_K3; | ||
45 | } else if (strcmp(attr->attr.name, "relay4") == 0) { | ||
46 | relay = RELAY_K4; | ||
47 | } | ||
48 | return sprintf(buff, "%d", gpio_get_value(relay)); | ||
49 | } | ||
50 | |||
51 | static struct kobj_attribute relay1_attribute = __ATTR(relay1, (S_IWUSR | S_IRUGO), get_relay, set_relay); | ||
52 | static struct kobj_attribute relay2_attribute = __ATTR(relay2, (S_IWUSR | S_IRUGO), get_relay, set_relay); | ||
53 | static struct kobj_attribute relay3_attribute = __ATTR(relay3, (S_IWUSR | S_IRUGO), get_relay, set_relay); | ||
54 | static struct kobj_attribute relay4_attribute = __ATTR(relay4, (S_IWUSR | S_IRUGO), get_relay, set_relay); | ||
55 | |||
56 | static int __init relay_init(void) { | ||
57 | gpio_request(RELAY_K1, "RELAY_K1"); | ||
58 | gpio_request(RELAY_K2, "RELAY_K2"); | ||
59 | gpio_request(RELAY_K3, "RELAY_K3"); | ||
60 | gpio_request(RELAY_K4, "RELAY_K4"); | ||
61 | |||
62 | gpio_direction_output(RELAY_K1, NO_ON); | ||
63 | gpio_direction_output(RELAY_K2, NO_ON); | ||
64 | gpio_direction_output(RELAY_K3, NO_ON); | ||
65 | gpio_direction_output(RELAY_K4, NO_ON); | ||
66 | |||
67 | relay_kobject = kobject_create_and_add("relay", NULL); | ||
68 | |||
69 | if (sysfs_create_file(relay_kobject, &relay1_attribute.attr)) { | ||
70 | pr_debug("failed to create relay1 sysfs!\n"); | ||
71 | } | ||
72 | if (sysfs_create_file(relay_kobject, &relay2_attribute.attr)) { | ||
73 | pr_debug("failed to create relay2 sysfs!\n"); | ||
74 | } | ||
75 | if (sysfs_create_file(relay_kobject, &relay3_attribute.attr)) { | ||
76 | pr_debug("failed to create relay3 sysfs!\n"); | ||
77 | } | ||
78 | if (sysfs_create_file(relay_kobject, &relay4_attribute.attr)) { | ||
79 | pr_debug("failed to create relay4 sysfs!\n"); | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static void __exit relay_exit(void) { | ||
86 | kobject_put(relay_kobject); | ||
87 | |||
88 | gpio_free(RELAY_K1); | ||
89 | gpio_free(RELAY_K2); | ||
90 | gpio_free(RELAY_K3); | ||
91 | gpio_free(RELAY_K4); | ||
92 | } | ||
93 | |||
94 | module_init(relay_init); | ||
95 | module_exit(relay_exit); | ||