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