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