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 <errno.h>
00038 #include <str_error.h>
00039 #include <stdio.h>
00040
00041 #include <io/keycode.h>
00042 #include <ipc/kbd.h>
00043 #include <async.h>
00044 #include <fibril.h>
00045 #include <fibril_synch.h>
00046
00047 #include <usb/usb.h>
00048 #include <usb/dev/dp.h>
00049 #include <usb/dev/request.h>
00050 #include <usb/hid/hid.h>
00051 #include <usb/dev/pipes.h>
00052 #include <usb/debug.h>
00053 #include <usb/hid/hidparser.h>
00054 #include <usb/classes/classes.h>
00055 #include <usb/hid/usages/core.h>
00056 #include <usb/hid/request.h>
00057 #include <usb/hid/hidreport.h>
00058 #include <usb/hid/usages/led.h>
00059
00060 #include <usb/dev/driver.h>
00061
00062 #include "kbddev.h"
00063
00064 #include "layout.h"
00065 #include "conv.h"
00066 #include "kbdrepeat.h"
00067
00068 #include "../usbhid.h"
00069
00070
00072 static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
00073
00074 static const uint8_t ERROR_ROLLOVER = 1;
00075
00077 static const uint8_t IDLE_RATE = 0;
00078
00080 static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
00081
00083 static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
00084
00085
00086
00088 usb_endpoint_description_t usb_hid_kbd_poll_endpoint_description = {
00089 .transfer_type = USB_TRANSFER_INTERRUPT,
00090 .direction = USB_DIRECTION_IN,
00091 .interface_class = USB_CLASS_HID,
00092 .interface_subclass = USB_HID_SUBCLASS_BOOT,
00093 .interface_protocol = USB_HID_PROTOCOL_KEYBOARD,
00094 .flags = 0
00095 };
00096
00097 const char *HID_KBD_FUN_NAME = "keyboard";
00098 const char *HID_KBD_CLASS_NAME = "keyboard";
00099
00100
00101
00102 enum {
00103 USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE = 63
00104 };
00105
00106 static const uint8_t USB_KBD_BOOT_REPORT_DESCRIPTOR[
00107 USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE] = {
00108 0x05, 0x01,
00109 0x09, 0x06,
00110 0xA1, 0x01,
00111 0x75, 0x01,
00112 0x95, 0x08,
00113 0x05, 0x07,
00114 0x19, 0xE0,
00115 0x29, 0xE7,
00116 0x15, 0x00,
00117 0x25, 0x01,
00118 0x81, 0x02,
00119 0x95, 0x01,
00120 0x75, 0x08,
00121 0x81, 0x01,
00122 0x95, 0x05,
00123 0x75, 0x01,
00124 0x05, 0x08,
00125 0x19, 0x01,
00126 0x29, 0x05,
00127 0x91, 0x02,
00128 0x95, 0x01,
00129 0x75, 0x03,
00130 0x91, 0x01,
00131 0x95, 0x06,
00132 0x75, 0x08,
00133 0x15, 0x00,
00134 0x25, 0xff,
00135 0x05, 0x07,
00136 0x19, 0x00,
00137 0x29, 0xff,
00138 0x81, 0x00,
00139 0xC0
00140
00141 };
00142
00143
00144
00145 typedef enum usb_kbd_flags {
00146 USB_KBD_STATUS_UNINITIALIZED = 0,
00147 USB_KBD_STATUS_INITIALIZED = 1,
00148 USB_KBD_STATUS_TO_DESTROY = -1
00149 } usb_kbd_flags;
00150
00151
00152
00153
00154
00155 #define NUM_LAYOUTS 3
00156
00158 static layout_op_t *layout[NUM_LAYOUTS] = {
00159 &us_qwerty_op,
00160 &us_dvorak_op,
00161 &cz_op
00162 };
00163
00164 static int active_layout = 0;
00165
00166
00167
00168
00169
00170 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
00171
00183 static void default_connection_handler(ddf_fun_t *fun,
00184 ipc_callid_t icallid, ipc_call_t *icall)
00185 {
00186 sysarg_t method = IPC_GET_IMETHOD(*icall);
00187
00188 usb_kbd_t *kbd_dev = (usb_kbd_t *)fun->driver_data;
00189 if (kbd_dev == NULL) {
00190 usb_log_debug("default_connection_handler: "
00191 "Missing parameter.\n");
00192 async_answer_0(icallid, EINVAL);
00193 return;
00194 }
00195
00196 if (method == IPC_M_CONNECT_TO_ME) {
00197 int callback = IPC_GET_ARG5(*icall);
00198
00199 if (kbd_dev->console_phone != -1) {
00200 usb_log_debug("default_connection_handler: "
00201 "console phone already set\n");
00202 async_answer_0(icallid, ELIMIT);
00203 return;
00204 }
00205
00206 kbd_dev->console_phone = callback;
00207
00208 usb_log_debug("default_connection_handler: OK\n");
00209 async_answer_0(icallid, EOK);
00210 return;
00211 }
00212
00213 usb_log_debug("default_connection_handler: Wrong function.\n");
00214 async_answer_0(icallid, EINVAL);
00215 }
00216
00217
00218
00219
00232 static void usb_kbd_set_led(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
00233 {
00234 if (kbd_dev->output_size == 0) {
00235 return;
00236 }
00237
00238
00239 memset(kbd_dev->led_data, 0, kbd_dev->led_output_size * sizeof(int32_t));
00240 usb_log_debug("Creating output report:\n");
00241
00242 usb_hid_report_field_t *field = usb_hid_report_get_sibling(
00243 hid_dev->report, NULL, kbd_dev->led_path,
00244 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00245 USB_HID_REPORT_TYPE_OUTPUT);
00246
00247 while (field != NULL) {
00248
00249 if ((field->usage == USB_HID_LED_NUM_LOCK)
00250 && (kbd_dev->mods & KM_NUM_LOCK)){
00251 field->value = 1;
00252 }
00253
00254 if ((field->usage == USB_HID_LED_CAPS_LOCK)
00255 && (kbd_dev->mods & KM_CAPS_LOCK)){
00256 field->value = 1;
00257 }
00258
00259 if ((field->usage == USB_HID_LED_SCROLL_LOCK)
00260 && (kbd_dev->mods & KM_SCROLL_LOCK)){
00261 field->value = 1;
00262 }
00263
00264 field = usb_hid_report_get_sibling(hid_dev->report, field,
00265 kbd_dev->led_path,
00266 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00267 USB_HID_REPORT_TYPE_OUTPUT);
00268 }
00269
00270
00271 int rc = usb_hid_report_output_translate(hid_dev->report, 0,
00272 kbd_dev->output_buffer, kbd_dev->output_size);
00273
00274 if (rc != EOK) {
00275 usb_log_warning("Error translating LED output to output report"
00276 ".\n");
00277 return;
00278 }
00279
00280 usb_log_debug("Output report buffer: %s\n",
00281 usb_debug_str_buffer(kbd_dev->output_buffer, kbd_dev->output_size,
00282 0));
00283
00284 usbhid_req_set_report(&hid_dev->usb_dev->ctrl_pipe,
00285 hid_dev->usb_dev->interface_no, USB_HID_REPORT_TYPE_OUTPUT,
00286 kbd_dev->output_buffer, kbd_dev->output_size);
00287 }
00288
00289
00306 void usb_kbd_push_ev(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev, int type,
00307 unsigned int key)
00308 {
00309 console_event_t ev;
00310 unsigned mod_mask;
00311
00312
00313
00314
00315
00316
00317
00318 switch (key) {
00319 case KC_LCTRL: mod_mask = KM_LCTRL; break;
00320 case KC_RCTRL: mod_mask = KM_RCTRL; break;
00321 case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
00322 case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
00323 case KC_LALT: mod_mask = KM_LALT; break;
00324 case KC_RALT: mod_mask = KM_RALT; break;
00325 default: mod_mask = 0; break;
00326 }
00327
00328 if (mod_mask != 0) {
00329 if (type == KEY_PRESS)
00330 kbd_dev->mods = kbd_dev->mods | mod_mask;
00331 else
00332 kbd_dev->mods = kbd_dev->mods & ~mod_mask;
00333 }
00334
00335 switch (key) {
00336 case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
00337 case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
00338 case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
00339 default: mod_mask = 0; break;
00340 }
00341
00342 if (mod_mask != 0) {
00343 if (type == KEY_PRESS) {
00344
00345
00346
00347
00348
00349 unsigned int locks_old = kbd_dev->lock_keys;
00350
00351 kbd_dev->mods =
00352 kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
00353 kbd_dev->lock_keys = kbd_dev->lock_keys | mod_mask;
00354
00355
00356 if (kbd_dev->lock_keys != locks_old
00357 && hid_dev != NULL) {
00358 usb_kbd_set_led(hid_dev, kbd_dev);
00359 }
00360 } else {
00361 kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
00362 }
00363 }
00364
00365 if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
00366
00367 return;
00368 }
00369
00370 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F1) {
00371 active_layout = 0;
00372 layout[active_layout]->reset();
00373 return;
00374 }
00375
00376 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F2) {
00377 active_layout = 1;
00378 layout[active_layout]->reset();
00379 return;
00380 }
00381
00382 if (type == KEY_PRESS && (kbd_dev->mods & KM_LCTRL) && key == KC_F3) {
00383 active_layout = 2;
00384 layout[active_layout]->reset();
00385 return;
00386 }
00387
00388 ev.type = type;
00389 ev.key = key;
00390 ev.mods = kbd_dev->mods;
00391
00392 ev.c = layout[active_layout]->parse_ev(&ev);
00393
00394 usb_log_debug2("Sending key %d to the console\n", ev.key);
00395 if (kbd_dev->console_phone < 0) {
00396 usb_log_warning(
00397 "Connection to console not ready, key discarded.\n");
00398 return;
00399 }
00400
00401 async_msg_4(kbd_dev->console_phone, KBD_EVENT, ev.type, ev.key,
00402 ev.mods, ev.c);
00403 }
00404
00405
00406
00407 static inline int usb_kbd_is_lock(unsigned int key_code)
00408 {
00409 return (key_code == KC_NUM_LOCK
00410 || key_code == KC_SCROLL_LOCK
00411 || key_code == KC_CAPS_LOCK);
00412 }
00413
00414
00430 static void usb_kbd_check_key_changes(usb_hid_dev_t *hid_dev,
00431 usb_kbd_t *kbd_dev)
00432 {
00433 unsigned int key;
00434 unsigned int i, j;
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 i = 0;
00445 while (i < kbd_dev->key_count && kbd_dev->keys[i] != ERROR_ROLLOVER) {
00446 ++i;
00447 }
00448 if (i != kbd_dev->key_count) {
00449 usb_log_debug("Phantom state occured.\n");
00450
00451 return;
00452 }
00453
00454
00455
00456
00457 for (j = 0; j < kbd_dev->key_count; ++j) {
00458
00459 i = 0;
00460 while (i < kbd_dev->key_count
00461 && kbd_dev->keys[i] != kbd_dev->keys_old[j]) {
00462 ++i;
00463 }
00464
00465 if (i == kbd_dev->key_count) {
00466
00467 key = usbhid_parse_scancode(kbd_dev->keys_old[j]);
00468 if (!usb_kbd_is_lock(key)) {
00469 usb_kbd_repeat_stop(kbd_dev, key);
00470 }
00471 usb_kbd_push_ev(hid_dev, kbd_dev, KEY_RELEASE, key);
00472 usb_log_debug2("Key released: %d\n", key);
00473 } else {
00474
00475 }
00476 }
00477
00478
00479
00480
00481 for (i = 0; i < kbd_dev->key_count; ++i) {
00482
00483 j = 0;
00484 while (j < kbd_dev->key_count
00485 && kbd_dev->keys_old[j] != kbd_dev->keys[i]) {
00486 ++j;
00487 }
00488
00489 if (j == kbd_dev->key_count) {
00490
00491 key = usbhid_parse_scancode(kbd_dev->keys[i]);
00492 usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
00493 kbd_dev->keys[i]);
00494 if (!usb_kbd_is_lock(key)) {
00495 usb_kbd_repeat_start(kbd_dev, key);
00496 }
00497 usb_kbd_push_ev(hid_dev, kbd_dev, KEY_PRESS, key);
00498 } else {
00499
00500 }
00501 }
00502
00503 memcpy(kbd_dev->keys_old, kbd_dev->keys, kbd_dev->key_count * 4);
00504
00505 usb_log_debug2("New stored keys: ");
00506 for (i = 0; i < kbd_dev->key_count; ++i) {
00507 usb_log_debug2("%d ", kbd_dev->keys_old[i]);
00508 }
00509 usb_log_debug2("\n");
00510 }
00511
00512
00513
00514
00531 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev
00532 )
00533 {
00534 assert(hid_dev->report != NULL);
00535 assert(hid_dev != NULL);
00536 assert(kbd_dev != NULL);
00537
00538
00539
00540
00541 usb_hid_report_path_t *path = usb_hid_report_path();
00542 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 usb_hid_report_path_set_report_id (path, hid_dev->report_id);
00554
00555
00556
00557 usb_hid_report_field_t *field = usb_hid_report_get_sibling(
00558 hid_dev->report, NULL, path,
00559 USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00560 USB_HID_REPORT_TYPE_INPUT);
00561 unsigned i = 0;
00562
00563 while (field != NULL) {
00564 usb_log_debug2("FIELD (%p) - VALUE(%d) USAGE(%u)\n",
00565 field, field->value, field->usage);
00566
00567 assert(i < kbd_dev->key_count);
00568
00569
00570 if (field->value != 0) {
00571 kbd_dev->keys[i] = field->usage;
00572 }
00573 else {
00574 kbd_dev->keys[i] = 0;
00575 }
00576 usb_log_debug2("Saved %u. key usage %d\n", i, kbd_dev->keys[i]);
00577
00578 ++i;
00579 field = usb_hid_report_get_sibling(hid_dev->report, field, path,
00580 USB_HID_PATH_COMPARE_END
00581 | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
00582 USB_HID_REPORT_TYPE_INPUT);
00583 }
00584
00585 usb_hid_report_path_free(path);
00586
00587 usb_kbd_check_key_changes(hid_dev, kbd_dev);
00588 }
00589
00590
00591
00592
00593
00594 static void usb_kbd_mark_unusable(usb_kbd_t *kbd_dev)
00595 {
00596 kbd_dev->initialized = USB_KBD_STATUS_TO_DESTROY;
00597 }
00598
00599
00600
00610 static usb_kbd_t *usb_kbd_new(void)
00611 {
00612 usb_kbd_t *kbd_dev =
00613 (usb_kbd_t *)calloc(1, sizeof(usb_kbd_t));
00614
00615 if (kbd_dev == NULL) {
00616 usb_log_fatal("No memory!\n");
00617 return NULL;
00618 }
00619
00620 kbd_dev->console_phone = -1;
00621 kbd_dev->initialized = USB_KBD_STATUS_UNINITIALIZED;
00622
00623 return kbd_dev;
00624 }
00625
00626
00627
00628 static int usb_kbd_create_function(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev)
00629 {
00630 assert(hid_dev != NULL);
00631 assert(hid_dev->usb_dev != NULL);
00632 assert(kbd_dev != NULL);
00633
00634
00635 usb_log_debug("Creating DDF function %s...\n", HID_KBD_FUN_NAME);
00636 ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
00637 HID_KBD_FUN_NAME);
00638 if (fun == NULL) {
00639 usb_log_error("Could not create DDF function node.\n");
00640 return ENOMEM;
00641 }
00642
00643
00644
00645
00646
00647 fun->ops = &kbd_dev->ops;
00648 fun->driver_data = kbd_dev;
00649
00650 int rc = ddf_fun_bind(fun);
00651 if (rc != EOK) {
00652 usb_log_error("Could not bind DDF function: %s.\n",
00653 str_error(rc));
00654 ddf_fun_destroy(fun);
00655 return rc;
00656 }
00657
00658 usb_log_debug("%s function created. Handle: %" PRIun "\n",
00659 HID_KBD_FUN_NAME, fun->handle);
00660
00661 usb_log_debug("Adding DDF function to class %s...\n",
00662 HID_KBD_CLASS_NAME);
00663 rc = ddf_fun_add_to_class(fun, HID_KBD_CLASS_NAME);
00664 if (rc != EOK) {
00665 usb_log_error(
00666 "Could not add DDF function to class %s: %s.\n",
00667 HID_KBD_CLASS_NAME, str_error(rc));
00668 ddf_fun_destroy(fun);
00669 return rc;
00670 }
00671
00672 return EOK;
00673 }
00674
00675
00676
00677
00698 int usb_kbd_init(usb_hid_dev_t *hid_dev, void **data)
00699 {
00700 usb_log_debug("Initializing HID/KBD structure...\n");
00701
00702 if (hid_dev == NULL) {
00703 usb_log_error("Failed to init keyboard structure: no structure"
00704 " given.\n");
00705 return EINVAL;
00706 }
00707
00708 usb_kbd_t *kbd_dev = usb_kbd_new();
00709 if (kbd_dev == NULL) {
00710 usb_log_error("Error while creating USB/HID KBD device "
00711 "structure.\n");
00712 return ENOMEM;
00713 }
00714
00715
00716
00717
00718 usb_hid_report_path_t *path = usb_hid_report_path();
00719 usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_KEYBOARD, 0);
00720
00721 usb_hid_report_path_set_report_id(path, 0);
00722
00723 kbd_dev->key_count = usb_hid_report_size(
00724 hid_dev->report, 0, USB_HID_REPORT_TYPE_INPUT);
00725 usb_hid_report_path_free(path);
00726
00727 usb_log_debug("Size of the input report: %zu\n", kbd_dev->key_count);
00728
00729 kbd_dev->keys = (int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
00730
00731 if (kbd_dev->keys == NULL) {
00732 usb_log_fatal("No memory!\n");
00733 free(kbd_dev);
00734 return ENOMEM;
00735 }
00736
00737 kbd_dev->keys_old =
00738 (int32_t *)calloc(kbd_dev->key_count, sizeof(int32_t));
00739
00740 if (kbd_dev->keys_old == NULL) {
00741 usb_log_fatal("No memory!\n");
00742 free(kbd_dev->keys);
00743 free(kbd_dev);
00744 return ENOMEM;
00745 }
00746
00747
00748
00749
00750 kbd_dev->output_size = 0;
00751 kbd_dev->output_buffer = usb_hid_report_output(hid_dev->report,
00752 &kbd_dev->output_size, 0);
00753 if (kbd_dev->output_buffer == NULL) {
00754 usb_log_warning("Error creating output report buffer.\n");
00755 free(kbd_dev->keys);
00756 return ENOMEM;
00757 }
00758
00759 usb_log_debug("Output buffer size: %zu\n", kbd_dev->output_size);
00760
00761 kbd_dev->led_path = usb_hid_report_path();
00762 usb_hid_report_path_append_item(
00763 kbd_dev->led_path, USB_HIDUT_PAGE_LED, 0);
00764
00765 kbd_dev->led_output_size = usb_hid_report_size(hid_dev->report,
00766 0, USB_HID_REPORT_TYPE_OUTPUT);
00767
00768 usb_log_debug("Output report size (in items): %zu\n",
00769 kbd_dev->led_output_size);
00770
00771 kbd_dev->led_data = (int32_t *)calloc(
00772 kbd_dev->led_output_size, sizeof(int32_t));
00773
00774 if (kbd_dev->led_data == NULL) {
00775 usb_log_warning("Error creating buffer for LED output report."
00776 "\n");
00777 free(kbd_dev->keys);
00778 usb_hid_report_output_free(kbd_dev->output_buffer);
00779 free(kbd_dev);
00780 return ENOMEM;
00781 }
00782
00783
00784
00785
00786 kbd_dev->modifiers = 0;
00787 kbd_dev->mods = DEFAULT_ACTIVE_MODS;
00788 kbd_dev->lock_keys = 0;
00789
00790
00791
00792
00793 kbd_dev->repeat.key_new = 0;
00794 kbd_dev->repeat.key_repeated = 0;
00795 kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
00796 kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
00797
00798 kbd_dev->repeat_mtx = (fibril_mutex_t *)(
00799 malloc(sizeof(fibril_mutex_t)));
00800 if (kbd_dev->repeat_mtx == NULL) {
00801 usb_log_fatal("No memory!\n");
00802 free(kbd_dev->keys);
00803 usb_hid_report_output_free(kbd_dev->output_buffer);
00804 free(kbd_dev);
00805 return ENOMEM;
00806 }
00807
00808 fibril_mutex_initialize(kbd_dev->repeat_mtx);
00809
00810
00811 *data = kbd_dev;
00812
00813
00814 kbd_dev->ops.default_handler = default_connection_handler;
00815
00816
00817
00818
00819
00820 usb_kbd_set_led(hid_dev, kbd_dev);
00821
00822 usbhid_req_set_idle(&hid_dev->usb_dev->ctrl_pipe,
00823 hid_dev->usb_dev->interface_no, IDLE_RATE);
00824
00825
00826
00827
00828 fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
00829 if (fid == 0) {
00830 usb_log_error("Failed to start fibril for KBD auto-repeat");
00831 return ENOMEM;
00832 }
00833 fibril_add_ready(fid);
00834
00835 kbd_dev->initialized = USB_KBD_STATUS_INITIALIZED;
00836 usb_log_debug("HID/KBD device structure initialized.\n");
00837
00838 usb_log_debug("Creating KBD function...\n");
00839 int rc = usb_kbd_create_function(hid_dev, kbd_dev);
00840 if (rc != EOK) {
00841 usb_kbd_free(&kbd_dev);
00842 return rc;
00843 }
00844
00845 return EOK;
00846 }
00847
00848
00849
00850 bool usb_kbd_polling_callback(usb_hid_dev_t *hid_dev, void *data
00851 )
00852 {
00853 if (hid_dev == NULL || data == NULL) {
00854
00855 return false;
00856 }
00857
00858 usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
00859 assert(kbd_dev != NULL);
00860
00861
00862 usb_kbd_process_data(hid_dev, kbd_dev);
00863
00864 return true;
00865 }
00866
00867
00868
00869 int usb_kbd_is_initialized(const usb_kbd_t *kbd_dev)
00870 {
00871 return (kbd_dev->initialized == USB_KBD_STATUS_INITIALIZED);
00872 }
00873
00874
00875
00876 int usb_kbd_is_ready_to_destroy(const usb_kbd_t *kbd_dev)
00877 {
00878 return (kbd_dev->initialized == USB_KBD_STATUS_TO_DESTROY);
00879 }
00880
00881
00887 void usb_kbd_free(usb_kbd_t **kbd_dev)
00888 {
00889 if (kbd_dev == NULL || *kbd_dev == NULL) {
00890 return;
00891 }
00892
00893
00894 async_hangup((*kbd_dev)->console_phone);
00895
00896 if ((*kbd_dev)->repeat_mtx != NULL) {
00897
00898 while (fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)) {}
00899 free((*kbd_dev)->repeat_mtx);
00900 }
00901
00902
00903 if ((*kbd_dev)->keys != NULL) {
00904 free((*kbd_dev)->keys);
00905 }
00906 if ((*kbd_dev)->keys_old != NULL) {
00907 free((*kbd_dev)->keys_old);
00908 }
00909 if ((*kbd_dev)->led_data != NULL) {
00910 free((*kbd_dev)->led_data);
00911 }
00912 if ((*kbd_dev)->led_path != NULL) {
00913 usb_hid_report_path_free((*kbd_dev)->led_path);
00914 }
00915 if ((*kbd_dev)->output_buffer != NULL) {
00916 usb_hid_report_output_free((*kbd_dev)->output_buffer);
00917 }
00918
00919 free(*kbd_dev);
00920 *kbd_dev = NULL;
00921 }
00922
00923
00924
00925 void usb_kbd_deinit(usb_hid_dev_t *hid_dev, void *data)
00926 {
00927 if (hid_dev == NULL) {
00928 return;
00929 }
00930
00931 if (data != NULL) {
00932 usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
00933 if (usb_kbd_is_initialized(kbd_dev)) {
00934 usb_kbd_mark_unusable(kbd_dev);
00935 } else {
00936 usb_kbd_free(&kbd_dev);
00937 }
00938 }
00939 }
00940
00941
00942
00943 int usb_kbd_set_boot_protocol(usb_hid_dev_t *hid_dev)
00944 {
00945 int rc = usb_hid_parse_report_descriptor(hid_dev->report,
00946 USB_KBD_BOOT_REPORT_DESCRIPTOR,
00947 USB_KBD_BOOT_REPORT_DESCRIPTOR_SIZE);
00948
00949 if (rc != EOK) {
00950 usb_log_error("Failed to parse boot report descriptor: %s\n",
00951 str_error(rc));
00952 return rc;
00953 }
00954
00955 rc = usbhid_req_set_protocol(&hid_dev->usb_dev->ctrl_pipe,
00956 hid_dev->usb_dev->interface_no, USB_HID_PROTOCOL_BOOT);
00957
00958 if (rc != EOK) {
00959 usb_log_warning("Failed to set boot protocol to the device: "
00960 "%s\n", str_error(rc));
00961 return rc;
00962 }
00963
00964 return EOK;
00965 }
00966