diff options
Diffstat (limited to 'pix_driver.c')
-rw-r--r-- | pix_driver.c | 258 |
1 files changed, 258 insertions, 0 deletions
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 | |||