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