Changeset 4578a6e in mainline


Ignore:
Timestamp:
2011-11-07T10:13:01Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
0f12c17
Parents:
0cda600
Message:

usbhid, kbd: Fix error paths.

Location:
uspace/drv/bus/usb/usbhid/kbd
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhid/kbd/kbddev.c

    r0cda600 r4578a6e  
    4141#include <io/keycode.h>
    4242#include <io/console.h>
     43#include <abi/ipc/methods.h>
    4344#include <ipc/kbdev.h>
    4445#include <async.h>
     
    8687
    8788/*----------------------------------------------------------------------------*/
    88 
    8989/** Keyboard polling endpoint description for boot protocol class. */
    9090const usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
     
    101101
    102102static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev);
    103 
    104 /*----------------------------------------------------------------------------*/
    105 
     103/*----------------------------------------------------------------------------*/
    106104enum {
    107105        USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
     
    144142
    145143};
    146 
    147 /*----------------------------------------------------------------------------*/
    148 
     144/*----------------------------------------------------------------------------*/
    149145typedef enum usb_kbd_flags {
    150146        USB_KBD_STATUS_UNINITIALIZED = 0,
     
    152148        USB_KBD_STATUS_TO_DESTROY = -1
    153149} usb_kbd_flags;
    154 
    155150/*----------------------------------------------------------------------------*/
    156151/* IPC method handler                                                         */
    157152/*----------------------------------------------------------------------------*/
    158 
    159 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    160 
    161153/**
    162154 * Default handler for IPC methods not handled by DDF.
    163155 *
    164  * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
    165  * assumes the caller is the console and thus it stores IPC session to it for
    166  * later use by the driver to notify about key events.
     156 * Currently recognizes only two methods (IPC_M_CONNECT_TO_ME and KBDEV_SET_IND)
     157 * IPC_M_CONNECT_TO_ME assumes the caller is the console and  stores IPC
     158 * session to it for later use by the driver to notify about key events.
     159 * KBDEV_SET_IND sets LED keyboard indicators.
    167160 *
    168161 * @param fun Device function handling the call.
     
    173166    ipc_callid_t icallid, ipc_call_t *icall)
    174167{
    175         sysarg_t method = IPC_GET_IMETHOD(*icall);
    176 
    177         usb_kbd_t *kbd_dev = (usb_kbd_t *) fun->driver_data;
    178         if (kbd_dev == NULL) {
    179                 usb_log_debug("default_connection_handler: "
    180                     "Missing parameter.\n");
     168        if (fun == NULL || fun->driver_data == NULL) {
     169                usb_log_error("%s: Missing parameter.\n", __FUNCTION__);
    181170                async_answer_0(icallid, EINVAL);
    182171                return;
    183172        }
    184173
    185         async_sess_t *sess =
    186             async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
    187         if (sess != NULL) {
     174        const sysarg_t method = IPC_GET_IMETHOD(*icall);
     175        usb_kbd_t *kbd_dev = fun->driver_data;
     176
     177        switch (method) {
     178        case KBDEV_SET_IND:
     179                kbd_dev->mods = IPC_GET_ARG1(*icall);
     180                usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
     181                async_answer_0(icallid, EOK);
     182                break;
     183        /* This might be ugly but async_callback_receive_start makes no
     184         * difference for incorrect call and malloc failure. */
     185        case IPC_M_CONNECT_TO_ME: {
     186                async_sess_t *sess =
     187                    async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
     188                /* Probably ENOMEM error, try again. */
     189                if (sess == NULL) {
     190                        usb_log_warning(
     191                            "Failed to create start console session.\n");
     192                        async_answer_0(icallid, EAGAIN);
     193                        break;
     194                }
    188195                if (kbd_dev->console_sess == NULL) {
    189196                        kbd_dev->console_sess = sess;
    190                         usb_log_debug("default_connection_handler: OK\n");
     197                        usb_log_debug("%s: OK\n", __FUNCTION__);
    191198                        async_answer_0(icallid, EOK);
    192199                } else {
    193                         usb_log_debug("default_connection_handler: "
    194                             "console session already set\n");
     200                        usb_log_error("%s: console session already set\n",
     201                           __FUNCTION__);
    195202                        async_answer_0(icallid, ELIMIT);
    196203                }
    197         } else {
    198                 switch (method) {
    199                 case KBDEV_SET_IND:
    200                         kbd_dev->mods = IPC_GET_ARG1(*icall);
    201                         usb_kbd_set_led(kbd_dev->hid_dev, kbd_dev);
    202                         async_answer_0(icallid, EOK);
    203                         break;
    204                 default:
    205                         usb_log_debug("default_connection_handler: Wrong function.\n");
     204                break;
     205        }
     206        default:
     207                        usb_log_error("%s: Unknown method: %d.\n",
     208                            __FUNCTION__, (int) method);
    206209                        async_answer_0(icallid, EINVAL);
    207210                        break;
    208                 }
    209         }
     211        }
     212
    210213}
    211214
     
    278281                0));
    279282
    280         usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe,
     283        rc = usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe,
    281284            hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT,
    282285            kbd_dev->output_buffer, kbd_dev->output_size);
    283 }
    284 
     286        if (rc != EOK) {
     287                usb_log_warning("Failed to set kbd indicators.\n");
     288        }
     289}
    285290/*----------------------------------------------------------------------------*/
    286291/** Send key event.
     
    291296 * @param key Key code
    292297 */
    293 void usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type,
    294     unsigned int key)
     298void usb_kbd_push_ev(usb_kbd_t *kbd_dev, int type, unsigned key)
    295299{
    296300        usb_log_debug2("Sending kbdev event %d/%d to the console\n", type, key);
     
    302306
    303307        async_exch_t *exch = async_exchange_begin(kbd_dev->console_sess);
    304         async_msg_2(exch, KBDEV_EVENT, type, key);
    305         async_exchange_end(exch);
    306 }
    307 
    308 /*----------------------------------------------------------------------------*/
    309 
     308        if (exch != NULL) {
     309                async_msg_2(exch, KBDEV_EVENT, type, key);
     310                async_exchange_end(exch);
     311        } else {
     312                usb_log_warning("Failed to send key to console.\n");
     313        }
     314}
     315/*----------------------------------------------------------------------------*/
    310316static inline int usb_kbd_is_lock(unsigned int key_code)
    311317{
     
    314320            || key_code == KC_CAPS_LOCK);
    315321}
    316 
     322/*----------------------------------------------------------------------------*/
    317323static size_t find_in_array_int32(int32_t val, int32_t *arr, size_t arr_size)
    318324{
     
    325331        return (size_t) -1;
    326332}
    327 
    328333/*----------------------------------------------------------------------------*/
    329334/**
     
    345350    usb_kbd_t *kbd_dev)
    346351{
    347         unsigned int key;
    348         size_t i;
    349352
    350353        /*
     
    356359         * whole input report.
    357360         */
    358         i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
     361        size_t i = find_in_array_int32(ERROR_ROLLOVER, kbd_dev->keys,
    359362            kbd_dev->key_count);
    360363        if (i != (size_t) -1) {
    361                 usb_log_debug("Detected phantom state.\n");
     364                usb_log_error("Detected phantom state.\n");
    362365                return;
    363366        }
     
    367370         */
    368371        for (i = 0; i < kbd_dev->key_count; i++) {
    369                 int32_t old_key = kbd_dev->keys_old[i];
     372                const int32_t old_key = kbd_dev->keys_old[i];
    370373                /* Find the old key among currently pressed keys. */
    371                 size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
     374                const size_t pos = find_in_array_int32(old_key, kbd_dev->keys,
    372375                    kbd_dev->key_count);
    373376                /* If the key was not found, we need to signal release. */
    374377                if (pos == (size_t) -1) {
    375                         key = usbhid_parse_scancode(old_key);
     378                        const unsigned key = usbhid_parse_scancode(old_key);
    376379                        if (!usb_kbd_is_lock(key)) {
    377380                                usb_kbd_repeat_stop(kbd_dev, key);
    378381                        }
    379                         usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
     382                        usb_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
    380383                        usb_log_debug2("Key released: %u "
    381384                            "(USB code %" PRIu32 ")\n", key, old_key);
     
    387390         */
    388391        for (i = 0; i < kbd_dev->key_count; ++i) {
    389                 int32_t new_key = kbd_dev->keys[i];
     392                const int32_t new_key = kbd_dev->keys[i];
    390393                /* Find the new key among already pressed keys. */
    391                 size_t pos = find_in_array_int32(new_key, kbd_dev->keys_old,
    392                     kbd_dev->key_count);
     394                const size_t pos = find_in_array_int32(new_key,
     395                    kbd_dev->keys_old, kbd_dev->key_count);
    393396                /* If the key was not found, we need to signal press. */
    394397                if (pos == (size_t) -1) {
    395                         key = usbhid_parse_scancode(kbd_dev->keys[i]);
     398                        unsigned key = usbhid_parse_scancode(kbd_dev->keys[i]);
    396399                        if (!usb_kbd_is_lock(key)) {
    397400                                usb_kbd_repeat_start(kbd_dev, key);
    398401                        }
    399                         usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
     402                        usb_kbd_push_ev(kbd_dev, KEY_PRESS, key);
    400403                        usb_log_debug2("Key pressed: %u "
    401404                            "(USB code %" PRIu32 ")\n", key, new_key);
     
    411414        usb_log_debug2("Stored keys %s.\n", key_buffer);
    412415}
    413 
    414416/*----------------------------------------------------------------------------*/
    415417/* General kbd functions                                                      */
     
    437439
    438440        usb_hid_report_path_t *path = usb_hid_report_path();
    439         usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
     441        if (path == NULL) {
     442                usb_log_error("Failed to create hid/kbd report path.\n");
     443                return;
     444        }
     445
     446        int ret =
     447           usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
     448        if (ret != EOK) {
     449                usb_log_error("Failed to append to hid/kbd report path.\n");
     450                return;
     451        }
    440452
    441453        usb_hid_report_path_set_report_id(path, hid_dev->report_id);
     
    475487        usb_kbd_check_key_changes(hid_dev, kbd_dev);
    476488}
    477 
    478489/*----------------------------------------------------------------------------*/
    479490/* HID/KBD structure manipulation                                             */
    480491/*----------------------------------------------------------------------------*/
    481 
    482 static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
    483 {
    484         kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
    485 }
    486 
    487 /*----------------------------------------------------------------------------*/
    488 
    489492static int usb_kbd_create_function(usb_kbd_t *kbd_dev)
    490493{
     
    521524            HID_KBD_FUN_NAME, fun->handle);
    522525
    523         usb_log_debug("Adding DDF function to category %s...\n", 
     526        usb_log_debug("Adding DDF function to category %s...\n",
    524527            HID_KBD_CLASS_NAME);
    525528        rc = ddf_fun_add_to_category(fun, HID_KBD_CATEGORY_NAME);
     
    528531                    "Could not add DDF function to category %s: %s.\n",
    529532                    HID_KBD_CLASS_NAME, str_error(rc));
     533                ddf_fun_unbind(fun);
    530534                fun->driver_data = NULL; /* We need this later */
    531535                ddf_fun_destroy(fun);
     
    536540        return EOK;
    537541}
    538 
    539542/*----------------------------------------------------------------------------*/
    540543/* API functions                                                              */
     
    570573        }
    571574
    572         usb_kbd_t *kbd_dev = malloc(sizeof(usb_kbd_t));
     575        usb_kbd_t *kbd_dev = calloc(1, sizeof(usb_kbd_t));
    573576        if (kbd_dev == NULL) {
    574577                usb_log_error("Failed to allocate KBD device structure.\n");
     
    577580        /* Default values */
    578581        fibril_mutex_initialize(&kbd_dev->repeat_mtx);
    579         kbd_dev->console_sess = NULL;
    580582        kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
    581583        kbd_dev->ops.default_handler = default_connection_handler;
     
    585587
    586588        /* Modifiers and locks */
    587         kbd_dev->modifiers = 0;
    588589        kbd_dev->mods = DEFAULT_ACTIVE_MODS;
    589         kbd_dev->lock_keys = 0;
    590590
    591591        /* Autorepeat */
    592         kbd_dev->repeat.key_new = 0;
    593         kbd_dev->repeat.key_repeated = 0;
    594592        kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
    595593        kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
     
    598596        // TODO: make more general
    599597        usb_hid_report_path_t *path = usb_hid_report_path();
    600         usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
     598        if (path == NULL) {
     599                usb_log_error("Failed to create kbd report path.\n");
     600                usb_kbd_destroy(kbd_dev);
     601                return ENOMEM;
     602        }
     603
     604        int ret =
     605            usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
     606        if (ret != EOK) {
     607                usb_log_error("Failed to append item to kbd report path.\n");
     608                usb_hid_report_path_free(path);
     609                usb_kbd_destroy(kbd_dev);
     610                return ret;
     611        }
    601612
    602613        usb_hid_report_path_set_report_id(path, 0);
    603614
    604         kbd_dev->key_count = usb_hid_report_size(
    605             &hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
     615        kbd_dev->key_count =
     616            usb_hid_report_size(&hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
     617
    606618        usb_hid_report_path_free(path);
    607619
     
    610622        kbd_dev->keys = calloc(kbd_dev->key_count, sizeof(int32_t));
    611623        if (kbd_dev->keys == NULL) {
    612                 free(kbd_dev);
     624                usb_log_error("Failed to allocate key buffer.\n");
     625                usb_kbd_destroy(kbd_dev);
    613626                return ENOMEM;
    614627        }
     
    616629        kbd_dev->keys_old = calloc(kbd_dev->key_count, sizeof(int32_t));
    617630        if (kbd_dev->keys_old == NULL) {
    618                 free(kbd_dev->keys);
    619                 free(kbd_dev);
     631                usb_log_error("Failed to allocate old_key buffer.\n");
     632                usb_kbd_destroy(kbd_dev);
    620633                return ENOMEM;
    621634        }
     
    627640        if (kbd_dev->output_buffer == NULL) {
    628641                usb_log_error("Error creating output report buffer.\n");
    629                 free(kbd_dev->keys_old);
    630                 free(kbd_dev->keys);
    631                 free(kbd_dev);
     642                usb_kbd_destroy(kbd_dev);
    632643                return ENOMEM;
    633644        }
     
    636647
    637648        kbd_dev->led_path = usb_hid_report_path();
    638         usb_hid_report_path_append_item(
     649        if (kbd_dev->led_path == NULL) {
     650                usb_log_error("Failed to create kbd led report path.\n");
     651                usb_kbd_destroy(kbd_dev);
     652                return ENOMEM;
     653        }
     654
     655        ret = usb_hid_report_path_append_item(
    639656            kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
     657        if (ret != EOK) {
     658                usb_log_error("Failed to append to kbd/led report path.\n");
     659                usb_kbd_destroy(kbd_dev);
     660                return ret;
     661        }
    640662
    641663        kbd_dev->led_output_size = usb_hid_report_size(
     
    648670        if (kbd_dev->led_data == NULL) {
    649671                usb_log_error("Error creating buffer for LED output report.\n");
    650                 usb_hid_report_output_free(kbd_dev->output_buffer);
    651                 free(kbd_dev->keys_old);
    652                 free(kbd_dev->keys);
    653                 free(kbd_dev);
     672                usb_kbd_destroy(kbd_dev);
    654673                return ENOMEM;
    655674        }
    656 
    657675
    658676        /*
     
    665683            hid_dev->usb_dev->interface_no, IDLE_RATE);
    666684
    667         /*
    668          * Create new fibril for auto-repeat
    669          */
     685        /* Save the KBD device structure into the HID device structure. */
     686        *data = kbd_dev;
     687
     688        kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
     689        usb_log_debug("HID/KBD device structure initialized.\n");
     690
     691        usb_log_debug("Creating KBD function...\n");
     692        ret = usb_kbd_create_function(kbd_dev);
     693        if (ret != EOK) {
     694                usb_kbd_destroy(kbd_dev);
     695                return ret;
     696        }
     697
     698        /* Create new fibril for auto-repeat. */
    670699        fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
    671700        if (fid == 0) {
     
    676705        fibril_add_ready(fid);
    677706
    678         kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
    679         usb_log_debug("HID/KBD device structure initialized.\n");
    680 
    681         usb_log_debug("Creating KBD function...\n");
    682         int rc = usb_kbd_create_function(kbd_dev);
    683         if (rc != EOK) {
    684                 usb_kbd_destroy(kbd_dev);
    685                 return rc;
    686         }
    687 
    688         /* Save the KBD device structure into the HID device structure. */
    689         *data = kbd_dev;
    690 
    691 
    692707        return EOK;
    693708}
    694 
    695 /*----------------------------------------------------------------------------*/
    696 
     709/*----------------------------------------------------------------------------*/
    697710bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data)
    698711{
     
    708721        return true;
    709722}
    710 
    711 /*----------------------------------------------------------------------------*/
    712 
     723/*----------------------------------------------------------------------------*/
    713724int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
    714725{
    715726        return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
    716727}
    717 
    718 /*----------------------------------------------------------------------------*/
    719 
     728/*----------------------------------------------------------------------------*/
    720729int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
    721730{
    722731        return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
    723732}
    724 
    725733/*----------------------------------------------------------------------------*/
    726734/**
     
    735743        }
    736744
    737         /* hangup session to the console. */
     745        /* Hangup session to the console. */
    738746        if (kbd_dev->console_sess)
    739747                async_hangup(kbd_dev->console_sess);
     
    744752        while (fibril_mutex_is_locked(&kbd_dev->repeat_mtx)) {}
    745753
    746         // free all buffers
     754        /* Free all buffers. */
    747755        free(kbd_dev->keys);
    748756        free(kbd_dev->keys_old);
    749757        free(kbd_dev->led_data);
    750758
    751         if (kbd_dev->led_path != NULL) {
    752                 usb_hid_report_path_free(kbd_dev->led_path);
    753         }
     759        usb_hid_report_path_free(kbd_dev->led_path);
    754760        usb_hid_report_output_free(kbd_dev->output_buffer);
    755761
     
    766772        free(kbd_dev);
    767773}
    768 
    769 /*----------------------------------------------------------------------------*/
    770 
     774/*----------------------------------------------------------------------------*/
    771775void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
    772776{
     
    774778                usb_kbd_t *kbd_dev = data;
    775779                if (usb_kbd_is_initialized(kbd_dev)) {
    776                         usb_kbd_mark_unusable(kbd_dev);
     780                        kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
    777781                        /* wait for autorepeat */
    778782                        async_usleep(CHECK_DELAY);
    779                         usb_kbd_destroy(kbd_dev);
    780                 }
    781         }
    782 }
    783 
    784 /*----------------------------------------------------------------------------*/
    785 
     783                }
     784                usb_kbd_destroy(kbd_dev);
     785        }
     786}
     787/*----------------------------------------------------------------------------*/
    786788int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
    787789{
     
    808810        return EOK;
    809811}
    810 
    811812/**
    812813 * @}
  • uspace/drv/bus/usb/usbhid/kbd/kbddev.h

    r0cda600 r4578a6e  
    135135void usb_kbd_destroy(usb_kbd_t *kbd_dev);
    136136
    137 void usb_kbd_push_ev(struct usb_hid_dev *hid_dev, usb_kbd_t *kbd_dev,
     137void usb_kbd_push_ev(usb_kbd_t *kbd_dev,
    138138    int type, unsigned int key);
    139139
  • uspace/drv/bus/usb/usbhid/kbd/kbdrepeat.c

    r0cda600 r4578a6e  
    8585                if (kbd->repeat.key_new > 0) {
    8686                        if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
    87                                 usb_log_debug2("Repeating key: %u.\n", 
     87                                usb_log_debug2("Repeating key: %u.\n",
    8888                                    kbd->repeat.key_repeated);
    89                                 // ugly hack with the NULL
    90                                 usb_kbd_push_ev(NULL, kbd, KEY_PRESS,
     89                                usb_kbd_push_ev(kbd, KEY_PRESS,
    9190                                    kbd->repeat.key_repeated);
    9291                                delay = kbd->repeat.delay_between;
Note: See TracChangeset for help on using the changeset viewer.