Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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");
684 
  This page was automatically generated by the LXR engine.