1 /* 2 * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #ifdef IMX6_PLATFORM 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <linux/fb.h> 33 #include <sys/ioctl.h> 34 #include <sys/types.h> 35 #include <stdlib.h> 36 #include <stdint.h> 37 #include <string.h> 38 #include <dlfcn.h> 39 #include <errno.h> 40 #include <linux/mxcfb.h> // note: i.MX unique header 41 42 #include "lensPort.h" 43 #include "lensPortInternal.h" 44 #include "lensPortLogger.h" 45 46 #define LENSFB_IMX6_CURSOR_DEVICE "/dev/fb1" 47 #define LENSFB_IMX6_CURSOR_SIZE 16 48 49 typedef struct { 50 int fd; 51 int width; 52 int height; 53 int x,y; 54 int screenWidth; 55 int screenHeight; 56 jlong currentCursor; 57 // When the cursor is at the extreme right or bottom of the screen, it 58 // needs to be shifted to show in the correct location. IMX doesn't let us 59 // position the framebuffer so that it is only partically visible. 60 int xShift; 61 int yShift; 62 jboolean isVisible; 63 } Imx6FBCursor; 64 65 static Imx6FBCursor cursor = { .fd = -1, .width = 0, .height = 0, .x = 0, .y = 0, .currentCursor = 0, .isVisible = 0, 66 .xShift = 0, .yShift = 0 }; 67 68 //TODO : platform supports 32 and 16 bits, how do we choose what to use ? 69 static int use32bit = 0; 70 71 typedef struct { 72 jint width; 73 jint height; 74 jint x; 75 jint y; 76 jbyte* buffer; 77 jint bufferSize; 78 } Imx6CursorImage; 79 80 81 static void fbImx6BlankCursor(){ 82 char buffer[256]; 83 int bytesToWrite; 84 85 // Set buffer to be transparent 86 memset((void*)buffer, use32bit ? 0 : LENSFB_16_CURSOR_COLOR_KEY, sizeof(buffer)); 87 88 if (lseek(cursor.fd, 0, SEEK_SET) == -1) { 89 GLASS_LOG_SEVERE("Cannot rewrite cursor image"); 90 return; 91 } 92 93 bytesToWrite = cursor.width * cursor.height * (use32bit ? 4 : 2); 94 while (bytesToWrite > 0) { 95 int n = bytesToWrite > sizeof(buffer) ? sizeof(buffer) : bytesToWrite; 96 int res; 97 if ((res = write(cursor.fd, buffer, n)) < n) { 98 GLASS_LOG_SEVERE("Cannot write cursor plane %i bytes, wrote %i bytes", n, res); 99 return; 100 } 101 bytesToWrite -= n; 102 } 103 } 104 105 106 /* Updates values of xShift and yShift based on the cursor location */ 107 static void fbImx6AdjustShift(){ 108 if (cursor.x > cursor.screenWidth - cursor.width) { 109 cursor.xShift = cursor.width + cursor.x - cursor.screenWidth; 110 } else { 111 cursor.xShift = 0; 112 } 113 if (cursor.y > cursor.screenHeight - cursor.height) { 114 cursor.yShift = cursor.height + cursor.y - cursor.screenHeight; 115 } else { 116 cursor.yShift = 0; 117 } 118 } 119 120 /* Writes an image into the cursor framebuffer with the given x and y shifts. */ 121 static void fbImx6WriteCursor(int fd, jbyte *cursorImage, int bpp) { 122 int i, j, k; 123 char buffer[256]; 124 int cursorSize = cursor.width * cursor.height * bpp; 125 int xShift = cursor.xShift; 126 int yShift = cursor.yShift; 127 128 if (!cursor.isVisible) { 129 return; 130 } 131 132 if (lseek(cursor.fd, 0, SEEK_SET) == -1) { 133 GLASS_LOG_SEVERE("Cannot rewrite cursor image"); 134 return; 135 } 136 137 GLASS_LOG_FINEST("Cursor shift = (%i, %i) at (%i, %i)\n", 138 xShift, yShift, cursor.x, cursor.y); 139 if (xShift == 0 && yShift == 0) { 140 GLASS_LOG_FINEST("write(cursor.fd, .. %i)", cursorSize); 141 if ((i = write(cursor.fd, cursorImage, cursorSize)) < cursorSize) { 142 GLASS_LOG_SEVERE("Cannot write cursor plane cursorSize : %i, wrote %i bytes", cursorSize, i); 143 } 144 return; 145 } 146 147 // Set buffer to be transparent 148 memset((void*)buffer, use32bit ? 0 : LENSFB_16_CURSOR_COLOR_KEY, sizeof(buffer)); 149 150 // fill the y-shift rectangular area 151 for (i = 0; i < yShift; i++) { 152 for (j = 0; j < cursor.width * bpp; j += sizeof(buffer)) { 153 size_t n = cursor.width * bpp - j; 154 if (n > sizeof(buffer)) { 155 n = sizeof(buffer); 156 } 157 GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); 158 if (write(cursor.fd, buffer, n) < (int)n) { 159 GLASS_LOG_SEVERE("Cannot write cursor plane"); 160 return; 161 } 162 } 163 } 164 // set the rest of the image 165 for (i = 0; i < cursor.height - yShift; i++) { 166 for (j = 0; j < xShift * bpp; j += sizeof(buffer)) { 167 size_t n = xShift * bpp; 168 if (n > sizeof(buffer)) { 169 n = sizeof(buffer); 170 } 171 GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); 172 if (write(cursor.fd, buffer, n) < (int)n) { 173 GLASS_LOG_SEVERE("Cannot write cursor plane"); 174 return; 175 } 176 } 177 size_t n = (cursor.width - xShift) * bpp; 178 GLASS_LOG_FINEST("write(cursor.fd, .. %u)", n); 179 if (write(cursor.fd, cursorImage + i * cursor.width * bpp, n) < (int)n) { 180 GLASS_LOG_SEVERE("Cannot write cursor plane"); 181 return; 182 } 183 } 184 } 185 186 187 188 189 190 static int fbImx6ChangeCursorSize(int width, int height) { 191 192 struct fb_var_screeninfo screenInfo; 193 if (ioctl(cursor.fd, FBIOGET_VSCREENINFO, &screenInfo)) { 194 GLASS_LOG_SEVERE("Error %s in getting screen info", strerror(errno)); 195 return -1; 196 } 197 198 screenInfo.xres = width; 199 screenInfo.yres = height; 200 screenInfo.xres_virtual = width; 201 screenInfo.yres_virtual = height; 202 screenInfo.xoffset = 0; 203 screenInfo.yoffset = 0; 204 screenInfo.activate = 0; 205 206 if(ioctl(cursor.fd, FBIOPUT_VSCREENINFO, &screenInfo)) { 207 GLASS_LOG_SEVERE("Error %s in setting screen info", strerror(errno)); 208 return -1; 209 } 210 211 cursor.width = width; 212 cursor.height = height; 213 214 return 0; 215 } 216 217 218 219 static void fbImx6CursorInitialize(int screenWidth, int screenHeight, int screenDepth) { 220 221 struct fb_var_screeninfo screenInfo; 222 int rc; 223 char * zero = "0\n"; 224 int fbc = -1; 225 int fbo = -1; 226 227 //TODO : the following 2 settings can be moved to a setup script procedure 228 if ((fbc = open("/sys/class/graphics/fbcon/cursor_blink",O_RDWR)) < 0) { 229 GLASS_LOG_SEVERE("Error %s in opening /sys/class/graphics/fbcon/cursor_blink", strerror(errno)); 230 } else { 231 write(fbc,zero,1); 232 close(fbc); 233 } 234 if ((fbo = open("/sys/class/graphics/fb1/blank", O_RDWR)) < 0) { 235 GLASS_LOG_SEVERE("Error %s in opening /sys/class/graphics/fb1/blank", strerror(errno)); 236 } else { 237 write(fbo,zero,1); 238 close(fbo); 239 } 240 241 // Init cursor global variable fields 242 cursor.width = LENSFB_IMX6_CURSOR_SIZE; 243 cursor.height = LENSFB_IMX6_CURSOR_SIZE; 244 cursor.x = 0; 245 cursor.y = 0; 246 cursor.currentCursor = 0; 247 cursor.isVisible = 0; 248 cursor.screenWidth = screenWidth; 249 cursor.screenHeight = screenHeight; 250 251 cursor.fd = open(LENSFB_IMX6_CURSOR_DEVICE, O_RDWR); 252 if (cursor.fd < 0) { 253 GLASS_LOG_SEVERE("Cannot open framebuffer device %s",LENSFB_IMX6_CURSOR_DEVICE); 254 return; 255 } 256 257 if (ioctl(cursor.fd, FBIOGET_VSCREENINFO, &screenInfo)) { 258 GLASS_LOG_SEVERE("Error %s in getting screen info", strerror(errno)); 259 return; 260 } 261 262 GLASS_LOG_INFO("Initializing %d bits pixel %dx%d cursor, current %d bits\n", 263 (use32bit ? 32 : 16), LENSFB_IMX6_CURSOR_SIZE, LENSFB_IMX6_CURSOR_SIZE, screenInfo.bits_per_pixel); 264 265 screenInfo.xres = LENSFB_IMX6_CURSOR_SIZE; 266 screenInfo.yres = LENSFB_IMX6_CURSOR_SIZE; 267 screenInfo.xres_virtual = LENSFB_IMX6_CURSOR_SIZE; 268 screenInfo.yres_virtual = LENSFB_IMX6_CURSOR_SIZE; 269 screenInfo.xoffset = 0; 270 screenInfo.yoffset = 0; 271 screenInfo.activate = 0; 272 273 if (use32bit) { 274 screenInfo.bits_per_pixel = 32; 275 screenInfo.red.length = 8; 276 screenInfo.red.offset = 16; 277 screenInfo.green.length = 8; 278 screenInfo.green.offset = 8; 279 screenInfo.blue.length = 8; 280 screenInfo.blue.offset = 0; 281 screenInfo.transp.length = 8; 282 screenInfo.transp.offset = 24; 283 } else { 284 // 565 285 screenInfo.bits_per_pixel = 16; 286 screenInfo.red.length = 5; 287 screenInfo.red.offset = 11; 288 screenInfo.green.length = 6; 289 screenInfo.green.offset = 5; 290 screenInfo.blue.length = 5; 291 screenInfo.blue.offset = 0; 292 screenInfo.transp.length = 0; 293 screenInfo.transp.offset = 0; 294 } 295 296 if(ioctl(cursor.fd, FBIOPUT_VSCREENINFO, &screenInfo)) { 297 GLASS_LOG_SEVERE("Error %s in setting screen info", strerror(errno)); 298 return; 299 } 300 301 if(ioctl(cursor.fd, FBIOBLANK, FB_BLANK_UNBLANK)) { 302 GLASS_LOG_SEVERE("Error %s in gstting cursor no-blanking", strerror(errno)); 303 return; 304 } 305 306 307 if (use32bit) { 308 // alpha is taken from each pixel 309 struct mxcfb_loc_alpha loc_alpha; 310 loc_alpha.enable = 1; 311 loc_alpha.alpha_in_pixel = 1; 312 if (ioctl(cursor.fd, MXCFB_SET_LOC_ALPHA, &loc_alpha) < 0) { 313 GLASS_LOG_SEVERE("Error %s in setting local alpha", strerror(errno)); 314 } 315 316 } else { 317 struct mxcfb_color_key color_key; 318 color_key.color_key = RGB565TOCOLORKEY(LENSFB_16_CURSOR_COLOR_KEY); 319 color_key.enable = 1; 320 if ( ioctl(cursor.fd, MXCFB_SET_CLR_KEY, &color_key) < 0) { 321 GLASS_LOG_SEVERE("Error %s in setting 16 bits color key", strerror(errno)); 322 } 323 324 struct mxcfb_gbl_alpha gbl_alpha; 325 gbl_alpha.alpha = 255; 326 gbl_alpha.enable = 1; 327 if(ioctl(cursor.fd, MXCFB_SET_GBL_ALPHA, &gbl_alpha) < 0) { 328 GLASS_LOG_SEVERE("Error %s in setting global alpha", strerror(errno)); 329 } 330 } 331 332 struct mxcfb_pos cpos = {(screenWidth - 16)/2, (screenHeight - 16)/2}; 333 if (ioctl(cursor.fd, MXCFB_SET_OVERLAY_POS, &cpos)) { 334 GLASS_LOG_SEVERE("Error %s in setting overlay position", strerror(errno)); 335 } 336 337 fbImx6BlankCursor(); 338 } 339 340 341 342 static jlong fbImx6CreateNativeCursor(JNIEnv *env, jint x, jint y, jbyte *srcArray, jint width, jint height) { 343 344 Imx6CursorImage *cursorImage = (Imx6CursorImage *)malloc(sizeof(Imx6CursorImage)); 345 cursorImage->x = x; 346 cursorImage->y = y; 347 cursorImage->width = width; 348 cursorImage->height = height; 349 cursorImage->bufferSize = width * height * (use32bit ? 4 : 2); 350 cursorImage->buffer = (jbyte*)malloc(cursorImage->bufferSize); 351 352 GLASS_LOG_INFO("Creating x : %d y : %d width : %d height : %d cursor %d bits per pixel",x, y, width, height, (use32bit ? 32 : 16)); 353 354 if (use32bit) { 355 memcpy((void*)(cursorImage->buffer), srcArray, cursorImage->bufferSize); 356 } else { 357 //565 358 int i; 359 uint16_t* dst = (uint16_t*)(cursorImage->buffer); 360 uint32_t* src = (uint32_t*)srcArray; 361 for (i = 0; i < cursorImage->bufferSize; i += 2) { 362 int pixel = *src++; 363 if ((pixel & 0xff000000) != 0) { 364 *dst++ = ((pixel >> 8) & 0xf800) 365 | ((pixel >> 5) & 0x7e0) 366 | ((pixel >> 3) & 0x1f); 367 } else { 368 *dst++ = LENSFB_16_CURSOR_COLOR_KEY; 369 } 370 } 371 } 372 373 return ptr_to_jlong(cursorImage); 374 } 375 376 377 static void fbImx6ReleaseNativeCursor(jlong nativeCursorHandle) { 378 379 Imx6CursorImage *cursorImage = (Imx6CursorImage *)jlong_to_ptr(nativeCursorHandle); 380 381 if (cursorImage->buffer != NULL) { 382 free(cursorImage->buffer); 383 } 384 385 free(cursorImage); 386 } 387 388 389 static void fbImx6SetNativeCursor(jlong nativeCursorHandle) { 390 391 Imx6CursorImage *cursorImage = (Imx6CursorImage *)jlong_to_ptr(nativeCursorHandle); 392 393 if (cursor.fd != -1 && cursor.currentCursor != nativeCursorHandle && 394 cursorImage != NULL && cursorImage->buffer != NULL) 395 { 396 if (cursorImage->width != cursor.width || cursorImage->height != cursor.height) { 397 fbImx6BlankCursor(); 398 if (fbImx6ChangeCursorSize(cursorImage->width, cursorImage->height)) { 399 GLASS_LOG_SEVERE("Error in fbImx6ChangeCursorSize() w : %d h : %d", cursorImage->width, cursorImage->height); 400 return; 401 } 402 } 403 404 cursor.currentCursor = nativeCursorHandle; 405 406 fbImx6AdjustShift(); 407 fbImx6WriteCursor(cursor.fd, cursorImage->buffer, use32bit ? 4 : 2); 408 } 409 } 410 411 412 413 static void fbImx6CursorSetPosition(int x, int y) { 414 int xShift = cursor.xShift; 415 int yShift = cursor.yShift; 416 417 if (x < 0) { 418 x = 0; 419 } 420 if (y < 0) { 421 y = 0; 422 } 423 if (x > cursor.screenWidth - 1) { 424 x = cursor.screenWidth - 1; 425 } 426 if (y > cursor.screenHeight - 1) { 427 y = cursor.screenHeight - 1; 428 } 429 430 cursor.x = x; 431 cursor.y = y; 432 433 if (cursor.isVisible) { 434 435 fbImx6AdjustShift(); 436 x -= cursor.xShift; 437 y -= cursor.yShift; 438 if (xShift != cursor.xShift || yShift != cursor.yShift) { 439 GLASS_LOG_FINEST("Calling lseek to rewind cursor fd"); 440 Imx6CursorImage *fbCursorImage = (Imx6CursorImage *) 441 jlong_to_ptr(cursor.currentCursor); 442 fbImx6WriteCursor(cursor.fd, fbCursorImage->buffer, use32bit ? 4 : 2); 443 } 444 445 struct mxcfb_pos cpos = {x, y}; 446 if (ioctl(cursor.fd, MXCFB_SET_OVERLAY_POS, &cpos)) { 447 GLASS_LOG_SEVERE("Error %s in setting overlay position", strerror(errno)); 448 } 449 } 450 } 451 452 453 void fbImx6CursorClose() { 454 if (cursor.fd >= 0) { 455 if (cursor.isVisible) { 456 fbImx6BlankCursor(); 457 } 458 close(cursor.fd); 459 cursor.fd = -1; 460 cursor.isVisible = 0; 461 cursor.currentCursor = 0; 462 cursor.width = 0; 463 cursor.height = 0; 464 } 465 } 466 467 static void fbImx6SetVisible(jboolean isVisible) { 468 if (isVisible) { 469 if (!cursor.isVisible && cursor.currentCursor != 0) { 470 cursor.isVisible = 1; 471 Imx6CursorImage *fbCursorImage = (Imx6CursorImage *) 472 jlong_to_ptr(cursor.currentCursor); 473 fbImx6WriteCursor(cursor.fd, fbCursorImage->buffer, use32bit ? 4 : 2); 474 } 475 } else { 476 if (cursor.isVisible) { 477 fbImx6BlankCursor(); 478 } 479 cursor.isVisible = 0; 480 } 481 } 482 483 static char * platformName = "imx6"; 484 485 jboolean check_imx6_cursor(LensNativePort *lensPort) { 486 487 if (access("/dev/mxc_vpu", F_OK) == 0) { 488 lensPort->platformName = platformName; 489 lensPort->setNativeCursor = fbImx6SetNativeCursor; 490 lensPort->cursorInitialize = fbImx6CursorInitialize; 491 lensPort->cursorSetPosition = fbImx6CursorSetPosition; 492 lensPort->cursorClose = fbImx6CursorClose; 493 lensPort->createNativeCursor = fbImx6CreateNativeCursor; 494 lensPort->releaseNativeCursor = fbImx6ReleaseNativeCursor; 495 lensPort->setVisible = fbImx6SetVisible; 496 lensPort->cursorTranslucency = (use32bit ? JNI_TRUE : JNI_FALSE); 497 498 return JNI_TRUE; 499 } 500 501 return JNI_FALSE; 502 } 503 504 #endif // IMX6_PLATFORM