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