kbddev.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Lubos Slovak
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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,  // Usage Page (Generic Desktop),
00109         0x09, 0x06,  // Usage (Keyboard),
00110         0xA1, 0x01,  // Collection (Application),
00111         0x75, 0x01,  //   Report Size (1),
00112         0x95, 0x08,  //   Report Count (8),       
00113         0x05, 0x07,  //   Usage Page (Key Codes);
00114         0x19, 0xE0,  //   Usage Minimum (224),
00115         0x29, 0xE7,  //   Usage Maximum (231),
00116         0x15, 0x00,  //   Logical Minimum (0),
00117         0x25, 0x01,  //   Logical Maximum (1),
00118         0x81, 0x02,  //   Input (Data, Variable, Absolute),   ; Modifier byte
00119         0x95, 0x01,  //   Report Count (1),
00120         0x75, 0x08,  //   Report Size (8),
00121         0x81, 0x01,  //   Input (Constant),                   ; Reserved byte
00122         0x95, 0x05,  //   Report Count (5),
00123         0x75, 0x01,  //   Report Size (1),
00124         0x05, 0x08,  //   Usage Page (Page# for LEDs),
00125         0x19, 0x01,  //   Usage Minimum (1),
00126         0x29, 0x05,  //   Usage Maxmimum (5),
00127         0x91, 0x02,  //   Output (Data, Variable, Absolute),  ; LED report
00128         0x95, 0x01,  //   Report Count (1),
00129         0x75, 0x03,  //   Report Size (3),
00130         0x91, 0x01,  //   Output (Constant),              ; LED report padding
00131         0x95, 0x06,  //   Report Count (6),
00132         0x75, 0x08,  //   Report Size (8),
00133         0x15, 0x00,  //   Logical Minimum (0),
00134         0x25, 0xff,  //   Logical Maximum (255),
00135         0x05, 0x07,  //   Usage Page (Key Codes),
00136         0x19, 0x00,  //   Usage Minimum (0),
00137         0x29, 0xff,  //   Usage Maximum (255),
00138         0x81, 0x00,  //   Input (Data, Array),            ; Key arrays (6 bytes)
00139         0xC0           // End Collection
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 /* Keyboard layouts                                                           */
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 /* IPC method handler                                                         */
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 /* Key processing functions                                                   */
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         /* Reset the LED data. */
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         // TODO: what about the Report ID?
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          * These parts are copy-pasted from the AT keyboard driver.
00314          *
00315          * They definitely require some refactoring, but will keep it for later
00316          * when the console and keyboard system is changed in HelenOS.
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                          * Only change lock state on transition from released
00346                          * to pressed. This prevents autorepeat from messing
00347                          * up the lock state.
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                         /* Update keyboard lock indicator lights. */
00356                         if (kbd_dev->lock_keys != locks_old 
00357                             && hid_dev != NULL) { // ugly hack
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                 // do not send anything to the console, this is our business
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          * First of all, check if the kbd have reported phantom state.
00438          *
00439          * As there is no way to distinguish keys from modifiers, we do not have
00440          * a way to check that 'all keys report Error Rollover'. We thus check
00441          * if there is at least one such error and in such case we ignore the
00442          * whole input report.
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                 // phantom state, do nothing
00451                 return;
00452         }
00453         
00454         /*
00455          * 1) Key releases
00456          */
00457         for (j = 0; j < kbd_dev->key_count; ++j) {
00458                 // try to find the old key in the new key list
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                         // not found, i.e. the key was released
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                         // found, nothing happens
00475                 }
00476         }
00477         
00478         /*
00479          * 1) Key presses
00480          */
00481         for (i = 0; i < kbd_dev->key_count; ++i) {
00482                 // try to find the new key in the old key list
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                         // not found, i.e. new key pressed
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                         // found, nothing happens
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 /* General kbd functions                                                      */
00514 /*----------------------------------------------------------------------------*/
00531 static void usb_kbd_process_data(usb_hid_dev_t *hid_dev, usb_kbd_t *kbd_dev/*,
00532                                  uint8_t *buffer, size_t actual_size*/)
00533 {
00534         assert(hid_dev->report != NULL);
00535         assert(hid_dev != NULL);
00536         assert(kbd_dev != NULL);
00537 
00538 //      usb_log_debug("Calling usb_hid_parse_report() with "
00539 //          "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
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 //      uint8_t report_id;
00545 //      int rc = usb_hid_parse_report(hid_dev->report, buffer, actual_size, 
00546 //          &report_id);
00547         
00548 //      if (rc != EOK) {
00549 //              usb_log_warning("Error in usb_hid_parse_report():"
00550 //                  "%s\n", str_error(rc));
00551 //      }
00552         
00553         usb_hid_report_path_set_report_id (path, hid_dev->report_id);
00554         
00555         // fill in the currently pressed keys
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                 // save the key usage
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 /* HID/KBD structure manipulation                                             */
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         /* Create the function exposed under /dev/devices. */
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          * Store the initialized HID device and HID ops
00645          * to the DDF function.
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 /* API functions                                                              */
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;  // TODO: some other code??
00713         }
00714         
00715         /*
00716          * TODO: make more general
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          * Output report
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          * Modifiers and locks
00785          */     
00786         kbd_dev->modifiers = 0;
00787         kbd_dev->mods = DEFAULT_ACTIVE_MODS;
00788         kbd_dev->lock_keys = 0;
00789         
00790         /*
00791          * Autorepeat
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         // save the KBD device structure into the HID device structure
00811         *data = kbd_dev;
00812         
00813         // set handler for incoming calls
00814         kbd_dev->ops.default_handler = default_connection_handler;
00815         
00816         /*
00817          * Set LEDs according to initial setup.
00818          * Set Idle rate
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          * Create new fibril for auto-repeat
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      uint8_t *buffer, size_t buffer_size*/)
00852 {
00853         if (hid_dev == NULL/* || buffer == NULL*/ || data == NULL) {
00854                 // do not continue polling (???)
00855                 return false;
00856         }
00857         
00858         usb_kbd_t *kbd_dev = (usb_kbd_t *)data;
00859         assert(kbd_dev != NULL);
00860         
00861         // TODO: add return value from this function
00862         usb_kbd_process_data(hid_dev, kbd_dev/*, buffer, buffer_size*/);
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         // hangup phone to the console
00894         async_hangup((*kbd_dev)->console_phone);
00895         
00896         if ((*kbd_dev)->repeat_mtx != NULL) {
00897                 //assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
00898                 while (fibril_mutex_is_locked((*kbd_dev)->repeat_mtx)) {}
00899                 free((*kbd_dev)->repeat_mtx);
00900         }
00901         
00902         // free all buffers
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 

Generated on Thu Jun 2 07:45:44 2011 for HelenOS/USB by  doxygen 1.4.7