00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifdef __HAVE_FBDEV__
00034
00035 #include <unistd.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <errno.h>
00039 #include <string.h>
00040 #include <strings.h>
00041 #include <fcntl.h>
00042 #include <sys/ioctl.h>
00043 #include <sys/mman.h>
00044 #include <sys/kd.h>
00045 #include <linux/vt.h>
00046 #include "mmsgui/fb/mmsfbdev.h"
00047
00048 #define INITCHECK if(!this->isinitialized){MMSFB_SetError(0,"MMSFBDev is not initialized");return false;}
00049
00050 MMSFBDev::MMSFBDev() {
00051
00052 this->isinitialized = false;
00053 this->fd = -1;
00054 this->framebuffer_base = NULL;
00055 this->reset_console_accel = false;
00056 memset(this->modes, 0, sizeof(this->modes));
00057 this->modes_cnt = 0;
00058 memset(this->layers, 0, sizeof(this->layers));
00059 this->layers_cnt = 0;
00060 this->active_screen = 0;
00061
00062
00063 this->vt.fd0 = -1;
00064 this->vt.fd = -1;
00065 this->vt.number = -1;
00066 this->vt.previous = -1;
00067 this->vt.org_fb = -1;
00068 }
00069
00070 MMSFBDev::~MMSFBDev() {
00071 closeDevice();
00072 }
00073
00074 void MMSFBDev::printFixScreenInfo() {
00075 char id[17];
00076 id[16]=0;
00077 printf("MMSFBDev: fix screen info ------------\n");
00078 printf(" device = %s\n", this->device_file.c_str());
00079 memcpy(id, fix_screeninfo.id, 16);
00080 printf(" id = %s\n", id);
00081 printf(" smem_start = 0x%x\n", (unsigned int)fix_screeninfo.smem_start);
00082 printf(" smem_len = %d\n", fix_screeninfo.smem_len);
00083 printf(" type = %d\n", fix_screeninfo.type);
00084 printf(" type_aux = %d\n", fix_screeninfo.type_aux);
00085 printf(" visual = %d\n", fix_screeninfo.visual);
00086 printf(" xpanstep = %d\n", fix_screeninfo.xpanstep);
00087 printf(" ypanstep = %d\n", fix_screeninfo.ypanstep);
00088 printf(" ywrapstep = %d\n", fix_screeninfo.ywrapstep);
00089 printf(" line_length = %d\n", fix_screeninfo.line_length);
00090 printf(" mmio_start = 0x%x\n", (unsigned int)fix_screeninfo.mmio_start);
00091 printf(" mmio_len = %d\n", fix_screeninfo.mmio_len);
00092 printf(" accel = %d\n", fix_screeninfo.accel);
00093 printf(" reserved[3] = %d, %d, %d\n", fix_screeninfo.reserved[0], fix_screeninfo.reserved[1], fix_screeninfo.reserved[2]);
00094 }
00095
00096 void MMSFBDev::printVarScreenInfo() {
00097 printf("MMSFBDev: var screen info ------------\n");
00098 printf(" xres = %d\n", var_screeninfo.xres);
00099 printf(" yres = %d\n", var_screeninfo.yres);
00100 printf(" xres_virtual = %d\n", var_screeninfo.xres_virtual);
00101 printf(" yres_virtual = %d\n", var_screeninfo.yres_virtual);
00102 printf(" xoffset = %d\n", var_screeninfo.xoffset);
00103 printf(" yoffset = %d\n", var_screeninfo.yoffset);
00104 printf(" bits_per_pixel = %d\n", var_screeninfo.bits_per_pixel);
00105 printf(" grayscale = %d\n", var_screeninfo.grayscale);
00106 printf(" red = %d(offs=%d)\n", var_screeninfo.red.length, var_screeninfo.red.offset);
00107 printf(" green = %d(offs=%d)\n", var_screeninfo.green.length, var_screeninfo.green.offset);
00108 printf(" blue = %d(offs=%d)\n", var_screeninfo.blue.length, var_screeninfo.blue.offset);
00109 printf(" transp = %d(offs=%d)\n", var_screeninfo.transp.length, var_screeninfo.transp.offset);
00110 printf(" nonstd = %d\n", var_screeninfo.nonstd);
00111 printf(" activate = %d\n", var_screeninfo.activate);
00112 printf(" height = %d\n", var_screeninfo.height);
00113 printf(" width = %d\n", var_screeninfo.width);
00114 printf(" accel_flags = %d\n", var_screeninfo.accel_flags);
00115
00116 printf(" pixclock = %d\n", var_screeninfo.pixclock);
00117 printf(" left_margin = %d\n", var_screeninfo.left_margin);
00118 printf(" right_margin = %d\n", var_screeninfo.right_margin);
00119 printf(" upper_margin = %d\n", var_screeninfo.upper_margin);
00120 printf(" lower_margin = %d\n", var_screeninfo.lower_margin);
00121 printf(" hsync_len = %d\n", var_screeninfo.hsync_len);
00122 printf(" vsync_len = %d\n", var_screeninfo.vsync_len);
00123 printf(" sync = %d\n", var_screeninfo.sync);
00124 printf(" vmode = %d\n", var_screeninfo.vmode);
00125 printf(" rotate = %d\n", var_screeninfo.rotate);
00126 printf(" accel_flags = %d\n", var_screeninfo.accel_flags);
00127 printf(" reserved[5] = %d, %d, %d, %d, %d\n", var_screeninfo.reserved[0], var_screeninfo.reserved[1], var_screeninfo.reserved[2], var_screeninfo.reserved[3], var_screeninfo.reserved[4]);
00128 }
00129
00130 bool MMSFBDev::buildPixelFormat() {
00131 this->layers[0].pixelformat = MMSFB_PF_NONE;
00132 switch (var_screeninfo.transp.length) {
00133 case 0:
00134
00135 if ((var_screeninfo.red.length == 5) && (var_screeninfo.green.length == 6) && (var_screeninfo.blue.length == 5)
00136 && (var_screeninfo.red.offset == 11) && (var_screeninfo.green.offset == 5) && (var_screeninfo.blue.offset == 0)) {
00137 this->layers[0].pixelformat = MMSFB_PF_RGB16;
00138 }
00139 else
00140 if ((var_screeninfo.red.length == 8) && (var_screeninfo.green.length == 8) && (var_screeninfo.blue.length == 8)
00141 && (var_screeninfo.red.offset == 16) && (var_screeninfo.green.offset == 8) && (var_screeninfo.blue.offset == 0)) {
00142 if (var_screeninfo.bits_per_pixel == 24)
00143 this->layers[0].pixelformat = MMSFB_PF_RGB24;
00144 else
00145 this->layers[0].pixelformat = MMSFB_PF_RGB32;
00146 }
00147 else
00148 if ((var_screeninfo.red.length == 8) && (var_screeninfo.green.length == 8) && (var_screeninfo.blue.length == 8)
00149 && (var_screeninfo.red.offset == 0) && (var_screeninfo.green.offset == 8) && (var_screeninfo.blue.offset == 16)) {
00150 if (var_screeninfo.bits_per_pixel == 24)
00151 this->layers[0].pixelformat = MMSFB_PF_BGR24;
00152 }
00153 else
00154 if ((var_screeninfo.red.length == 5) && (var_screeninfo.green.length == 5) && (var_screeninfo.blue.length == 5)
00155 && (var_screeninfo.red.offset == 0) && (var_screeninfo.green.offset == 5) && (var_screeninfo.blue.offset == 10)) {
00156 if (var_screeninfo.bits_per_pixel == 16)
00157 this->layers[0].pixelformat = MMSFB_PF_BGR555;
00158 }
00159 else
00160 if ((var_screeninfo.red.length == 0) && (var_screeninfo.green.length == 0) && (var_screeninfo.blue.length == 0)
00161 && (var_screeninfo.red.offset == 0) && (var_screeninfo.green.offset == 0) && (var_screeninfo.blue.offset == 0)) {
00162 if (var_screeninfo.bits_per_pixel == 4)
00163 this->layers[0].pixelformat = MMSFB_PF_A4;
00164 else
00165 if (var_screeninfo.bits_per_pixel == 16)
00166 this->layers[0].pixelformat = MMSFB_PF_YUY2;
00167 else
00168 this->layers[0].pixelformat = MMSFB_PF_NONE;
00169 }
00170 break;
00171 case 8:
00172
00173 if ((var_screeninfo.red.length == 8) && (var_screeninfo.green.length == 8) && (var_screeninfo.blue.length == 8)
00174 && (var_screeninfo.red.offset == 16) && (var_screeninfo.green.offset == 8) && (var_screeninfo.blue.offset == 0)) {
00175 this->layers[0].pixelformat = MMSFB_PF_ARGB;
00176 }
00177 else
00178 if ((var_screeninfo.red.length == 8) && (var_screeninfo.green.length == 8) && (var_screeninfo.blue.length == 8)
00179 && (var_screeninfo.red.offset == 0) && (var_screeninfo.green.offset == 8) && (var_screeninfo.blue.offset == 16)) {
00180 this->layers[0].pixelformat = MMSFB_PF_ABGR;
00181 }
00182 break;
00183 }
00184
00185 if (this->layers[0].pixelformat != MMSFB_PF_NONE) {
00186 printf("MMSFBDev: current pixelformat is %s\n", getMMSFBPixelFormatString(this->layers[0].pixelformat).c_str());
00187 return true;
00188 }
00189
00190 return false;
00191 }
00192
00193 bool MMSFBDev::readModes() {
00194
00195 this->modes_cnt = 0;
00196
00197
00198 FILE *fp;
00199 if (!(fp = fopen("/etc/fb.modes","r")))
00200 return false;
00201
00202
00203 char line[128];
00204 while (fgets(line, sizeof(line)-1, fp)) {
00205 char label[32];
00206 if (sscanf(line, "mode \"%31[^\"]\"", label) == 1) {
00207
00208 bool geom_set = false;
00209 bool timings_set = false;
00210 struct fb_var_screeninfo *mode = &this->modes[this->modes_cnt];
00211 memset(mode, 0, sizeof(struct fb_var_screeninfo));
00212
00213
00214 while (fgets(line, sizeof(line)-1, fp) && !(strstr(line, "endmode"))) {
00215 char value[16];
00216 int dummy;
00217 if (sscanf(line, " geometry %d %d %d %d %d",
00218 &mode->xres, &mode->yres, &dummy, &dummy, &mode->bits_per_pixel) == 5)
00219 geom_set = true;
00220 else
00221 if (sscanf(line, " timings %d %d %d %d %d %d %d",
00222 &mode->pixclock, &mode->left_margin, &mode->right_margin,
00223 &mode->upper_margin, &mode->lower_margin, &mode->hsync_len, &mode->vsync_len) == 7)
00224 timings_set = true;
00225 else
00226 if ((sscanf(line, " hsync %15s", value) == 1) && !strcasecmp(value, "high"))
00227 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
00228 else
00229 if ((sscanf(line, " vsync %15s", value) == 1) && !strcasecmp(value, "high"))
00230 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
00231 else
00232 if ((sscanf(line, " csync %15s", value) == 1) && !strcasecmp(value, "high"))
00233 mode->sync |= FB_SYNC_COMP_HIGH_ACT;
00234 else
00235 if ((sscanf(line, " gsync %15s", value) == 1) && !strcasecmp(value, "true"))
00236 mode->sync |= FB_SYNC_ON_GREEN;
00237 else
00238 if ((sscanf(line, " extsync %15s", value) == 1) && !strcasecmp(value, "true"))
00239 mode->sync |= FB_SYNC_EXT;
00240 else
00241 if ((sscanf(line, " bcast %15s", value) == 1) && !strcasecmp(value, "true"))
00242 mode->sync |= FB_SYNC_BROADCAST;
00243 else
00244 if ((sscanf(line, " laced %15s", value) == 1) && !strcasecmp(value, "true"))
00245 mode->vmode |= FB_VMODE_INTERLACED;
00246 else
00247 if ((sscanf(line, " double %15s", value) == 1) && !strcasecmp(value, "true"))
00248 mode->vmode |= FB_VMODE_DOUBLE;
00249 }
00250
00251 if (geom_set && timings_set) {
00252
00253 this->modes_cnt++;
00254
00255 printf("MMSFBDev: mode %s (%dx%d, %d bits) loaded from /etc/fb.modes\n", label, mode->xres, mode->yres, mode->bits_per_pixel);
00256 }
00257 else {
00258
00259 printf("MMSFBDev: ignore mode %s (%dx%d, %d bits) from /etc/fb.modes\n", label, mode->xres, mode->yres, mode->bits_per_pixel);
00260 }
00261 }
00262 }
00263
00264 fclose (fp);
00265 return true;
00266 }
00267
00268
00269 bool MMSFBDev::openDevice(char *device_file, int console) {
00270
00271 closeDevice();
00272
00273 if (device_file) {
00274
00275 this->fd = open(device_file, O_RDWR);
00276 if (this->fd < 0) {
00277 printf("MMSFBDev: opening device %s failed\n", device_file);
00278 return false;
00279 }
00280 this->device_file = device_file;
00281 }
00282 else {
00283
00284 this->fd = open("/dev/fb0", O_RDWR);
00285 if (this->fd < 0) {
00286 this->fd = open("/dev/fb/0", O_RDWR);
00287 if (this->fd < 0) {
00288 printf("MMSFBDev: opening device /dev/fb0 and /dev/fb/0 failed\n");
00289 return false;
00290 }
00291 this->device_file = "/dev/fb/0";
00292 }
00293 else
00294 this->device_file = "/dev/fb0";
00295 }
00296
00297
00298 fcntl(this->fd, F_SETFD, FD_CLOEXEC);
00299
00300
00301 memset(this->device, 0, sizeof(this->device));
00302 sprintf(this->device, "fb0");
00303 if (this->device_file.substr(0, 8) == "/dev/fb/")
00304 sprintf(this->device, "fb%s", this->device_file.substr(8, 5).c_str());
00305 else
00306 if (this->device_file.substr(0, 7) == "/dev/fb")
00307 sprintf(this->device, "fb%s", this->device_file.substr(7, 5).c_str());
00308
00309
00310 readModes();
00311 printf("MMSFBDev: %d modes loaded from /etc/fb.modes\n", this->modes_cnt);
00312
00313
00314 if (console >= -1)
00315 if (!vtOpen(console)) {
00316 closeDevice();
00317 return false;
00318 }
00319
00320
00321 if (ioctl(this->fd, FBIOGET_FSCREENINFO, &this->fix_screeninfo) < 0) {
00322 printf("MMSFBDev: could not get fix screen infos from %s\n", this->device_file.c_str());
00323 closeDevice();
00324 return false;
00325 }
00326 printFixScreenInfo();
00327
00328
00329 if ((this->framebuffer_base=mmap(NULL, this->fix_screeninfo.smem_len,
00330 PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, 0)) == MAP_FAILED) {
00331 if ((this->framebuffer_base=mmap(NULL, this->fix_screeninfo.smem_len,
00332 PROT_READ | PROT_WRITE, MAP_PRIVATE, this->fd, 0)) == MAP_FAILED) {
00333 printf("MMSFBDev: could not mmap framebuffer memory for %s\n", this->device_file.c_str());
00334 this->framebuffer_base = NULL;
00335 closeDevice();
00336 return false;
00337 }
00338 }
00339
00340
00341 if (ioctl(this->fd, FBIOGET_VSCREENINFO, &this->org_var_screeninfo) < 0) {
00342 printf("MMSFBDev: could not get var screen infos from %s\n", this->device_file.c_str());
00343 closeDevice();
00344 return false;
00345 }
00346
00347
00348 this->var_screeninfo = this->org_var_screeninfo;
00349 this->var_screeninfo.accel_flags = 0;
00350 if (ioctl(this->fd, FBIOPUT_VSCREENINFO, &this->var_screeninfo) < 0) {
00351 printf("MMSFBDev: could not disable console acceleration for %s\n", this->device_file.c_str());
00352 closeDevice();
00353 return false;
00354 }
00355 printVarScreenInfo();
00356
00357
00358 buildPixelFormat();
00359
00360
00361 this->isinitialized = true;
00362
00363 return true;
00364 }
00365
00366 void MMSFBDev::closeDevice() {
00367
00368 vtClose();
00369
00370
00371 if (this->reset_console_accel) {
00372
00373 ioctl(this->fd, FBIOPUT_VSCREENINFO, &this->org_var_screeninfo);
00374 this->reset_console_accel = false;
00375 }
00376
00377 if (this->framebuffer_base) {
00378 munmap(this->framebuffer_base, this->fix_screeninfo.smem_len);
00379 this->framebuffer_base = NULL;
00380 }
00381
00382 if (this->fd != -1) {
00383 close(this->fd);
00384 this->fd = -1;
00385 }
00386
00387
00388 this->isinitialized = false;
00389 memset(this->modes, 0, sizeof(this->modes));
00390 this->modes_cnt = 0;
00391 memset(this->layers, 0, sizeof(this->layers));
00392 this->layers_cnt = 0;
00393 this->active_screen = 0;
00394 }
00395
00396 bool MMSFBDev::isInitialized() {
00397 return this->isinitialized;
00398 }
00399
00400 bool MMSFBDev::waitForVSync() {
00401
00402 INITCHECK;
00403
00404
00405 if (this->active_screen != 0) {
00406 printf("MMSFBDev: screen %d is not supported\n", this->active_screen);
00407 return false;
00408 }
00409
00410 static const int s = 0;
00411 if (ioctl(this->fd, FBIO_WAITFORVSYNC, &s)) {
00412
00413 }
00414
00415 return true;
00416 }
00417
00418 bool MMSFBDev::panDisplay(int buffer_id, void *framebuffer_base) {
00419
00420 INITCHECK;
00421
00422
00423 if (framebuffer_base) {
00424 if (framebuffer_base != this->framebuffer_base) {
00425 printf("MMSFBDev: framebuffer base pointer not correct\n");
00426 return false;
00427 }
00428 }
00429
00430
00431 int yoffset = buffer_id * this->var_screeninfo.yres;
00432 if ((yoffset < 0) || (yoffset + this->var_screeninfo.yres > this->var_screeninfo.yres_virtual)) {
00433 return false;
00434 }
00435 int xoffset_save = this->var_screeninfo.xoffset;
00436 int yoffset_save = this->var_screeninfo.yoffset;
00437
00438
00439 this->var_screeninfo.xoffset = 0;
00440 this->var_screeninfo.yoffset = yoffset;
00441 if (this->fix_screeninfo.ypanstep)
00442 this->var_screeninfo.vmode &= ~FB_VMODE_YWRAP;
00443 else
00444 this->var_screeninfo.vmode |= FB_VMODE_YWRAP;
00445
00446
00447 this->var_screeninfo.activate = FB_ACTIVATE_VBL;
00448 if (ioctl(this->fd, FBIOPAN_DISPLAY, &this->var_screeninfo) < 0) {
00449 printf("MMSFBDev: display panning not supported\n");
00450 this->var_screeninfo.xoffset = xoffset_save;
00451 this->var_screeninfo.yoffset = yoffset_save;
00452 return false;
00453 }
00454
00455 return true;
00456 }
00457
00458 bool MMSFBDev::testLayer(int layer_id) {
00459
00460 INITCHECK;
00461
00462
00463 if (layer_id != 0) {
00464 printf("MMSFBDev: layer %d is not supported\n", layer_id);
00465 return false;
00466 }
00467
00468 return true;
00469 }
00470
00471 bool MMSFBDev::initLayer(int layer_id, int width, int height, MMSFBSurfacePixelFormat pixelformat, int backbuffer) {
00472
00473 INITCHECK;
00474
00475
00476 if (layer_id != 0) {
00477 printf("MMSFBDev: layer %d is not supported\n", layer_id);
00478 return false;
00479 }
00480
00481
00482 if (!setMode(width, height, pixelformat, backbuffer))
00483 return false;
00484
00485 if (width <= 0 || height <= 0) {
00486
00487 this->layers[layer_id].isinitialized = false;
00488 return true;
00489 }
00490
00491
00492 this->layers[layer_id].width = this->var_screeninfo.xres;
00493 this->layers[layer_id].height = this->var_screeninfo.yres;
00494
00495
00496 memset(&this->layers[layer_id].buffers, 0, sizeof(this->layers[layer_id].buffers));
00497 switch (backbuffer) {
00498 case 2:
00499 this->layers[layer_id].buffers[2].ptr = ((char *)this->framebuffer_base)
00500 + 2 * this->fix_screeninfo.line_length * this->var_screeninfo.yres;
00501 this->layers[layer_id].buffers[2].pitch= this->fix_screeninfo.line_length;
00502 this->layers[layer_id].buffers[2].hwbuffer = true;
00503 case 1:
00504 this->layers[layer_id].buffers[1].ptr = ((char *)this->framebuffer_base)
00505 + this->fix_screeninfo.line_length * this->var_screeninfo.yres;
00506 this->layers[layer_id].buffers[1].pitch= this->fix_screeninfo.line_length;
00507 this->layers[layer_id].buffers[1].hwbuffer = true;
00508 case 0:
00509 this->layers[layer_id].buffers[0].ptr = this->framebuffer_base;
00510 this->layers[layer_id].buffers[0].pitch= this->fix_screeninfo.line_length;
00511 this->layers[layer_id].buffers[0].hwbuffer = true;
00512 break;
00513 default:
00514 return false;
00515 }
00516
00517
00518 this->layers[layer_id].isinitialized = true;
00519
00520
00521 this->active_screen = 0;
00522
00523 return true;
00524 }
00525
00526 bool MMSFBDev::releaseLayer(int layer_id) {
00527 printf("MMSFBDev: layer %d cannot be released\n", layer_id);
00528 return false;
00529 }
00530
00531 bool MMSFBDev::restoreLayer(int layer_id) {
00532 printf("MMSFBDev: layer %d cannot be restored\n", layer_id);
00533 return false;
00534 }
00535
00536 bool MMSFBDev::getPixelFormat(int layer_id, MMSFBSurfacePixelFormat *pf) {
00537
00538 INITCHECK;
00539
00540
00541 if (!this->layers[layer_id].isinitialized)
00542 return false;
00543
00544
00545 *pf = this->layers[layer_id].pixelformat;
00546 return true;
00547 }
00548
00549 bool MMSFBDev::getPhysicalMemory(unsigned long *mem) {
00550
00551 INITCHECK;
00552 *mem = this->fix_screeninfo.smem_start;
00553 return true;
00554 }
00555
00556 bool MMSFBDev::getFrameBufferBase(unsigned char **base) {
00557
00558 INITCHECK;
00559 *base = (unsigned char *)this->framebuffer_base;
00560 return true;
00561 }
00562
00563 bool MMSFBDev::getFrameBufferPtr(int layer_id, MMSFBSurfacePlanesBuffer buffers, int *width, int *height) {
00564
00565 INITCHECK;
00566
00567
00568 if (!this->layers[layer_id].isinitialized) {
00569 return false;
00570 }
00571
00572
00573 if (buffers)
00574 memcpy(buffers, this->layers[layer_id].buffers, sizeof(this->layers[layer_id].buffers));
00575 *width = this->layers[layer_id].width;
00576 *height = this->layers[layer_id].height;
00577
00578 return true;
00579 }
00580
00581
00582 bool MMSFBDev::mapMmio(unsigned char **mmio) {
00583
00584 INITCHECK;
00585
00586 *mmio = (unsigned char *)mmap(NULL, this->fix_screeninfo.mmio_len, PROT_READ | PROT_WRITE, MAP_SHARED,
00587 this->fd, this->fix_screeninfo.smem_len);
00588 if (!*mmio) {
00589 printf("MMSFBDev: could not mmap mmio buffer\n");
00590 return false;
00591 }
00592
00593 long page_size = sysconf(_SC_PAGESIZE);
00594 unsigned long page_mask = page_size < 0 ? 0 : (page_size - 1);
00595
00596 *mmio = (*mmio) + (this->fix_screeninfo.mmio_start & page_mask);
00597
00598 return true;
00599 }
00600
00601 bool MMSFBDev::unmapMmio(unsigned char *mmio) {
00602
00603 INITCHECK;
00604
00605 long page_size = sysconf(_SC_PAGESIZE);
00606 unsigned long page_mask = page_size < 0 ? 0 : (page_size - 1);
00607
00608 munmap((void*)(mmio - (this->fix_screeninfo.mmio_start & page_mask)), this->fix_screeninfo.mmio_len);
00609
00610 return true;
00611 }
00612
00613 void MMSFBDev::genFBPixelFormat(MMSFBSurfacePixelFormat pf, unsigned int *nonstd_format, MMSFBPixelDef *pixeldef) {
00614
00615
00616 if (nonstd_format) *nonstd_format = 0;
00617 getBitsPerPixel(pf, pixeldef);
00618
00619
00620 this->onGenFBPixelFormat.emit(pf, nonstd_format, pixeldef);
00621 }
00622
00623 void MMSFBDev::disable(int fd, string device_file) {
00624
00625 if (!this->onDisable.emit(fd, device_file)) {
00626
00627 struct fb_var_screeninfo var_screeninfo;
00628 ioctl(fd, FBIOGET_VSCREENINFO, &var_screeninfo);
00629 var_screeninfo.activate = FB_ACTIVATE_NOW;
00630 var_screeninfo.accel_flags = 0;
00631 var_screeninfo.xres = 0;
00632 var_screeninfo.yres = 0;
00633 var_screeninfo.xres_virtual = 0;
00634 var_screeninfo.yres_virtual = 0;
00635 var_screeninfo.xoffset = 0;
00636 var_screeninfo.yoffset = 0;
00637 var_screeninfo.grayscale = 0;
00638 ioctl(fd, FBIOPUT_VSCREENINFO, &var_screeninfo);
00639 ioctl(fd, FBIOBLANK, 1);
00640 }
00641 }
00642
00643 bool MMSFBDev::activate(int fd, string device_file, struct fb_var_screeninfo *var_screeninfo,
00644 int width, int height, MMSFBSurfacePixelFormat pixelformat, bool switch_mode) {
00645
00646
00647 if (!this->onActivate.emit(fd, device_file, var_screeninfo, width, height, pixelformat, switch_mode)) {
00648
00649 if (switch_mode) {
00650 if (ioctl(fd, FBIOPUT_VSCREENINFO, var_screeninfo) < 0) {
00651 printf("MMSFBDev: could not switch to mode %dx%d, pixelformat %s (%d bits, nonstd %d), %s\n",
00652 width, height, getMMSFBPixelFormatString(pixelformat).c_str(),
00653 var_screeninfo->bits_per_pixel, var_screeninfo->nonstd,
00654 device_file.c_str());
00655 return false;
00656 }
00657 }
00658 }
00659
00660
00661 if (ioctl(this->fd, FBIOGET_FSCREENINFO, &this->fix_screeninfo) < 0) {
00662 printf("MMSFBDev: could not get fix screen infos from %s\n", this->device_file.c_str());
00663 return false;
00664 }
00665 printFixScreenInfo();
00666
00667
00668 if (ioctl(this->fd, FBIOGET_VSCREENINFO, &this->var_screeninfo) < 0) {
00669 printf("MMSFBDev: could not get var screen infos from %s\n", this->device_file.c_str());
00670 return false;
00671 }
00672 printVarScreenInfo();
00673
00674 return true;
00675 }
00676
00677 bool MMSFBDev::setMode(int width, int height, MMSFBSurfacePixelFormat pixelformat, int backbuffer) {
00678 bool do_switch = false;
00679
00680
00681 INITCHECK;
00682
00683 if (width <= 0 || height <= 0) {
00684
00685 disable(this->fd, this->device_file);
00686 return true;
00687 }
00688
00689
00690 if (ioctl(this->fd, FBIOGET_FSCREENINFO, &this->fix_screeninfo) < 0) {
00691 printf("MMSFBDev: could not get fix screen infos from %s\n", this->device_file.c_str());
00692 return false;
00693 }
00694 printFixScreenInfo();
00695
00696
00697 if (ioctl(this->fd, FBIOGET_VSCREENINFO, &this->var_screeninfo) < 0) {
00698 printf("MMSFBDev: could not get var screen infos from %s\n", this->device_file.c_str());
00699 return false;
00700 }
00701 printVarScreenInfo();
00702
00703 if (backbuffer) {
00704 if ((!this->fix_screeninfo.ypanstep)&&(!this->fix_screeninfo.ywrapstep)) {
00705 printf("MMSFBDev: backbuffer requested, but hardware does not support it for %s\n", this->device_file.c_str());
00706 return false;
00707 }
00708 }
00709
00710
00711 unsigned int nonstd_format;
00712 MMSFBPixelDef pixeldef;
00713 genFBPixelFormat(pixelformat, &nonstd_format, &pixeldef);
00714
00715
00716 if (!nonstd_format) {
00717
00718 if ((width == (int)this->var_screeninfo.xres) && (height == (int)this->var_screeninfo.yres)
00719 && (pixeldef.bits == (int)this->var_screeninfo.bits_per_pixel) && (this->layers[0].pixelformat == pixelformat)
00720 && (!backbuffer || (this->var_screeninfo.yres_virtual >= this->var_screeninfo.yres * (backbuffer+1)))) {
00721
00722 printf("MMSFBDev: using preset mode %dx%d, pixelformat %s (%d bits), %s\n",
00723 width, height, getMMSFBPixelFormatString(pixelformat).c_str(), pixeldef.bits,
00724 this->device_file.c_str());
00725
00726
00727 activate(this->fd, this->device_file, &this->var_screeninfo, width, height, pixelformat, false);
00728 return true;
00729 }
00730 }
00731
00732 if (!do_switch) {
00733
00734 for (int cnt = 0; cnt < this->modes_cnt; cnt++) {
00735 struct fb_var_screeninfo *mode = &this->modes[cnt];
00736 if ((width == (int)mode->xres) && (height == (int)mode->yres) && (pixeldef.bits == (int)mode->bits_per_pixel)) {
00737
00738 this->var_screeninfo = *mode;
00739
00740 this->var_screeninfo.activate = FB_ACTIVATE_NOW;
00741 this->var_screeninfo.accel_flags = 0;
00742
00743 this->var_screeninfo.nonstd = nonstd_format;
00744
00745 this->var_screeninfo.red.length = pixeldef.red_length;
00746 this->var_screeninfo.red.offset = pixeldef.red_offset;
00747 this->var_screeninfo.green.length = pixeldef.green_length;
00748 this->var_screeninfo.green.offset = pixeldef.green_offset;
00749 this->var_screeninfo.blue.length = pixeldef.blue_length;
00750 this->var_screeninfo.blue.offset = pixeldef.blue_offset;
00751 this->var_screeninfo.transp.length = pixeldef.transp_length;
00752 this->var_screeninfo.transp.offset = pixeldef.transp_offset;
00753
00754 this->var_screeninfo.xres_virtual = this->var_screeninfo.xres;
00755 this->var_screeninfo.yres_virtual = this->var_screeninfo.yres * (backbuffer+1);
00756 this->var_screeninfo.xoffset = 0;
00757 this->var_screeninfo.yoffset = 0;
00758 this->var_screeninfo.grayscale = 0;
00759
00760 do_switch = true;
00761 break;
00762 }
00763 }
00764 }
00765
00766 if (!do_switch) {
00767
00768 printf("MMSFBDev: no mode %dx%d, bit depth %d (%s) found in /etc/fb.modes\n",
00769 width, height, pixeldef.bits, getMMSFBPixelFormatString(pixelformat).c_str());
00770
00771
00772 for (int cnt = 0; cnt < this->modes_cnt; cnt++) {
00773 struct fb_var_screeninfo *mode = &this->modes[cnt];
00774 if ((width == (int)mode->xres) && (height == (int)mode->yres)) {
00775
00776 this->var_screeninfo = *mode;
00777
00778 printf("MMSFBDev: trying to use first mode %dx%d, bit depth %d from /etc/fb.modes\n", width, height, this->var_screeninfo.bits_per_pixel);
00779
00780 this->var_screeninfo.activate = FB_ACTIVATE_NOW;
00781 this->var_screeninfo.accel_flags = 0;
00782
00783 this->var_screeninfo.nonstd = nonstd_format;
00784
00785 this->var_screeninfo.bits_per_pixel = pixeldef.bits;
00786 this->var_screeninfo.red.length = pixeldef.red_length;
00787 this->var_screeninfo.red.offset = pixeldef.red_offset;
00788 this->var_screeninfo.green.length = pixeldef.green_length;
00789 this->var_screeninfo.green.offset = pixeldef.green_offset;
00790 this->var_screeninfo.blue.length = pixeldef.blue_length;
00791 this->var_screeninfo.blue.offset = pixeldef.blue_offset;
00792 this->var_screeninfo.transp.length = pixeldef.transp_length;
00793 this->var_screeninfo.transp.offset = pixeldef.transp_offset;
00794
00795 this->var_screeninfo.xres_virtual = this->var_screeninfo.xres;
00796 this->var_screeninfo.yres_virtual = this->var_screeninfo.yres * (backbuffer+1);
00797 this->var_screeninfo.xoffset = 0;
00798 this->var_screeninfo.yoffset = 0;
00799 this->var_screeninfo.grayscale = 0;
00800
00801 do_switch = true;
00802 break;
00803 }
00804 }
00805 }
00806
00807 if (!do_switch) {
00808
00809 printf("MMSFBDev: no mode %dx%d with any bit depth found in /etc/fb.modes\n", width, height);
00810
00811
00812 if ((width == (int)this->var_screeninfo.xres) && (height == (int)this->var_screeninfo.yres)) {
00813
00814 printf("MMSFBDev: resolution is the same, so try to change the pixelformat to %s, %s\n",
00815 getMMSFBPixelFormatString(pixelformat).c_str(),
00816 this->device_file.c_str());
00817
00818 this->var_screeninfo.activate = FB_ACTIVATE_NOW;
00819 this->var_screeninfo.accel_flags = 0;
00820
00821 this->var_screeninfo.nonstd = nonstd_format;
00822
00823 this->var_screeninfo.bits_per_pixel = pixeldef.bits;
00824 this->var_screeninfo.red.length = pixeldef.red_length;
00825 this->var_screeninfo.red.offset = pixeldef.red_offset;
00826 this->var_screeninfo.green.length = pixeldef.green_length;
00827 this->var_screeninfo.green.offset = pixeldef.green_offset;
00828 this->var_screeninfo.blue.length = pixeldef.blue_length;
00829 this->var_screeninfo.blue.offset = pixeldef.blue_offset;
00830 this->var_screeninfo.transp.length = pixeldef.transp_length;
00831 this->var_screeninfo.transp.offset = pixeldef.transp_offset;
00832
00833 if (backbuffer) {
00834 this->var_screeninfo.xres_virtual = this->var_screeninfo.xres;
00835 this->var_screeninfo.yres_virtual = this->var_screeninfo.yres * (backbuffer+1);
00836 this->var_screeninfo.xoffset = 0;
00837 this->var_screeninfo.yoffset = 0;
00838 }
00839
00840 do_switch = true;
00841 }
00842 else
00843 if (this->layers[0].pixelformat == pixelformat) {
00844
00845 printf("MMSFBDev: pixelformat is the same, so try to change the resolution to %dx%d, %s\n",
00846 width, height,
00847 this->device_file.c_str());
00848
00849 this->var_screeninfo.activate = FB_ACTIVATE_NOW;
00850 this->var_screeninfo.accel_flags = 0;
00851
00852 this->var_screeninfo.xres = width;
00853 this->var_screeninfo.yres = height;
00854
00855 this->var_screeninfo.xres_virtual = this->var_screeninfo.xres;
00856 this->var_screeninfo.yres_virtual = this->var_screeninfo.yres * (backbuffer+1);
00857 this->var_screeninfo.xoffset = 0;
00858 this->var_screeninfo.yoffset = 0;
00859 this->var_screeninfo.grayscale = 0;
00860
00861 do_switch = true;
00862 }
00863 }
00864
00865 if (do_switch) {
00866
00867 if (!activate(this->fd, this->device_file, &this->var_screeninfo, width, height, pixelformat)) {
00868 return false;
00869 }
00870
00871
00872 if ((width == (int)this->var_screeninfo.xres) && (height == (int)this->var_screeninfo.yres)
00873 && (pixeldef.bits == (int)this->var_screeninfo.bits_per_pixel)) {
00874
00875 printf("MMSFBDev: mode successfully switched to %dx%d, pixelformat %s (%d bits), %s\n",
00876 width, height, getMMSFBPixelFormatString(pixelformat).c_str(), pixeldef.bits,
00877 this->device_file.c_str());
00878
00879 if (backbuffer) {
00880 if (this->var_screeninfo.yres_virtual < this->var_screeninfo.yres * (backbuffer+1)) {
00881 printf("MMSFBDev: buffer size %dx%d is to small (%dx%d requested), %s\n",
00882 this->var_screeninfo.xres_virtual, this->var_screeninfo.yres_virtual,
00883 this->var_screeninfo.xres, this->var_screeninfo.yres * (backbuffer+1),
00884 this->device_file.c_str());
00885 return false;
00886 }
00887 }
00888 }
00889 else {
00890 printf("MMSFBDev: mode switch to %dx%d, pixelformat %s (%d bits) failed, %s\n",
00891 width, height, getMMSFBPixelFormatString(pixelformat).c_str(), pixeldef.bits,
00892 this->device_file.c_str());
00893 return false;
00894 }
00895
00896
00897 if (!buildPixelFormat()) {
00898 printf("MMSFBDev: unsupported pixelformat: r=%d(offs=%d), g=%d(offs=%d), b=%d(offs=%d), a=%d(offs=%d) (%d bit)\n",
00899 this->var_screeninfo.red.length, this->var_screeninfo.red.offset,
00900 this->var_screeninfo.green.length, this->var_screeninfo.green.offset,
00901 this->var_screeninfo.blue.length, this->var_screeninfo.blue.offset,
00902 this->var_screeninfo.transp.length, this->var_screeninfo.transp.offset,
00903 this->var_screeninfo.bits_per_pixel);
00904 return false;
00905 }
00906
00907 if (this->layers[0].pixelformat != pixelformat) {
00908 printf("MMSFBDev: pixelformat not correctly set, %s set, %s requested\n",
00909 getMMSFBPixelFormatString(this->layers[0].pixelformat).c_str(),
00910 getMMSFBPixelFormatString(pixelformat).c_str());
00911 return false;
00912 }
00913
00914 return true;
00915 }
00916
00917 return false;
00918 }
00919
00920
00921
00922 bool MMSFBDev::vtOpen(int console) {
00923
00924 vtClose();
00925
00926
00927 setsid();
00928
00929
00930 this->vt.fd0 = open("/dev/tty0", O_RDONLY | O_NOCTTY);
00931 if (this->vt.fd0 < 0) {
00932 if (errno == ENXIO) {
00933 printf("MMSFBDev: virtual terminal not available (working without it)\n");
00934 return true;
00935 }
00936 if (errno == ENOENT) {
00937 this->vt.fd0 = open("/dev/vc/0", O_RDONLY | O_NOCTTY);
00938 if (this->vt.fd0 < 0) {
00939 printf("MMSFBDev: opening device /dev/tty0 and /dev/vc/0 failed\n");
00940 return false;
00941 }
00942 }
00943 else {
00944 printf("MMSFBDev: opening device /dev/tty0 failed\n");
00945 return false;
00946 }
00947 }
00948
00949
00950 struct vt_stat vs;
00951 if (ioctl(this->vt.fd0, VT_GETSTATE, &vs) < 0) {
00952 printf("MMSFBDev: could not get vt state\n");
00953 vtClose();
00954 return false;
00955 }
00956 this->vt.previous = vs.v_active;
00957 printf("MMSFBDev: started from virtual terminal #%d\n", this->vt.previous);
00958
00959 if (console >= 0) {
00960 this->vt.number = console;
00961 }
00962 else {
00963
00964 int n = ioctl(this->vt.fd0, VT_OPENQRY, &this->vt.number);
00965 if ((n < 0) || (this->vt.number == -1)) {
00966 printf("MMSFBDev: query vt number failed\n");
00967 vtClose();
00968 return false;
00969 }
00970 }
00971 printf("MMSFBDev: using virtual terminal #%d\n", this->vt.number);
00972
00973
00974 struct fb_con2fbmap c2f;
00975 c2f.console = this->vt.number;
00976 if (ioctl(this->fd, FBIOGET_CON2FBMAP, &c2f)) {
00977 printf("MMSFBDev: get original framebuffer failed for vt #%d\n", this->vt.number);
00978 vtClose();
00979 return false;
00980 }
00981 this->vt.org_fb = c2f.framebuffer;
00982
00983
00984 struct stat fbs;
00985 if (fstat(this->fd, &fbs)) {
00986 printf("MMSFBDev: stat fb device failed\n");
00987 this->vt.org_fb = -1;
00988 vtClose();
00989 return false;
00990 }
00991 c2f.framebuffer = (fbs.st_rdev & 0xFF) >> 5;
00992 c2f.console = this->vt.number;
00993 if (ioctl(this->fd, FBIOPUT_CON2FBMAP, &c2f) < 0) {
00994 printf("MMSFBDev: set console for framebuffer failed\n");
00995 this->vt.org_fb = -1;
00996 vtClose();
00997 return false;
00998 }
00999
01000
01001 while (ioctl(this->vt.fd0, VT_ACTIVATE, this->vt.number) < 0) {
01002 if (errno == EINTR) continue;
01003 printf("MMSFBDev: cannot switch (VT_ACTIVATE) to console #%d\n", this->vt.number);
01004 vtClose();
01005 return false;
01006 }
01007 while (ioctl(this->vt.fd0, VT_WAITACTIVE, this->vt.number) < 0) {
01008 if (errno == EINTR) continue;
01009 printf("MMSFBDev: cannot switch (VT_WAITACTIVE) to console #%d\n", this->vt.number);
01010 vtClose();
01011 return false;
01012 }
01013 usleep(50*1000);
01014
01015
01016 char tty[16];
01017 sprintf(tty, "/dev/tty%d", this->vt.number);
01018 this->vt.fd = open(tty, O_RDWR | O_NOCTTY);
01019 if (this->vt.fd < 0) {
01020 if (errno == ENOENT) {
01021 sprintf(tty, "/dev/vc/%d", this->vt.number);
01022 this->vt.fd = open(tty, O_RDWR | O_NOCTTY);
01023 if (this->vt.fd < 0) {
01024 printf("MMSFBDev: opening device /dev/tty%d and /dev/vc/%d failed\n", this->vt.number, this->vt.number);
01025 vtClose();
01026 return false;
01027 }
01028 }
01029 else {
01030 printf("MMSFBDev: opening device /dev/tty%d failed\n", this->vt.number);
01031 vtClose();
01032 return false;
01033 }
01034 }
01035
01036
01037 ioctl(this->vt.fd, TIOCSCTTY, 0);
01038
01039
01040 const char cursor_off[] = "\033[?1;0;0c";
01041 write(this->vt.fd, cursor_off, sizeof(cursor_off));
01042
01043
01044 ioctl(this->vt.fd, KDSETMODE, KD_GRAPHICS);
01045
01046
01047 ioctl(this->vt.fd, KDSKBMODE, K_MEDIUMRAW);
01048 ioctl(this->vt.fd, KDSKBLED, 0);
01049 tcgetattr(this->vt.fd, &this->saved_ts);
01050 struct termios ts;
01051 ts = this->saved_ts;
01052 ts.c_cc[VTIME] = 0;
01053 ts.c_cc[VMIN] = 1;
01054 ts.c_lflag &= ~(ICANON|ECHO|ISIG);
01055 ts.c_iflag = 0;
01056 tcsetattr(this->vt.fd, TCSAFLUSH, &ts);
01057 tcsetpgrp(this->vt.fd, getpgrp());
01058
01059 return true;
01060 }
01061
01062 void MMSFBDev::vtClose() {
01063 if (this->vt.fd != -1) {
01064
01065 tcsetattr(this->vt.fd, TCSAFLUSH, &this->saved_ts);
01066 ioctl(this->vt.fd, KDSKBMODE, K_XLATE);
01067 ioctl(this->vt.fd, KDSETMODE, KD_TEXT);
01068 const char cursor_on[] = "\033[?0;0;0c";
01069 write(this->vt.fd, cursor_on, sizeof(cursor_on));
01070 close(this->vt.fd);
01071 this->vt.fd = -1;
01072 }
01073
01074 if (this->vt.org_fb != -1) {
01075
01076 struct fb_con2fbmap c2f;
01077 c2f.framebuffer = this->vt.org_fb;
01078 c2f.console = this->vt.number;
01079 ioctl(this->fd, FBIOPUT_CON2FBMAP, &c2f);
01080 this->vt.org_fb = -1;
01081 }
01082
01083 if (this->vt.previous != -1) {
01084
01085 ioctl(this->vt.fd0, VT_ACTIVATE, this->vt.previous);
01086 ioctl(this->vt.fd0, VT_WAITACTIVE, this->vt.previous);
01087 usleep(50*1000);
01088 ioctl(this->vt.fd0, VT_DISALLOCATE, this->vt.number);
01089 this->vt.number = -1;
01090 this->vt.previous = -1;
01091 }
01092
01093 if (this->vt.fd0 != -1) {
01094
01095 close(this->vt.fd0);
01096 this->vt.fd0 = -1;
01097 }
01098 }
01099
01100 bool MMSFBDev::vtGetFd(int *fd) {
01101 if (this->vt.fd != -1) {
01102 *fd = this->vt.fd;
01103 return true;
01104 }
01105 return false;
01106 }
01107
01108 #endif