Subversion Repositories HelenOS-historic

Rev

Rev 1481 | Rev 1489 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2006 Josef Cejka
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29.  
  30. #include <kbd.h>
  31. #include <fb.h>
  32. #include <ipc/ipc.h>
  33. #include <ipc/fb.h>
  34. #include <ipc/services.h>
  35. #include <errno.h>
  36. #include <key_buffer.h>
  37. #include <console.h>
  38. #include <unistd.h>
  39. #include <async.h>
  40. #include <libadt/fifo.h>
  41. #include <screenbuffer.h>
  42.  
  43. static void sysput(char c)
  44. {
  45.     __SYSCALL3(SYS_IO, 1, &c, 1);
  46. }
  47.  
  48. //#define CONSOLE_COUNT VFB_CONNECTIONS
  49. #define CONSOLE_COUNT 8
  50. #define MAX_KEYREQUESTS_BUFFERED 32
  51.  
  52. #define NAME "CONSOLE"
  53.  
  54. int active_console = 1;
  55.  
  56. struct {
  57.     int phone;      /**< Framebuffer phone */
  58.     int rows;       /**< Framebuffer rows */
  59.     int cols;       /**< Framebuffer columns */
  60. } fb_info;
  61.  
  62. typedef struct {
  63.     keybuffer_t keybuffer;
  64.     FIFO_CREATE_STATIC(keyrequests, ipc_callid_t , MAX_KEYREQUESTS_BUFFERED);
  65.     int keyrequest_counter;
  66.     int client_phone;
  67.     int used;
  68.     screenbuffer_t screenbuffer;
  69. } connection_t;
  70.  
  71. connection_t connections[CONSOLE_COUNT];
  72.  
  73. static int find_free_connection()
  74. {
  75.     int i = 0;
  76.    
  77.     while (i < CONSOLE_COUNT) {
  78.         if (connections[i].used == 0)
  79.             return i;
  80.         ++i;
  81.     }
  82.     return CONSOLE_COUNT;
  83. }
  84.  
  85.  
  86. static int find_connection(int client_phone)
  87. {
  88.     int i = 0;
  89.    
  90.     while (i < CONSOLE_COUNT) {
  91.         if (connections[i].client_phone == client_phone)
  92.             return i;
  93.         ++i;
  94.     }
  95.     return  CONSOLE_COUNT;
  96. }
  97.  
  98. /* Handler for keyboard */
  99. static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
  100. {
  101.     ipc_callid_t callid;
  102.     ipc_call_t call;
  103.     int retval;
  104.     int i, j;
  105.     char c;
  106.  
  107.     /* Ignore parameters, the connection is alread opened */
  108.     while (1) {
  109.         callid = async_get_call(&call);
  110.         switch (IPC_GET_METHOD(call)) {
  111.         case IPC_M_PHONE_HUNGUP:
  112.             ipc_answer_fast(callid,0,0,0);
  113.             /* TODO: Handle hangup */
  114.             return;
  115.         case KBD_PUSHCHAR:
  116.             /* got key from keyboard driver */
  117.            
  118.             retval = 0;
  119.             c = IPC_GET_ARG1(call);
  120. //          ipc_call_sync_2(connections[3].vfb_phone, FB_PUTCHAR, 0, c,NULL,NULL);
  121.        
  122.             /* switch to another virtual console */
  123.            
  124.             if ((c >= KBD_KEY_F1) && (c < KBD_KEY_F1 + CONSOLE_COUNT)) {
  125.                 /*FIXME: draw another console content from buffer */
  126.  
  127.                 active_console = c - KBD_KEY_F1;
  128.                 ipc_call_async_2(fb_info.phone, FB_CLEAR, 0, 0, NULL, NULL);
  129.                 ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, 'a', 0, 0,NULL,NULL, NULL);
  130.                
  131.                 for (i = 0; i < connections[active_console].screenbuffer.size_x; i++)
  132.                     for (j = 0; j < connections[active_console].screenbuffer.size_y; j++) {
  133.                    
  134.                     ipc_call_async_3(fb_info.phone, FB_PUTCHAR, get_field_at(&(connections[active_console].screenbuffer),\
  135.                                 i, j)->character, j, i, NULL, NULL, NULL);
  136.                 }
  137.  
  138.                 break;
  139.             }
  140.            
  141.             /* if client is awaiting key, send it */
  142.             if (connections[active_console].keyrequest_counter > 0) {      
  143.                 connections[active_console].keyrequest_counter--;
  144.                 ipc_answer_fast(fifo_pop(connections[active_console].keyrequests), 0, c, 0);
  145.                 break;
  146.             }
  147.            
  148.             /*FIXME: else store key to its buffer */
  149.             keybuffer_push(&(connections[active_console].keybuffer), c);
  150.            
  151.             /* Send it to first FB, DEBUG */
  152. //          ipc_call_async_2(connections[0].vfb_phone, FB_PUTCHAR, 0, IPC_GET_ARG1(call),NULL,NULL);
  153. //          ipc_call_sync_2(connections[4].vfb_phone, FB_PUTCHAR, 0, c,NULL,NULL);
  154.  
  155.             break;
  156.         default:
  157.             retval = ENOENT;
  158.         }      
  159.         ipc_answer_fast(callid, retval, 0, 0);
  160.     }
  161. }
  162.  
  163. /** Default thread for new connections */
  164. void client_connection(ipc_callid_t iid, ipc_call_t *icall)
  165. {
  166.     ipc_callid_t callid;
  167.     ipc_call_t call;
  168.     int consnum;
  169.     ipcarg_t arg1;
  170.  
  171.     if ((consnum = find_free_connection()) == CONSOLE_COUNT) {
  172.         ipc_answer_fast(iid,ELIMIT,0,0);
  173.         return;
  174.     }
  175.    
  176.     connections[consnum].used = 1;
  177.     connections[consnum].client_phone = IPC_GET_ARG3(call);
  178.     screenbuffer_clear(&(connections[consnum].screenbuffer));
  179.  
  180.     /* Accept the connection */
  181.     ipc_answer_fast(iid,0,0,0);
  182.    
  183.     while (1) {
  184.         callid = async_get_call(&call);
  185.         switch (IPC_GET_METHOD(call)) {
  186.         case IPC_M_PHONE_HUNGUP:
  187.             /* TODO */
  188.             ipc_answer_fast(callid, 0,0,0);
  189.             return;
  190.         case CONSOLE_PUTCHAR:
  191.            
  192.             /* Send message to fb */
  193.             if (consnum == active_console) {
  194.                 ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, IPC_GET_ARG2(call), connections[consnum].screenbuffer.position_y, \
  195.                         connections[consnum].screenbuffer.position_x, NULL, NULL, NULL);
  196.             }
  197.            
  198.             screenbuffer_putchar(&(connections[consnum].screenbuffer), IPC_GET_ARG2(call));
  199.             break;
  200.         case CONSOLE_CLEAR:
  201.             /* Send message to fb */
  202.             if (consnum == active_console) {
  203.                 ipc_call_async_2(fb_info.phone, FB_CLEAR, 0, 0, NULL, NULL);
  204.             }
  205.            
  206.             screenbuffer_clear(&(connections[consnum].screenbuffer));
  207.            
  208.             break;
  209.         case CONSOLE_GOTO:
  210.            
  211.             screenbuffer_goto(&(connections[consnum].screenbuffer), IPC_GET_ARG1(call), IPC_GET_ARG2(call));
  212.            
  213.             break;
  214.  
  215.         case CONSOLE_GETCHAR:
  216.             if (keybuffer_empty(&(connections[consnum].keybuffer))) {
  217.                 /* buffer is empty -> store request */
  218.                 if (connections[consnum].keyrequest_counter < MAX_KEYREQUESTS_BUFFERED) {      
  219.                     fifo_push(connections[consnum].keyrequests, callid);
  220.                     connections[consnum].keyrequest_counter++;
  221.                 } else {
  222.                     /* no key available and too many requests => fail */
  223.                     ipc_answer_fast(callid, ELIMIT, 0, 0);
  224.                 }
  225.                 continue;
  226.             };
  227.             keybuffer_pop(&(connections[consnum].keybuffer), (char *)&arg1);
  228. //          ipc_call_sync_2(connections[6].vfb_phone, FB_PUTCHAR, 0, arg1,NULL,NULL);
  229.            
  230.             break;
  231.         }
  232.         ipc_answer_fast(callid, 0, arg1, 0);
  233.     }
  234. }
  235.  
  236. int main(int argc, char *argv[])
  237. {
  238.     ipcarg_t phonehash;
  239.     int kbd_phone, fb_phone;
  240.     ipcarg_t retval, arg1 = 0xdead, arg2 = 0xbeef;
  241.     int i;
  242.    
  243.     /* Connect to keyboard driver */
  244.  
  245.     while ((kbd_phone = ipc_connect_me_to(PHONE_NS, SERVICE_KEYBOARD, 0)) < 0) {
  246.         usleep(10000);
  247.     };
  248.    
  249.     if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, &phonehash) != 0) {
  250.         return -1;
  251.     };
  252.     async_new_connection(phonehash, 0, NULL, keyboard_events);
  253.  
  254.     /* Connect to framebuffer driver */
  255.    
  256.     while ((fb_info.phone = ipc_connect_me_to(PHONE_NS, SERVICE_VIDEO, 0)) < 0) {
  257.         usleep(10000);
  258.     }
  259.    
  260.     ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, '1', 0, 0,NULL,NULL, NULL);
  261.     ipc_call_sync_2(fb_info.phone, FB_GET_CSIZE, 0, 0, &(fb_info.rows), &(fb_info.cols));
  262.    
  263.     /* Init virtual consoles */
  264.     for (i = 0; i < CONSOLE_COUNT; i++) {
  265.         ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, '$', 2*i, 1,NULL,NULL, NULL);
  266.         connections[i].used = 0;
  267.         keybuffer_init(&(connections[i].keybuffer));
  268.         ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, '>', 2*i+1, 1,NULL,NULL, NULL);
  269.        
  270.         connections[i].keyrequests.head = connections[i].keyrequests.tail = 0;
  271.         connections[i].keyrequests.items = MAX_KEYREQUESTS_BUFFERED;
  272.         connections[i].keyrequest_counter = 0;
  273.        
  274.         ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, '?', 2*i+1, 1,NULL,NULL, NULL);
  275.         if (screenbuffer_init(&(connections[i].screenbuffer), fb_info.cols, fb_info.rows ) == NULL) {
  276.             /*FIXME: handle error */
  277.             return -1;
  278.         }
  279.     }
  280.    
  281.     if (ipc_connect_to_me(PHONE_NS, SERVICE_CONSOLE, 0, &phonehash) != 0) {
  282.         return -1;
  283.     };
  284.    
  285.     ipc_call_sync_3(fb_info.phone, FB_PUTCHAR, 'M', 3, 3,NULL,NULL, NULL);
  286.     async_manager();
  287.  
  288.     return 0;  
  289. }
  290.