Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbhid/mouse/mousedev.c

    r9d58539 rb803845  
    5252#include "../usbhid.h"
    5353
    54 #define NAME "mouse"
     54/** Number of simulated arrow-key presses for singel wheel step. */
     55#define ARROWS_PER_SINGLE_WHEEL 3
     56
     57#define NAME  "mouse"
    5558
    5659/*----------------------------------------------------------------------------*/
     
    6669
    6770const char *HID_MOUSE_FUN_NAME = "mouse";
     71const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
    6872const char *HID_MOUSE_CATEGORY = "mouse";
     73const char *HID_MOUSE_WHEEL_CATEGORY = "keyboard";
    6974
    7075/** Default idle rate for mouses. */
     
    7277
    7378/*----------------------------------------------------------------------------*/
    74 static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[] = {
     79
     80enum {
     81        USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
     82};
     83
     84static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
     85    USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
    7586        0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    7687        0x09, 0x02,                    // USAGE (Mouse)
     
    112123    ipc_callid_t icallid, ipc_call_t *icall)
    113124{
    114         usb_mouse_t *mouse_dev = fun->driver_data;
     125        usb_mouse_t *mouse_dev = (usb_mouse_t *) fun->driver_data;
    115126
    116127        if (mouse_dev == NULL) {
    117                 usb_log_debug("%s: Missing parameters.\n", __FUNCTION__);
     128                usb_log_debug("default_connection_handler: Missing "
     129                    "parameters.\n");
    118130                async_answer_0(icallid, EINVAL);
    119131                return;
    120132        }
    121133
    122         usb_log_debug("%s: fun->name: %s\n", __FUNCTION__, fun->name);
    123         usb_log_debug("%s: mouse_sess: %p\n",
    124             __FUNCTION__, mouse_dev->mouse_sess);
     134        usb_log_debug("default_connection_handler: fun->name: %s\n",
     135                      fun->name);
     136        usb_log_debug("default_connection_handler: mouse_sess: %p, "
     137            "wheel_sess: %p\n", mouse_dev->mouse_sess, mouse_dev->wheel_sess);
     138
     139        async_sess_t **sess_ptr =
     140            (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0) ?
     141            &mouse_dev->mouse_sess : &mouse_dev->wheel_sess;
    125142
    126143        async_sess_t *sess =
    127144            async_callback_receive_start(EXCHANGE_SERIALIZE, icall);
    128145        if (sess != NULL) {
    129                 if (mouse_dev->mouse_sess == NULL) {
    130                         mouse_dev->mouse_sess = sess;
    131                         usb_log_debug("Console session to %s set ok (%p).\n",
    132                             fun->name, sess);
     146                if (*sess_ptr == NULL) {
     147                        *sess_ptr = sess;
     148                        usb_log_debug("Console session to mouse set ok (%p).\n",
     149                            sess);
    133150                        async_answer_0(icallid, EOK);
    134151                } else {
    135                         usb_log_error("Console session to %s already set.\n",
    136                             fun->name);
     152                        usb_log_debug("default_connection_handler: Console "
     153                            "session to mouse already set.\n");
    137154                        async_answer_0(icallid, ELIMIT);
    138                         async_hangup(sess);
    139155                }
    140156        } else {
    141                 usb_log_debug("%s: Invalid function.\n", __FUNCTION__);
     157                usb_log_debug("default_connection_handler: Invalid function.\n");
    142158                async_answer_0(icallid, EINVAL);
    143159        }
    144160}
    145 /*----------------------------------------------------------------------------*/
     161
     162/*----------------------------------------------------------------------------*/
     163
     164static usb_mouse_t *usb_mouse_new(void)
     165{
     166        usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
     167        if (mouse == NULL) {
     168                return NULL;
     169        }
     170        mouse->mouse_sess = NULL;
     171        mouse->wheel_sess = NULL;
     172
     173        return mouse;
     174}
     175
     176/*----------------------------------------------------------------------------*/
     177
     178static void usb_mouse_destroy(usb_mouse_t *mouse_dev)
     179{
     180        assert(mouse_dev != NULL);
     181
     182        // hangup session to the console
     183        if (mouse_dev->mouse_sess != NULL)
     184                async_hangup(mouse_dev->mouse_sess);
     185
     186        if (mouse_dev->wheel_sess != NULL)
     187                async_hangup(mouse_dev->wheel_sess);
     188        int ret = ddf_fun_unbind(mouse_dev->mouse_fun);
     189        if (ret != EOK) {
     190                usb_log_error("Failed to unbind mouse function.\n");
     191        } else {
     192                ddf_fun_destroy(mouse_dev->mouse_fun);
     193                /* Prevent double free */
     194                mouse_dev->wheel_fun->driver_data = NULL;
     195        }
     196
     197        ret = ddf_fun_unbind(mouse_dev->wheel_fun);
     198        if (ret != EOK) {
     199                usb_log_error("Failed to unbind wheel function.\n");
     200        } else {
     201                ddf_fun_destroy(mouse_dev->wheel_fun);
     202        }
     203}
     204
     205/*----------------------------------------------------------------------------*/
     206
     207static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
     208{
     209        unsigned int key = (wheel > 0) ? KC_UP : KC_DOWN;
     210
     211        if (mouse_dev->wheel_sess == NULL) {
     212                usb_log_warning(
     213                    "Connection to console not ready, wheel roll discarded.\n");
     214                return;
     215        }
     216
     217        int count = ((wheel < 0) ? -wheel : wheel) * ARROWS_PER_SINGLE_WHEEL;
     218        int i;
     219
     220        for (i = 0; i < count; i++) {
     221                /* Send arrow press and release. */
     222                usb_log_debug2("Sending key %d to the console\n", key);
     223               
     224                async_exch_t *exch = async_exchange_begin(mouse_dev->wheel_sess);
     225               
     226                async_msg_4(exch, KBDEV_EVENT, KEY_PRESS, key, 0, 0);
     227                async_msg_4(exch, KBDEV_EVENT, KEY_RELEASE, key, 0, 0);
     228               
     229                async_exchange_end(exch);
     230        }
     231}
     232
     233/*----------------------------------------------------------------------------*/
     234
    146235static int get_mouse_axis_move_value(uint8_t rid, usb_hid_report_t *report,
    147236    int32_t usage)
     
    178267        }
    179268
    180         const int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
     269        int shift_x = get_mouse_axis_move_value(hid_dev->report_id,
    181270            &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
    182         const int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
     271        int shift_y = get_mouse_axis_move_value(hid_dev->report_id,
    183272            &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
    184         const int wheel = get_mouse_axis_move_value(hid_dev->report_id,
     273        int wheel = get_mouse_axis_move_value(hid_dev->report_id,
    185274            &hid_dev->report, USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
    186275
    187         if (shift_x || shift_y || wheel) {
     276        if ((shift_x != 0) || (shift_y != 0)) {
    188277                async_exch_t *exch =
    189278                    async_exchange_begin(mouse_dev->mouse_sess);
    190                 if (exch != NULL) {
    191                         async_msg_3(exch, MOUSEEV_MOVE_EVENT,
    192                             shift_x, shift_y, wheel);
    193                         async_exchange_end(exch);
    194                 }
    195         }
    196 
    197         /* Buttons */
     279                async_req_2_0(exch, MOUSEEV_MOVE_EVENT, shift_x, shift_y);
     280                async_exchange_end(exch);
     281        }
     282
     283        if (wheel != 0)
     284                usb_mouse_send_wheel(mouse_dev, wheel);
     285
     286        /*
     287         * Buttons
     288         */
    198289        usb_hid_report_path_t *path = usb_hid_report_path();
    199         if (path == NULL) {
    200                 usb_log_warning("Failed to create USB HID report path.\n");
    201                 return true;
    202         }
    203         int ret =
    204            usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
    205         if (ret != EOK) {
    206                 usb_hid_report_path_free(path);
    207                 usb_log_warning("Failed to add buttons to report path.\n");
    208                 return true;
    209         }
     290        usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
    210291        usb_hid_report_path_set_report_id(path, hid_dev->report_id);
    211292
     
    217298                usb_log_debug2(NAME " VALUE(%X) USAGE(%X)\n", field->value,
    218299                    field->usage);
    219                 assert(field->usage > field->usage_minimum);
    220                 const unsigned index = field->usage - field->usage_minimum;
    221                 assert(index < mouse_dev->buttons_count);
    222 
    223                 if (mouse_dev->buttons[index] == 0 && field->value != 0) {
     300               
     301                if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0
     302                    && field->value != 0) {
    224303                        async_exch_t *exch =
    225304                            async_exchange_begin(mouse_dev->mouse_sess);
    226                         if (exch != NULL) {
    227                                 async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
    228                                     field->usage, 1);
    229                                 async_exchange_end(exch);
    230                                 mouse_dev->buttons[index] = field->value;
    231                         }
    232 
    233                 } else if (mouse_dev->buttons[index] != 0 && field->value == 0) {
     305                        async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, field->usage, 1);
     306                        async_exchange_end(exch);
     307                       
     308                        mouse_dev->buttons[field->usage - field->usage_minimum]
     309                            = field->value;
     310                } else if (mouse_dev->buttons[field->usage - field->usage_minimum] != 0
     311                    && field->value == 0) {
    234312                        async_exch_t *exch =
    235313                            async_exchange_begin(mouse_dev->mouse_sess);
    236                         if (exch != NULL) {
    237                                 async_req_2_0(exch, MOUSEEV_BUTTON_EVENT,
    238                                     field->usage, 0);
    239                                 async_exchange_end(exch);
    240                                 mouse_dev->buttons[index] = field->value;
    241                         }
     314                        async_req_2_0(exch, MOUSEEV_BUTTON_EVENT, field->usage, 0);
     315                        async_exchange_end(exch);
     316
     317                        mouse_dev->buttons[field->usage - field->usage_minimum] =
     318                           field->value;
    242319                }
    243320
     
    252329        return true;
    253330}
    254 /*----------------------------------------------------------------------------*/
    255 #define FUN_UNBIND_DESTROY(fun) \
    256 if (fun) { \
    257         if (ddf_fun_unbind((fun)) == EOK) { \
    258                 (fun)->driver_data = NULL; \
    259                 ddf_fun_destroy((fun)); \
    260         } else { \
    261                 usb_log_error("Could not unbind function `%s', it " \
    262                     "will not be destroyed.\n", (fun)->name); \
    263         } \
    264 } else (void)0
    265 /*----------------------------------------------------------------------------*/
     331
     332/*----------------------------------------------------------------------------*/
     333
    266334static int usb_mouse_create_function(usb_hid_dev_t *hid_dev, usb_mouse_t *mouse)
    267335{
     
    271339        /* Create the exposed function. */
    272340        usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
    273         ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
     341        ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, 
    274342            HID_MOUSE_FUN_NAME);
    275343        if (fun == NULL) {
    276                 usb_log_error("Could not create DDF function node `%s'.\n",
    277                     HID_MOUSE_FUN_NAME);
     344                usb_log_error("Could not create DDF function node.\n");
    278345                return ENOMEM;
    279346        }
     
    284351        int rc = ddf_fun_bind(fun);
    285352        if (rc != EOK) {
    286                 usb_log_error("Could not bind DDF function `%s': %s.\n",
    287                     fun->name, str_error(rc));
    288                 fun->driver_data = NULL;
    289                 ddf_fun_destroy(fun);
    290                 return rc;
    291         }
    292 
    293         usb_log_debug("Adding DDF function `%s' to category %s...\n",
    294             fun->name, HID_MOUSE_CATEGORY);
     353                usb_log_error("Could not bind DDF function: %s.\n",
     354                    str_error(rc));
     355                return rc;
     356        }
     357
     358        usb_log_debug("Adding DDF function to category %s...\n",
     359            HID_MOUSE_CATEGORY);
    295360        rc = ddf_fun_add_to_category(fun, HID_MOUSE_CATEGORY);
    296361        if (rc != EOK) {
     
    298363                    "Could not add DDF function to category %s: %s.\n",
    299364                    HID_MOUSE_CATEGORY, str_error(rc));
    300                 FUN_UNBIND_DESTROY(fun);
    301365                return rc;
    302366        }
    303367        mouse->mouse_fun = fun;
    304368
     369        /*
     370         * Special function for acting as keyboard (wheel)
     371         */
     372        usb_log_debug("Creating DDF function %s...\n",
     373                      HID_MOUSE_WHEEL_FUN_NAME);
     374        fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
     375            HID_MOUSE_WHEEL_FUN_NAME);
     376        if (fun == NULL) {
     377                usb_log_error("Could not create DDF function node.\n");
     378                return ENOMEM;
     379        }
     380
     381        /*
     382         * Store the initialized HID device and HID ops
     383         * to the DDF function.
     384         */
     385        fun->ops = &mouse->ops;
     386        fun->driver_data = mouse;
     387
     388        rc = ddf_fun_bind(fun);
     389        if (rc != EOK) {
     390                usb_log_error("Could not bind DDF function: %s.\n",
     391                    str_error(rc));
     392                return rc;
     393        }
     394
     395        usb_log_debug("Adding DDF function to category %s...\n",
     396            HID_MOUSE_WHEEL_CATEGORY);
     397        rc = ddf_fun_add_to_category(fun, HID_MOUSE_WHEEL_CATEGORY);
     398        if (rc != EOK) {
     399                usb_log_error(
     400                    "Could not add DDF function to category %s: %s.\n",
     401                    HID_MOUSE_WHEEL_CATEGORY, str_error(rc));
     402                return rc;
     403        }
     404        mouse->wheel_fun = fun;
     405
    305406        return EOK;
    306407}
     408
     409/*----------------------------------------------------------------------------*/
    307410
    308411/** Get highest index of a button mentioned in given report.
     
    345448        return highest_button;
    346449}
    347 /*----------------------------------------------------------------------------*/
     450
     451/*----------------------------------------------------------------------------*/
     452
    348453int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
    349454{
     
    356461        }
    357462
    358         usb_mouse_t *mouse_dev = calloc(1, sizeof(usb_mouse_t));
     463        usb_mouse_t *mouse_dev = usb_mouse_new();
    359464        if (mouse_dev == NULL) {
    360465                usb_log_error("Error while creating USB/HID Mouse device "
     
    379484        }
    380485
     486
     487        // save the Mouse device structure into the HID device structure
     488        *data = mouse_dev;
     489
    381490        // set handler for incoming calls
    382491        mouse_dev->ops.default_handler = default_connection_handler;
    383492
    384493        // TODO: how to know if the device supports the request???
    385         usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
     494        usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe, 
    386495            hid_dev->usb_dev->interface_no, IDLE_RATE);
    387496
    388497        int rc = usb_mouse_create_function(hid_dev, mouse_dev);
    389498        if (rc != EOK) {
    390                 free(mouse_dev->buttons);
    391                 free(mouse_dev);
    392                 return rc;
    393         }
    394 
    395         /* Save the Mouse device structure into the HID device structure. */
    396         *data = mouse_dev;
     499                usb_mouse_destroy(mouse_dev);
     500                return rc;
     501        }
    397502
    398503        return EOK;
    399504}
    400 /*----------------------------------------------------------------------------*/
     505
     506/*----------------------------------------------------------------------------*/
     507
    401508bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data)
    402509{
    403510        if (hid_dev == NULL || data == NULL) {
    404                 usb_log_error(
    405                     "Missing argument to the mouse polling callback.\n");
     511                usb_log_error("Missing argument to the mouse polling callback."
     512                    "\n");
    406513                return false;
    407514        }
    408515
    409         usb_mouse_t *mouse_dev = data;
    410 
     516        usb_mouse_t *mouse_dev = (usb_mouse_t *)data;
     517               
    411518        return usb_mouse_process_report(hid_dev, mouse_dev);
    412519}
    413 /*----------------------------------------------------------------------------*/
     520
     521/*----------------------------------------------------------------------------*/
     522
    414523void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
    415524{
    416         if (data == NULL)
    417                 return;
    418 
    419         usb_mouse_t *mouse_dev = data;
    420 
    421         /* Hangup session to the console */
    422         if (mouse_dev->mouse_sess != NULL) {
    423                 const int ret = async_hangup(mouse_dev->mouse_sess);
    424                 if (ret != EOK)
    425                         usb_log_warning("Failed to hang up mouse session: "
    426                             "%p, %s.\n", mouse_dev->mouse_sess, str_error(ret));
    427         }
    428 
    429         FUN_UNBIND_DESTROY(mouse_dev->mouse_fun);
    430 
    431         free(mouse_dev->buttons);
    432         free(mouse_dev);
    433 }
    434 /*----------------------------------------------------------------------------*/
     525        if (data != NULL) {
     526                usb_mouse_destroy(data);
     527        }
     528}
     529
     530/*----------------------------------------------------------------------------*/
     531
    435532int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
    436533{
    437534        int rc = usb_hid_parse_report_descriptor(
    438535            &hid_dev->report, USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
    439             sizeof(USB_MOUSE_BOOT_REPORT_DESCRIPTOR));
     536            USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
    440537
    441538        if (rc != EOK) {
Note: See TracChangeset for help on using the changeset viewer.