1 /* 2 * Copyright (c) 2012, 2013, 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 #include <fcntl.h> 27 #include <stdlib.h> 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <linux/fb.h> 31 #include <sys/ioctl.h> 32 #include <sys/types.h> 33 #include <stdint.h> 34 #include <string.h> 35 36 #include "lensPort.h" 37 #include "lensPortInternal.h" 38 #include "lensPortLogger.h" 39 40 #if defined(OMAP3) 41 42 #include <linux/omapfb.h> 43 44 typedef struct { 45 int fd; 46 struct omapfb_plane_info plane; 47 int x; 48 int y; 49 int width; 50 int height; 51 int screenWidth; 52 int screenHeight; 53 int screenDepth; 54 jlong currentCursor; 55 jboolean isVisible; 56 // When the cursor is at the extreme right or bottom of the screen, it 57 // needs to be shifted to show in the correct location. OMAP doesn't let us 58 // position the framebuffer so that it is only partically visible. 59 int xShift; 60 int yShift; 61 } FBCursor; 62 63 typedef struct { 64 int width; 65 int height; 66 int bpp; 67 jbyte *buffer; 68 } FBCursorImage; 69 70 71 FBCursor cursor = { .fd = -1, .x = 0, .y = 0, 72 .width = 0, .height = 0, .screenDepth = 0, 73 .currentCursor = 0, .isVisible = 0, 74 .xShift = 0, .yShift = 0 }; 75 76 /* Writes an image into the cursor framebuffer with the given x and y offsets. */ 77 static void fbOmapWriteCursor(int fd, jbyte *cursorImage, int bpp); 78 79 /* Updates values of xShift and yShift based on the cursor location */ 80 static void fbOmapAdjustShift(); 81 82 void fbOmapCursorClose() { 83 if (cursor.fd >= 0) { 84 cursor.plane.enabled = 0; 85 if (ioctl(cursor.fd, OMAPFB_SETUP_PLANE, &cursor.plane)) { 86 GLASS_LOG_SEVERE("Failed to disable cursor plane"); 87 } 88 close(cursor.fd); 89 cursor.fd = -1; 90 cursor.isVisible = 0; 91 } 92 } 93 94 void fbOmapCreateCursor(jbyte *cursorImage, int width, int height, int bpp) { 95 struct fb_var_screeninfo screenInfo; 96 cursor.width = width; 97 cursor.height = height; 98 99 GLASS_LOG_FINE("open(%s, O_RDWR)", FB_CURSOR_DEVICE); 100 cursor.fd = open(FB_CURSOR_DEVICE, O_RDWR); 101 if (cursor.fd < 0) { 102 GLASS_LOG_SEVERE("Cannot open frame buffer device for cursor"); 103 return; 104 } 105 if (ioctl(cursor.fd, FBIOGET_VSCREENINFO, &screenInfo)) { 106 GLASS_LOG_SEVERE("Cannot query screen info"); 107 fbOmapCursorClose(); 108 return; 109 } 110 screenInfo.xoffset = 0; 111 screenInfo.yoffset = 0; 112 screenInfo.xres = screenInfo.xres_virtual = cursor.width; 113 screenInfo.yres = screenInfo.yres_virtual = cursor.height; 114 115 if (ioctl(cursor.fd, FBIOPUT_VSCREENINFO, &screenInfo)) { 116 GLASS_LOG_SEVERE("Cannot set screen info"); 117 fbOmapCursorClose(); 118 return; 119 } 120 cursor.plane.enabled = 1; 121 cursor.plane.out_width = cursor.width; 122 cursor.plane.out_height = cursor.height; 123 if (ioctl(cursor.fd, OMAPFB_SETUP_PLANE, &cursor.plane)) { 124 GLASS_LOG_SEVERE("Cannot set plane info"); 125 fbOmapCursorClose(); 126 return; 127 } 128 129 if (ioctl(cursor.fd, OMAPFB_QUERY_PLANE, &cursor.plane)) { 130 GLASS_LOG_SEVERE("Cannot query plane info"); 131 fbOmapCursorClose(); 132 return; 133 } 134 135 // Set up the color key 136 struct omapfb_color_key color_key; 137 if (ioctl(cursor.fd, OMAPFB_GET_COLOR_KEY, &color_key)) { 138 GLASS_LOG_SEVERE("Cannot set color key"); 139 return; 140 } 141 142 color_key.key_type = OMAPFB_COLOR_KEY_VID_SRC; 143 if (cursor.screenDepth == 32) { 144 color_key.trans_key = LENSFB_32_CURSOR_COLOR_KEY; 145 } else { //16 bit cursor 146 color_key.trans_key = LENSFB_16_CURSOR_COLOR_KEY; 147 } 148 149 if (ioctl(cursor.fd, OMAPFB_SET_COLOR_KEY, &color_key)) { 150 GLASS_LOG_SEVERE("OMAPFB_SET_COLOR_KEY"); 151 return; 152 } 153 154 fbOmapAdjustShift(); 155 fbOmapWriteCursor(cursor.fd, cursorImage, bpp); 156 } 157 158 static void fbOmapWriteCursor(int fd, jbyte *cursorImage, int bpp) { 159 unsigned i, j, k; 160 char buffer[256]; 161 size_t cursorSize = cursor.width * cursor.height * bpp; 162 unsigned xShift = (unsigned) cursor.xShift; 163 unsigned yShift = (unsigned) cursor.yShift; 164 GLASS_LOG_FINEST("Cursor shift = (%i, %i) at (%i, %i)\n", 165 xShift, yShift, cursor.x, cursor.y); 166 if (xShift == 0 && yShift == 0) { 167 GLASS_LOG_FINEST("write(fd, .. %i)", cursorSize); 168 if (write(fd, cursorImage, cursorSize) < (int) cursorSize) { 169 GLASS_LOG_SEVERE("Cannot write cursor plane"); 170 } 171 return; 172 } 173 174 // Set buffer to be transparent 175 memset((void*)buffer, (cursor.screenDepth == 32) ? LENSFB_32_CURSOR_COLOR_KEY : LENSFB_16_CURSOR_COLOR_KEY, 176 sizeof(buffer)); 177 178 for (i = 0; i < yShift; i++) { 179 for (j = 0; j < (unsigned) cursor.width * bpp; j += sizeof(buffer)) { 180 size_t n = cursor.width * bpp - j; 181 if (n > sizeof(buffer)) { 182 n = sizeof(buffer); 183 } 184 GLASS_LOG_FINEST("write(fd, .. %u)", n); 185 if (write(fd, buffer, n) < (int) n) { 186 GLASS_LOG_SEVERE("Cannot write cursor plane"); 187 return; 188 } 189 } 190 } 191 for (i = 0; i < cursor.height - yShift; i++) { 192 for (j = 0; j < xShift * bpp; j += sizeof(buffer)) { 193 size_t n = xShift * bpp; 194 if (n > sizeof(buffer)) { 195 n = sizeof(buffer); 196 } 197 GLASS_LOG_FINEST("write(fd, .. %u)", n); 198 if (write(fd, buffer, n) < (int) n) { 199 GLASS_LOG_SEVERE("Cannot write cursor plane"); 200 return; 201 } 202 } 203 size_t n = (cursor.width - xShift) * bpp; 204 GLASS_LOG_FINEST("write(fd, .. %u)", n); 205 if (write(fd, cursorImage + i * cursor.width * bpp, n) < (int) n) { 206 GLASS_LOG_SEVERE("Cannot write cursor plane"); 207 return; 208 } 209 } 210 } 211 212 jlong fbOmapCreateNativeCursor(JNIEnv *env, jint x, jint y, jbyte *srcArray, jint width, jint height) { 213 FBCursorImage *cursorImage; 214 int imageSize = width * height * cursor.screenDepth; 215 cursorImage = (FBCursorImage *)malloc(sizeof(FBCursorImage) + imageSize); 216 217 cursorImage->width = width; 218 cursorImage->height = height; 219 cursorImage->bpp = cursor.screenDepth/8; 220 cursorImage->buffer = (jbyte *)(cursorImage + 1); 221 222 int i; 223 int pixel; 224 if (cursor.screenDepth == 16) { 225 uint16_t* dst = (uint16_t*)(cursorImage->buffer); 226 uint32_t* src = (uint32_t*)srcArray; 227 for (i = 0; i < imageSize; i += 2) { 228 pixel = *src++; 229 if ((pixel & 0xff000000) != 0) { 230 *dst++ = ((pixel >> 8) & 0xf800) 231 | ((pixel >> 5) & 0x7e0) 232 | ((pixel >> 3) & 0x1f); 233 } else { 234 *dst++ = LENSFB_16_CURSOR_COLOR_KEY; 235 } 236 } 237 } else { // 32 bit screen depth 238 uint32_t* dst = (uint32_t*)(cursorImage->buffer); 239 uint32_t* src = (uint32_t*)srcArray; 240 for (i = 0; (i + 3) < imageSize; i += cursorImage->bpp) { 241 pixel = *src++; 242 if ((pixel & 0xff000000) != 0) { 243 *dst++ = pixel; 244 } else { 245 *dst++ = LENSFB_32_CURSOR_COLOR_KEY; 246 } 247 } 248 } 249 return ptr_to_jlong(cursorImage); 250 } 251 252 void fbOmapCursorInitialize(int screenWidth, int screenHeight, int screenDepth) { 253 cursor.screenWidth = screenWidth; 254 cursor.screenHeight = screenHeight; 255 cursor.screenDepth = screenDepth; 256 } 257 258 void fbOmapAdjustShift() { 259 if (cursor.x > cursor.screenWidth - cursor.width) { 260 cursor.xShift = cursor.width + cursor.x - cursor.screenWidth; 261 } else { 262 cursor.xShift = 0; 263 } 264 if (cursor.y > cursor.screenHeight - cursor.height) { 265 cursor.yShift = cursor.height + cursor.y - cursor.screenHeight; 266 } else { 267 cursor.yShift = 0; 268 } 269 } 270 271 void fbOmapCursorSetPosition(int x, int y) { 272 int xShift = cursor.xShift; 273 int yShift = cursor.yShift; 274 if (x < 0) { 275 x = 0; 276 } 277 if (y < 0) { 278 y = 0; 279 } 280 if (x > cursor.screenWidth - 1) { 281 x = cursor.screenWidth - 1; 282 } 283 if (y > cursor.screenHeight - 1) { 284 y = cursor.screenHeight - 1; 285 } 286 cursor.x = x; 287 cursor.y = y; 288 fbOmapAdjustShift(); 289 x -= cursor.xShift; 290 y -= cursor.yShift; 291 292 if (cursor.fd >= 0) { 293 if (xShift != cursor.xShift || yShift != cursor.yShift) { 294 GLASS_LOG_FINEST("Calling lseek to rewind cursor fd"); 295 if (lseek(cursor.fd, 0, SEEK_SET) == -1) { 296 GLASS_LOG_SEVERE("Cannot rewrite cursor image"); 297 } else { 298 FBCursorImage *fbCursorImage = (FBCursorImage *) 299 jlong_to_ptr(cursor.currentCursor); 300 fbOmapWriteCursor(cursor.fd, fbCursorImage->buffer, fbCursorImage->bpp); 301 } 302 } 303 304 cursor.plane.enabled = 1; 305 cursor.plane.pos_x = x; 306 cursor.plane.pos_y = y; 307 if (ioctl(cursor.fd, OMAPFB_SETUP_PLANE, &cursor.plane)) { 308 GLASS_LOG_SEVERE("Cannot set plane info to show cursor at %i,%i", x, y); 309 } 310 } 311 } 312 313 void fbOmapSetNativeCursor(jlong nativeCursorPointer) { 314 FBCursorImage *cursorImage = (FBCursorImage *)jlong_to_ptr(nativeCursorPointer); 315 if (cursor.currentCursor == nativeCursorPointer) { 316 return; 317 } 318 319 cursor.currentCursor = nativeCursorPointer; 320 321 if (cursor.isVisible) { 322 fbOmapCursorClose(); 323 fbOmapCreateCursor(cursorImage->buffer, cursorImage->width, cursorImage->height, cursorImage->bpp); 324 // reset the visibility - because closing the cursor also makes it 325 // not visible 326 cursor.isVisible = 1; 327 } 328 } 329 330 void fbOmapReleaseNativeCursor(jlong nativeCursorPointer) { 331 if (nativeCursorPointer != 0) { 332 FBCursorImage *cursorImage = (FBCursorImage *)jlong_to_ptr(nativeCursorPointer); 333 free(cursorImage); 334 } 335 336 if (cursor.currentCursor == nativeCursorPointer) { 337 fbOmapCursorClose(); 338 cursor.currentCursor = 0; 339 } 340 } 341 342 void fbOmapSetVisible(jboolean isVisible) { 343 if (isVisible) { 344 if (!cursor.isVisible && cursor.currentCursor != 0) { 345 FBCursorImage *cursorImage = 346 (FBCursorImage *)jlong_to_ptr(cursor.currentCursor); 347 fbOmapCreateCursor(cursorImage->buffer, cursorImage->width, 348 cursorImage->height, cursorImage->bpp); 349 } 350 } else { 351 fbOmapCursorClose(); 352 } 353 354 cursor.isVisible = isVisible; 355 } 356 357 358 jboolean fbOmapPlatformCursorTranslucency() { 359 return JNI_FALSE; 360 } 361 362 void fbOmapCursorTerminate(void) { 363 fbOmapCursorClose(); 364 } 365 366 static char * platformName = "omap"; 367 368 jboolean select_omap_cursor(LensNativePort *lensPort) { 369 lensPort->platformName = platformName; 370 lensPort->setNativeCursor = fbOmapSetNativeCursor; 371 lensPort->cursorInitialize = fbOmapCursorInitialize; 372 lensPort->cursorSetPosition = fbOmapCursorSetPosition; 373 lensPort->cursorClose = fbOmapCursorClose; 374 lensPort->createNativeCursor = fbOmapCreateNativeCursor; 375 lensPort->releaseNativeCursor = fbOmapReleaseNativeCursor; 376 lensPort->setVisible = fbOmapSetVisible; 377 lensPort->createCursor = fbOmapCreateCursor; 378 379 return JNI_TRUE; 380 } 381 382 #endif // OMAP3