Ignore:
File:
1 edited

Legend:

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

    rb366a6f4 r79ae36dd  
    11/*
    22 * Copyright (c) 2006 Josef Cejka
    3  * Copyright (c) 2011 Jiri Svoboda
    43 * All rights reserved.
    54 *
     
    3534
    3635#include <libc.h>
    37 #include <ipc/input.h>
     36#include <ipc/kbd.h>
    3837#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>
    5657#include <fcntl.h>
    5758#include <vfs/vfs.h>
     
    5960#include <io/style.h>
    6061#include <io/screenbuffer.h>
     62#include <inttypes.h>
    6163
    6264#include "console.h"
     
    6466#include "keybuffer.h"
    6567
     68// FIXME: remove this header
     69#include <kernel/ipc/ipc_methods.h>
     70
    6671#define NAME       "console"
    6772#define NAMESPACE  "term"
    6873
    69 /** Session with the input server. */
    70 static async_sess_t *input_sess;
     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. */
     81static ipc_callid_t driver_phones[MAX_IPC_OUTGOING_PHONES] = { 0 };
     82
     83/** Phone to the keyboard driver. */
     84static int kbd_phone;
     85
     86/** Phone to the mouse driver. */
     87static int mouse_phone;
    7188
    7289/** Information about framebuffer */
     
    108125static FIBRIL_CONDVAR_INITIALIZE(input_cv);
    109126
    110 static FIBRIL_MUTEX_INITIALIZE(big_console_lock);
    111 
    112 static void console_serialize_start(void)
    113 {
    114         fibril_mutex_lock(&big_console_lock);
    115 }
    116 
    117 static void console_serialize_end(void)
    118 {
    119         fibril_mutex_unlock(&big_console_lock);
    120 }
    121 
    122127static void curs_visibility(bool visible)
    123128{
     
    150155}
    151156
    152 static 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 
    165 static 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);
     157static void kbd_yield(void)
     158{
     159        async_obsolete_req_0_0(kbd_phone, KBD_YIELD);
     160}
     161
     162static void kbd_reclaim(void)
     163{
     164        async_obsolete_req_0_0(kbd_phone, KBD_RECLAIM);
    176165}
    177166
     
    350339       
    351340        if (cons == kernel_console) {
    352                 console_serialize_start();
     341                async_obsolete_serialize_start();
    353342                curs_hide_sync();
    354343                gcons_in_kernel();
    355344                screen_yield();
    356                 input_yield();
    357                 console_serialize_end();
    358                
    359                 if (console_kcon()) {
     345                kbd_yield();
     346                async_obsolete_serialize_end();
     347               
     348                if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
    360349                        prev_console = active_console;
    361350                        active_console = kernel_console;
     
    365354       
    366355        if (cons != kernel_console) {
    367                 console_serialize_start();
     356                async_obsolete_serialize_start();
    368357               
    369358                if (active_console == kernel_console) {
    370359                        screen_reclaim();
    371                         input_reclaim();
     360                        kbd_reclaim();
    372361                        gcons_redraw_console();
    373362                }
     
    420409                curs_visibility(cons->scr.is_cursor_visible);
    421410               
    422                 console_serialize_end();
    423         }
    424 }
    425 
    426 /** Handler for input events */
    427 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     411                async_obsolete_serialize_end();
     412        }
     413}
     414
     415static 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 */
     429static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
    428430{
    429431        /* Ignore parameters, the connection is already opened */
     
    437439                if (!IPC_GET_IMETHOD(call)) {
    438440                        /* TODO: Handle hangup */
    439                         async_hangup(input_sess);
     441                        close_driver_phone(iid);
    440442                        return;
    441443                }
    442444               
    443445                switch (IPC_GET_IMETHOD(call)) {
    444                 case INPUT_EVENT_KEY:
    445                         /* Got key press/release event */
     446                case KBD_EVENT:
     447                        /* Got event from keyboard driver. */
    446448                        retval = 0;
    447449                        ev.type = IPC_GET_ARG1(call);
     
    464466                        fibril_mutex_unlock(&input_mutex);
    465467                        break;
    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 */
     468                default:
     469                        retval = ENOENT;
     470                }
     471                async_answer_0(callid, retval);
     472        }
     473}
     474
     475/** Handler for mouse events */
     476static 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:
    474493                        if (IPC_GET_ARG1(call) == 1) {
    475494                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     
    479498                        retval = 0;
    480499                        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;
    481505                default:
    482506                        retval = ENOENT;
     
    498522        }
    499523       
    500         console_serialize_start();
     524        async_obsolete_serialize_start();
    501525       
    502526        size_t off = 0;
     
    506530        }
    507531       
    508         console_serialize_end();
     532        async_obsolete_serialize_end();
    509533       
    510534        gcons_notify_char(cons->index);
     
    573597
    574598/** Default thread for new connections */
    575 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     599static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
    576600{
    577601        console_t *cons = NULL;
     
    601625        int rc;
    602626       
    603         console_serialize_start();
     627        async_obsolete_serialize_start();
    604628        if (cons->refcount == 0)
    605629                gcons_notify_connect(cons->index);
     
    611635       
    612636        while (true) {
    613                 console_serialize_end();
     637                async_obsolete_serialize_end();
    614638                callid = async_get_call(&call);
    615                 console_serialize_start();
     639                async_obsolete_serialize_start();
    616640               
    617641                arg1 = 0;
     
    623647                        if (cons->refcount == 0)
    624648                                gcons_notify_disconnect(cons->index);
    625                         console_serialize_end();
    626649                        return;
    627650                }
     
    629652                switch (IPC_GET_IMETHOD(call)) {
    630653                case VFS_OUT_READ:
    631                         console_serialize_end();
     654                        async_obsolete_serialize_end();
    632655                        cons_read(cons, callid, &call);
    633                         console_serialize_start();
     656                        async_obsolete_serialize_start();
    634657                        continue;
    635658                case VFS_OUT_WRITE:
    636                         console_serialize_end();
     659                        async_obsolete_serialize_end();
    637660                        cons_write(cons, callid, &call);
    638                         console_serialize_start();
     661                        async_obsolete_serialize_start();
    639662                        continue;
    640663                case VFS_OUT_SYNC:
     
    707730                        break;
    708731                case CONSOLE_GET_EVENT:
    709                         console_serialize_end();
     732                        async_obsolete_serialize_end();
    710733                        cons_get_event(cons, callid, &call);
    711                         console_serialize_start();
     734                        async_obsolete_serialize_start();
    712735                        continue;
     736                case CONSOLE_KCON_ENABLE:
     737                        change_console(kernel_console);
     738                        break;
    713739                }
    714740                async_answer_3(callid, EOK, arg1, arg2, arg3);
     
    721747}
    722748
    723 static async_sess_t *connect_input(const char *dev_path)
    724 {
    725         async_sess_t *sess;
    726         async_exch_t *exch;
     749static 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
     769static int connect_keyboard_or_mouse(const char *devname,
     770    async_client_conn_t handler, const char *dev)
     771{
     772        int phone;
    727773        devmap_handle_t handle;
    728774       
    729         int rc = devmap_device_get_handle(dev_path, &handle, 0);
     775        int rc = devmap_device_get_handle(dev, &handle, 0);
    730776        if (rc == EOK) {
    731                 sess = devmap_device_connect(EXCHANGE_ATOMIC, handle, 0);
    732                 if (sess == NULL) {
    733                         printf("%s: Failed to connect to input server\n", NAME);
    734                         return NULL;
    735                 }
    736         } else {
    737                 return NULL;
    738         }
    739        
    740         exch = async_exchange_begin(sess);
    741         if (exch == NULL) {
    742                 printf("%s: Failed to create callback from input server.\n", NAME);
    743                 return NULL;
    744         }
     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;
    745784       
    746785        /* NB: The callback connection is slotted for removal */
    747         rc = async_connect_to_me(exch, 0, 0, 0, input_events, NULL);
    748 
    749         async_exchange_end(exch);
    750 
     786        ipc_callid_t hash;
     787        rc = async_connect_to_me_hack(phone, SERVICE_CONSOLE, 0, phone,
     788            handler, &hash);
    751789        if (rc != EOK) {
    752                 async_hangup(sess);
    753                 printf("%s: Failed to create callback from input server (%s).\n",
     790                async_obsolete_hangup(phone);
     791                printf("%s: Failed to create callback from input device (%s).\n",
    754792                    NAME, str_error(rc));
    755                 return NULL;
    756         }
    757        
    758         return sess;
    759 }
    760 
    761 static bool console_srv_init(char *input_dev)
    762 {
    763         /* Connect to input server */
    764         input_sess = connect_input(input_dev);
    765         if (input_sess == NULL)
     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
     801static int connect_keyboard(const char *dev)
     802{
     803        return connect_keyboard_or_mouse("keyboard", keyboard_events, dev);
     804}
     805
     806static int connect_mouse(const char *dev)
     807{
     808        return connect_keyboard_or_mouse("mouse", mouse_events, dev);
     809}
     810
     811struct 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 */
     823static 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 */
     852static 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
     880static bool console_srv_init(char *kdev)
     881{
     882        /* Connect to input device */
     883        kbd_phone = connect_keyboard(kdev);
     884        if (kbd_phone < 0)
    766885                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        }
    767892       
    768893        /* Connect to framebuffer driver */
     
    830955        }
    831956       
     957        /* Disable kernel output to the console */
     958        __SYSCALL0(SYS_DEBUG_DISABLE_CONSOLE);
     959       
    832960        /* Initialize the screen */
    833         console_serialize_start();
     961        async_obsolete_serialize_start();
    834962        gcons_redraw_console();
    835963        set_style(STYLE_NORMAL);
     
    837965        curs_goto(0, 0);
    838966        curs_visibility(active_console->scr.is_cursor_visible);
    839         console_serialize_end();
     967        async_obsolete_serialize_end();
    840968       
    841969        /* Receive kernel notifications */
     
    844972                printf("%s: Error registering kconsole notifications\n", NAME);
    845973       
     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       
    846978        return true;
    847979}
     
    849981static void usage(void)
    850982{
    851         printf("Usage: console <input_dev>\n");
     983        printf("Usage: console <input>\n");
    852984}
    853985
Note: See TracChangeset for help on using the changeset viewer.