11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * /dev/lcd driver for Apple Network Servers. 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/types.h> 61da177e4SLinus Torvalds #include <linux/errno.h> 71da177e4SLinus Torvalds #include <linux/kernel.h> 81da177e4SLinus Torvalds #include <linux/miscdevice.h> 91da177e4SLinus Torvalds #include <linux/fcntl.h> 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/delay.h> 121da177e4SLinus Torvalds #include <linux/fs.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <asm/uaccess.h> 151da177e4SLinus Torvalds #include <asm/sections.h> 161da177e4SLinus Torvalds #include <asm/prom.h> 171da177e4SLinus Torvalds #include <asm/ans-lcd.h> 181da177e4SLinus Torvalds #include <asm/io.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #define ANSLCD_ADDR 0xf301c000 211da177e4SLinus Torvalds #define ANSLCD_CTRL_IX 0x00 221da177e4SLinus Torvalds #define ANSLCD_DATA_IX 0x10 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static unsigned long anslcd_short_delay = 80; 251da177e4SLinus Torvalds static unsigned long anslcd_long_delay = 3280; 261da177e4SLinus Torvalds static volatile unsigned char __iomem *anslcd_ptr; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #undef DEBUG 291da177e4SLinus Torvalds 30aacaf9bdSJon Loeliger static void 311da177e4SLinus Torvalds anslcd_write_byte_ctrl ( unsigned char c ) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds #ifdef DEBUG 341da177e4SLinus Torvalds printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c); 351da177e4SLinus Torvalds #endif 361da177e4SLinus Torvalds out_8(anslcd_ptr + ANSLCD_CTRL_IX, c); 371da177e4SLinus Torvalds switch(c) { 381da177e4SLinus Torvalds case 1: 391da177e4SLinus Torvalds case 2: 401da177e4SLinus Torvalds case 3: 411da177e4SLinus Torvalds udelay(anslcd_long_delay); break; 421da177e4SLinus Torvalds default: udelay(anslcd_short_delay); 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 46aacaf9bdSJon Loeliger static void 471da177e4SLinus Torvalds anslcd_write_byte_data ( unsigned char c ) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds out_8(anslcd_ptr + ANSLCD_DATA_IX, c); 501da177e4SLinus Torvalds udelay(anslcd_short_delay); 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds 53aacaf9bdSJon Loeliger static ssize_t 541da177e4SLinus Torvalds anslcd_write( struct file * file, const char __user * buf, 551da177e4SLinus Torvalds size_t count, loff_t *ppos ) 561da177e4SLinus Torvalds { 571da177e4SLinus Torvalds const char __user *p = buf; 581da177e4SLinus Torvalds int i; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds #ifdef DEBUG 611da177e4SLinus Torvalds printk(KERN_DEBUG "LCD: write\n"); 621da177e4SLinus Torvalds #endif 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds if (!access_ok(VERIFY_READ, buf, count)) 651da177e4SLinus Torvalds return -EFAULT; 661da177e4SLinus Torvalds for ( i = *ppos; count > 0; ++i, ++p, --count ) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds char c; 691da177e4SLinus Torvalds __get_user(c, p); 701da177e4SLinus Torvalds anslcd_write_byte_data( c ); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds *ppos = i; 731da177e4SLinus Torvalds return p - buf; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 76aacaf9bdSJon Loeliger static int 771da177e4SLinus Torvalds anslcd_ioctl( struct inode * inode, struct file * file, 781da177e4SLinus Torvalds unsigned int cmd, unsigned long arg ) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds char ch, __user *temp; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds #ifdef DEBUG 831da177e4SLinus Torvalds printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg); 841da177e4SLinus Torvalds #endif 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds switch ( cmd ) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds case ANSLCD_CLEAR: 891da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x38 ); 901da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x0f ); 911da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x06 ); 921da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x01 ); 931da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x02 ); 941da177e4SLinus Torvalds return 0; 951da177e4SLinus Torvalds case ANSLCD_SENDCTRL: 961da177e4SLinus Torvalds temp = (char __user *) arg; 971da177e4SLinus Torvalds __get_user(ch, temp); 981da177e4SLinus Torvalds for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */ 991da177e4SLinus Torvalds anslcd_write_byte_ctrl ( ch ); 1001da177e4SLinus Torvalds __get_user(ch, temp); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds return 0; 1031da177e4SLinus Torvalds case ANSLCD_SETSHORTDELAY: 1041da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 1051da177e4SLinus Torvalds return -EACCES; 1061da177e4SLinus Torvalds anslcd_short_delay=arg; 1071da177e4SLinus Torvalds return 0; 1081da177e4SLinus Torvalds case ANSLCD_SETLONGDELAY: 1091da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 1101da177e4SLinus Torvalds return -EACCES; 1111da177e4SLinus Torvalds anslcd_long_delay=arg; 1121da177e4SLinus Torvalds return 0; 1131da177e4SLinus Torvalds default: 1141da177e4SLinus Torvalds return -EINVAL; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 118aacaf9bdSJon Loeliger static int 1191da177e4SLinus Torvalds anslcd_open( struct inode * inode, struct file * file ) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds return 0; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 124fa027c2aSArjan van de Ven const struct file_operations anslcd_fops = { 1251da177e4SLinus Torvalds .write = anslcd_write, 1261da177e4SLinus Torvalds .ioctl = anslcd_ioctl, 1271da177e4SLinus Torvalds .open = anslcd_open, 1281da177e4SLinus Torvalds }; 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds static struct miscdevice anslcd_dev = { 1311da177e4SLinus Torvalds ANSLCD_MINOR, 1321da177e4SLinus Torvalds "anslcd", 1331da177e4SLinus Torvalds &anslcd_fops 1341da177e4SLinus Torvalds }; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds const char anslcd_logo[] = "********************" /* Line #1 */ 1371da177e4SLinus Torvalds "* LINUX! *" /* Line #3 */ 1381da177e4SLinus Torvalds "* Welcome to *" /* Line #2 */ 1391da177e4SLinus Torvalds "********************"; /* Line #4 */ 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds static int __init 1421da177e4SLinus Torvalds anslcd_init(void) 1431da177e4SLinus Torvalds { 1441da177e4SLinus Torvalds int a; 1451da177e4SLinus Torvalds int retval; 1461da177e4SLinus Torvalds struct device_node* node; 1471da177e4SLinus Torvalds 148*30686ba6SStephen Rothwell node = of_find_node_by_name(NULL, "lcd"); 149*30686ba6SStephen Rothwell if (!node || !node->parent || strcmp(node->parent->name, "gc")) { 150*30686ba6SStephen Rothwell of_node_put(node); 1511da177e4SLinus Torvalds return -ENODEV; 152*30686ba6SStephen Rothwell } 153*30686ba6SStephen Rothwell of_node_put(node); 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds retval = misc_register(&anslcd_dev); 1581da177e4SLinus Torvalds if(retval < 0){ 1591da177e4SLinus Torvalds printk(KERN_INFO "LCD: misc_register failed\n"); 1601da177e4SLinus Torvalds iounmap(anslcd_ptr); 1611da177e4SLinus Torvalds return retval; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds #ifdef DEBUG 1651da177e4SLinus Torvalds printk(KERN_DEBUG "LCD: init\n"); 1661da177e4SLinus Torvalds #endif 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x38 ); 1691da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x0c ); 1701da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x06 ); 1711da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x01 ); 1721da177e4SLinus Torvalds anslcd_write_byte_ctrl ( 0x02 ); 1731da177e4SLinus Torvalds for(a=0;a<80;a++) { 1741da177e4SLinus Torvalds anslcd_write_byte_data(anslcd_logo[a]); 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds static void __exit 1801da177e4SLinus Torvalds anslcd_exit(void) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds misc_deregister(&anslcd_dev); 1831da177e4SLinus Torvalds iounmap(anslcd_ptr); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds module_init(anslcd_init); 1871da177e4SLinus Torvalds module_exit(anslcd_exit); 188