1 /*
2 * some generic framebuffer device stuff
3 *
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <termios.h>
12 #include <signal.h>
13 #include <errno.h>
14 #include <setjmp.h>
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
17 #include <sys/wait.h>
18 #include <sys/stat.h>
19
20 #include <linux/kd.h>
21 #include <linux/vt.h>
22 #include <linux/fb.h>
23
24 #include <asm/page.h>
25
26 #include "fbtools.h"
27
28 /* -------------------------------------------------------------------- */
29 /* exported stuff */
30
31 struct fb_fix_screeninfo fb_fix;
32 struct fb_var_screeninfo fb_var;
33 unsigned char *fb_mem;
34 int fb_mem_offset = 0;
35 int fb_switch_state = FB_ACTIVE;
36
37 /* -------------------------------------------------------------------- */
38 /* internal variables */
39
40 static int fb,tty;
41 #if 0
42 static int bpp,black,white;
43 #endif
44
45 static int orig_vt_no = 0;
46 static struct vt_mode vt_mode;
47
48 static int kd_mode;
49 static struct vt_mode vt_omode;
50 static struct termios term;
51 static struct fb_var_screeninfo fb_ovar;
52 static unsigned short ored[256], ogreen[256], oblue[256];
53 static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue };
54
55 /* -------------------------------------------------------------------- */
56 /* devices */
57
58 struct DEVS {
59 char *fb0;
60 char *fbnr;
61 char *ttynr;
62 };
63
64 struct DEVS devs_default = {
65 fb0: "/dev/fb0",
66 fbnr: "/dev/fb%d",
67 ttynr: "/dev/tty%d",
68 };
69 struct DEVS devs_devfs = {
70 fb0: "/dev/fb/0",
71 fbnr: "/dev/fb/%d",
72 ttynr: "/dev/vc/%d",
73 };
74 struct DEVS *devices;
75
76 static void dev_init(void)
77 {
78 struct stat dummy;
79
80 if (NULL != devices)
81 return;
82 if (0 == stat("/dev/.devfsd",&dummy))
83 devices = &devs_devfs;
84 else
85 devices = &devs_default;
86 }
87
88 /* -------------------------------------------------------------------- */
89 /* console switching */
90
91 extern int debug;
92
93 static void
94 fb_switch_signal(int signal)
95 {
96 if (signal == SIGUSR1) {
97 /* release */
98 fb_switch_state = FB_REL_REQ;
99 if (debug)
100 write(2,"vt: SIGUSR1\n",12);
101 }
102 if (signal == SIGUSR2) {
103 /* acquisition */
104 fb_switch_state = FB_ACQ_REQ;
105 if (debug)
106 write(2,"vt: SIGUSR2\n",12);
107 }
108 }
109
110 void
111 fb_switch_release()
112 {
113 ioctl(tty, VT_RELDISP, 1);
114 fb_switch_state = FB_INACTIVE;
115 if (debug)
116 write(2,"vt: release\n",12);
117 }
118
119 void
120 fb_switch_acquire()
121 {
122 ioctl(tty, VT_RELDISP, VT_ACKACQ);
123 fb_switch_state = FB_ACTIVE;
124 if (debug)
125 write(2,"vt: acquire\n",12);
126 }
127
128 int
129 fb_switch_init()
130 {
131 struct sigaction act,old;
132
133 memset(&act,0,sizeof(act));
134 act.sa_handler = fb_switch_signal;
135 sigemptyset(&act.sa_mask);
136 sigaction(SIGUSR1,&act,&old);
137 sigaction(SIGUSR2,&act,&old);
138
139 if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) {
140 perror("ioctl VT_GETMODE");
141 exit(1);
142 }
143 vt_mode.mode = VT_PROCESS;
144 vt_mode.waitv = 0;
145 vt_mode.relsig = SIGUSR1;
146 vt_mode.acqsig = SIGUSR2;
147
148 if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) {
149 perror("ioctl VT_SETMODE");
150 exit(1);
151 }
152 return 0;
153 }
154
155 /* -------------------------------------------------------------------- */
156 /* initialisation & cleanup */
157
158 void
159 fb_memset (void *addr, int c, size_t len)
160 {
161 #if 1 /* defined(__powerpc__) */
162 unsigned int i, *p;
163
164 i = (c & 0xff) << 8;
165 i |= i << 16;
166 len >>= 2;
167 for (p = addr; len--; p++)
168 *p = i;
169 #else
170 memset(addr, c, len);
171 #endif
172 }
173
174 static int
175 fb_setmode(char *name)
176 {
177 FILE *fp;
178 char line[80],label[32],value[16];
179 int geometry=0, timings=0;
180
181 /* load current values */
182 if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) {
183 perror("ioctl FBIOGET_VSCREENINFO");
184 exit(1);
185 }
186
187 if (NULL == name)
188 return -1;
189 if (NULL == (fp = fopen("/etc/fb.modes","r")))
190 return -1;
191 while (NULL != fgets(line,79,fp)) {
192 if (1 == sscanf(line, "mode \"%31[^\"]\"",label) &&
193 0 == strcmp(label,name)) {
194 /* fill in new values */
195 fb_var.sync = 0;
196 fb_var.vmode = 0;
197 while (NULL != fgets(line,79,fp) &&
198 NULL == strstr(line,"endmode")) {
199 if (5 == sscanf(line," geometry %d %d %d %d %d",
200 &fb_var.xres,&fb_var.yres,
201 &fb_var.xres_virtual,&fb_var.yres_virtual,
202 &fb_var.bits_per_pixel))
203 geometry = 1;
204 if (7 == sscanf(line," timings %d %d %d %d %d %d %d",
205 &fb_var.pixclock,
206 &fb_var.left_margin, &fb_var.right_margin,
207 &fb_var.upper_margin, &fb_var.lower_margin,
208 &fb_var.hsync_len, &fb_var.vsync_len))
209 timings = 1;
210 if (1 == sscanf(line, " hsync %15s",value) &&
211 0 == strcasecmp(value,"high"))
212 fb_var.sync |= FB_SYNC_HOR_HIGH_ACT;
213 if (1 == sscanf(line, " vsync %15s",value) &&
214 0 == strcasecmp(value,"high"))
215 fb_var.sync |= FB_SYNC_VERT_HIGH_ACT;
216 if (1 == sscanf(line, " csync %15s",value) &&
217 0 == strcasecmp(value,"high"))
218 fb_var.sync |= FB_SYNC_COMP_HIGH_ACT;
219 if (1 == sscanf(line, " extsync %15s",value) &&
220 0 == strcasecmp(value,"true"))
221 fb_var.sync |= FB_SYNC_EXT;
222 if (1 == sscanf(line, " laced %15s",value) &&
223 0 == strcasecmp(value,"true"))
224 fb_var.vmode |= FB_VMODE_INTERLACED;
225 if (1 == sscanf(line, " double %15s",value) &&
226 0 == strcasecmp(value,"true"))
227 fb_var.vmode |= FB_VMODE_DOUBLE;
228 }
229 /* ok ? */
230 if (!geometry || !timings)
231 return -1;
232 /* set */
233 fb_var.xoffset = 0;
234 fb_var.yoffset = 0;
235 if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_var))
236 perror("ioctl FBIOPUT_VSCREENINFO");
237 /* look what we have now ... */
238 if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) {
239 perror("ioctl FBIOGET_VSCREENINFO");
240 exit(1);
241 }
242 return 0;
243 }
244 }
245 return -1;
246 }
247
248 static void
249 fb_setvt(int vtno)
250 {
251 struct vt_stat vts;
252 char vtname[12];
253
254 if (vtno < 0) {
255 if (-1 == ioctl(tty,VT_OPENQRY, &vtno) || vtno == -1) {
256 perror("ioctl VT_OPENQRY");
257 exit(1);
258 }
259 }
260
261 vtno &= 0xff;
262 sprintf(vtname, devices->ttynr, vtno);
263 chown(vtname, getuid(), getgid());
264 if (-1 == access(vtname, R_OK | W_OK)) {
265 fprintf(stderr,"access %s: %s\n",vtname,strerror(errno));
266 exit(1);
267 }
268 switch (fork()) {
269 case 0:
270 break;
271 case -1:
272 perror("fork");
273 exit(1);
274 default:
275 exit(0);
276 }
277 close(tty);
278 close(0);
279 close(1);
280 close(2);
281 setsid();
282 open(vtname,O_RDWR);
283 dup(0);
284 dup(0);
285
286 if (-1 == ioctl(tty,VT_GETSTATE, &vts)) {
287 perror("ioctl VT_GETSTATE");
288 exit(1);
289 }
290 orig_vt_no = vts.v_active;
291 if (-1 == ioctl(tty,VT_ACTIVATE, vtno)) {
292 perror("ioctl VT_ACTIVATE");
293 exit(1);
294 }
295 if (-1 == ioctl(tty,VT_WAITACTIVE, vtno)) {
296 perror("ioctl VT_WAITACTIVE");
297 exit(1);
298 }
299 }
300
301 /* Hmm. radeonfb needs this. matroxfb doesn't. */
302 static int fb_activate_current(int tty)
303 {
304 struct vt_stat vts;
305
306 if (-1 == ioctl(tty,VT_GETSTATE, &vts)) {
307 perror("ioctl VT_GETSTATE");
308 return -1;
309 }
310 if (-1 == ioctl(tty,VT_ACTIVATE, vts.v_active)) {
311 perror("ioctl VT_ACTIVATE");
312 return -1;
313 }
314 if (-1 == ioctl(tty,VT_WAITACTIVE, vts.v_active)) {
315 perror("ioctl VT_WAITACTIVE");
316 return -1;
317 }
318 return 0;
319 }
320
321 int
322 fb_init(char *device, char *mode, int vt)
323 {
324 char fbdev[16];
325 struct vt_stat vts;
326
327 dev_init();
328 tty = 0;
329 if (vt != 0)
330 fb_setvt(vt);
331
332 if (-1 == ioctl(tty,VT_GETSTATE, &vts)) {
333 fprintf(stderr,"ioctl VT_GETSTATE: %s (not a linux console?)\n",
334 strerror(errno));
335 exit(1);
336 }
337
338 if (NULL == device) {
339 device = getenv("FRAMEBUFFER");
340 if (NULL == device) {
341 struct fb_con2fbmap c2m;
342 if (-1 == (fb = open(devices->fb0,O_WRONLY,0))) {
343 fprintf(stderr,"open %s: %s\n",devices->fb0,strerror(errno));
344 exit(1);
345 }
346 c2m.console = vts.v_active;
347 if (-1 == ioctl(fb, FBIOGET_CON2FBMAP, &c2m)) {
348 perror("ioctl FBIOGET_CON2FBMAP");
349 exit(1);
350 }
351 close(fb);
352 fprintf(stderr,"map: vt%02d => fb%d\n",
353 c2m.console,c2m.framebuffer);
354 sprintf(fbdev,devices->fbnr,c2m.framebuffer);
355 device = fbdev;
356 }
357 }
358
359 /* get current settings (which we have to restore) */
360 if (-1 == (fb = open(device,O_RDWR /* O_WRONLY */))) {
361 fprintf(stderr,"open %s: %s\n",device,strerror(errno));
362 exit(1);
363 }
364 if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) {
365 perror("ioctl FBIOGET_VSCREENINFO");
366 exit(1);
367 }
368 if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
369 perror("ioctl FBIOGET_FSCREENINFO");
370 exit(1);
371 }
372 if (fb_ovar.bits_per_pixel == 8 ||
373 fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
374 if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) {
375 perror("ioctl FBIOGETCMAP");
376 exit(1);
377 }
378 }
379 if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) {
380 perror("ioctl KDGETMODE");
381 exit(1);
382 }
383 if (-1 == ioctl(tty,VT_GETMODE, &vt_omode)) {
384 perror("ioctl VT_GETMODE");
385 exit(1);
386 }
387 tcgetattr(tty, &term);
388
389 /* switch mode */
390 fb_setmode(mode);
391
392 /* checks & initialisation */
393 if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
394 perror("ioctl FBIOGET_FSCREENINFO");
395 exit(1);
396 }
397 if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
398 fprintf(stderr,"can handle only packed pixel frame buffers\n");
399 goto err;
400 }
401 #if 0
402 switch (fb_var.bits_per_pixel) {
403 case 8:
404 white = 255; black = 0; bpp = 1;
405 break;
406 case 15:
407 case 16:
408 if (fb_var.green.length == 6)
409 white = 0xffff;
410 else
411 white = 0x7fff;
412 black = 0; bpp = 2;
413 break;
414 case 24:
415 white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
416 break;
417 case 32:
418 white = 0xffffff; black = 0; bpp = fb_var.bits_per_pixel/8;
419 fb_setpixels = fb_setpixels4;
420 break;
421 default:
422 fprintf(stderr, "Oops: %i bit/pixel ???\n",
423 fb_var.bits_per_pixel);
424 goto err;
425 }
426 #endif
427 fb_mem_offset = (unsigned long)(fb_fix.smem_start) & (~PAGE_MASK);
428 fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset,
429 PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
430 if (-1L == (long)fb_mem) {
431 perror("mmap");
432 goto err;
433 }
434 /* move viewport to upper left corner */
435 if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
436 fb_var.xoffset = 0;
437 fb_var.yoffset = 0;
438 if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) {
439 perror("ioctl FBIOPAN_DISPLAY");
440 goto err;
441 }
442 }
443 if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) {
444 perror("ioctl KDSETMODE");
445 goto err;
446 }
447 fb_activate_current(tty);
448
449 /* cls */
450 fb_memset(fb_mem+fb_mem_offset,0,fb_fix.smem_len);
451 return fb;
452
453 err:
454 fb_cleanup();
455 exit(1);
456 }
457
458 void
459 fb_cleanup(void)
460 {
461 /* restore console */
462 if (-1 == ioctl(fb,FBIOPUT_VSCREENINFO,&fb_ovar))
463 perror("ioctl FBIOPUT_VSCREENINFO");
464 if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix))
465 perror("ioctl FBIOGET_FSCREENINFO");
466 if (fb_ovar.bits_per_pixel == 8 ||
467 fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
468 if (-1 == ioctl(fb,FBIOPUTCMAP,&ocmap))
469 perror("ioctl FBIOPUTCMAP");
470 }
471 close(fb);
472
473 if (-1 == ioctl(tty,KDSETMODE, kd_mode))
474 perror("ioctl KDSETMODE");
475 if (-1 == ioctl(tty,VT_SETMODE, &vt_omode))
476 perror("ioctl VT_SETMODE");
477 if (orig_vt_no && -1 == ioctl(tty, VT_ACTIVATE, orig_vt_no))
478 perror("ioctl VT_ACTIVATE");
479 if (orig_vt_no && -1 == ioctl(tty, VT_WAITACTIVE, orig_vt_no))
480 perror("ioctl VT_WAITACTIVE");
481 tcsetattr(tty, TCSANOW, &term);
482 close(tty);
483 }
484
485 /* -------------------------------------------------------------------- */
486 /* handle fatal errors */
487
488 static jmp_buf fb_fatal_cleanup;
489
490 static void
491 fb_catch_exit_signal(int signal)
492 {
493 siglongjmp(fb_fatal_cleanup,signal);
494 }
495
496 void
497 fb_catch_exit_signals(void)
498 {
499 struct sigaction act,old;
500 int termsig;
501
502 memset(&act,0,sizeof(act));
503 act.sa_handler = fb_catch_exit_signal;
504 sigemptyset(&act.sa_mask);
505 sigaction(SIGINT, &act,&old);
506 sigaction(SIGQUIT,&act,&old);
507 sigaction(SIGTERM,&act,&old);
508
509 sigaction(SIGABRT,&act,&old);
510 sigaction(SIGTSTP,&act,&old);
511
512 sigaction(SIGBUS, &act,&old);
513 sigaction(SIGILL, &act,&old);
514 sigaction(SIGSEGV,&act,&old);
515
516 if (0 == (termsig = sigsetjmp(fb_fatal_cleanup,0)))
517 return;
518
519 /* cleanup */
520 fb_cleanup();
521 fprintf(stderr,"Oops: %s\n",sys_siglist[termsig]);
522 exit(42);
523 }
524
|
This page was automatically generated by the
LXR engine.
|