more changes on original files
[linux-2.4.git] / drivers / macintosh / ans-lcd.c
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
22 static unsigned long anslcd_short_delay = 80;
23 static unsigned long anslcd_long_delay = 3280;
24 static volatile unsigned char* anslcd_ptr;
25
26 #undef DEBUG
27
28 static void __pmac
29 anslcd_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
44 static void __pmac
45 anslcd_write_byte_data ( unsigned char c )
46 {
47         out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
48         udelay(anslcd_short_delay);
49 }
50
51 static ssize_t __pmac
52 anslcd_write( struct file * file, const char * buf, 
53                                 size_t count, loff_t *ppos )
54 {
55         const char * p = buf;
56
57 #ifdef DEBUG
58         printk(KERN_DEBUG "LCD: write\n");
59 #endif
60
61         if ( verify_area(VERIFY_READ, buf, count) )
62                 return -EFAULT;
63         while (count--) {
64                 char c;
65                 if (__get_user(c, p++))
66                         return -EFAULT;
67                 anslcd_write_byte_data( c );
68         }
69         *ppos = p - buf;
70         return p - buf;
71 }
72
73 static int __pmac
74 anslcd_ioctl( struct inode * inode, struct file * file,
75                                 unsigned int cmd, unsigned long arg )
76 {
77         char ch, *temp;
78
79 #ifdef DEBUG
80         printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
81 #endif
82
83         switch ( cmd )
84         {
85         case ANSLCD_CLEAR:
86                 anslcd_write_byte_ctrl ( 0x38 );
87                 anslcd_write_byte_ctrl ( 0x0f );
88                 anslcd_write_byte_ctrl ( 0x06 );
89                 anslcd_write_byte_ctrl ( 0x01 );
90                 anslcd_write_byte_ctrl ( 0x02 );
91                 return 0;
92         case ANSLCD_SENDCTRL:
93                 temp = (char *) arg;
94                 __get_user(ch, temp);
95                 for (; ch; temp++) { /* FIXME: This is ugly, but should work, as a \0 byte is not a valid command code */
96                         anslcd_write_byte_ctrl ( ch );
97                         __get_user(ch, temp);
98                 }
99                 return 0;
100         case ANSLCD_SETSHORTDELAY:
101                 if (!capable(CAP_SYS_ADMIN))
102                         return -EACCES;
103                 anslcd_short_delay=arg;
104                 return 0;
105         case ANSLCD_SETLONGDELAY:
106                 if (!capable(CAP_SYS_ADMIN))
107                         return -EACCES;
108                 anslcd_long_delay=arg;
109                 return 0;
110         default:
111                 return -EINVAL;
112         }
113 }
114
115 static int __pmac
116 anslcd_open( struct inode * inode, struct file * file )
117 {
118         return 0;
119 }
120
121 struct file_operations anslcd_fops = {
122         write:  anslcd_write,
123         ioctl:  anslcd_ioctl,
124         open:   anslcd_open,
125 };
126
127 static struct miscdevice anslcd_dev = {
128         ANSLCD_MINOR,
129         "anslcd",
130         &anslcd_fops
131 };
132
133 const char anslcd_logo[] =      "********************"  /* Line #1 */
134                                 "*      LINUX!      *"  /* Line #3 */
135                                 "*    Welcome to    *"  /* Line #2 */
136                                 "********************"; /* Line #4 */
137
138 int __init
139 anslcd_init(void)
140 {
141         int a;
142         struct device_node* node;
143
144         node = find_devices("lcd");
145         if (!node || !node->parent)
146                 return -ENODEV;
147         if (strcmp(node->parent->name, "gc"))
148                 return -ENODEV;
149
150         anslcd_ptr = (volatile unsigned char*)ioremap(ANSLCD_ADDR, 0x20);
151         
152         misc_register(&anslcd_dev);
153
154 #ifdef DEBUG
155         printk(KERN_DEBUG "LCD: init\n");
156 #endif
157
158         anslcd_write_byte_ctrl ( 0x38 );
159         anslcd_write_byte_ctrl ( 0x0c );
160         anslcd_write_byte_ctrl ( 0x06 );
161         anslcd_write_byte_ctrl ( 0x01 );
162         anslcd_write_byte_ctrl ( 0x02 );
163         for(a=0;a<80;a++) {
164                 anslcd_write_byte_data(anslcd_logo[a]);
165         }
166         return 0;
167 }
168
169 __initcall(anslcd_init);
170