Changeset eb522e8 in mainline for uspace/srv/hid/console/console.c


Ignore:
Timestamp:
2011-06-01T08:43:42Z (15 years ago)
Author:
Lubos Slovak <lubos.slovak@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8d6c1f1
Parents:
9e2e715 (diff), e51a514 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Huuuuuge merge from development - all the work actually :)

File:
1 edited

Legend:

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

    r9e2e715 reb522e8  
    3434
    3535#include <libc.h>
    36 #include <ipc/ipc.h>
    3736#include <ipc/kbd.h>
    3837#include <io/keycode.h>
     
    4039#include <ipc/fb.h>
    4140#include <ipc/services.h>
     41#include <ipc/ns.h>
    4242#include <errno.h>
     43#include <str_error.h>
    4344#include <ipc/console.h>
    4445#include <unistd.h>
     
    5657#include <io/style.h>
    5758#include <io/screenbuffer.h>
     59#include <inttypes.h>
    5860
    5961#include "console.h"
     
    6466#define NAME       "console"
    6567#define NAMESPACE  "term"
     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 };
    6675
    6776/** Phone to the keyboard driver. */
     
    7483struct {
    7584        int phone;           /**< Framebuffer phone */
    76         ipcarg_t cols;       /**< Framebuffer columns */
    77         ipcarg_t rows;       /**< Framebuffer rows */
    78         ipcarg_t color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
     85        sysarg_t cols;       /**< Framebuffer columns */
     86        sysarg_t rows;       /**< Framebuffer rows */
     87        sysarg_t color_cap;  /**< Color capabilities (FB_CCAP_xxx) */
    7988} fb_info;
    8089
     
    8291        size_t index;             /**< Console index */
    8392        size_t refcount;          /**< Connection reference count */
    84         dev_handle_t dev_handle;  /**< Device handle */
     93        devmap_handle_t devmap_handle;  /**< Device handle */
    8594        keybuffer_t keybuffer;    /**< Buffer for incoming keys. */
    8695        screenbuffer_t scr;       /**< Screenbuffer for saving screen
     
    8897} console_t;
    8998
     99
     100
    90101/** Array of data for virtual consoles */
    91102static console_t consoles[CONSOLE_COUNT];
     
    101112/** Information on row-span yet unsent to FB driver. */
    102113struct {
    103         ipcarg_t col;  /**< Leftmost column of the span. */
    104         ipcarg_t row;  /**< Row where the span lies. */
    105         ipcarg_t cnt;  /**< Width of the span. */
     114        sysarg_t col;  /**< Leftmost column of the span. */
     115        sysarg_t row;  /**< Row where the span lies. */
     116        sysarg_t cnt;  /**< Width of the span. */
    106117} fb_pending;
    107118
     
    116127static void curs_hide_sync(void)
    117128{
    118         ipc_call_sync_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
    119 }
    120 
    121 static void curs_goto(ipcarg_t x, ipcarg_t y)
     129        async_req_1_0(fb_info.phone, FB_CURSOR_VISIBILITY, false);
     130}
     131
     132static void curs_goto(sysarg_t x, sysarg_t y)
    122133{
    123134        async_msg_2(fb_info.phone, FB_CURSOR_GOTO, x, y);
     
    131142static void screen_yield(void)
    132143{
    133         ipc_call_sync_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         ipc_call_sync_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
     149        async_req_0_0(fb_info.phone, FB_SCREEN_RECLAIM);
    139150}
    140151
    141152static void kbd_yield(void)
    142153{
    143         ipc_call_sync_0_0(kbd_phone, KBD_YIELD);
     154        async_req_0_0(kbd_phone, KBD_YIELD);
    144155}
    145156
    146157static void kbd_reclaim(void)
    147158{
    148         ipc_call_sync_0_0(kbd_phone, KBD_RECLAIM);
     159        async_req_0_0(kbd_phone, KBD_RECLAIM);
    149160}
    150161
     
    180191}
    181192
    182 static int ccap_fb_to_con(ipcarg_t ccap_fb, ipcarg_t *ccap_con)
     193static int ccap_fb_to_con(sysarg_t ccap_fb, sysarg_t *ccap_con)
    183194{
    184195        switch (ccap_fb) {
     
    203214
    204215/** Send an area of screenbuffer to the FB driver. */
    205 static void fb_update_area(console_t *cons, ipcarg_t x0, ipcarg_t y0, ipcarg_t width, ipcarg_t height)
     216static void fb_update_area(console_t *cons, sysarg_t x0, sysarg_t y0, sysarg_t width, sysarg_t height)
    206217{
    207218        if (interbuffer) {
    208                 ipcarg_t x;
    209                 ipcarg_t y;
     219                sysarg_t x;
     220                sysarg_t y;
    210221               
    211222                for (y = 0; y < height; y++) {
     
    237248 *
    238249 */
    239 static void cell_mark_changed(ipcarg_t col, ipcarg_t row)
     250static void cell_mark_changed(sysarg_t col, sysarg_t row)
    240251{
    241252        if (fb_pending.cnt != 0) {
     
    255266
    256267/** Print a character to the active VC with buffering. */
    257 static void fb_putchar(wchar_t c, ipcarg_t col, ipcarg_t row)
     268static void fb_putchar(wchar_t c, sysarg_t col, sysarg_t row)
    258269{
    259270        async_msg_3(fb_info.phone, FB_PUTCHAR, c, col, row);
     
    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();
     
    352364                curs_visibility(false);
    353365               
    354                 ipcarg_t x;
    355                 ipcarg_t y;
     366                sysarg_t x;
     367                sysarg_t y;
    356368                int rc = 0;
    357369               
     
    397409}
    398410
     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
    399424/** Handler for keyboard */
    400425static void keyboard_events(ipc_callid_t iid, ipc_call_t *icall)
     
    408433                console_event_t ev;
    409434               
    410                 switch (IPC_GET_METHOD(call)) {
     435                switch (IPC_GET_IMETHOD(call)) {
    411436                case IPC_M_PHONE_HUNGUP:
    412437                        /* TODO: Handle hangup */
     438                        close_driver_phone(iid);
    413439                        return;
    414440                case KBD_EVENT:
     
    437463                        retval = ENOENT;
    438464                }
    439                 ipc_answer_0(callid, retval);
     465                async_answer_0(callid, retval);
    440466        }
    441467}
     
    451477                int retval;
    452478               
    453                 switch (IPC_GET_METHOD(call)) {
     479                switch (IPC_GET_IMETHOD(call)) {
    454480                case IPC_M_PHONE_HUNGUP:
    455481                        /* TODO: Handle hangup */
     482                        close_driver_phone(iid);
    456483                        return;
    457484                case MEVENT_BUTTON:
    458485                        if (IPC_GET_ARG1(call) == 1) {
    459486                                int newcon = gcons_mouse_btn((bool) IPC_GET_ARG2(call));
    460                                 if (newcon != -1)
     487                                if (newcon != -1) {
    461488                                        change_console(&consoles[newcon]);
     489                                }
    462490                        }
    463491                        retval = 0;
     
    472500                }
    473501
    474                 ipc_answer_0(callid, retval);
     502                async_answer_0(callid, retval);
    475503        }
    476504}
     
    483511       
    484512        if (rc != EOK) {
    485                 ipc_answer_0(rid, rc);
     513                async_answer_0(rid, rc);
    486514                return;
    487515        }
     
    498526       
    499527        gcons_notify_char(cons->index);
    500         ipc_answer_1(rid, EOK, size);
     528        async_answer_1(rid, EOK, size);
    501529       
    502530        free(buf);
     
    508536        size_t size;
    509537        if (!async_data_read_receive(&callid, &size)) {
    510                 ipc_answer_0(callid, EINVAL);
    511                 ipc_answer_0(rid, EINVAL);
     538                async_answer_0(callid, EINVAL);
     539                async_answer_0(rid, EINVAL);
    512540                return;
    513541        }
     
    515543        char *buf = (char *) malloc(size);
    516544        if (buf == NULL) {
    517                 ipc_answer_0(callid, ENOMEM);
    518                 ipc_answer_0(rid, ENOMEM);
     545                async_answer_0(callid, ENOMEM);
     546                async_answer_0(rid, ENOMEM);
    519547                return;
    520548        }
     
    534562        if (pos == size) {
    535563                (void) async_data_read_finalize(callid, buf, size);
    536                 ipc_answer_1(rid, EOK, size);
     564                async_answer_1(rid, EOK, size);
    537565                free(buf);
    538566        } else {
     
    552580recheck:
    553581        if (keybuffer_pop(&cons->keybuffer, &ev)) {
    554                 ipc_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
     582                async_answer_4(rid, EOK, ev.type, ev.key, ev.mods, ev.c);
    555583        } else {
    556584                fibril_condvar_wait(&input_cv, &input_mutex);
     
    571599                        continue;
    572600               
    573                 if (consoles[i].dev_handle == (dev_handle_t) IPC_GET_ARG1(*icall)) {
     601                if (consoles[i].devmap_handle == (devmap_handle_t) IPC_GET_ARG1(*icall)) {
    574602                        cons = &consoles[i];
    575603                        break;
     
    578606       
    579607        if (cons == NULL) {
    580                 ipc_answer_0(iid, ENOENT);
     608                async_answer_0(iid, ENOENT);
    581609                return;
    582610        }
     
    584612        ipc_callid_t callid;
    585613        ipc_call_t call;
    586         ipcarg_t arg1;
    587         ipcarg_t arg2;
    588         ipcarg_t arg3;
     614        sysarg_t arg1;
     615        sysarg_t arg2;
     616        sysarg_t arg3;
    589617       
    590618        int rc;
     
    597625       
    598626        /* Accept the connection */
    599         ipc_answer_0(iid, EOK);
     627        async_answer_0(iid, EOK);
    600628       
    601629        while (true) {
     
    608636                arg3 = 0;
    609637               
    610                 switch (IPC_GET_METHOD(call)) {
     638                switch (IPC_GET_IMETHOD(call)) {
    611639                case IPC_M_PHONE_HUNGUP:
    612640                        cons->refcount--;
     
    657685                        rc = ccap_fb_to_con(fb_info.color_cap, &arg1);
    658686                        if (rc != EOK) {
    659                                 ipc_answer_0(callid, rc);
     687                                async_answer_0(callid, rc);
    660688                                continue;
    661689                        }
     
    701729                        break;
    702730                }
    703                 ipc_answer_3(callid, EOK, arg1, arg2, arg3);
     731                async_answer_3(callid, EOK, arg1, arg2, arg3);
    704732        }
    705733}
     
    710738}
    711739
     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)
     748                return rc;
     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);
     779        if (rc != EOK) {
     780                async_hangup(phone);
     781                printf(NAME ": " \
     782                    "Failed to create callback from input device: %s.\n",
     783                    str_error(rc));
     784                return rc;
     785        }
     786       
     787        driver_phones[phone] = hash;
     788
     789        printf(NAME ": found %s \"%s\" (%" PRIxn ").\n", devname, path, hash);
     790
     791        return phone;
     792}
     793
     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
    712873static bool console_init(char *input)
    713874{
    714875        /* Connect to input device */
    715         int input_fd = open(input, O_RDONLY);
    716         if (input_fd < 0) {
    717                 printf(NAME ": Failed opening %s\n", input);
     876        kbd_phone = connect_keyboard(input);
     877        if (kbd_phone < 0) {
    718878                return false;
    719879        }
    720        
    721         kbd_phone = fd_phone(input_fd);
    722         if (kbd_phone < 0) {
    723                 printf(NAME ": Failed to connect to input device\n");
    724                 return false;
    725         }
    726        
    727         /* NB: The callback connection is slotted for removal */
    728         ipcarg_t phonehash;
    729         if (ipc_connect_to_me(kbd_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
    730                 printf(NAME ": Failed to create callback from input device\n");
    731                 return false;
    732         }
    733        
    734         async_new_connection(phonehash, 0, NULL, keyboard_events);
    735        
    736         /* Connect to mouse device */
    737         mouse_phone = -1;
    738         int mouse_fd = open("/dev/hid_in/mouse", O_RDONLY);
    739        
    740         if (mouse_fd < 0) {
    741                 printf(NAME ": Notice - failed opening %s\n", "/dev/hid_in/mouse");
    742                 goto skip_mouse;
    743         }
    744        
    745         mouse_phone = fd_phone(mouse_fd);
     880
     881        mouse_phone = connect_mouse("/dev/hid_in/mouse");
    746882        if (mouse_phone < 0) {
    747                 printf(NAME ": Failed to connect to mouse device\n");
    748                 goto skip_mouse;
    749         }
    750        
    751         if (ipc_connect_to_me(mouse_phone, SERVICE_CONSOLE, 0, 0, &phonehash) != 0) {
    752                 printf(NAME ": Failed to create callback from mouse device\n");
    753                 mouse_phone = -1;
    754                 goto skip_mouse;
    755         }
    756        
    757         async_new_connection(phonehash, 0, NULL, mouse_events);
    758 skip_mouse:
     883                printf(NAME ": Failed to connect to mouse device: %s.\n",
     884                    str_error(mouse_phone));
     885        }
    759886       
    760887        /* Connect to framebuffer driver */
    761         fb_info.phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VIDEO, 0, 0);
     888        fb_info.phone = service_connect_blocking(SERVICE_VIDEO, 0, 0);
    762889        if (fb_info.phone < 0) {
    763890                printf(NAME ": Failed to connect to video service\n");
     
    804931                        if (screenbuffer_init(&consoles[i].scr,
    805932                            fb_info.cols, fb_info.rows) == NULL) {
    806                                 printf(NAME ": Unable to allocate screen buffer %u\n", i);
     933                                printf(NAME ": Unable to allocate screen buffer %zu\n", i);
    807934                                return false;
    808935                        }
     
    813940                       
    814941                        char vc[DEVMAP_NAME_MAXLEN + 1];
    815                         snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%u", NAMESPACE, i);
     942                        snprintf(vc, DEVMAP_NAME_MAXLEN, "%s/vc%zu", NAMESPACE, i);
    816943                       
    817                         if (devmap_device_register(vc, &consoles[i].dev_handle) != EOK) {
    818                                 devmap_hangup_phone(DEVMAP_DRIVER);
     944                        if (devmap_device_register(vc, &consoles[i].devmap_handle) != EOK) {
    819945                                printf(NAME ": Unable to register device %s\n", vc);
    820946                                return false;
     
    836962       
    837963        /* Receive kernel notifications */
     964        async_set_interrupt_received(interrupt_received);
    838965        if (event_subscribe(EVENT_KCONSOLE, 0) != EOK)
    839966                printf(NAME ": Error registering kconsole notifications\n");
    840967       
    841         async_set_interrupt_received(interrupt_received);
    842        
     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
    843972        return true;
    844973}
     
    860989        if (!console_init(argv[1]))
    861990                return -1;
    862        
     991
    863992        printf(NAME ": Accepting connections\n");
    864993        async_manager();
Note: See TracChangeset for help on using the changeset viewer.