]>
Commit | Line | Data |
---|---|---|
a45b8395 BH |
1 | /* |
2 | * Drivers for the Total Impact PPC based computer "BRIQ" | |
3 | * by Dr. Karsten Jeppesen | |
4 | * | |
5 | */ | |
6 | ||
7 | #include <linux/module.h> | |
8 | ||
9 | #include <linux/types.h> | |
10 | #include <linux/errno.h> | |
11 | #include <linux/sched.h> | |
12 | #include <linux/tty.h> | |
13 | #include <linux/timer.h> | |
14 | #include <linux/config.h> | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/wait.h> | |
17 | #include <linux/string.h> | |
18 | #include <linux/slab.h> | |
19 | #include <linux/ioport.h> | |
20 | #include <linux/delay.h> | |
21 | #include <linux/miscdevice.h> | |
22 | #include <linux/fs.h> | |
23 | #include <linux/mm.h> | |
24 | #include <linux/init.h> | |
25 | ||
26 | #include <asm/uaccess.h> | |
27 | #include <asm/io.h> | |
28 | #include <asm/prom.h> | |
29 | ||
30 | #define BRIQ_PANEL_MINOR 156 | |
31 | #define BRIQ_PANEL_VFD_IOPORT 0x0390 | |
32 | #define BRIQ_PANEL_LED_IOPORT 0x0398 | |
33 | #define BRIQ_PANEL_VER "1.1 (04/20/2002)" | |
34 | #define BRIQ_PANEL_MSG0 "Loading Linux" | |
35 | ||
36 | static int vfd_is_open; | |
37 | static unsigned char vfd[40]; | |
38 | static int vfd_cursor; | |
39 | static unsigned char ledpb, led; | |
40 | ||
41 | static void update_vfd(void) | |
42 | { | |
43 | int i; | |
44 | ||
45 | /* cursor home */ | |
46 | outb(0x02, BRIQ_PANEL_VFD_IOPORT); | |
47 | for (i=0; i<20; i++) | |
48 | outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); | |
49 | ||
50 | /* cursor to next line */ | |
51 | outb(0xc0, BRIQ_PANEL_VFD_IOPORT); | |
52 | for (i=20; i<40; i++) | |
53 | outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1); | |
54 | ||
55 | } | |
56 | ||
57 | static void set_led(char state) | |
58 | { | |
59 | if (state == 'R') | |
60 | led = 0x01; | |
61 | else if (state == 'G') | |
62 | led = 0x02; | |
63 | else if (state == 'Y') | |
64 | led = 0x03; | |
65 | else if (state == 'X') | |
66 | led = 0x00; | |
67 | outb(led, BRIQ_PANEL_LED_IOPORT); | |
68 | } | |
69 | ||
70 | static int briq_panel_open(struct inode *ino, struct file *filep) | |
71 | { | |
72 | /* enforce single access */ | |
73 | if (vfd_is_open) | |
74 | return -EBUSY; | |
75 | vfd_is_open = 1; | |
76 | ||
77 | return 0; | |
78 | } | |
79 | ||
80 | static int briq_panel_release(struct inode *ino, struct file *filep) | |
81 | { | |
82 | if (!vfd_is_open) | |
83 | return -ENODEV; | |
84 | ||
85 | vfd_is_open = 0; | |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | static ssize_t briq_panel_read(struct file *file, char *buf, size_t count, | |
91 | loff_t *ppos) | |
92 | { | |
93 | unsigned short c; | |
94 | unsigned char cp; | |
95 | ||
96 | #if 0 /* Can't seek (pread) on this device */ | |
97 | if (ppos != &file->f_pos) | |
98 | return -ESPIPE; | |
99 | #endif | |
100 | ||
101 | if (!vfd_is_open) | |
102 | return -ENODEV; | |
103 | ||
104 | c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003); | |
105 | set_led(' '); | |
106 | /* upper button released */ | |
107 | if ((!(ledpb & 0x0004)) && (c & 0x0004)) { | |
108 | cp = ' '; | |
109 | ledpb = c; | |
110 | if (copy_to_user(buf, &cp, 1)) | |
111 | return -EFAULT; | |
112 | return 1; | |
113 | } | |
114 | /* lower button released */ | |
115 | else if ((!(ledpb & 0x0008)) && (c & 0x0008)) { | |
116 | cp = '\r'; | |
117 | ledpb = c; | |
118 | if (copy_to_user(buf, &cp, 1)) | |
119 | return -EFAULT; | |
120 | return 1; | |
121 | } else { | |
122 | ledpb = c; | |
123 | return 0; | |
124 | } | |
125 | } | |
126 | ||
127 | static void scroll_vfd( void ) | |
128 | { | |
129 | int i; | |
130 | ||
131 | for (i=0; i<20; i++) { | |
132 | vfd[i] = vfd[i+20]; | |
133 | vfd[i+20] = ' '; | |
134 | } | |
135 | vfd_cursor = 20; | |
136 | } | |
137 | ||
138 | static ssize_t briq_panel_write(struct file *file, const char *buf, size_t len, | |
139 | loff_t *ppos) | |
140 | { | |
141 | size_t indx = len; | |
142 | int i, esc = 0; | |
143 | ||
144 | #if 0 /* Can't seek (pwrite) on this device */ | |
145 | if (ppos != &file->f_pos) | |
146 | return -ESPIPE; | |
147 | #endif | |
148 | ||
149 | if (!vfd_is_open) | |
150 | return -EBUSY; | |
151 | ||
152 | for (;;) { | |
153 | if (!indx) | |
154 | break; | |
155 | if (esc) { | |
156 | set_led(*buf); | |
157 | esc = 0; | |
158 | } else if (*buf == 27) { | |
159 | esc = 1; | |
160 | } else if (*buf == 12) { | |
161 | /* do a form feed */ | |
162 | for (i=0; i<40; i++) | |
163 | vfd[i] = ' '; | |
164 | vfd_cursor = 0; | |
165 | } else if (*buf == 10) { | |
166 | if (vfd_cursor < 20) | |
167 | vfd_cursor = 20; | |
168 | else if (vfd_cursor < 40) | |
169 | vfd_cursor = 40; | |
170 | else if (vfd_cursor < 60) | |
171 | vfd_cursor = 60; | |
172 | if (vfd_cursor > 59) | |
173 | scroll_vfd(); | |
174 | } else { | |
175 | /* just a character */ | |
176 | if (vfd_cursor > 39) | |
177 | scroll_vfd(); | |
178 | vfd[vfd_cursor++] = *buf; | |
179 | } | |
180 | indx--; | |
181 | buf++; | |
182 | } | |
183 | update_vfd(); | |
184 | ||
185 | return len; | |
186 | } | |
187 | ||
188 | static struct file_operations briq_panel_fops = { | |
189 | .owner = THIS_MODULE, | |
190 | .read = briq_panel_read, | |
191 | .write = briq_panel_write, | |
192 | .open = briq_panel_open, | |
193 | .release = briq_panel_release, | |
194 | }; | |
195 | ||
196 | static struct miscdevice briq_panel_miscdev = { | |
197 | BRIQ_PANEL_MINOR, | |
198 | "briq_panel", | |
199 | &briq_panel_fops | |
200 | }; | |
201 | ||
202 | static int __init briq_panel_init(void) | |
203 | { | |
204 | struct device_node *root = find_path_device("/"); | |
205 | char *machine; | |
206 | int i; | |
207 | ||
208 | machine = get_property(root, "model", NULL); | |
209 | if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) | |
210 | return -ENODEV; | |
211 | ||
212 | printk(KERN_INFO | |
213 | "briq_panel: v%s Dr. Karsten Jeppesen ([email protected])\n", | |
214 | BRIQ_PANEL_VER); | |
215 | ||
216 | if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel")) | |
217 | return -EBUSY; | |
218 | ||
219 | if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) { | |
220 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | |
221 | return -EBUSY; | |
222 | } | |
223 | ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c; | |
224 | ||
225 | if (misc_register(&briq_panel_miscdev) < 0) { | |
226 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | |
227 | release_region(BRIQ_PANEL_LED_IOPORT, 2); | |
228 | return -EBUSY; | |
229 | } | |
230 | ||
231 | outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */ | |
232 | outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */ | |
233 | outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */ | |
234 | outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */ | |
235 | for (i=0; i<40; i++) | |
236 | vfd[i]=' '; | |
237 | #ifndef MODULE | |
238 | vfd[0] = 'L'; | |
239 | vfd[1] = 'o'; | |
240 | vfd[2] = 'a'; | |
241 | vfd[3] = 'd'; | |
242 | vfd[4] = 'i'; | |
243 | vfd[5] = 'n'; | |
244 | vfd[6] = 'g'; | |
245 | vfd[7] = ' '; | |
246 | vfd[8] = '.'; | |
247 | vfd[9] = '.'; | |
248 | vfd[10] = '.'; | |
249 | #endif /* !MODULE */ | |
250 | ||
251 | update_vfd(); | |
252 | ||
253 | return 0; | |
254 | } | |
255 | ||
256 | static void __exit briq_panel_exit(void) | |
257 | { | |
258 | misc_deregister(&briq_panel_miscdev); | |
259 | release_region(BRIQ_PANEL_VFD_IOPORT, 4); | |
260 | release_region(BRIQ_PANEL_LED_IOPORT, 2); | |
261 | } | |
262 | ||
263 | module_init(briq_panel_init); | |
264 | module_exit(briq_panel_exit); | |
265 | ||
266 | MODULE_LICENSE("GPL"); | |
267 | MODULE_AUTHOR("Karsten Jeppesen <[email protected]>"); | |
268 | MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel"); |