• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Drivers for the Total Impact PPC based computer "BRIQ"
3  * by Dr. Karsten Jeppesen
4  *
5  */
6 
7 #include <linux/module.h>
8 
9 #include <linux/smp_lock.h>
10 #include <linux/types.h>
11 #include <linux/errno.h>
12 #include <linux/tty.h>
13 #include <linux/timer.h>
14 #include <linux/kernel.h>
15 #include <linux/wait.h>
16 #include <linux/string.h>
17 #include <linux/slab.h>
18 #include <linux/ioport.h>
19 #include <linux/delay.h>
20 #include <linux/miscdevice.h>
21 #include <linux/fs.h>
22 #include <linux/mm.h>
23 #include <linux/init.h>
24 
25 #include <asm/uaccess.h>
26 #include <asm/io.h>
27 #include <asm/prom.h>
28 
29 #define		BRIQ_PANEL_MINOR	156
30 #define		BRIQ_PANEL_VFD_IOPORT	0x0390
31 #define		BRIQ_PANEL_LED_IOPORT	0x0398
32 #define		BRIQ_PANEL_VER		"1.1 (04/20/2002)"
33 #define		BRIQ_PANEL_MSG0		"Loading Linux"
34 
35 static int		vfd_is_open;
36 static unsigned char	vfd[40];
37 static int		vfd_cursor;
38 static unsigned char	ledpb, led;
39 
update_vfd(void)40 static void update_vfd(void)
41 {
42 	int	i;
43 
44 	/* cursor home */
45 	outb(0x02, BRIQ_PANEL_VFD_IOPORT);
46 	for (i=0; i<20; i++)
47 		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
48 
49 	/* cursor to next line */
50 	outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
51 	for (i=20; i<40; i++)
52 		outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
53 
54 }
55 
set_led(char state)56 static void set_led(char state)
57 {
58 	if (state == 'R')
59 		led = 0x01;
60 	else if (state == 'G')
61 		led = 0x02;
62 	else if (state == 'Y')
63 		led = 0x03;
64 	else if (state == 'X')
65 		led = 0x00;
66 	outb(led, BRIQ_PANEL_LED_IOPORT);
67 }
68 
briq_panel_open(struct inode * ino,struct file * filep)69 static int briq_panel_open(struct inode *ino, struct file *filep)
70 {
71 	lock_kernel();
72 	/* enforce single access, vfd_is_open is protected by BKL */
73 	if (vfd_is_open) {
74 		unlock_kernel();
75 		return -EBUSY;
76 	}
77 	vfd_is_open = 1;
78 
79 	unlock_kernel();
80 	return 0;
81 }
82 
briq_panel_release(struct inode * ino,struct file * filep)83 static int briq_panel_release(struct inode *ino, struct file *filep)
84 {
85 	if (!vfd_is_open)
86 		return -ENODEV;
87 
88 	vfd_is_open = 0;
89 
90 	return 0;
91 }
92 
briq_panel_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)93 static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
94 			 loff_t *ppos)
95 {
96 	unsigned short c;
97 	unsigned char cp;
98 
99 	if (!vfd_is_open)
100 		return -ENODEV;
101 
102 	c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
103 	set_led(' ');
104 	/* upper button released */
105 	if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
106 		cp = ' ';
107 		ledpb = c;
108 		if (copy_to_user(buf, &cp, 1))
109 			return -EFAULT;
110 		return 1;
111 	}
112 	/* lower button released */
113 	else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
114 		cp = '\r';
115 		ledpb = c;
116 		if (copy_to_user(buf, &cp, 1))
117 			return -EFAULT;
118 		return 1;
119 	} else {
120 		ledpb = c;
121 		return 0;
122 	}
123 }
124 
scroll_vfd(void)125 static void scroll_vfd( void )
126 {
127 	int	i;
128 
129 	for (i=0; i<20; i++) {
130 		vfd[i] = vfd[i+20];
131 		vfd[i+20] = ' ';
132 	}
133 	vfd_cursor = 20;
134 }
135 
briq_panel_write(struct file * file,const char __user * buf,size_t len,loff_t * ppos)136 static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
137 			  loff_t *ppos)
138 {
139 	size_t indx = len;
140 	int i, esc = 0;
141 
142 	if (!vfd_is_open)
143 		return -EBUSY;
144 
145 	for (;;) {
146 		char c;
147 		if (!indx)
148 			break;
149 		if (get_user(c, buf))
150 			return -EFAULT;
151 		if (esc) {
152 			set_led(c);
153 			esc = 0;
154 		} else if (c == 27) {
155 			esc = 1;
156 		} else if (c == 12) {
157 			/* do a form feed */
158 			for (i=0; i<40; i++)
159 				vfd[i] = ' ';
160 			vfd_cursor = 0;
161 		} else if (c == 10) {
162 			if (vfd_cursor < 20)
163 				vfd_cursor = 20;
164 			else if (vfd_cursor < 40)
165 				vfd_cursor = 40;
166 			else if (vfd_cursor < 60)
167 				vfd_cursor = 60;
168 			if (vfd_cursor > 59)
169 				scroll_vfd();
170 		} else {
171 			/* just a character */
172 			if (vfd_cursor > 39)
173 				scroll_vfd();
174 			vfd[vfd_cursor++] = c;
175 		}
176 		indx--;
177 		buf++;
178 	}
179 	update_vfd();
180 
181 	return len;
182 }
183 
184 static const struct file_operations briq_panel_fops = {
185 	.owner		= THIS_MODULE,
186 	.read		= briq_panel_read,
187 	.write		= briq_panel_write,
188 	.open		= briq_panel_open,
189 	.release	= briq_panel_release,
190 };
191 
192 static struct miscdevice briq_panel_miscdev = {
193 	BRIQ_PANEL_MINOR,
194 	"briq_panel",
195 	&briq_panel_fops
196 };
197 
briq_panel_init(void)198 static int __init briq_panel_init(void)
199 {
200 	struct device_node *root = of_find_node_by_path("/");
201 	const char *machine;
202 	int i;
203 
204 	machine = of_get_property(root, "model", NULL);
205 	if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
206 		of_node_put(root);
207 		return -ENODEV;
208 	}
209 	of_node_put(root);
210 
211 	printk(KERN_INFO
212 		"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
213 		BRIQ_PANEL_VER);
214 
215 	if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
216 		return -EBUSY;
217 
218 	if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
219 		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
220 		return -EBUSY;
221 	}
222 	ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
223 
224 	if (misc_register(&briq_panel_miscdev) < 0) {
225 		release_region(BRIQ_PANEL_VFD_IOPORT, 4);
226 		release_region(BRIQ_PANEL_LED_IOPORT, 2);
227 		return -EBUSY;
228 	}
229 
230 	outb(0x38, BRIQ_PANEL_VFD_IOPORT);	/* Function set */
231 	outb(0x01, BRIQ_PANEL_VFD_IOPORT);	/* Clear display */
232 	outb(0x0c, BRIQ_PANEL_VFD_IOPORT);	/* Display on */
233 	outb(0x06, BRIQ_PANEL_VFD_IOPORT);	/* Entry normal */
234 	for (i=0; i<40; i++)
235 		vfd[i]=' ';
236 #ifndef MODULE
237 	vfd[0] = 'L';
238 	vfd[1] = 'o';
239 	vfd[2] = 'a';
240 	vfd[3] = 'd';
241 	vfd[4] = 'i';
242 	vfd[5] = 'n';
243 	vfd[6] = 'g';
244 	vfd[7] = ' ';
245 	vfd[8] = '.';
246 	vfd[9] = '.';
247 	vfd[10] = '.';
248 #endif /* !MODULE */
249 
250 	update_vfd();
251 
252 	return 0;
253 }
254 
briq_panel_exit(void)255 static void __exit briq_panel_exit(void)
256 {
257 	misc_deregister(&briq_panel_miscdev);
258 	release_region(BRIQ_PANEL_VFD_IOPORT, 4);
259 	release_region(BRIQ_PANEL_LED_IOPORT, 2);
260 }
261 
262 module_init(briq_panel_init);
263 module_exit(briq_panel_exit);
264 
265 MODULE_LICENSE("GPL");
266 MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
267 MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
268