Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hid/console/console.c

    r79ae36dd r1875a0c  
    11/*
    22 * Copyright (c) 2006 Josef Cejka
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    3435
    3536#include <libc.h>
    36 #include <ipc/kbd.h>
     37#include <ipc/input.h>
    3738#include <io/keycode.h>
    38 #include <ipc/mouse.h>
    3939#include <ipc/fb.h>
    4040#include <ipc/services.h>
     
    5454#include <event.h>
    5555#include <devmap.h>
    56 #include <devmap_obsolete.h>
    5756#include <fcntl.h>
    5857#include <vfs/vfs.h>
     
    6059#include <io/style.h>
    6160#include <io/screenbuffer.h>
    62 #include <inttypes.h>
    6361
    6462#include "console.h"
     
    6664#include "keybuffer.h"
    6765
    68 // FIXME: remove this header
    69 #include <kernel/ipc/ipc_methods.h>
    70 
    7166#define NAME       "console"
    7267#define NAMESPACE  "term"
    7368
    74 /** Interval for checking for new keyboard (1/4s). */
    75 #define HOTPLUG_WATCH_INTERVAL (1000 * 250)
    76 
    77 /* Kernel defines 32 but does not export it. */
    78 #define MAX_IPC_OUTGOING_PHONES 128
    79 
    80 /** To allow proper phone closing. */
    81 static ipc_callid_t driver_phones[MAX_IPC_OUTGOING_PHONES] = { 0 };
    82 
    83 /** Phone to the keyboard driver. */
    84 static int kbd_phone;
    85 
    86 /** Phone to the mouse driver. */
    87 static int mouse_phone;
     69/** Session with the input server. */
     70static async_sess_t *input_sess;
    8871
    8972/** Information about framebuffer */
     
    125108static FIBRIL_CONDVAR_INITIALIZE(input_cv);
    126109
     110static FIBRIL_MUTEX_INITIALIZE(big_console_lock);
     111
     112static void console_serialize_start(void)
     113{
     114        fibril_mutex_lock(&big_console_lock);
     115}
     116
     117static void console_serialize_end(void)
     118{
     119        fibril_mutex_unlock(&big_console_lock);
     120}
     121
    127122static void curs_visibility(bool visible)
    128123{
     
    155150}
    156151
    157 static void kbd_yield(void)
    158 {
    159         async_obsolete_req_0_0(kbd_phone, KBD_YIELD);
    160 }
    161 
    162 static void kbd_reclaim(void)
    163 {
    164         async_obsolete_req_0_0(kbd_phone, KBD_RECLAIM);
     152static void input_yield(void)
     153{
     154        async_exch_t *exch = async_exchange_begin(input_sess);
     155        if (exch == NULL) {
     156                printf("%s: Failed starting exchange with input device.\n",
     157                    NAME);
     158                return;
     159        }
     160       
     161        async_req_0_0(exch, INPUT_YIELD);
     162        async_exchange_end(exch);
     163}
     164
     165static void input_reclaim(void)
     166{
     167        async_exch_t *exch = async_exchange_begin(input_sess);
     168        if (exch == NULL) {
     169                printf("%s: Failed starting exchange with input device.\n",
     170                    NAME);
     171                return;
     172        }
     173       
     174        async_req_0_0(exch, INPUT_RECLAIM);
     175        async_exchange_end(exch);
    165176}
    166177
     
    339350       
    340351        if (cons == kernel_console) {
    341                 async_obsolete_serialize_start();
     352                console_serialize_start();
    342353                curs_hide_sync();
    343354                gcons_in_kernel();
    344355                screen_yield();
    345                 kbd_yield();
    346                 async_obsolete_serialize_end();
     356                input_yield();
     357                console_serialize_end();
    347358               
    348359                if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
     
    354365       
    355366        if (cons != kernel_console) {
    356                 async_obsolete_serialize_start();
     367                console_serialize_start();
    357368               
    358369                if (active_console == kernel_console) {
    359370                        screen_reclaim();
    360                         kbd_reclaim();
     371                        input_reclaim();
    361372                        gcons_redraw_console();
    362373                }
     
    409420                curs_visibility(cons->scr.is_cursor_visible);
    410421               
    411                 async_obsolete_serialize_end();
    412         }
    413 }
    414 
    415 static void close_driver_phone(ipc_callid_t hash)
    416 {
    417         int i;
    418         for (i = 0; i < MAX_IPC_OUTGOING_PHONES; i++) {
    419                 if (driver_phones[i] == hash) {
    420                         printf("Device %" PRIxn " gone.\n", hash);
    421                         driver_phones[i] = 0;
    422                         async_obsolete_hangup(i);
    423                         return;
    424                 }
    425         }
    426 }
    427 
    428 /** Handler for keyboard */
    429 static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
     422                console_serialize_end();
     423        }
     424}
     425
     426/** Handler for input events */
     427static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    430428{
    431429        /* Ignore parameters, the connection is already opened */
     
    439437                if (!IPC_GET_IMETHOD(call)) {
    440438                        /* TODO: Handle hangup */
    441                         close_driver_phone(iid);
     439                        async_hangup(input_sess);
    442440                        return;
    443441                }
    444442               
    445443                switch (IPC_GET_IMETHOD(call)) {
    446                 case KBD_EVENT:
    447                         /* Got event from keyboard driver. */
     444                case INPUT_EVENT_KEY:
     445                        /* Got key press/release event */
    448446                        retval = 0;
    449447                        ev.type = IPC_GET_ARG1(call);
     
    466464                        fibril_mutex_unlock(&input_mutex);
    467465                        break;
    468                 default:
    469                         retval = ENOENT;
    470                 }
    471                 async_answer_0(callid, retval);
    472         }
    473 }
    474 
    475 /** Handler for mouse events */
    476 static void mouse_events(ipc_callid_t iid, ipc_call_t *icall)
    477 {
    478         /* Ignore parameters, the connection is already opened */
    479         while (true) {
    480                 ipc_call_t call;
    481                 ipc_callid_t callid = async_get_call(&call);
    482                
    483                 int retval;
    484                
    485                 if (!IPC_GET_IMETHOD(call)) {
    486                         /* TODO: Handle hangup */
    487                         close_driver_phone(iid);
    488                         return;
    489                 }
    490                
    491                 switch (IPC_GET_IMETHOD(call)) {
    492                 case MEVENT_BUTTON:
     466                case INPUT_EVENT_MOVE:
     467                        /* Got pointer move event */
     468                        gcons_mouse_move((int) IPC_GET_ARG1(call),
     469                            (int) IPC_GET_ARG2(call));
     470                        retval = 0;
     471                        break;
     472                case INPUT_EVENT_BUTTON:
     473                        /* Got pointer button press/release event */
    493474                        if (IPC_GET_ARG1(call) == 1) {
    494475                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     
    498479                        retval = 0;
    499480                        break;
    500                 case MEVENT_MOVE:
    501                         gcons_mouse_move((int) IPC_GET_ARG1(call),
    502                             (int) IPC_GET_ARG2(call));
    503                         retval = 0;
    504                         break;
    505481                default:
    506482                        retval = ENOENT;
     
    522498        }
    523499       
    524         async_obsolete_serialize_start();
     500        console_serialize_start();
    525501       
    526502        size_t off = 0;
     
    530506        }
    531507       
    532         async_obsolete_serialize_end();
     508        console_serialize_end();
    533509       
    534510        gcons_notify_char(cons->index);
     
    597573
    598574/** Default thread for new connections */
    599 static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
     575static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    600576{
    601577        console_t *cons = NULL;
     
    625601        int rc;
    626602       
    627         async_obsolete_serialize_start();
     603        console_serialize_start();
    628604        if (cons->refcount == 0)
    629605                gcons_notify_connect(cons->index);
     
    635611       
    636612        while (true) {
    637                 async_obsolete_serialize_end();
     613                console_serialize_end();
    638614                callid = async_get_call(&call);
    639                 async_obsolete_serialize_start();
     615                console_serialize_start();
    640616               
    641617                arg1 = 0;
     
    647623                        if (cons->refcount == 0)
    648624                                gcons_notify_disconnect(cons->index);
     625                        console_serialize_end();
    649626                        return;
    650627                }
     
    652629                switch (IPC_GET_IMETHOD(call)) {
    653630                case VFS_OUT_READ:
    654                         async_obsolete_serialize_end();
     631                        console_serialize_end();
    655632                        cons_read(cons, callid, &call);
    656                         async_obsolete_serialize_start();
     633                        console_serialize_start();
    657634                        continue;
    658635                case VFS_OUT_WRITE:
    659                         async_obsolete_serialize_end();
     636                        console_serialize_end();
    660637                        cons_write(cons, callid, &call);
    661                         async_obsolete_serialize_start();
     638                        console_serialize_start();
    662639                        continue;
    663640                case VFS_OUT_SYNC:
     
    730707                        break;
    731708                case CONSOLE_GET_EVENT:
    732                         async_obsolete_serialize_end();
     709                        console_serialize_end();
    733710                        cons_get_event(cons, callid, &call);
    734                         async_obsolete_serialize_start();
     711                        console_serialize_start();
    735712                        continue;
    736713                case CONSOLE_KCON_ENABLE:
     
    747724}
    748725
    749 static int async_connect_to_me_hack(int phone, sysarg_t arg1, sysarg_t arg2,
    750     sysarg_t arg3, async_client_conn_t client_receiver, ipc_callid_t *hash)
    751 {
    752         sysarg_t task_hash;
    753         sysarg_t phone_hash;
    754         int rc = async_obsolete_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
    755             NULL, NULL, NULL, &task_hash, &phone_hash);
    756         if (rc != EOK)
    757                 return rc;
    758        
    759         if (client_receiver != NULL)
    760                 async_new_connection(task_hash, phone_hash, phone_hash, NULL,
    761                     client_receiver);
    762        
    763         if (hash != NULL)
    764                 *hash = phone_hash;
    765        
    766         return EOK;
    767 }
    768 
    769 static int connect_keyboard_or_mouse(const char *devname,
    770     async_client_conn_t handler, const char *dev)
    771 {
    772         int phone;
     726static async_sess_t *connect_input(const char *dev_path)
     727{
     728        async_sess_t *sess;
     729        async_exch_t *exch;
    773730        devmap_handle_t handle;
    774731       
    775         int rc = devmap_device_get_handle(dev, &handle, 0);
     732        int rc = devmap_device_get_handle(dev_path, &handle, 0);
    776733        if (rc == EOK) {
    777                 phone = devmap_obsolete_device_connect(handle, 0);
    778                 if (phone < 0) {
    779                         printf("%s: Failed to connect to input device\n", NAME);
    780                         return phone;
    781                 }
    782         } else
    783                 return rc;
     734                sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
     735                if (sess == NULL) {
     736                        printf("%s: Failed to connect to input server\n", NAME);
     737                        return NULL;
     738                }
     739        } else {
     740                return NULL;
     741        }
     742       
     743        exch = async_exchange_begin(sess);
     744        if (exch == NULL) {
     745                printf("%s: Failed to create callback from input server.\n", NAME);
     746                return NULL;
     747        }
    784748       
    785749        /* NB: The callback connection is slotted for removal */
    786         ipc_callid_t hash;
    787         rc = async_connect_to_me_hack(phone, SERVICE_CONSOLE, 0, phone,
    788             handler, &hash);
     750        rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
     751
     752        async_exchange_end(exch);
     753
    789754        if (rc != EOK) {
    790                 async_obsolete_hangup(phone);
    791                 printf("%s: Failed to create callback from input device (%s).\n",
     755                async_hangup(sess);
     756                printf("%s: Failed to create callback from input server (%s).\n",
    792757                    NAME, str_error(rc));
    793                 return rc;
    794         }
    795        
    796         driver_phones[phone] = hash;
    797         printf("%s: found %s \"%s\" (%" PRIxn ").\n", NAME, devname, dev, hash);
    798         return phone;
    799 }
    800 
    801 static int connect_keyboard(const char *dev)
    802 {
    803         return connect_keyboard_or_mouse("keyboard", keyboard_events, dev);
    804 }
    805 
    806 static int connect_mouse(const char *dev)
    807 {
    808         return connect_keyboard_or_mouse("mouse", mouse_events, dev);
    809 }
    810 
    811 struct hid_class_info {
    812         char *classname;
    813         int (*connection_func)(const char *);
    814 };
    815 
    816 /** Periodically check for new keyboards in /dev/class/.
    817  *
    818  * @param arg Class name.
    819  *
    820  * @return This function should never exit.
    821  *
    822  */
    823 static int check_new_device_fibril(void *arg)
    824 {
    825         struct hid_class_info *dev_info = (struct hid_class_info *) arg;
    826        
    827         size_t index = 1;
    828        
    829         while (true) {
    830                 async_usleep(HOTPLUG_WATCH_INTERVAL);
    831                
    832                 char *dev;
    833                 int rc = asprintf(&dev, "class/%s\\%zu",
    834                     dev_info->classname, index);
    835                 if (rc < 0)
    836                         continue;
    837                
    838                 rc = dev_info->connection_func(dev);
    839                 if (rc > 0) {
    840                         /* We do not allow unplug. */
    841                         index++;
    842                 }
    843                
    844                 free(dev);
    845         }
    846        
    847         return EOK;
    848 }
    849 
    850 /** Start a fibril monitoring hot-plugged keyboards.
    851  */
    852 static void check_new_devices_in_background(int (*connection_func)(const char *),
    853     const char *classname)
    854 {
    855         struct hid_class_info *dev_info = malloc(sizeof(struct hid_class_info));
    856         if (dev_info == NULL) {
    857                 printf("%s: Out of memory, no hot-plug support.\n", NAME);
    858                 return;
    859         }
    860        
    861         int rc = asprintf(&dev_info->classname, "%s", classname);
    862         if (rc < 0) {
    863                 printf("%s: Failed to format classname: %s.\n", NAME,
    864                     str_error(rc));
    865                 return;
    866         }
    867        
    868         dev_info->connection_func = connection_func;
    869        
    870         fid_t fid = fibril_create(check_new_device_fibril, (void *) dev_info);
    871         if (!fid) {
    872                 printf("%s: Failed to create hot-plug fibril for %s.\n", NAME,
    873                     classname);
    874                 return;
    875         }
    876        
    877         fibril_add_ready(fid);
    878 }
    879 
    880 static bool console_srv_init(char *kdev)
    881 {
    882         /* Connect to input device */
    883         kbd_phone = connect_keyboard(kdev);
    884         if (kbd_phone < 0)
     758                return NULL;
     759        }
     760       
     761        return sess;
     762}
     763
     764static bool console_srv_init(char *input_dev)
     765{
     766        /* Connect to input server */
     767        input_sess = connect_input(input_dev);
     768        if (input_sess == NULL)
    885769                return false;
    886        
    887         mouse_phone = connect_mouse("hid_in/mouse");
    888         if (mouse_phone < 0) {
    889                 printf("%s: Failed to connect to mouse device %s\n", NAME,
    890                     str_error(mouse_phone));
    891         }
    892770       
    893771        /* Connect to framebuffer driver */
     
    959837       
    960838        /* Initialize the screen */
    961         async_obsolete_serialize_start();
     839        console_serialize_start();
    962840        gcons_redraw_console();
    963841        set_style(STYLE_NORMAL);
     
    965843        curs_goto(0, 0);
    966844        curs_visibility(active_console->scr.is_cursor_visible);
    967         async_obsolete_serialize_end();
     845        console_serialize_end();
    968846       
    969847        /* Receive kernel notifications */
     
    972850                printf("%s: Error registering kconsole notifications\n", NAME);
    973851       
    974         /* Start fibril for checking on hot-plugged keyboards. */
    975         check_new_devices_in_background(connect_keyboard, "keyboard");
    976         check_new_devices_in_background(connect_mouse, "mouse");
    977        
    978852        return true;
    979853}
     
    981855static void usage(void)
    982856{
    983         printf("Usage: console <input>\n");
     857        printf("Usage: console <input_dev>\n");
    984858}
    985859
Note: See TracChangeset for help on using the changeset viewer.