00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00037 #include <usb/debug.h>
00038 #include <usb/classes/classes.h>
00039 #include <usb/hid/hid.h>
00040 #include <usb/hid/request.h>
00041 #include <usb/hid/usages/core.h>
00042 #include <errno.h>
00043 #include <str_error.h>
00044 #include <ipc/mouse.h>
00045 #include <io/console.h>
00046
00047 #include <ipc/kbd.h>
00048 #include <io/keycode.h>
00049
00050 #include "mousedev.h"
00051 #include "../usbhid.h"
00052
00053 #define NAME "mouse"
00054
00055
00056
00057 usb_endpoint_description_t usb_hid_mouse_poll_endpoint_description = {
00058 .transfer_type = USB_TRANSFER_INTERRUPT,
00059 .direction = USB_DIRECTION_IN,
00060 .interface_class = USB_CLASS_HID,
00061 .interface_subclass = USB_HID_SUBCLASS_BOOT,
00062 .interface_protocol = USB_HID_PROTOCOL_MOUSE,
00063 .flags = 0
00064 };
00065
00066 const char *HID_MOUSE_FUN_NAME = "mouse";
00067 const char *HID_MOUSE_WHEEL_FUN_NAME = "mouse-wheel";
00068 const char *HID_MOUSE_CLASS_NAME = "mouse";
00069 const char *HID_MOUSE_WHEEL_CLASS_NAME = "keyboard";
00070
00072 static const uint8_t IDLE_RATE = 0;
00073 static const size_t USB_MOUSE_BUTTON_COUNT = 3;
00074
00075
00076
00077 enum {
00078 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE = 63
00079 };
00080
00081 static const uint8_t USB_MOUSE_BOOT_REPORT_DESCRIPTOR[
00082 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE] = {
00083 0x05, 0x01,
00084 0x09, 0x02,
00085 0xa1, 0x01,
00086 0x09, 0x01,
00087 0xa1, 0x00,
00088 0x95, 0x03,
00089 0x75, 0x01,
00090 0x05, 0x09,
00091 0x19, 0x01,
00092 0x29, 0x03,
00093 0x15, 0x00,
00094 0x25, 0x01,
00095 0x81, 0x02,
00096 0x95, 0x01,
00097 0x75, 0x05,
00098 0x81, 0x01,
00099 0x75, 0x08,
00100 0x95, 0x02,
00101 0x05, 0x01,
00102 0x09, 0x30,
00103 0x09, 0x31,
00104 0x15, 0x81,
00105 0x25, 0x7f,
00106 0x81, 0x06,
00107 0xc0,
00108 0xc0
00109 };
00110
00111
00112
00119 static void default_connection_handler(ddf_fun_t *fun,
00120 ipc_callid_t icallid, ipc_call_t *icall)
00121 {
00122 sysarg_t method = IPC_GET_IMETHOD(*icall);
00123
00124 usb_mouse_t *mouse_dev = (usb_mouse_t *)fun->driver_data;
00125
00126 if (mouse_dev == NULL) {
00127 usb_log_debug("default_connection_handler: Missing "
00128 "parameters.\n");
00129 async_answer_0(icallid, EINVAL);
00130 return;
00131 }
00132
00133 usb_log_debug("default_connection_handler: fun->name: %s\n",
00134 fun->name);
00135 usb_log_debug("default_connection_handler: mouse_phone: %d, wheel "
00136 "phone: %d\n", mouse_dev->mouse_phone, mouse_dev->wheel_phone);
00137
00138 int *phone = (str_cmp(fun->name, HID_MOUSE_FUN_NAME) == 0)
00139 ? &mouse_dev->mouse_phone : &mouse_dev->wheel_phone;
00140
00141 if (method == IPC_M_CONNECT_TO_ME) {
00142 int callback = IPC_GET_ARG5(*icall);
00143
00144 if (*phone != -1) {
00145 usb_log_debug("default_connection_handler: Console "
00146 "phone to mouse already set.\n");
00147 async_answer_0(icallid, ELIMIT);
00148 return;
00149 }
00150
00151 *phone = callback;
00152 usb_log_debug("Console phone to mouse set ok (%d).\n", *phone);
00153 async_answer_0(icallid, EOK);
00154 return;
00155 }
00156
00157 usb_log_debug("default_connection_handler: Invalid function.\n");
00158 async_answer_0(icallid, EINVAL);
00159 }
00160
00161
00162
00163 static usb_mouse_t *usb_mouse_new(void)
00164 {
00165 usb_mouse_t *mouse = calloc(1, sizeof(usb_mouse_t));
00166 if (mouse == NULL) {
00167 return NULL;
00168 }
00169 mouse->mouse_phone = -1;
00170 mouse->wheel_phone = -1;
00171
00172 return mouse;
00173 }
00174
00175
00176
00177 static void usb_mouse_free(usb_mouse_t **mouse_dev)
00178 {
00179 assert(mouse_dev != NULL && *mouse_dev != NULL);
00180
00181
00182 if ((*mouse_dev)->mouse_phone >= 0) {
00183 async_hangup((*mouse_dev)->mouse_phone);
00184 }
00185
00186 if ((*mouse_dev)->wheel_phone >= 0) {
00187 async_hangup((*mouse_dev)->wheel_phone);
00188 }
00189
00190 free(*mouse_dev);
00191 *mouse_dev = NULL;
00192 }
00193
00194
00195
00196 static void usb_mouse_send_wheel(const usb_mouse_t *mouse_dev, int wheel)
00197 {
00198 console_event_t ev;
00199
00200 ev.type = KEY_PRESS;
00201 ev.key = (wheel > 0) ? KC_UP : (wheel < 0) ? KC_DOWN : 0;
00202 ev.mods = 0;
00203 ev.c = 0;
00204
00205 if (mouse_dev->wheel_phone < 0) {
00206 usb_log_warning(
00207 "Connection to console not ready, key discarded.\n");
00208 return;
00209 }
00210
00211 int count = (wheel < 0) ? -wheel : wheel;
00212 int i;
00213
00214 for (i = 0; i < count * 3; ++i) {
00215 usb_log_debug2("Sending key %d to the console\n", ev.key);
00216 async_msg_4(mouse_dev->wheel_phone, KBD_EVENT, ev.type,
00217 ev.key, ev.mods, ev.c);
00218
00219 async_msg_4(mouse_dev->wheel_phone, KBD_EVENT, KEY_RELEASE,
00220 ev.key, ev.mods, ev.c);
00221 }
00222 }
00223
00224
00225
00226 static bool usb_mouse_process_report(usb_hid_dev_t *hid_dev,
00227 usb_mouse_t *mouse_dev
00228 )
00229 {
00230 assert(mouse_dev != NULL);
00231
00232
00233
00234
00235 if (mouse_dev->mouse_phone < 0) {
00236 usb_log_warning(NAME " No console phone.\n");
00237 return true;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 int shift_x = 0;
00262
00263 usb_hid_report_path_t *path = usb_hid_report_path();
00264 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP,
00265 USB_HIDUT_USAGE_GENERIC_DESKTOP_X);
00266
00267 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
00268
00269 usb_hid_report_field_t *field = usb_hid_report_get_sibling(
00270 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END,
00271 USB_HID_REPORT_TYPE_INPUT);
00272
00273 if (field != NULL) {
00274 usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value,
00275 field->usage);
00276 shift_x = field->value;
00277 }
00278
00279 usb_hid_report_path_free(path);
00280
00281
00282
00283
00284 int shift_y = 0;
00285
00286 path = usb_hid_report_path();
00287 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP,
00288 USB_HIDUT_USAGE_GENERIC_DESKTOP_Y);
00289
00290 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
00291
00292 field = usb_hid_report_get_sibling(
00293 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END,
00294 USB_HID_REPORT_TYPE_INPUT);
00295
00296 if (field != NULL) {
00297 usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value,
00298 field->usage);
00299 shift_y = field->value;
00300 }
00301
00302 usb_hid_report_path_free(path);
00303
00304 if ((shift_x != 0) || (shift_y != 0)) {
00305 async_req_2_0(mouse_dev->mouse_phone,
00306 MEVENT_MOVE, shift_x, shift_y);
00307 }
00308
00309
00310
00311
00312 int wheel = 0;
00313
00314 path = usb_hid_report_path();
00315 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_GENERIC_DESKTOP,
00316 USB_HIDUT_USAGE_GENERIC_DESKTOP_WHEEL);
00317
00318 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
00319
00320 field = usb_hid_report_get_sibling(
00321 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END,
00322 USB_HID_REPORT_TYPE_INPUT);
00323
00324 if (field != NULL) {
00325 usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value,
00326 field->usage);
00327 wheel = field->value;
00328 }
00329
00330 usb_hid_report_path_free(path);
00331
00332
00333
00334 usb_mouse_send_wheel(mouse_dev, wheel);
00335
00336
00337
00338
00339
00340 path = usb_hid_report_path();
00341 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_BUTTON, 0);
00342 usb_hid_report_path_set_report_id(path, hid_dev->report_id);
00343
00344 field = usb_hid_report_get_sibling(
00345 hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
00346 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00347 USB_HID_REPORT_TYPE_INPUT);
00348
00349 while (field != NULL) {
00350 usb_log_debug(NAME " VALUE(%X) USAGE(%X)\n", field->value,
00351 field->usage);
00352
00353 if (mouse_dev->buttons[field->usage - field->usage_minimum] == 0
00354 && field->value != 0) {
00355 async_req_2_0(mouse_dev->mouse_phone,
00356 MEVENT_BUTTON, field->usage, 1);
00357 mouse_dev->buttons[field->usage - field->usage_minimum]
00358 = field->value;
00359 } else if (
00360 mouse_dev->buttons[field->usage - field->usage_minimum] != 0
00361 && field->value == 0) {
00362 async_req_2_0(mouse_dev->mouse_phone,
00363 MEVENT_BUTTON, field->usage, 0);
00364 mouse_dev->buttons[field->usage - field->usage_minimum]
00365 = field->value;
00366 }
00367
00368 field = usb_hid_report_get_sibling(
00369 hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
00370 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00371 USB_HID_REPORT_TYPE_INPUT);
00372 }
00373
00374 usb_hid_report_path_free(path);
00375
00376 return true;
00377 }
00378
00379
00380
00381 static int usb_mouse_create_function(usb_hid_dev_t *hid_dev, usb_mouse_t *mouse)
00382 {
00383 assert(hid_dev != NULL);
00384 assert(mouse != NULL);
00385
00386
00387 usb_log_debug("Creating DDF function %s...\n", HID_MOUSE_FUN_NAME);
00388 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
00389 HID_MOUSE_FUN_NAME);
00390 if (fun == NULL) {
00391 usb_log_error("Could not create DDF function node.\n");
00392 return ENOMEM;
00393 }
00394
00395 fun->ops = &mouse->ops;
00396 fun->driver_data = mouse;
00397
00398 int rc = ddf_fun_bind(fun);
00399 if (rc != EOK) {
00400 usb_log_error("Could not bind DDF function: %s.\n",
00401 str_error(rc));
00402 ddf_fun_destroy(fun);
00403 return rc;
00404 }
00405
00406 usb_log_debug("Adding DDF function to class %s...\n",
00407 HID_MOUSE_CLASS_NAME);
00408 rc = ddf_fun_add_to_class(fun, HID_MOUSE_CLASS_NAME);
00409 if (rc != EOK) {
00410 usb_log_error(
00411 "Could not add DDF function to class %s: %s.\n",
00412 HID_MOUSE_CLASS_NAME, str_error(rc));
00413 ddf_fun_destroy(fun);
00414 return rc;
00415 }
00416
00417
00418
00419
00420 usb_log_debug("Creating DDF function %s...\n",
00421 HID_MOUSE_WHEEL_FUN_NAME);
00422 fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
00423 HID_MOUSE_WHEEL_FUN_NAME);
00424 if (fun == NULL) {
00425 usb_log_error("Could not create DDF function node.\n");
00426 return ENOMEM;
00427 }
00428
00429
00430
00431
00432
00433 fun->ops = &mouse->ops;
00434 fun->driver_data = mouse;
00435
00436 rc = ddf_fun_bind(fun);
00437 if (rc != EOK) {
00438 usb_log_error("Could not bind DDF function: %s.\n",
00439 str_error(rc));
00440 ddf_fun_destroy(fun);
00441 return rc;
00442 }
00443
00444 usb_log_debug("Adding DDF function to class %s...\n",
00445 HID_MOUSE_WHEEL_CLASS_NAME);
00446 rc = ddf_fun_add_to_class(fun, HID_MOUSE_WHEEL_CLASS_NAME);
00447 if (rc != EOK) {
00448 usb_log_error(
00449 "Could not add DDF function to class %s: %s.\n",
00450 HID_MOUSE_WHEEL_CLASS_NAME, str_error(rc));
00451 ddf_fun_destroy(fun);
00452 return rc;
00453 }
00454
00455 return EOK;
00456 }
00457
00458
00459
00460 int usb_mouse_init(usb_hid_dev_t *hid_dev, void **data)
00461 {
00462 usb_log_debug("Initializing HID/Mouse structure...\n");
00463
00464 if (hid_dev == NULL) {
00465 usb_log_error("Failed to init keyboard structure: no structure"
00466 " given.\n");
00467 return EINVAL;
00468 }
00469
00470 usb_mouse_t *mouse_dev = usb_mouse_new();
00471 if (mouse_dev == NULL) {
00472 usb_log_error("Error while creating USB/HID Mouse device "
00473 "structure.\n");
00474 return ENOMEM;
00475 }
00476
00477 mouse_dev->buttons = (int32_t *)calloc(USB_MOUSE_BUTTON_COUNT,
00478 sizeof(int32_t));
00479
00480 if (mouse_dev->buttons == NULL) {
00481 usb_log_fatal("No memory!\n");
00482 free(mouse_dev);
00483 return ENOMEM;
00484 }
00485
00486
00487 *data = mouse_dev;
00488
00489
00490 mouse_dev->ops.default_handler = default_connection_handler;
00491
00492
00493 usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
00494 hid_dev->usb_dev->interface_no, IDLE_RATE);
00495
00496 int rc = usb_mouse_create_function(hid_dev, mouse_dev);
00497 if (rc != EOK) {
00498 usb_mouse_free(&mouse_dev);
00499 return rc;
00500 }
00501
00502 return EOK;
00503 }
00504
00505
00506
00507 bool usb_mouse_polling_callback(usb_hid_dev_t *hid_dev, void *data
00508 )
00509 {
00510 usb_log_debug("usb_mouse_polling_callback()\n");
00511
00512
00513 if (hid_dev == NULL || data == NULL) {
00514 usb_log_error("Missing argument to the mouse polling callback."
00515 "\n");
00516 return false;
00517 }
00518
00519 usb_mouse_t *mouse_dev = (usb_mouse_t *)data;
00520
00521 return usb_mouse_process_report(hid_dev, mouse_dev
00522 );
00523 }
00524
00525
00526
00527 void usb_mouse_deinit(usb_hid_dev_t *hid_dev, void *data)
00528 {
00529 if (data != NULL) {
00530 usb_mouse_free((usb_mouse_t **)&data);
00531 }
00532 }
00533
00534
00535
00536 int usb_mouse_set_boot_protocol(usb_hid_dev_t *hid_dev)
00537 {
00538 int rc = usb_hid_parse_report_descriptor(hid_dev->report,
00539 USB_MOUSE_BOOT_REPORT_DESCRIPTOR,
00540 USB_MOUSE_BOOT_REPORT_DESCRIPTOR_SIZE);
00541
00542 if (rc != EOK) {
00543 usb_log_error("Failed to parse boot report descriptor: %s\n",
00544 str_error(rc));
00545 return rc;
00546 }
00547
00548 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
00549 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
00550
00551 if (rc != EOK) {
00552 usb_log_warning("Failed to set boot protocol to the device: "
00553 "%s\n", str_error(rc));
00554 return rc;
00555 }
00556
00557 return EOK;
00558 }
00559