1/* 2 * /dev/lcd driver for Apple Network Servers. 3 */ 4 5#include <linux/types.h> 6#include <linux/errno.h> 7#include <linux/kernel.h> 8#include <linux/miscdevice.h> 9#include <linux/fcntl.h> 10#include <linux/init.h> 11#include <linux/delay.h> 12#include <asm/uaccess.h> 13#include <asm/sections.h> 14#include <asm/prom.h> 15#include <asm/ans-lcd.h> 16#include <asm/io.h> 17 18#define ANSLCD_ADDR 0xf301c000 19#define ANSLCD_CTRL_IX 0x00 20#define ANSLCD_DATA_IX 0x10 21 22static unsigned long anslcd_short_delay = 80; 23static unsigned long anslcd_long_delay = 3280; 24static volatile unsigned char* anslcd_ptr; 25 26#undef DEBUG 27 28static void __pmac 29anslcd_write_byte_ctrl ( unsigned char c ) 30{ 31#ifdef DEBUG 32 printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c); 33#endif 34 out_8(anslcd_ptr + ANSLCD_CTRL_IX, c); 35 switch(c) { 36 case 1: 37 case 2: 38 case 3: 39 udelay(anslcd_long_delay); break; 40 default: udelay(anslcd_short_delay); 41 } 42} 43 44static void __pmac 45anslcd_write_byte_data ( unsigned char c ) 46{ 47 out_8(anslcd_ptr + ANSLCD_DATA_IX, c); 48 udelay(anslcd_short_delay); 49} 50 51static ssize_t __pmac 52anslcd_write( struct file * file, const char * buf, 53 size_t count, loff_t *ppos ) 54{ 55 const char * p = buf; 56 int i; 57 58#ifdef DEBUG 59 printk(KERN_DEBUG "LCD: write\n"); 60#endif 61 62 if ( verify_area(VERIFY_READ, buf, count) ) 63 return -EFAULT; 64 for ( i = *ppos; count > 0; ++i, ++p, --count ) 65 { 66 char c; 67 __get_user(c, p); 68 anslcd_write_byte_data( c ); 69 } 70 *ppos = i; 71 return p - buf; 72} 73 74static int __pmac 75anslcd_ioctl( struct inode * inode, struct file * file, 76 unsigned int cmd, unsigned long arg ) 77{ 78 char ch, *temp; 79 80#ifdef DEBUG 81 printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg); 82#endif 83 84 switch ( cmd ) 85 { 86 case ANSLCD_CLEAR: 87 anslcd_write_byte_ctrl ( 0x38 ); 88 anslcd_write_byte_ctrl ( 0x0f ); 89 anslcd_write_byte_ctrl ( 0x06 ); 90 anslcd_write_byte_ctrl ( 0x01 ); 91 anslcd_write_byte_ctrl ( 0x02 ); 92 return 0; 93 case ANSLCD_SENDCTRL: 94 temp = (char *) arg; 95 __get_user(ch, temp); 96 for (; ch; temp++) { 97 anslcd_write_byte_ctrl ( ch ); 98 __get_user(ch, temp); 99 } 100 return 0; 101 case ANSLCD_SETSHORTDELAY: 102 if (!capable(CAP_SYS_ADMIN)) 103 return -EACCES; 104 anslcd_short_delay=arg; 105 return 0; 106 case ANSLCD_SETLONGDELAY: 107 if (!capable(CAP_SYS_ADMIN)) 108 return -EACCES; 109 anslcd_long_delay=arg; 110 return 0; 111 default: 112 return -EINVAL; 113 } 114} 115 116static int __pmac 117anslcd_open( struct inode * inode, struct file * file ) 118{ 119 return 0; 120} 121 122struct file_operations anslcd_fops = { 123 write: anslcd_write, 124 ioctl: anslcd_ioctl, 125 open: anslcd_open, 126}; 127 128static struct miscdevice anslcd_dev = { 129 ANSLCD_MINOR, 130 "anslcd", 131 &anslcd_fops 132}; 133 134const char anslcd_logo[] = "********************" /* Line #1 */ 135 "* LINUX! *" /* Line #3 */ 136 "* Welcome to *" /* Line #2 */ 137 "********************"; /* Line #4 */ 138 139int __init 140anslcd_init(void) 141{ 142 int a; 143 struct device_node* node; 144 145 node = find_devices("lcd"); 146 if (!node || !node->parent) 147 return -ENODEV; 148 if (strcmp(node->parent->name, "gc")) 149 return -ENODEV; 150 151 anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20); 152 153 misc_register(&anslcd_dev); 154 155#ifdef DEBUG 156 printk(KERN_DEBUG "LCD: init\n"); 157#endif 158 159 anslcd_write_byte_ctrl ( 0x38 ); 160 anslcd_write_byte_ctrl ( 0x0c ); 161 anslcd_write_byte_ctrl ( 0x06 ); 162 anslcd_write_byte_ctrl ( 0x01 ); 163 anslcd_write_byte_ctrl ( 0x02 ); 164 for(a=0;a<80;a++) { 165 anslcd_write_byte_data(anslcd_logo[a]); 166 } 167 return 0; 168} 169 170__initcall(anslcd_init); 171 172