1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  *
4  * Curses console driver
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * revision history: (please note changes here)
21  *  -ss040615   Stian Skjelstad <stian@nixia.no>
22  *    -first release
23  *  -doj040914  Dirk Jagdmann  <doj@cubic.org>
24  *    -trust the framebuffers smem_len
25  *  -ss040918   Stian Skjelstad <stian@nixia.no>
26  *    -devfs/kernel 2.6 framebuffer names
27  */
28 
29 #define _CONSOLE_DRIVER
30 
31 #include "config.h"
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/ioctl.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <linux/fb.h>
42 #include <linux/version.h>
43 #include "types.h"
44 
45 #include "poutput-fb.h"
46 #include "boot/console.h"
47 #include "poutput.h"
48 
49 static struct fb_fix_screeninfo fix;
50 static struct fb_var_screeninfo orgmode;
51 static struct fb_var_screeninfo lowres;
52 static struct fb_var_screeninfo highres;
53 static struct fb_cmap colormap;
54 static uint16_t red[256]=  {0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff};
55 static uint16_t green[256]={0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa, 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff};
56 static uint16_t blue[256]= {0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff};
57 
58 static int fd;
59 static uint8_t *fbmem;
60 
get_static_info(void)61 static int get_static_info(void)
62 {
63 	if (ioctl(fd, FBIOGET_FSCREENINFO, &fix))
64 	{
65 		perror("fb: ioctl(1, FBIOGET_FSCREENINFO, &fix)");
66 		return -1;
67 	}
68 	return 0;
69 }
70 
show_cursor(void)71 static void show_cursor(void)
72 {
73 #ifdef FBIOGET_CURSORSTATE
74 	struct fb_cursorstate cur;
75 	if (ioctl(fd, FBIOGET_CURSORSTATE, &cur, sizeof(cur)))
76 	{
77 		perror("fb: ioctl(1, FBIOGET_CURSORSTATE, &cursor)");
78 		return;
79 	}
80 	cur.mode=FB_CURSOR_FLASH;
81 	if (ioctl(fd, FBIOPUT_CURSORSTATE, &cur, sizeof(cur)))
82 	{
83 		perror("fb: ioctl(1, FBIOPUT_CURSORSTATE, &cursor)");
84 		return;
85 	}
86 #endif
87 }
88 
hide_cursor(void)89 static void hide_cursor(void)
90 {
91 #ifdef FBIOGET_CURSORSTATE
92 	struct fb_cursorstate cur;
93 	if (ioctl(fd, FBIOGET_CURSORSTATE, &cur))
94 	{
95 		perror("fb: ioctl(1, FBIOGET_CURSORSTATE, &cursor)");
96 		return;
97 	}
98 	cur.mode=FB_CURSOR_OFF;
99 	if (ioctl(fd, FBIOPUT_CURSORSTATE, &cur))
100 	{
101 		perror("fb: ioctl(1, FBIOGET_CURSORSTATE, &cursor)");
102 		return;
103 	}
104 #endif
105 }
106 
test_mode(struct fb_var_screeninfo * info)107 static int test_mode(struct fb_var_screeninfo *info)
108 {
109 	int old;
110 	old=info->activate;
111 	info->activate=FB_ACTIVATE_TEST;
112 	if (ioctl(fd, FBIOPUT_VSCREENINFO, info))
113 	{
114 		perror("fb: ioctl(1, FBIOPUT_VSCREENINFO, info)");
115 		info->activate=old;
116 		return -1;
117 	}
118 	info->activate=old;
119 	return 0;
120 }
121 
__gupdatepal(unsigned char color,unsigned char _red,unsigned char _green,unsigned char _blue)122 static void __gupdatepal(unsigned char color, unsigned char _red, unsigned char _green, unsigned char _blue)
123 {
124 	red[color]=_red<<10;
125 	green[color]=_green<<10;
126 	blue[color]=_blue<<10;
127 }
128 
__gflushpal(void)129 static void __gflushpal(void)
130 {
131 	if (ioctl(fd, FBIOPUTCMAP, &colormap))
132 		perror("fb: ioctl(fb, FBIOGETCMAP, &colormap)");
133 }
134 
__plSetGraphMode(int high)135 static int __plSetGraphMode(int high)
136 {
137 /*
138 	struct fb_fix_screeninfo fix2;
139 */
140 
141 #ifdef DEBUG_FRAMEBUFFER
142 	if (high==-1)
143 		fprintf(stderr, "fb: set normale mode\n");
144 	else if (high)
145 		fprintf(stderr, "fb: set 1024x768\n");
146 	else
147 		fprintf(stderr, "fb: set 640x480\n");
148 #endif
149 	if (high==-1)
150 	{
151 		plVidMem = 0;
152 		ioctl(fd, FBIOPUT_VSCREENINFO, &orgmode);
153 		return 0;
154 	}
155 
156 	if (high)
157 	{
158 		if (!highres.xres)
159 			return -1;
160 		plScrMode=101;
161 		plScrWidth=128;
162 		plScrHeight=60;
163 		ioctl(fd, FBIOPUT_VSCREENINFO, &highres);
164 		plScrLineBytes=1024; /* not good, but my framebuffer bugs to much */
165 	} else {
166 		if (!lowres.xres)
167 			return -1;
168 		plScrMode=100;
169 		plScrWidth=80;
170 		plScrHeight=60;
171 		ioctl(fd, FBIOPUT_VSCREENINFO, &lowres);
172 		plScrLineBytes=640; /* not good, but my framebuffer bugs to much */
173 	}
174 
175 	plVidMem = fbmem;
176 	memset(fbmem, 0, fix.smem_len);
177 
178 	colormap.start=0;
179 	colormap.len=256;
180 	colormap.red=red;
181 	colormap.green=green;
182 	colormap.blue=blue;
183 	/* Since some framebuffer-drivers fails give out the current palette with the bits scaled correct, we can't really
184 	 * use the FBIOGETCMAP. That sucks!
185 
186 	if (ioctl(fd, FBIOGETCMAP, &colormap))
187 		perror("fb: ioctl(fb, FBIOGETCMAP, &colormap)");
188 
189 	 * And tridentfb atleast is broken when reporting fix.line_length... hehe.. FUCK that driver!!!!
190 
191 	if (ioctl(fd, FBIOGET_FSCREENINFO, &fix2))
192 		perror("fb: ioctl(1, FBIOGET_FSCREENINFO, &fix)");
193 	fix2.line_length=fix.line_length;
194 	fprintf(stderr, "DEBUG LINES: current %d, org %d, new %d\n", plScrLineBytes, fix.line_length, fix2.line_length);
195 	plScrLineBytes=fix2.line_length;
196 	 */
197 	return 0;
198 }
199 
fb_init(int minor)200 int fb_init(int minor)
201 {
202 	struct fb_var_screeninfo var2;
203 	char *temp;
204 
205 	memset(&lowres, 0, sizeof(lowres));
206 	memset(&lowres, 0, sizeof(highres));
207 
208 	if ((temp=getenv("FRAMEBUFFER")))
209 	{
210 		if ((fd=open(temp, O_RDWR))<0)
211 		{
212 			perror("fb: open($FRAMEBUFFER)");
213 			return -1;
214 		}
215 	} else {
216 		if ((fd=open("/dev/fb", O_RDWR))<0)
217 		{
218 			perror("fb: open(/dev/fb)");
219 			if ((fd=open("/dev/fb/0", O_RDWR))<0)
220 			{
221 				perror("fb: open(/dev/fb/0)");
222 				return -1;
223 			}
224 		}
225 	}
226 	if (get_static_info())
227 	{
228 		close(fd);
229 		fd=-1;
230 		return -1;
231 	}
232 	plScrLineBytes=fix.line_length;
233 #ifdef VERBOSE_FRAMEBUFFER
234 	fprintf(stderr, "fb: FIX SCREEN INFO\n");
235 	fprintf(stderr, "fb:  id=%s\n", fix.id);
236 	fprintf(stderr, "fb:  smem_start=0x%08lx\n", fix.smem_start);
237 	fprintf(stderr, "fb:  smem_len=0x%08x\n", fix.smem_len);
238 	fprintf(stderr, "fb:  stype=");
239 	switch (fix.type)
240 	{
241 		case FB_TYPE_PACKED_PIXELS:
242 			fprintf(stderr, "Packed Pixels\n");
243 			break;
244 		case FB_TYPE_PLANES:
245 			fprintf(stderr, "Non interleaved planes\n");
246 			break;
247 		case FB_TYPE_INTERLEAVED_PLANES:
248 			fprintf(stderr, "Interleaved planes\n");
249 			break;
250 		case FB_TYPE_TEXT:
251 			fprintf(stderr, "Text/attributes\nfb:  type_aux=");
252 			switch (fix.type_aux)
253 			{
254 				case FB_AUX_TEXT_MDA:
255 					fprintf(stderr, "Monochrome text\n");
256 					break;
257 				case FB_AUX_TEXT_CGA:
258 					fprintf(stderr, "CGA/EGA/VGA Color text\n");
259 					break;
260 				case FB_AUX_TEXT_S3_MMIO:
261 					fprintf(stderr, "S3 MMIO fasttext\n");
262 					break;
263 				case FB_AUX_TEXT_MGA_STEP16:
264 					fprintf(stderr, "MGA Millenium I: text, attr, 14 reserved bytes\n");
265 					break;
266 				case FB_AUX_TEXT_MGA_STEP8:
267 					fprintf(stderr, "other MGAs:      text, attr,  6 reserved bytes\n");
268 					break;
269 				default:
270 					fprintf(stderr, "Unknown\n");
271 			}
272 			break;
273 		case FB_TYPE_VGA_PLANES:
274 			fprintf(stderr, "EGA/VGA planes\nfb:   type_aux=");
275 			switch (fix.type_aux)
276 			{
277 				case FB_AUX_VGA_PLANES_VGA4:
278 					fprintf(stderr, "16 color planes (EGA/VGA)\n");
279 					break;
280 				case FB_AUX_VGA_PLANES_CFB4:
281 					fprintf(stderr, "CFB4 in planes (VGA)\n");
282 					break;
283 				case FB_AUX_VGA_PLANES_CFB8:
284 					fprintf(stderr, "CFB8 in planes (VGA)\n");
285 					break;
286 				default:
287 					fprintf(stderr, "Unknown\n");
288 			}
289 			break;
290 		default:
291 			fprintf(stderr, "Unknown\n");
292 			break;
293 	}
294 	fprintf(stderr, "fb:   visual=");
295 	switch (fix.visual)
296 	{
297 		case FB_VISUAL_MONO01:
298 			fprintf(stderr, "Monochr. 1=Black 0=White\n");
299 			break;
300 		case FB_VISUAL_MONO10:
301 			fprintf(stderr, "Monochr. 1=White 0=Black\n");
302 			break;
303 		case FB_VISUAL_TRUECOLOR:
304 			fprintf(stderr, "True color\n");
305 			break;
306 		case FB_VISUAL_PSEUDOCOLOR:
307 			fprintf(stderr, "Pseudo color (like atari)\n");
308 			break;
309 		case FB_VISUAL_DIRECTCOLOR:
310 			fprintf(stderr, "Direct color\n");
311 			break;
312 		case FB_VISUAL_STATIC_PSEUDOCOLOR:
313 			fprintf(stderr, "Pseudo color readonly\n");
314 			break;
315 		default:
316 			fprintf(stderr, "Unknown\n");
317 	}
318 	fprintf(stderr, "fb:  xpanstep=");
319 	if (fix.xpanstep)
320 		fprintf(stderr, "%d\n", fix.xpanstep);
321 	else
322 		fprintf(stderr, "Not supported\n");
323 	fprintf(stderr, "fb:  ypanstep=");
324 	if (fix.ypanstep)
325 		fprintf(stderr, "%d\n", fix.ypanstep);
326 	else
327 		fprintf(stderr, "Not supported\n");
328 	fprintf(stderr, "fb:  ywrapstep=");
329 	if (fix.ywrapstep)
330 		fprintf(stderr, "%d\n", fix.ywrapstep);
331 	else
332 		fprintf(stderr, "Not supported\n");
333 	fprintf(stderr, "fb:  line_length=%d\n", fix.line_length);
334 	fprintf(stderr, "fb:  mmio_start=0x%08lx\n", fix.mmio_start);
335 	fprintf(stderr, "fb:  mmio_len=0x%08x\n", fix.mmio_len);
336 	fprintf(stderr, "fb:  accel=%d\n", fix.accel);
337 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
338 	fprintf(stderr, "fb:  capabilities=0x%04x\n", fix.capabilities);
339 	fprintf(stderr, "fb:  reserved0=0x%04x reserved1=0x%04x\n", fix.reserved[0], fix.reserved[1]);
340 #else
341 	fprintf(stderr, "fb:  reserved0=0x%04x reserved1=0x%04x reserved2=0x%04x\n", fix.reserved[0], fix.reserved[1], fix.reserved[2]);
342 #endif
343 #endif
344 	if (ioctl(fd, FBIOGET_VSCREENINFO, &orgmode))
345 	{
346 		perror("fb: ioctl(1, FBIOGET_VSCREENINFO, &orgmode)");
347 		close(fd);
348 		fd=-1;
349 		return -1;
350 	}
351 	orgmode.activate=FB_ACTIVATE_NOW;
352 #if VERBOSE_FRAMEBUFFER
353 	fprintf(stderr, "VAR SCREEN INFO\n");
354 	fprintf(stderr, "xres=%d\n", orgmode.xres);
355 	fprintf(stderr, "yres=%d\n", orgmode.yres);
356 	fprintf(stderr, "xres_virtual=%d\n", orgmode.xres_virtual);
357 	fprintf(stderr, "yres_virtual=%d\n", orgmode.yres_virtual);
358 	fprintf(stderr, "xoffset=%d\n", orgmode.xoffset);
359 	fprintf(stderr, "yoffsett=%d\n", orgmode.yoffset);
360 	fprintf(stderr, "bits_per_pixel=%d\n", orgmode.bits_per_pixel);
361 	fprintf(stderr, "grayscale=%d\n", orgmode.grayscale);
362 	/* R, G, B, Alpha goes here */
363 	fprintf(stderr, "nonstd=%d\n", orgmode.nonstd);
364 	fprintf(stderr, "(activate=%d)\n", orgmode.activate);
365 	/* height / width goes here */
366 	/* accel flags goes here */
367 #endif
368 	var2.xres=var2.xres_virtual=640;
369 	var2.yres=var2.yres_virtual=480;
370 	var2.xoffset=var2.yoffset=0;
371 	var2.bits_per_pixel=8;
372 	var2.grayscale=0;
373 	var2.nonstd=0;
374 	var2.height=orgmode.height;
375 	var2.width=orgmode.width;
376 	var2.accel_flags=0;
377 	var2.pixclock=32052;
378 	var2.left_margin=128;
379 	var2.right_margin=24;
380 	var2.upper_margin=28;
381 	var2.lower_margin=9;
382 	var2.hsync_len=40;
383 	var2.vsync_len=3;
384 	var2.sync=orgmode.sync;
385 	var2.vmode=0;
386 	if (test_mode(&var2))
387 	{
388 		memcpy(&var2, &orgmode, sizeof(orgmode));
389 		var2.activate=FB_ACTIVATE_TEST;
390 	} else {
391 		var2.activate=FB_ACTIVATE_NOW;
392 	}
393 	if ((var2.xres==640)&&(var2.yres==480))
394 	{
395 		fprintf(stderr, "fb:  640x480 is available\n");
396 		memcpy(&lowres, &var2, sizeof(var2));
397 	} else
398 		fprintf(stderr, "fb:  640x480 is not available\n");
399 
400 	var2.xres=var2.xres_virtual=1024;
401 	var2.yres=var2.yres_virtual=768;
402 	var2.xoffset=var2.yoffset=0;
403 	var2.bits_per_pixel=8;
404 	var2.grayscale=0;
405 	var2.nonstd=0;
406 	var2.height=orgmode.height;
407 	var2.width=orgmode.width;
408 	var2.accel_flags=0;
409 	var2.pixclock=15385;
410 	var2.left_margin=160;
411 	var2.right_margin=24;
412 	var2.upper_margin=29;
413 	var2.lower_margin=3;
414 	var2.hsync_len=136;
415 	var2.vsync_len=6;
416 	var2.sync=orgmode.sync;
417 	var2.vmode=0;
418 	if (test_mode(&var2))
419 	{
420 		memcpy(&var2, &orgmode, sizeof(orgmode));
421 		var2.activate=FB_ACTIVATE_TEST;
422 	} else {
423 		var2.activate=FB_ACTIVATE_NOW;
424 	}
425 	if ((var2.xres==1024)&&(var2.yres==768))
426 	{
427 		fprintf(stderr, "fb:  1024x768 is available\n");
428 		memcpy(&highres, &var2, sizeof(var2));
429 	} else
430 		fprintf(stderr, "fb:  1024x768 is not available\n");
431 	if ((!highres.xres)&&(!lowres.xres))
432 	{
433 		close(fd);
434 		fd=-1;
435 		return -1;
436 	}
437 
438 	if ((fbmem=mmap(0, fix.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0))==MAP_FAILED)
439 	{
440 		perror("fb: mmap()");
441 		close(fd);
442 		fd=-1;
443 		return -1;
444 	}
445 
446 	_plSetGraphMode=__plSetGraphMode;
447 	_gdrawstr=generic_gdrawstr;
448 	_gdrawchar8=generic_gdrawchar8;
449 	_gdrawchar8p=generic_gdrawchar8p;
450 	_gdrawchar8t=generic_gdrawchar8t;
451 	_gdrawcharp=generic_gdrawcharp;
452 	_gdrawchar=generic_gdrawchar;
453 	_gupdatestr=generic_gupdatestr;
454 	_gupdatepal=__gupdatepal;
455 	_gflushpal=__gflushpal;
456 	hide_cursor();
457 	plVidType=vidVESA;
458 
459 	return 0;
460 }
461 
fb_done(void)462 void fb_done(void)
463 {
464 	show_cursor();
465 	munmap(fbmem, fix.smem_len);
466 	if (fd<0)
467 		return;
468 	ioctl(fd, FBIOPUT_VSCREENINFO, &orgmode);
469 	close(fd);
470 	fd=-1;
471 }
472