Ignore:
File:
1 edited

Legend:

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

    r854eddd6 r8c74d15  
    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>
    41 #include <ns.h>
    42 #include <ns_obsolete.h>
     41#include <ipc/ns.h>
    4342#include <errno.h>
    4443#include <str_error.h>
     
    4645#include <unistd.h>
    4746#include <async.h>
    48 #include <async_obsolete.h>
    4947#include <adt/fifo.h>
    5048#include <sys/mman.h>
     
    5452#include <event.h>
    5553#include <devmap.h>
    56 #include <devmap_obsolete.h>
    5754#include <fcntl.h>
    5855#include <vfs/vfs.h>
     
    6057#include <io/style.h>
    6158#include <io/screenbuffer.h>
     59#include <inttypes.h>
    6260
    6361#include "console.h"
     
    6563#include "keybuffer.h"
    6664
     65
    6766#define NAME       "console"
    6867#define NAMESPACE  "term"
    69 
    70 /** Phone to the input server. */
    71 static int input_phone;
     68/** Interval for checking for new keyboard (1/4s). */
     69#define HOTPLUG_WATCH_INTERVAL (1000 * 250)
     70
     71/* Kernel defines 32 but does not export it. */
     72#define MAX_IPC_OUTGOING_PHONES 128
     73/** To allow proper phone closing. */
     74static ipc_callid_t driver_phones[MAX_IPC_OUTGOING_PHONES] = { 0 };
     75
     76/** Phone to the keyboard driver. */
     77static int kbd_phone;
     78
     79/** Phone to the mouse driver. */
     80static int mouse_phone;
    7281
    7382/** Information about framebuffer */
     
    8897} console_t;
    8998
     99
     100
    90101/** Array of data for virtual consoles */
    91102static console_t consoles[CONSOLE_COUNT];
     
    111122static void curs_visibility(bool visible)
    112123{
    113         async_obsolete_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
     124        async_msg_1(fb_info.phone, FB_CURSOR_VISIBILITY, visible);
    114125}
    115126
    116127static void curs_hide_sync(void)
    117128{
    118         async_obsolete_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
     129        async_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
    119130}
    120131
    121132static void curs_goto(sysarg_t x, sysarg_t y)
    122133{
    123         async_obsolete_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
     134        async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
    124135}
    125136
    126137static void screen_clear(void)
    127138{
    128         async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
     139        async_msg_0(fb_info.phone, FB_CLEAR);
    129140}
    130141
    131142static void screen_yield(void)
    132143{
    133         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
     144        async_req_0_0(fb_info.phone, FB_SCREEN_YIELD);
    134145}
    135146
    136147static void screen_reclaim(void)
    137148{
    138         async_obsolete_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
    139 }
    140 
    141 static void input_yield(void)
    142 {
    143         async_obsolete_req_0_0(input_phone, INPUT_YIELD);
    144 }
    145 
    146 static void input_reclaim(void)
    147 {
    148         async_obsolete_req_0_0(input_phone, INPUT_RECLAIM);
     149        async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
     150}
     151
     152static void kbd_yield(void)
     153{
     154        async_req_0_0(kbd_phone, KBD_YIELD);
     155}
     156
     157static void kbd_reclaim(void)
     158{
     159        async_req_0_0(kbd_phone, KBD_RECLAIM);
    149160}
    150161
    151162static void set_style(uint8_t style)
    152163{
    153         async_obsolete_msg_1(fb_info.phone, FB_SET_STYLE, style);
     164        async_msg_1(fb_info.phone, FB_SET_STYLE, style);
    154165}
    155166
    156167static void set_color(uint8_t fgcolor, uint8_t bgcolor, uint8_t flags)
    157168{
    158         async_obsolete_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
     169        async_msg_3(fb_info.phone, FB_SET_COLOR, fgcolor, bgcolor, flags);
    159170}
    160171
    161172static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
    162173{
    163         async_obsolete_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
     174        async_msg_2(fb_info.phone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
    164175}
    165176
     
    216227                }
    217228               
    218                 async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
     229                async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    219230                    x0, y0, width, height);
    220231        }
     
    257268static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
    258269{
    259         async_obsolete_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
     270        async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
    260271}
    261272
     
    306317               
    307318                if (cons == active_console)
    308                         async_obsolete_msg_1(fb_info.phone, FB_SCROLL, 1);
     319                        async_msg_1(fb_info.phone, FB_SCROLL, 1);
    309320        }
    310321       
     
    317328static void change_console(console_t *cons)
    318329{
    319         if (cons == active_console)
     330        if (cons == active_console) {
    320331                return;
     332        }
    321333       
    322334        fb_pending_flush();
    323335       
    324336        if (cons == kernel_console) {
    325                 async_obsolete_serialize_start();
     337                async_serialize_start();
    326338                curs_hide_sync();
    327339                gcons_in_kernel();
    328340                screen_yield();
    329                 input_yield();
    330                 async_obsolete_serialize_end();
     341                kbd_yield();
     342                async_serialize_end();
    331343               
    332344                if (__SYSCALL0(SYS_DEBUG_ENABLE_CONSOLE)) {
     
    338350       
    339351        if (cons != kernel_console) {
    340                 async_obsolete_serialize_start();
     352                async_serialize_start();
    341353               
    342354                if (active_console == kernel_console) {
    343355                        screen_reclaim();
    344                         input_reclaim();
     356                        kbd_reclaim();
    345357                        gcons_redraw_console();
    346358                }
     
    365377                       
    366378                        /* This call can preempt, but we are already at the end */
    367                         rc = async_obsolete_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
     379                        rc = async_req_4_0(fb_info.phone, FB_DRAW_TEXT_DATA,
    368380                            0, 0, cons->scr.size_x,
    369381                            cons->scr.size_y);
     
    393405                curs_visibility(cons->scr.is_cursor_visible);
    394406               
    395                 async_obsolete_serialize_end();
    396         }
    397 }
    398 
    399 /** Handler for input events */
    400 static void input_events(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     407                async_serialize_end();
     408        }
     409}
     410
     411static void close_driver_phone(ipc_callid_t hash)
     412{
     413        int i;
     414        for (i = 0; i < MAX_IPC_OUTGOING_PHONES; i++) {
     415                if (driver_phones[i] == hash) {
     416                        printf("Device %" PRIxn " gone.\n", hash);
     417                        driver_phones[i] = 0;
     418                        async_hangup(i);
     419                        return;
     420                }
     421        }
     422}
     423
     424/** Handler for keyboard */
     425static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
    401426{
    402427        /* Ignore parameters, the connection is already opened */
     
    406431               
    407432                int retval;
    408                 kbd_event_t ev;
    409                
    410                 if (!IPC_GET_IMETHOD(call)) {
     433                console_event_t ev;
     434               
     435                switch (IPC_GET_IMETHOD(call)) {
     436                case IPC_M_PHONE_HUNGUP:
    411437                        /* TODO: Handle hangup */
    412                         async_obsolete_hangup(input_phone);
     438                        close_driver_phone(iid);
    413439                        return;
    414                 }
    415                
    416                 switch (IPC_GET_IMETHOD(call)) {
    417                 case INPUT_EVENT_KEY:
    418                         /* Got key press/release event */
     440                case KBD_EVENT:
     441                        /* Got event from keyboard driver. */
    419442                        retval = 0;
    420443                        ev.type = IPC_GET_ARG1(call);
     
    437460                        fibril_mutex_unlock(&input_mutex);
    438461                        break;
    439                 case INPUT_EVENT_MOVE:
    440                         /* Got pointer move event */
     462                default:
     463                        retval = ENOENT;
     464                }
     465                async_answer_0(callid, retval);
     466        }
     467}
     468
     469/** Handler for mouse events */
     470static void mouse_events(ipc_callid_t iid, ipc_call_t *icall)
     471{
     472        /* Ignore parameters, the connection is already opened */
     473        while (true) {
     474                ipc_call_t call;
     475                ipc_callid_t callid = async_get_call(&call);
     476               
     477                int retval;
     478               
     479                switch (IPC_GET_IMETHOD(call)) {
     480                case IPC_M_PHONE_HUNGUP:
     481                        /* TODO: Handle hangup */
     482                        close_driver_phone(iid);
     483                        return;
     484                case MEVENT_BUTTON:
     485                        if (IPC_GET_ARG1(call) == 1) {
     486                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
     487                                if (newcon != -1) {
     488                                        change_console(&consoles[newcon]);
     489                                }
     490                        }
     491                        retval = 0;
     492                        break;
     493                case MEVENT_MOVE:
    441494                        gcons_mouse_move((int) IPC_GET_ARG1(call),
    442495                            (int) IPC_GET_ARG2(call));
    443496                        retval = 0;
    444497                        break;
    445                 case INPUT_EVENT_BUTTON:
    446                         /* Got pointer button press/release event */
    447                         if (IPC_GET_ARG1(call) == 1) {
    448                                 int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
    449                                 if (newcon != -1)
    450                                         change_console(&consoles[newcon]);
    451                         }
    452                         retval = 0;
    453                         break;
    454498                default:
    455499                        retval = ENOENT;
    456500                }
     501
    457502                async_answer_0(callid, retval);
    458503        }
     
    470515        }
    471516       
    472         async_obsolete_serialize_start();
     517        async_serialize_start();
    473518       
    474519        size_t off = 0;
     
    478523        }
    479524       
    480         async_obsolete_serialize_end();
     525        async_serialize_end();
    481526       
    482527        gcons_notify_char(cons->index);
     
    504549       
    505550        size_t pos = 0;
    506         kbd_event_t ev;
     551        console_event_t ev;
    507552        fibril_mutex_lock(&input_mutex);
    508553       
     
    529574static void cons_get_event(console_t *cons, ipc_callid_t rid, ipc_call_t *request)
    530575{
    531         kbd_event_t ev;
     576        console_event_t ev;
    532577       
    533578        fibril_mutex_lock(&input_mutex);
     
    545590
    546591/** Default thread for new connections */
    547 static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     592static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
    548593{
    549594        console_t *cons = NULL;
     
    573618        int rc;
    574619       
    575         async_obsolete_serialize_start();
     620        async_serialize_start();
    576621        if (cons->refcount == 0)
    577622                gcons_notify_connect(cons->index);
     
    583628       
    584629        while (true) {
    585                 async_obsolete_serialize_end();
     630                async_serialize_end();
    586631                callid = async_get_call(&call);
    587                 async_obsolete_serialize_start();
     632                async_serialize_start();
    588633               
    589634                arg1 = 0;
     
    591636                arg3 = 0;
    592637               
    593                 if (!IPC_GET_IMETHOD(call)) {
     638                switch (IPC_GET_IMETHOD(call)) {
     639                case IPC_M_PHONE_HUNGUP:
    594640                        cons->refcount--;
    595641                        if (cons->refcount == 0)
    596642                                gcons_notify_disconnect(cons->index);
    597643                        return;
    598                 }
    599                
    600                 switch (IPC_GET_IMETHOD(call)) {
    601644                case VFS_OUT_READ:
    602                         async_obsolete_serialize_end();
     645                        async_serialize_end();
    603646                        cons_read(cons, callid, &call);
    604                         async_obsolete_serialize_start();
     647                        async_serialize_start();
    605648                        continue;
    606649                case VFS_OUT_WRITE:
    607                         async_obsolete_serialize_end();
     650                        async_serialize_end();
    608651                        cons_write(cons, callid, &call);
    609                         async_obsolete_serialize_start();
     652                        async_serialize_start();
    610653                        continue;
    611654                case VFS_OUT_SYNC:
    612655                        fb_pending_flush();
    613656                        if (cons == active_console) {
    614                                 async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
     657                                async_req_0_0(fb_info.phone, FB_FLUSH);
    615658                                curs_goto(cons->scr.position_x, cons->scr.position_y);
    616659                        }
     
    619662                        /* Send message to fb */
    620663                        if (cons == active_console)
    621                                 async_obsolete_msg_0(fb_info.phone, FB_CLEAR);
     664                                async_msg_0(fb_info.phone, FB_CLEAR);
    622665                       
    623666                        screenbuffer_clear(&cons->scr);
     
    678721                        break;
    679722                case CONSOLE_GET_EVENT:
    680                         async_obsolete_serialize_end();
     723                        async_serialize_end();
    681724                        cons_get_event(cons, callid, &call);
    682                         async_obsolete_serialize_start();
     725                        async_serialize_start();
    683726                        continue;
    684727                case CONSOLE_KCON_ENABLE:
     
    695738}
    696739
    697 static int connect_input(const char *dev_path)
    698 {
    699         int phone;
    700         devmap_handle_t handle;
    701        
    702         int rc = devmap_device_get_handle(dev_path, &handle, 0);
    703         if (rc == EOK) {
    704                 phone = devmap_obsolete_device_connect(handle, 0);
    705                 if (phone < 0) {
    706                         printf("%s: Failed to connect to input device\n", NAME);
    707                         return phone;
    708                 }
    709         } else {
     740static int async_connect_to_me_hack(int phone, sysarg_t arg1, sysarg_t arg2,
     741sysarg_t arg3, async_client_conn_t client_receiver, ipc_callid_t *hash)
     742{
     743        sysarg_t task_hash;
     744        sysarg_t phone_hash;
     745        int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
     746            NULL, NULL, NULL, &task_hash, &phone_hash);
     747        if (rc != EOK)
    710748                return rc;
    711         }
    712        
    713         /* NB: The callback connection is slotted for removal */
    714         rc = async_obsolete_connect_to_me(phone, SERVICE_CONSOLE, 0, 0,
    715             input_events, NULL);
    716 
     749
     750        if (client_receiver != NULL)
     751                async_new_connection(task_hash, phone_hash, phone_hash, NULL,
     752                    client_receiver);
     753
     754        if (hash != NULL) {
     755                *hash = phone_hash;
     756        }
     757
     758        return EOK;
     759}
     760
     761static int connect_keyboard_or_mouse(const char *devname,
     762    async_client_conn_t handler, const char *path)
     763{
     764        int fd = open(path, O_RDONLY);
     765        if (fd < 0) {
     766                return fd;
     767        }
     768       
     769        int phone = fd_phone(fd);
     770        close(fd);
     771        if (phone < 0) {
     772                printf(NAME ": Failed to connect to input device\n");
     773                return phone;
     774        }
     775       
     776        ipc_callid_t hash;
     777        int rc = async_connect_to_me_hack(phone, SERVICE_CONSOLE, 0, phone,
     778            handler, &hash);
    717779        if (rc != EOK) {
    718                 async_obsolete_hangup(phone);
    719                 printf("%s: Failed to create callback from input device (%s).\n",
    720                     NAME, str_error(rc));
     780                async_hangup(phone);
     781                printf(NAME ": " \
     782                    "Failed to create callback from input device: %s.\n",
     783                    str_error(rc));
    721784                return rc;
    722785        }
    723786       
     787        driver_phones[phone] = hash;
     788
     789        printf(NAME ": found %s \"%s\" (%" PRIxn ").\n", devname, path, hash);
     790
    724791        return phone;
    725792}
    726793
    727 static bool console_srv_init(char *input_dev)
    728 {
    729         /* Connect to input server */
    730         input_phone = connect_input(input_dev);
    731         if (input_phone < 0)
     794static int connect_keyboard(const char *path)
     795{
     796        return connect_keyboard_or_mouse("keyboard", keyboard_events, path);
     797}
     798
     799static int connect_mouse(const char *path)
     800{
     801        return connect_keyboard_or_mouse("mouse", mouse_events, path);
     802}
     803
     804struct hid_class_info {
     805        char *classname;
     806        int (*connection_func)(const char *);
     807};
     808
     809/** Periodically check for new keyboards in /dev/class/.
     810 *
     811 * @param arg Class name.
     812 * @return This function should never exit.
     813 */
     814static int check_new_device_fibril(void *arg)
     815{
     816        struct hid_class_info *dev_info = arg;
     817
     818        size_t index = 1;
     819
     820        while (true) {
     821                async_usleep(HOTPLUG_WATCH_INTERVAL);
     822                char *path;
     823                int rc = asprintf(&path, "/dev/class/%s\\%zu",
     824                    dev_info->classname, index);
     825                if (rc < 0) {
     826                        continue;
     827                }
     828                rc = 0;
     829                rc = dev_info->connection_func(path);
     830                if (rc > 0) {
     831                        /* We do not allow unplug. */
     832                        index++;
     833                }
     834
     835                free(path);
     836        }
     837
     838        return EOK;
     839}
     840
     841
     842/** Start a fibril monitoring hot-plugged keyboards.
     843 */
     844static void check_new_devices_in_background(int (*connection_func)(const char *),
     845    const char *classname)
     846{
     847        struct hid_class_info *dev_info = malloc(sizeof(struct hid_class_info));
     848        if (dev_info == NULL) {
     849                printf(NAME ": " \
     850                    "out of memory, will not start hot-plug-watch fibril.\n");
     851                return;
     852        }
     853        int rc;
     854
     855        rc = asprintf(&dev_info->classname, "%s", classname);
     856        if (rc < 0) {
     857                printf(NAME ": failed to format classname: %s.\n",
     858                    str_error(rc));
     859                return;
     860        }
     861        dev_info->connection_func = connection_func;
     862
     863        fid_t fid = fibril_create(check_new_device_fibril, (void *)dev_info);
     864        if (!fid) {
     865                printf(NAME
     866                    ": failed to create hot-plug-watch fibril for %s.\n",
     867                    classname);
     868                return;
     869        }
     870        fibril_add_ready(fid);
     871}
     872
     873static bool console_init(char *input)
     874{
     875        /* Connect to input device */
     876        kbd_phone = connect_keyboard(input);
     877        if (kbd_phone < 0) {
    732878                return false;
     879        }
     880
     881        mouse_phone = connect_mouse("/dev/hid_in/mouse");
     882        if (mouse_phone < 0) {
     883                printf(NAME ": Failed to connect to mouse device: %s.\n",
     884                    str_error(mouse_phone));
     885        }
    733886       
    734887        /* Connect to framebuffer driver */
    735         fb_info.phone = service_obsolete_connect_blocking(SERVICE_VIDEO, 0, 0);
     888        fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0);
    736889        if (fb_info.phone < 0) {
    737                 printf("%s: Failed to connect to video service\n", NAME);
    738                 return false;
     890                printf(NAME ": Failed to connect to video service\n");
     891                return -1;
    739892        }
    740893       
     
    742895        int rc = devmap_driver_register(NAME, client_connection);
    743896        if (rc < 0) {
    744                 printf("%s: Unable to register driver (%d)\n", NAME, rc);
     897                printf(NAME ": Unable to register driver (%d)\n", rc);
    745898                return false;
    746899        }
     
    750903       
    751904        /* Synchronize, the gcons could put something in queue */
    752         async_obsolete_req_0_0(fb_info.phone, FB_FLUSH);
    753         async_obsolete_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
    754         async_obsolete_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
     905        async_req_0_0(fb_info.phone, FB_FLUSH);
     906        async_req_0_2(fb_info.phone, FB_GET_CSIZE, &fb_info.cols, &fb_info.rows);
     907        async_req_0_1(fb_info.phone, FB_GET_COLOR_CAP, &fb_info.color_cap);
    755908       
    756909        /* Set up shared memory buffer. */
     
    763916       
    764917        if (interbuffer) {
    765                 if (async_obsolete_share_out_start(fb_info.phone, interbuffer,
     918                if (async_share_out_start(fb_info.phone, interbuffer,
    766919                    AS_AREA_READ) != EOK) {
    767920                        as_area_destroy(interbuffer);
     
    778931                        if (screenbuffer_init(&consoles[i].scr,
    779932                            fb_info.cols, fb_info.rows) == NULL) {
    780                                 printf("%s: Unable to allocate screen buffer %zu\n", NAME, i);
     933                                printf(NAME ": Unable to allocate screen buffer %zu\n", i);
    781934                                return false;
    782935                        }
     
    790943                       
    791944                        if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
    792                                 printf("%s: Unable to register device %s\n", NAME, vc);
     945                                printf(NAME ": Unable to register device %s\n", vc);
    793946                                return false;
    794947                        }
     
    800953       
    801954        /* Initialize the screen */
    802         async_obsolete_serialize_start();
     955        async_serialize_start();
    803956        gcons_redraw_console();
    804957        set_style(STYLE_NORMAL);
     
    806959        curs_goto(0, 0);
    807960        curs_visibility(active_console->scr.is_cursor_visible);
    808         async_obsolete_serialize_end();
     961        async_serialize_end();
    809962       
    810963        /* Receive kernel notifications */
    811964        async_set_interrupt_received(interrupt_received);
    812965        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    813                 printf("%s: Error registering kconsole notifications\n", NAME);
    814        
     966                printf(NAME ": Error registering kconsole notifications\n");
     967       
     968        /* Start fibril for checking on hot-plugged keyboards. */
     969        check_new_devices_in_background(connect_keyboard, "keyboard");
     970        check_new_devices_in_background(connect_mouse, "mouse");
     971
    815972        return true;
    816973}
     
    818975static void usage(void)
    819976{
    820         printf("Usage: console <input_dev>\n");
     977        printf("Usage: console <input>\n");
    821978}
    822979
     
    830987        printf(NAME ": HelenOS Console service\n");
    831988       
    832         if (!console_srv_init(argv[1]))
     989        if (!console_init(argv[1]))
    833990                return -1;
    834        
     991
    835992        printf(NAME ": Accepting connections\n");
    836993        async_manager();
Note: See TracChangeset for help on using the changeset viewer.