+#define ts_add_nsec(ts, ns) { \
+ ts.tv_nsec += ns; \
+ if (ts.tv_nsec >= 1000000000) { \
+ ts.tv_sec++; \
+ ts.tv_nsec -= 1000000000; \
+ } \
+}
+
+static void *fb_sync_thread(void *arg)
+{
+ int invalid_fb_addr = 1;
+ int manual_refresh = 0;
+ struct timespec ts;
+ int ret, wait_ret;
+
+ //ret = pthread_setschedprio(pthread_self(), -1);
+ //log("pthread_setschedprio %d\n", ret);
+ //ret = setpriority(PRIO_PROCESS, 0, -1);
+ //log("setpriority %d\n", ret);
+
+ ret = clock_gettime(CLOCK_REALTIME, &ts);
+ if (ret != 0) {
+ perror(PFX "clock_gettime");
+ exit(1);
+ }
+
+ while (1) {
+ u8 *gp2x_fb, *gp2x_fb_end;
+ int mode, bpp;
+
+ ret = pthread_mutex_lock(&fb_mutex);
+ wait_ret = pthread_cond_timedwait(&fb_cond, &fb_mutex, &ts);
+ ret |= pthread_mutex_unlock(&fb_mutex);
+ if (ret != 0) {
+ err("fb_thread: mutex error: %d\n", ret);
+ sleep(1);
+ continue;
+ }
+ if (wait_ret != 0 && wait_ret != ETIMEDOUT) {
+ err("fb_thread: cond error: %d\n", wait_ret);
+ sleep(1);
+ continue;
+ }
+
+ if (wait_ret != ETIMEDOUT) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts_add_nsec(ts, 50000000);
+ manual_refresh++;
+ if (manual_refresh == 2)
+ log("fb_thread: switch to manual refresh\n");
+ } else {
+ ts_add_nsec(ts, 16666667);
+ if (manual_refresh > 1)
+ log("fb_thread: switch to auto refresh\n");
+ manual_refresh = 0;
+ }
+
+ mode = (mmsp2.mlc_stl_cntl >> 9) & 3;
+ bpp = mode ? mode * 8 : 4;
+
+ gp2x_fb = uppermem_lookup(mmsp2.mlc_stl_adr, &gp2x_fb_end);
+ if (gp2x_fb == NULL || gp2x_fb + 320*240 * bpp / 8 > gp2x_fb_end) {
+ if (!invalid_fb_addr) {
+ err("fb_thread: %08x is out of range\n", mmsp2.mlc_stl_adr);
+ invalid_fb_addr = 1;
+ }
+ continue;
+ }
+
+ mlc_flip(gp2x_fb, bpp);
+ }
+}
+