diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/lcd.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/lcd.c')
-rw-r--r-- | drivers/char/lcd.c | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c new file mode 100644 index 000000000000..cf01a720eb2e --- /dev/null +++ b/drivers/char/lcd.c | |||
@@ -0,0 +1,683 @@ | |||
1 | /* | ||
2 | * LCD, LED and Button interface for Cobalt | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 1996, 1997 by Andrew Bose | ||
9 | * | ||
10 | * Linux kernel version history: | ||
11 | * March 2001: Ported from 2.0.34 by Liam Davies | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #define RTC_IO_EXTENT 0x10 /*Only really two ports, but... */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/ioport.h> | ||
23 | #include <linux/fcntl.h> | ||
24 | #include <linux/mc146818rtc.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | #include <asm/system.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #include "lcd.h" | ||
35 | |||
36 | static DEFINE_SPINLOCK(lcd_lock); | ||
37 | |||
38 | static int lcd_ioctl(struct inode *inode, struct file *file, | ||
39 | unsigned int cmd, unsigned long arg); | ||
40 | |||
41 | static unsigned int lcd_present = 1; | ||
42 | |||
43 | /* used in arch/mips/cobalt/reset.c */ | ||
44 | int led_state = 0; | ||
45 | |||
46 | #if defined(CONFIG_TULIP) && 0 | ||
47 | |||
48 | #define MAX_INTERFACES 8 | ||
49 | static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES]; | ||
50 | static void *linkcheck_cookies[MAX_INTERFACES]; | ||
51 | |||
52 | int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie) | ||
53 | { | ||
54 | if (iface_num < 0 || | ||
55 | iface_num >= MAX_INTERFACES || | ||
56 | linkcheck_callbacks[iface_num] != NULL) | ||
57 | return -1; | ||
58 | linkcheck_callbacks[iface_num] = (linkcheck_func_t) func; | ||
59 | linkcheck_cookies[iface_num] = cookie; | ||
60 | return 0; | ||
61 | } | ||
62 | #endif | ||
63 | |||
64 | static int lcd_ioctl(struct inode *inode, struct file *file, | ||
65 | unsigned int cmd, unsigned long arg) | ||
66 | { | ||
67 | struct lcd_display button_display; | ||
68 | unsigned long address, a; | ||
69 | |||
70 | switch (cmd) { | ||
71 | case LCD_On: | ||
72 | udelay(150); | ||
73 | BusyCheck(); | ||
74 | LCDWriteInst(0x0F); | ||
75 | break; | ||
76 | |||
77 | case LCD_Off: | ||
78 | udelay(150); | ||
79 | BusyCheck(); | ||
80 | LCDWriteInst(0x08); | ||
81 | break; | ||
82 | |||
83 | case LCD_Reset: | ||
84 | udelay(150); | ||
85 | LCDWriteInst(0x3F); | ||
86 | udelay(150); | ||
87 | LCDWriteInst(0x3F); | ||
88 | udelay(150); | ||
89 | LCDWriteInst(0x3F); | ||
90 | udelay(150); | ||
91 | LCDWriteInst(0x3F); | ||
92 | udelay(150); | ||
93 | LCDWriteInst(0x01); | ||
94 | udelay(150); | ||
95 | LCDWriteInst(0x06); | ||
96 | break; | ||
97 | |||
98 | case LCD_Clear: | ||
99 | udelay(150); | ||
100 | BusyCheck(); | ||
101 | LCDWriteInst(0x01); | ||
102 | break; | ||
103 | |||
104 | case LCD_Cursor_Left: | ||
105 | udelay(150); | ||
106 | BusyCheck(); | ||
107 | LCDWriteInst(0x10); | ||
108 | break; | ||
109 | |||
110 | case LCD_Cursor_Right: | ||
111 | udelay(150); | ||
112 | BusyCheck(); | ||
113 | LCDWriteInst(0x14); | ||
114 | break; | ||
115 | |||
116 | case LCD_Cursor_Off: | ||
117 | udelay(150); | ||
118 | BusyCheck(); | ||
119 | LCDWriteInst(0x0C); | ||
120 | break; | ||
121 | |||
122 | case LCD_Cursor_On: | ||
123 | udelay(150); | ||
124 | BusyCheck(); | ||
125 | LCDWriteInst(0x0F); | ||
126 | break; | ||
127 | |||
128 | case LCD_Blink_Off: | ||
129 | udelay(150); | ||
130 | BusyCheck(); | ||
131 | LCDWriteInst(0x0E); | ||
132 | break; | ||
133 | |||
134 | case LCD_Get_Cursor_Pos:{ | ||
135 | struct lcd_display display; | ||
136 | |||
137 | udelay(150); | ||
138 | BusyCheck(); | ||
139 | display.cursor_address = (LCDReadInst); | ||
140 | display.cursor_address = | ||
141 | (display.cursor_address & 0x07F); | ||
142 | if (copy_to_user | ||
143 | ((struct lcd_display *) arg, &display, | ||
144 | sizeof(struct lcd_display))) | ||
145 | return -EFAULT; | ||
146 | |||
147 | break; | ||
148 | } | ||
149 | |||
150 | |||
151 | case LCD_Set_Cursor_Pos:{ | ||
152 | struct lcd_display display; | ||
153 | |||
154 | if (copy_from_user | ||
155 | (&display, (struct lcd_display *) arg, | ||
156 | sizeof(struct lcd_display))) | ||
157 | return -EFAULT; | ||
158 | |||
159 | a = (display.cursor_address | kLCD_Addr); | ||
160 | |||
161 | udelay(150); | ||
162 | BusyCheck(); | ||
163 | LCDWriteInst(a); | ||
164 | |||
165 | break; | ||
166 | } | ||
167 | |||
168 | case LCD_Get_Cursor:{ | ||
169 | struct lcd_display display; | ||
170 | |||
171 | udelay(150); | ||
172 | BusyCheck(); | ||
173 | display.character = LCDReadData; | ||
174 | |||
175 | if (copy_to_user | ||
176 | ((struct lcd_display *) arg, &display, | ||
177 | sizeof(struct lcd_display))) | ||
178 | return -EFAULT; | ||
179 | udelay(150); | ||
180 | BusyCheck(); | ||
181 | LCDWriteInst(0x10); | ||
182 | |||
183 | break; | ||
184 | } | ||
185 | |||
186 | case LCD_Set_Cursor:{ | ||
187 | struct lcd_display display; | ||
188 | |||
189 | if (copy_from_user | ||
190 | (&display, (struct lcd_display *) arg, | ||
191 | sizeof(struct lcd_display))) | ||
192 | return -EFAULT; | ||
193 | |||
194 | udelay(150); | ||
195 | BusyCheck(); | ||
196 | LCDWriteData(display.character); | ||
197 | udelay(150); | ||
198 | BusyCheck(); | ||
199 | LCDWriteInst(0x10); | ||
200 | |||
201 | break; | ||
202 | } | ||
203 | |||
204 | |||
205 | case LCD_Disp_Left: | ||
206 | udelay(150); | ||
207 | BusyCheck(); | ||
208 | LCDWriteInst(0x18); | ||
209 | break; | ||
210 | |||
211 | case LCD_Disp_Right: | ||
212 | udelay(150); | ||
213 | BusyCheck(); | ||
214 | LCDWriteInst(0x1C); | ||
215 | break; | ||
216 | |||
217 | case LCD_Home: | ||
218 | udelay(150); | ||
219 | BusyCheck(); | ||
220 | LCDWriteInst(0x02); | ||
221 | break; | ||
222 | |||
223 | case LCD_Write:{ | ||
224 | struct lcd_display display; | ||
225 | unsigned int index; | ||
226 | |||
227 | |||
228 | if (copy_from_user | ||
229 | (&display, (struct lcd_display *) arg, | ||
230 | sizeof(struct lcd_display))) | ||
231 | return -EFAULT; | ||
232 | |||
233 | udelay(150); | ||
234 | BusyCheck(); | ||
235 | LCDWriteInst(0x80); | ||
236 | udelay(150); | ||
237 | BusyCheck(); | ||
238 | |||
239 | for (index = 0; index < (display.size1); index++) { | ||
240 | udelay(150); | ||
241 | BusyCheck(); | ||
242 | LCDWriteData(display.line1[index]); | ||
243 | BusyCheck(); | ||
244 | } | ||
245 | |||
246 | udelay(150); | ||
247 | BusyCheck(); | ||
248 | LCDWriteInst(0xC0); | ||
249 | udelay(150); | ||
250 | BusyCheck(); | ||
251 | for (index = 0; index < (display.size2); index++) { | ||
252 | udelay(150); | ||
253 | BusyCheck(); | ||
254 | LCDWriteData(display.line2[index]); | ||
255 | } | ||
256 | |||
257 | break; | ||
258 | } | ||
259 | |||
260 | case LCD_Read:{ | ||
261 | struct lcd_display display; | ||
262 | |||
263 | BusyCheck(); | ||
264 | for (address = kDD_R00; address <= kDD_R01; | ||
265 | address++) { | ||
266 | a = (address | kLCD_Addr); | ||
267 | |||
268 | udelay(150); | ||
269 | BusyCheck(); | ||
270 | LCDWriteInst(a); | ||
271 | udelay(150); | ||
272 | BusyCheck(); | ||
273 | display.line1[address] = LCDReadData; | ||
274 | } | ||
275 | |||
276 | display.line1[0x27] = '\0'; | ||
277 | |||
278 | for (address = kDD_R10; address <= kDD_R11; | ||
279 | address++) { | ||
280 | a = (address | kLCD_Addr); | ||
281 | |||
282 | udelay(150); | ||
283 | BusyCheck(); | ||
284 | LCDWriteInst(a); | ||
285 | |||
286 | udelay(150); | ||
287 | BusyCheck(); | ||
288 | display.line2[address - 0x40] = | ||
289 | LCDReadData; | ||
290 | } | ||
291 | |||
292 | display.line2[0x27] = '\0'; | ||
293 | |||
294 | if (copy_to_user | ||
295 | ((struct lcd_display *) arg, &display, | ||
296 | sizeof(struct lcd_display))) | ||
297 | return -EFAULT; | ||
298 | break; | ||
299 | } | ||
300 | |||
301 | // set all GPIO leds to led_display.leds | ||
302 | |||
303 | case LED_Set:{ | ||
304 | struct lcd_display led_display; | ||
305 | |||
306 | |||
307 | if (copy_from_user | ||
308 | (&led_display, (struct lcd_display *) arg, | ||
309 | sizeof(struct lcd_display))) | ||
310 | return -EFAULT; | ||
311 | |||
312 | led_state = led_display.leds; | ||
313 | LEDSet(led_state); | ||
314 | |||
315 | break; | ||
316 | } | ||
317 | |||
318 | |||
319 | // set only bit led_display.leds | ||
320 | |||
321 | case LED_Bit_Set:{ | ||
322 | unsigned int i; | ||
323 | int bit = 1; | ||
324 | struct lcd_display led_display; | ||
325 | |||
326 | |||
327 | if (copy_from_user | ||
328 | (&led_display, (struct lcd_display *) arg, | ||
329 | sizeof(struct lcd_display))) | ||
330 | return -EFAULT; | ||
331 | |||
332 | for (i = 0; i < (int) led_display.leds; i++) { | ||
333 | bit = 2 * bit; | ||
334 | } | ||
335 | |||
336 | led_state = led_state | bit; | ||
337 | LEDSet(led_state); | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | // clear only bit led_display.leds | ||
342 | |||
343 | case LED_Bit_Clear:{ | ||
344 | unsigned int i; | ||
345 | int bit = 1; | ||
346 | struct lcd_display led_display; | ||
347 | |||
348 | |||
349 | if (copy_from_user | ||
350 | (&led_display, (struct lcd_display *) arg, | ||
351 | sizeof(struct lcd_display))) | ||
352 | return -EFAULT; | ||
353 | |||
354 | for (i = 0; i < (int) led_display.leds; i++) { | ||
355 | bit = 2 * bit; | ||
356 | } | ||
357 | |||
358 | led_state = led_state & ~bit; | ||
359 | LEDSet(led_state); | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | |||
364 | case BUTTON_Read:{ | ||
365 | button_display.buttons = GPIRead; | ||
366 | if (copy_to_user | ||
367 | ((struct lcd_display *) arg, &button_display, | ||
368 | sizeof(struct lcd_display))) | ||
369 | return -EFAULT; | ||
370 | break; | ||
371 | } | ||
372 | |||
373 | case LINK_Check:{ | ||
374 | button_display.buttons = | ||
375 | *((volatile unsigned long *) (0xB0100060)); | ||
376 | if (copy_to_user | ||
377 | ((struct lcd_display *) arg, &button_display, | ||
378 | sizeof(struct lcd_display))) | ||
379 | return -EFAULT; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | case LINK_Check_2:{ | ||
384 | int iface_num; | ||
385 | |||
386 | /* panel-utils should pass in the desired interface status is wanted for | ||
387 | * in "buttons" of the structure. We will set this to non-zero if the | ||
388 | * link is in fact up for the requested interface. --DaveM | ||
389 | */ | ||
390 | if (copy_from_user | ||
391 | (&button_display, (struct lcd_display *) arg, | ||
392 | sizeof(button_display))) | ||
393 | return -EFAULT; | ||
394 | iface_num = button_display.buttons; | ||
395 | #if defined(CONFIG_TULIP) && 0 | ||
396 | if (iface_num >= 0 && | ||
397 | iface_num < MAX_INTERFACES && | ||
398 | linkcheck_callbacks[iface_num] != NULL) { | ||
399 | button_display.buttons = | ||
400 | linkcheck_callbacks[iface_num] | ||
401 | (linkcheck_cookies[iface_num]); | ||
402 | } else | ||
403 | #endif | ||
404 | button_display.buttons = 0; | ||
405 | |||
406 | if (__copy_to_user | ||
407 | ((struct lcd_display *) arg, &button_display, | ||
408 | sizeof(struct lcd_display))) | ||
409 | return -EFAULT; | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | // Erase the flash | ||
414 | |||
415 | case FLASH_Erase:{ | ||
416 | |||
417 | int ctr = 0; | ||
418 | |||
419 | if ( !capable(CAP_SYS_ADMIN) ) return -EPERM; | ||
420 | |||
421 | pr_info(LCD "Erasing Flash\n"); | ||
422 | |||
423 | // Chip Erase Sequence | ||
424 | WRITE_FLASH(kFlash_Addr1, kFlash_Data1); | ||
425 | WRITE_FLASH(kFlash_Addr2, kFlash_Data2); | ||
426 | WRITE_FLASH(kFlash_Addr1, kFlash_Erase3); | ||
427 | WRITE_FLASH(kFlash_Addr1, kFlash_Data1); | ||
428 | WRITE_FLASH(kFlash_Addr2, kFlash_Data2); | ||
429 | WRITE_FLASH(kFlash_Addr1, kFlash_Erase6); | ||
430 | |||
431 | while ((!dqpoll(0x00000000, 0xFF)) | ||
432 | && (!timeout(0x00000000))) { | ||
433 | ctr++; | ||
434 | } | ||
435 | |||
436 | if (READ_FLASH(0x07FFF0) == 0xFF) { | ||
437 | pr_info(LCD "Erase Successful\n"); | ||
438 | } else if (timeout) { | ||
439 | pr_info(LCD "Erase Timed Out\n"); | ||
440 | } | ||
441 | |||
442 | break; | ||
443 | } | ||
444 | |||
445 | // burn the flash | ||
446 | |||
447 | case FLASH_Burn:{ | ||
448 | |||
449 | volatile unsigned long burn_addr; | ||
450 | unsigned long flags; | ||
451 | unsigned int i, index; | ||
452 | unsigned char *rom; | ||
453 | |||
454 | |||
455 | struct lcd_display display; | ||
456 | |||
457 | if ( !capable(CAP_SYS_ADMIN) ) return -EPERM; | ||
458 | |||
459 | if (copy_from_user | ||
460 | (&display, (struct lcd_display *) arg, | ||
461 | sizeof(struct lcd_display))) | ||
462 | return -EFAULT; | ||
463 | rom = (unsigned char *) kmalloc((128), GFP_ATOMIC); | ||
464 | if (rom == NULL) { | ||
465 | printk(KERN_ERR LCD "kmalloc() failed in %s\n", | ||
466 | __FUNCTION__); | ||
467 | return -ENOMEM; | ||
468 | } | ||
469 | |||
470 | pr_info(LCD "Starting Flash burn\n"); | ||
471 | for (i = 0; i < FLASH_SIZE; i = i + 128) { | ||
472 | |||
473 | if (copy_from_user | ||
474 | (rom, display.RomImage + i, 128)) { | ||
475 | kfree(rom); | ||
476 | return -EFAULT; | ||
477 | } | ||
478 | burn_addr = kFlashBase + i; | ||
479 | spin_lock_irqsave(&lcd_lock, flags); | ||
480 | for (index = 0; index < (128); index++) { | ||
481 | |||
482 | WRITE_FLASH(kFlash_Addr1, | ||
483 | kFlash_Data1); | ||
484 | WRITE_FLASH(kFlash_Addr2, | ||
485 | kFlash_Data2); | ||
486 | WRITE_FLASH(kFlash_Addr1, | ||
487 | kFlash_Prog); | ||
488 | *((volatile unsigned char *)burn_addr) = | ||
489 | (volatile unsigned char) rom[index]; | ||
490 | |||
491 | while ((!dqpoll (burn_addr, | ||
492 | (volatile unsigned char) | ||
493 | rom[index])) && | ||
494 | (!timeout(burn_addr))) { } | ||
495 | burn_addr++; | ||
496 | } | ||
497 | spin_unlock_irqrestore(&lcd_lock, flags); | ||
498 | if (* ((volatile unsigned char *) | ||
499 | (burn_addr - 1)) == | ||
500 | (volatile unsigned char) | ||
501 | rom[index - 1]) { | ||
502 | } else if (timeout) { | ||
503 | pr_info(LCD "Flash burn timed out\n"); | ||
504 | } | ||
505 | |||
506 | |||
507 | } | ||
508 | kfree(rom); | ||
509 | |||
510 | pr_info(LCD "Flash successfully burned\n"); | ||
511 | |||
512 | break; | ||
513 | } | ||
514 | |||
515 | // read the flash all at once | ||
516 | |||
517 | case FLASH_Read:{ | ||
518 | |||
519 | unsigned char *user_bytes; | ||
520 | volatile unsigned long read_addr; | ||
521 | unsigned int i; | ||
522 | |||
523 | user_bytes = | ||
524 | &(((struct lcd_display *) arg)->RomImage[0]); | ||
525 | |||
526 | if (!access_ok | ||
527 | (VERIFY_WRITE, user_bytes, FLASH_SIZE)) | ||
528 | return -EFAULT; | ||
529 | |||
530 | pr_info(LCD "Reading Flash"); | ||
531 | for (i = 0; i < FLASH_SIZE; i++) { | ||
532 | unsigned char tmp_byte; | ||
533 | read_addr = kFlashBase + i; | ||
534 | tmp_byte = | ||
535 | *((volatile unsigned char *) | ||
536 | read_addr); | ||
537 | if (__put_user(tmp_byte, &user_bytes[i])) | ||
538 | return -EFAULT; | ||
539 | } | ||
540 | |||
541 | |||
542 | break; | ||
543 | } | ||
544 | |||
545 | default: | ||
546 | return -EINVAL; | ||
547 | |||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | |||
552 | } | ||
553 | |||
554 | static int lcd_open(struct inode *inode, struct file *file) | ||
555 | { | ||
556 | if (!lcd_present) | ||
557 | return -ENXIO; | ||
558 | else | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | /* Only RESET or NEXT counts as button pressed */ | ||
563 | |||
564 | static inline int button_pressed(void) | ||
565 | { | ||
566 | unsigned long buttons = GPIRead; | ||
567 | |||
568 | if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B) | ||
569 | || (buttons == BUTTON_Reset_B)) | ||
570 | return buttons; | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | /* LED daemon sits on this and we wake him up once a key is pressed. */ | ||
575 | |||
576 | static int lcd_waiters = 0; | ||
577 | |||
578 | static long lcd_read(struct inode *inode, struct file *file, char *buf, | ||
579 | unsigned long count) | ||
580 | { | ||
581 | long buttons_now; | ||
582 | |||
583 | if (lcd_waiters > 0) | ||
584 | return -EINVAL; | ||
585 | |||
586 | lcd_waiters++; | ||
587 | while (((buttons_now = (long) button_pressed()) == 0) && | ||
588 | !(signal_pending(current))) { | ||
589 | msleep_interruptible(2000); | ||
590 | } | ||
591 | lcd_waiters--; | ||
592 | |||
593 | if (signal_pending(current)) | ||
594 | return -ERESTARTSYS; | ||
595 | return buttons_now; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * The various file operations we support. | ||
600 | */ | ||
601 | |||
602 | static struct file_operations lcd_fops = { | ||
603 | .read = lcd_read, | ||
604 | .ioctl = lcd_ioctl, | ||
605 | .open = lcd_open, | ||
606 | }; | ||
607 | |||
608 | static struct miscdevice lcd_dev = { | ||
609 | MISC_DYNAMIC_MINOR, | ||
610 | "lcd", | ||
611 | &lcd_fops | ||
612 | }; | ||
613 | |||
614 | static int lcd_init(void) | ||
615 | { | ||
616 | unsigned long data; | ||
617 | |||
618 | pr_info("%s\n", LCD_DRIVER); | ||
619 | misc_register(&lcd_dev); | ||
620 | |||
621 | /* Check region? Naaah! Just snarf it up. */ | ||
622 | /* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ | ||
623 | |||
624 | udelay(150); | ||
625 | data = LCDReadData; | ||
626 | if ((data & 0x000000FF) == (0x00)) { | ||
627 | lcd_present = 0; | ||
628 | pr_info(LCD "LCD Not Present\n"); | ||
629 | } else { | ||
630 | lcd_present = 1; | ||
631 | WRITE_GAL(kGal_DevBank2PReg, kGal_DevBank2Cfg); | ||
632 | WRITE_GAL(kGal_DevBank3PReg, kGal_DevBank3Cfg); | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static void __exit lcd_exit(void) | ||
639 | { | ||
640 | misc_deregister(&lcd_dev); | ||
641 | } | ||
642 | |||
643 | // | ||
644 | // Function: dqpoll | ||
645 | // | ||
646 | // Description: Polls the data lines to see if the flash is busy | ||
647 | // | ||
648 | // In: address, byte data | ||
649 | // | ||
650 | // Out: 0 = busy, 1 = write or erase complete | ||
651 | // | ||
652 | // | ||
653 | |||
654 | static int dqpoll(volatile unsigned long address, volatile unsigned char data) | ||
655 | { | ||
656 | volatile unsigned char dq7; | ||
657 | |||
658 | dq7 = data & 0x80; | ||
659 | |||
660 | return ((READ_FLASH(address) & 0x80) == dq7); | ||
661 | } | ||
662 | |||
663 | // | ||
664 | // Function: timeout | ||
665 | // | ||
666 | // Description: Checks to see if erase or write has timed out | ||
667 | // By polling dq5 | ||
668 | // | ||
669 | // In: address | ||
670 | // | ||
671 | // | ||
672 | // Out: 0 = not timed out, 1 = timed out | ||
673 | |||
674 | static int timeout(volatile unsigned long address) | ||
675 | { | ||
676 | return (READ_FLASH(address) & 0x20) == 0x20; | ||
677 | } | ||
678 | |||
679 | module_init(lcd_init); | ||
680 | module_exit(lcd_exit); | ||
681 | |||
682 | MODULE_AUTHOR("Andrew Bose"); | ||
683 | MODULE_LICENSE("GPL"); | ||