diff --git a/graphics/vnc/server/vnc_fbdev.c b/graphics/vnc/server/vnc_fbdev.c index 2d67f980cab..46bcc47e53d 100644 --- a/graphics/vnc/server/vnc_fbdev.c +++ b/graphics/vnc/server/vnc_fbdev.c @@ -80,7 +80,7 @@ struct vnc_fbinfo_s * configuration of each color plane. */ -static int up_getvideoinfo(FAR struct fb_vtable_s *vtable, +static int up_getvideoinfo(FAR struct fb_vtable_s *vtable, FAR struct fb_videoinfo_s *vinfo); static int up_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, FAR struct fb_planeinfo_s *pinfo); @@ -123,9 +123,7 @@ static struct fb_cursorsize_s g_csize; #endif #endif -/* The framebuffer object -- There is no private state information in this simple - * framebuffer simulation. - */ +/* The framebuffer objects, one for each configured display. */ static struct vnc_fbinfo_s g_fbinfo[RFB_MAX_DISPLAYS]; @@ -133,6 +131,13 @@ static struct vnc_fbinfo_s g_fbinfo[RFB_MAX_DISPLAYS]; * Public Data ****************************************************************************/ +/* Used to synchronize the server thread with the framebuffer driver. + * NOTE: This depends on the fact that all zero is correct initial state + * for the semaphores. + */ + +sem_t g_fbsem[RFB_MAX_DISPLAYS]; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -324,7 +329,7 @@ static int up_getcursor(FAR struct fb_vtable_s *vtable, #endif /**************************************************************************** - * Name: + * Name: up_setcursor ****************************************************************************/ #ifdef CONFIG_FB_HWCURSOR @@ -374,6 +379,57 @@ static int up_setcursor(FAR struct fb_vtable_s *vtable, } #endif +/**************************************************************************** + * Name: vnc_wait_server + * + * Description: + * Wait for the server to be connected to the VNC client. We can do + * nothing until that connection is established. + * + * Input parameters: + * display - In the case of hardware with multiple displays, this + * specifies the display. Normally this is zero. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +static inline int vnc_wait_server(int display) +{ + /* Check if there has been a session allocated yet. This is one of the + * first things that the VNC server will do with the kernel thread is + * started. But we might be here before the thread has gotten that far. + * + * If it has been allocated, then wait until it is in the RUNNING state. + * The RUNNING state indicates that the server has started, it has + * established a connection with the VNC client, it is negotiated + * encodings and framebuffer characteristics, and it has started the + * updater thread. The server is now ready to recieve Client-to-Server + * messages and to perform remote framebuffer updates. + */ + + while (g_vnc_sessions[display] == NULL || + g_vnc_sessions[display]->state != VNCSERVER_RUNNING) + { + /* The server is not yet running. Wait for the server to post the FB + * semaphore. In certain error situations, the server may post the + * semaphore, then reset it to zero. There are are certainly race + * conditions here, but I think none that are fatal. + */ + + while (sem_wait(&g_fbsem[display]) < 0) + { + /* sem_wait() should fail only if it is interrupt by a signal. */ + + DEBUGASSERT(get_errno() == EINTR); + } + } + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -408,23 +464,33 @@ int up_fbinitialize(int display) gvdbg("Starting the VNC server for display %d\n", display); DEBUGASSERT(display >= 0 && display < RFB_MAX_DISPLAYS); - (void)itoa(display, str, 10); - argv[0] = str; - argv[1] = NULL; + /* Check if the server is already running */ - pid = kernel_thread("vnc_server", CONFIG_VNCSERVER_PRIO, - CONFIG_VNCSERVER_STACKSIZE, - (main_t)vnc_server, argv); - if (pid < 0) + if (g_vnc_sessions[display] != NULL) { - gdbg("ERROR: Failed to start the VNC server: %d\n", (int)pid); - return (int)pid; + DEBUGASSERT(g_vnc_sessions[display]->state >= VNCSERVER_INITIALIZED); + } + else + { + /* Format the kernel thread arguments (ASCII.. yech) */ + + (void)itoa(display, str, 10); + argv[0] = str; + argv[1] = NULL; + + pid = kernel_thread("vnc_server", CONFIG_VNCSERVER_PRIO, + CONFIG_VNCSERVER_STACKSIZE, + (main_t)vnc_server, argv); + if (pid < 0) + { + gdbg("ERROR: Failed to start the VNC server: %d\n", (int)pid); + return (int)pid; + } } /* Wait for the VNC client to connect and for the RFB to be ready */ -#warning Missing logic - return OK; + return vnc_wait_server(display); } /**************************************************************************** @@ -503,6 +569,7 @@ FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane) void up_fbuninitialize(int display) { +#if 0 /* Do nothing */ FAR struct vnc_session_s *session = vnc_find_session(display); FAR struct vnc_fbinfo_s *fbinfo; @@ -511,6 +578,7 @@ void up_fbuninitialize(int display) #warning Missing logic UNUSED(session); UNUSED(fbinfo); +#endif } /**************************************************************************** diff --git a/graphics/vnc/server/vnc_receiver.c b/graphics/vnc/server/vnc_receiver.c index 03749a544fb..8715ee69a87 100644 --- a/graphics/vnc/server/vnc_receiver.c +++ b/graphics/vnc/server/vnc_receiver.c @@ -159,7 +159,7 @@ int vnc_receiver(FAR struct vnc_session_s *session) } else { -#warning Missing logic + /* REVISIT: SetPixelFormat is currently ignored */ } } break; @@ -198,7 +198,7 @@ int vnc_receiver(FAR struct vnc_session_s *session) } else { -#warning Missing logic + /* REVISIT: SetEncodings is currently ignored */ } } } @@ -353,7 +353,7 @@ int vnc_receiver(FAR struct vnc_session_s *session) } else { -#warning Missing logic + /* REVISIT: ClientCutText is currently ignored */ } } } diff --git a/graphics/vnc/server/vnc_server.c b/graphics/vnc/server/vnc_server.c index 12043ec5a5a..9cd9b8e18e9 100644 --- a/graphics/vnc/server/vnc_server.c +++ b/graphics/vnc/server/vnc_server.c @@ -62,14 +62,14 @@ ****************************************************************************/ /**************************************************************************** - * Private Data + * Public Data ****************************************************************************/ /* Given a display number as an index, the following array can be used to * look-up the session structure for that display. */ -static FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS]; +FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS]; /**************************************************************************** * Private Functions @@ -281,6 +281,7 @@ int vnc_server(int argc, FAR char *argv[]) */ vnc_reset_session(session, fb); + sem_reset(&g_fbsem[display], 0); /* Establish a connection with the VNC client */ @@ -313,7 +314,13 @@ int vnc_server(int argc, FAR char *argv[]) continue; } - /* Start the VNC receiver on this this. The VNC receiver handles + /* Let the framebuffer driver know that we are ready to preform + * updates. + */ + + sem_post(&g_fbsem[display]); + + /* Run the VNC receiver on this trhead. The VNC receiver handles * all Client-to-Server messages. The VNC receiver function does * not return until the session has been terminated (or an error * occurs). diff --git a/graphics/vnc/server/vnc_server.h b/graphics/vnc/server/vnc_server.h index 8433924cba8..6129060c0be 100644 --- a/graphics/vnc/server/vnc_server.h +++ b/graphics/vnc/server/vnc_server.h @@ -230,7 +230,7 @@ struct vnc_session_s }; /**************************************************************************** - * Public Function Prototypes + * Public Data ****************************************************************************/ #ifdef __cplusplus @@ -241,6 +241,20 @@ extern "C" #define EXTERN extern #endif +/* Given a display number as an index, the following array can be used to + * look-up the session structure for that display. + */ + +EXTERN FAR struct vnc_session_s *g_vnc_sessions[RFB_MAX_DISPLAYS]; + +/* Used to synchronize the server thread with the framebuffer driver. */ + +EXTERN sem_t g_fbsem[RFB_MAX_DISPLAYS]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + /**************************************************************************** * Name: vnc_server *