Change-Id: If881ec130833c7e7e62caa3d31e350a531f5bc8e Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-on: http://review.coreboot.org/12398 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi <pgeorgi@google.com>
		
			
				
	
	
		
			318 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Public Domain Curses */
 | |
| 
 | |
| #include "pdcx11.h"
 | |
| 
 | |
| RCSID("$Id: pdcx11.c,v 1.96 2008/07/14 04:24:52 wmcbrine Exp $")
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| /*** Functions that are called by both processes ***/
 | |
| 
 | |
| unsigned char *Xcurscr;
 | |
| 
 | |
| int XCursesProcess = 1;
 | |
| int shmidSP;
 | |
| int shmid_Xcurscr;
 | |
| int shmkeySP;
 | |
| int shmkey_Xcurscr;
 | |
| int xc_otherpid;
 | |
| int XCursesLINES = 24;
 | |
| int XCursesCOLS = 80;
 | |
| int xc_display_sock;
 | |
| int xc_key_sock;
 | |
| int xc_display_sockets[2];
 | |
| int xc_key_sockets[2];
 | |
| int xc_exit_sock;
 | |
| 
 | |
| fd_set xc_readfds;
 | |
| 
 | |
| static void _dummy_function(void)
 | |
| {
 | |
| }
 | |
| 
 | |
| void XC_get_line_lock(int row)
 | |
| {
 | |
|     /* loop until we can write to the line -- Patch by:
 | |
|        Georg Fuchs, georg.fuchs@rz.uni-regensburg.de */
 | |
| 
 | |
|     while (*(Xcurscr + XCURSCR_FLAG_OFF + row))
 | |
|         _dummy_function();
 | |
| 
 | |
|     *(Xcurscr + XCURSCR_FLAG_OFF + row) = 1;
 | |
| }
 | |
| 
 | |
| void XC_release_line_lock(int row)
 | |
| {
 | |
|     *(Xcurscr + XCURSCR_FLAG_OFF + row) = 0;
 | |
| }
 | |
| 
 | |
| int XC_write_socket(int sock_num, const void *buf, int len)
 | |
| {
 | |
|     int start = 0, rc;
 | |
| 
 | |
|     PDC_LOG(("%s:XC_write_socket called: sock_num %d len %d\n",
 | |
|              XCLOGMSG, sock_num, len));
 | |
| 
 | |
| #ifdef MOUSE_DEBUG
 | |
|     if (sock_num == xc_key_sock)
 | |
|         printf("%s:XC_write_socket(key) len: %d\n", XCLOGMSG, len);
 | |
| #endif
 | |
|     while (1)
 | |
|     {
 | |
|         rc = write(sock_num, buf + start, len);
 | |
| 
 | |
|         if (rc < 0 || rc == len)
 | |
|             return rc;
 | |
| 
 | |
|         len -= rc;
 | |
|         start = rc;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int XC_read_socket(int sock_num, void *buf, int len)
 | |
| {
 | |
|     int start = 0, length = len, rc;
 | |
| 
 | |
|     PDC_LOG(("%s:XC_read_socket called: sock_num %d len %d\n",
 | |
|              XCLOGMSG, sock_num, len));
 | |
| 
 | |
|     while (1)
 | |
|     {
 | |
|         rc = read(sock_num, buf + start, length);
 | |
| 
 | |
| #ifdef MOUSE_DEBUG
 | |
|         if (sock_num == xc_key_sock)
 | |
|             printf("%s:XC_read_socket(key) rc %d errno %d "
 | |
|                    "resized: %d\n", XCLOGMSG, rc, errno, SP->resized);
 | |
| #endif
 | |
|         if (rc < 0 && sock_num == xc_key_sock && errno == EINTR
 | |
|             && SP->resized != FALSE)
 | |
|         {
 | |
|             MOUSE_LOG(("%s:continuing\n", XCLOGMSG));
 | |
| 
 | |
|             rc = 0;
 | |
| 
 | |
|             if (SP->resized > 1)
 | |
|                 SP->resized = TRUE;
 | |
|             else
 | |
|                 SP->resized = FALSE;
 | |
| 
 | |
|             memcpy(buf, &rc, sizeof(int));
 | |
| 
 | |
|             return 0;
 | |
|         }
 | |
| 
 | |
|         if (rc <= 0 || rc == length)
 | |
|             return rc;
 | |
| 
 | |
|         length -= rc;
 | |
|         start = rc;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int XC_write_display_socket_int(int x)
 | |
| {
 | |
|     return XC_write_socket(xc_display_sock, &x, sizeof(int));
 | |
| }
 | |
| 
 | |
| #ifdef PDCDEBUG
 | |
| void XC_say(const char *msg)
 | |
| {
 | |
|     PDC_LOG(("%s:%s", XCLOGMSG, msg));
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*** Functions that are called by the "curses" process ***/
 | |
| 
 | |
| int XCursesInstruct(int flag)
 | |
| {
 | |
|     PDC_LOG(("%s:XCursesInstruct() - called flag %d\n", XCLOGMSG, flag));
 | |
| 
 | |
|     /* Send a request to X */
 | |
| 
 | |
|     if (XC_write_display_socket_int(flag) < 0)
 | |
|         XCursesExitCursesProcess(4, "exiting from XCursesInstruct");
 | |
| 
 | |
|     return OK;
 | |
| }
 | |
| 
 | |
| int XCursesInstructAndWait(int flag)
 | |
| {
 | |
|     int result;
 | |
| 
 | |
|     XC_LOG(("XCursesInstructAndWait() - called\n"));
 | |
| 
 | |
|     /* tell X we want to do something */
 | |
| 
 | |
|     XCursesInstruct(flag);
 | |
| 
 | |
|     /* wait for X to say the refresh has occurred*/
 | |
| 
 | |
|     if (XC_read_socket(xc_display_sock, &result, sizeof(int)) < 0)
 | |
|         XCursesExitCursesProcess(5, "exiting from XCursesInstructAndWait");
 | |
| 
 | |
|     if (result != CURSES_CONTINUE)
 | |
|         XCursesExitCursesProcess(6, "exiting from XCursesInstructAndWait"
 | |
|                                     " - synchronization error");
 | |
| 
 | |
|     return OK;
 | |
| }
 | |
| 
 | |
| static int _setup_curses(void)
 | |
| {
 | |
|     int wait_value;
 | |
| 
 | |
|     XC_LOG(("_setup_curses called\n"));
 | |
| 
 | |
|     close(xc_display_sockets[1]);
 | |
|     close(xc_key_sockets[1]);
 | |
| 
 | |
|     xc_display_sock = xc_display_sockets[0];
 | |
|     xc_key_sock = xc_key_sockets[0];
 | |
| 
 | |
|     FD_ZERO(&xc_readfds);
 | |
| 
 | |
|     XC_read_socket(xc_display_sock, &wait_value, sizeof(int));
 | |
| 
 | |
|     if (wait_value != CURSES_CHILD)
 | |
|         return ERR;
 | |
| 
 | |
|     /* Set LINES and COLS now so that the size of the shared memory
 | |
|        segment can be allocated */
 | |
| 
 | |
|     if ((shmidSP = shmget(shmkeySP, sizeof(SCREEN) + XCURSESSHMMIN, 0700)) < 0)
 | |
|     {
 | |
|         perror("Cannot allocate shared memory for SCREEN");
 | |
|         kill(xc_otherpid, SIGKILL);
 | |
|         return ERR;
 | |
|     }
 | |
| 
 | |
|     SP = (SCREEN*)shmat(shmidSP, 0, 0);
 | |
| 
 | |
|     XCursesLINES = SP->lines;
 | |
|     LINES = XCursesLINES - SP->linesrippedoff - SP->slklines;
 | |
|     XCursesCOLS = COLS = SP->cols;
 | |
| 
 | |
|     if ((shmid_Xcurscr = shmget(shmkey_Xcurscr,
 | |
|                                 SP->XcurscrSize + XCURSESSHMMIN, 0700)) < 0)
 | |
|     {
 | |
|         perror("Cannot allocate shared memory for curscr");
 | |
|         kill(xc_otherpid, SIGKILL);
 | |
|         return ERR;
 | |
|     }
 | |
| 
 | |
|     PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n",
 | |
|              XCLOGMSG, shmid_Xcurscr, shmkey_Xcurscr, LINES, COLS));
 | |
| 
 | |
|     Xcurscr = (unsigned char *)shmat(shmid_Xcurscr, 0, 0);
 | |
|     xc_atrtab = (short *)(Xcurscr + XCURSCR_ATRTAB_OFF);
 | |
| 
 | |
|     XC_LOG(("cursesprocess exiting from Xinitscr\n"));
 | |
| 
 | |
|     /* Always trap SIGWINCH if the C library supports SIGWINCH */
 | |
| 
 | |
|     XCursesSetSignal(SIGWINCH, XCursesSigwinchHandler);
 | |
| 
 | |
|     atexit(XCursesExit);
 | |
| 
 | |
|     return OK;
 | |
| }
 | |
| 
 | |
| int XCursesInitscr(int argc, char *argv[])
 | |
| {
 | |
|     int pid, rc;
 | |
| 
 | |
|     XC_LOG(("XCursesInitscr() - called\n"));
 | |
| 
 | |
|     shmkeySP = getpid();
 | |
| 
 | |
|     if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_display_sockets) < 0)
 | |
|     {
 | |
|         fprintf(stderr, "ERROR: cannot create display socketpair\n");
 | |
|         return ERR;
 | |
|     }
 | |
| 
 | |
|     if (socketpair(AF_UNIX, SOCK_STREAM, 0, xc_key_sockets) < 0)
 | |
|     {
 | |
|         fprintf(stderr, "ERROR: cannot create key socketpair\n");
 | |
|         return ERR;
 | |
|     }
 | |
| 
 | |
|     pid = fork();
 | |
| 
 | |
|     switch(pid)
 | |
|     {
 | |
|     case -1:
 | |
|         fprintf(stderr, "ERROR: cannot fork()\n");
 | |
|         return ERR;
 | |
|         break;
 | |
| 
 | |
|     case 0: /* child */
 | |
|         shmkey_Xcurscr = getpid();
 | |
| #ifdef XISPARENT
 | |
|         XCursesProcess = 0;
 | |
|         rc = _setup_curses();
 | |
| #else
 | |
|         XCursesProcess = 1;
 | |
|         xc_otherpid = getppid();
 | |
|         rc = XCursesSetupX(argc, argv);
 | |
| #endif
 | |
|         break;
 | |
| 
 | |
|     default:  /* parent */
 | |
|         shmkey_Xcurscr = pid;
 | |
| #ifdef XISPARENT
 | |
|         XCursesProcess = 1;
 | |
|         xc_otherpid = pid;
 | |
|         rc = XCursesSetupX(argc, argv);
 | |
| #else
 | |
|         XCursesProcess = 0;
 | |
|         rc = _setup_curses();
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| static void _cleanup_curses_process(int rc)
 | |
| {
 | |
|     PDC_LOG(("%s:_cleanup_curses_process() - called: %d\n", XCLOGMSG, rc));
 | |
| 
 | |
|     shutdown(xc_display_sock, 2);
 | |
|     close(xc_display_sock);
 | |
| 
 | |
|     shutdown(xc_key_sock, 2);
 | |
|     close(xc_key_sock);
 | |
| 
 | |
|     shmdt((char *)SP);
 | |
|     shmdt((char *)Xcurscr);
 | |
| 
 | |
|     if (rc)
 | |
|         _exit(rc);
 | |
| }
 | |
| 
 | |
| void XCursesExitCursesProcess(int rc, char *msg)
 | |
| {
 | |
|     PDC_LOG(("%s:XCursesExitCursesProcess() - called: %d %s\n",
 | |
|              XCLOGMSG, rc, msg));
 | |
| 
 | |
|     endwin();
 | |
|     _cleanup_curses_process(rc);
 | |
| }
 | |
| 
 | |
| void XCursesExit(void)
 | |
| {
 | |
|     static bool called = FALSE;
 | |
| 
 | |
|     XC_LOG(("XCursesExit() - called\n"));
 | |
| 
 | |
|     if (FALSE == called)
 | |
|     {
 | |
|         XCursesInstruct(CURSES_EXIT);
 | |
|         _cleanup_curses_process(0);
 | |
| 
 | |
|         called = TRUE;
 | |
|     }
 | |
| }
 |