Ignore:
Timestamp:
2011-05-06T09:29:03Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9a884ed
Parents:
c709eb0 (diff), 310c4df (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge development/ changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/usbhid/lgtch-ultrax/lgtch-ultrax.c

    rc709eb0 r30f9f8f  
    3838#include "lgtch-ultrax.h"
    3939#include "../usbhid.h"
     40#include "keymap.h"
    4041
    4142#include <usb/classes/hidparser.h>
    4243#include <usb/debug.h>
     44#include <usb/classes/hidut.h>
     45
    4346#include <errno.h>
    4447#include <str_error.h>
    4548
     49#include <ipc/kbd.h>
     50#include <io/console.h>
     51
    4652#define NAME "lgtch-ultrax"
    4753
    48 /*----------------------------------------------------------------------------*/
    49 
    50 static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
    51     uint8_t report_id, void *arg);
    52 
    53 static const usb_hid_report_in_callbacks_t usb_lgtch_parser_callbacks = {
    54         .keyboard = usb_lgtch_process_keycodes
     54typedef enum usb_lgtch_flags {
     55        USB_LGTCH_STATUS_UNINITIALIZED = 0,
     56        USB_LGTCH_STATUS_INITIALIZED = 1,
     57        USB_LGTCH_STATUS_TO_DESTROY = -1
     58} usb_lgtch_flags;
     59
     60/*----------------------------------------------------------------------------*/
     61/**
     62 * Logitech UltraX device type.
     63 */
     64typedef struct usb_lgtch_ultrax_t {
     65        /** Previously pressed keys (not translated to key codes). */
     66        int32_t *keys_old;
     67        /** Currently pressed keys (not translated to key codes). */
     68        int32_t *keys;
     69        /** Count of stored keys (i.e. number of keys in the report). */
     70        size_t key_count;
     71       
     72        /** IPC phone to the console device (for sending key events). */
     73        int console_phone;
     74
     75        /** Information for auto-repeat of keys. */
     76//      usb_kbd_repeat_t repeat;
     77       
     78        /** Mutex for accessing the information about auto-repeat. */
     79//      fibril_mutex_t *repeat_mtx;
     80
     81        /** State of the structure (for checking before use).
     82         *
     83         * 0 - not initialized
     84         * 1 - initialized
     85         * -1 - ready for destroying
     86         */
     87        int initialized;
     88} usb_lgtch_ultrax_t;
     89
     90
     91/*----------------------------------------------------------------------------*/
     92/**
     93 * Default handler for IPC methods not handled by DDF.
     94 *
     95 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
     96 * assumes the caller is the console and thus it stores IPC phone to it for
     97 * later use by the driver to notify about key events.
     98 *
     99 * @param fun Device function handling the call.
     100 * @param icallid Call id.
     101 * @param icall Call data.
     102 */
     103static void default_connection_handler(ddf_fun_t *fun,
     104    ipc_callid_t icallid, ipc_call_t *icall)
     105{
     106        usb_log_debug(NAME " default_connection_handler()\n");
     107       
     108        sysarg_t method = IPC_GET_IMETHOD(*icall);
     109       
     110        usb_hid_dev_t *hid_dev = (usb_hid_dev_t *)fun->driver_data;
     111       
     112        if (hid_dev == NULL || hid_dev->data == NULL) {
     113                async_answer_0(icallid, EINVAL);
     114                return;
     115        }
     116       
     117        assert(hid_dev != NULL);
     118        assert(hid_dev->data != NULL);
     119        usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)hid_dev->data;
     120
     121        if (method == IPC_M_CONNECT_TO_ME) {
     122                int callback = IPC_GET_ARG5(*icall);
     123
     124                if (lgtch_dev->console_phone != -1) {
     125                        async_answer_0(icallid, ELIMIT);
     126                        return;
     127                }
     128
     129                lgtch_dev->console_phone = callback;
     130                usb_log_debug(NAME " Saved phone to console: %d\n", callback);
     131                async_answer_0(icallid, EOK);
     132                return;
     133        }
     134       
     135        async_answer_0(icallid, EINVAL);
     136}
     137
     138/*----------------------------------------------------------------------------*/
     139
     140static ddf_dev_ops_t lgtch_ultrax_ops = {
     141        .default_handler = default_connection_handler
    55142};
    56143
    57144/*----------------------------------------------------------------------------*/
    58145
    59 static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
    60     uint8_t report_id, void *arg)
    61 {
    62         // TODO: checks
    63        
    64         usb_log_debug(NAME " Got keys from parser (report id: %u): %s\n",
    65             report_id, usb_debug_str_buffer(key_codes, count, 0));
     146//static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
     147//    uint8_t report_id, void *arg);
     148
     149//static const usb_hid_report_in_callbacks_t usb_lgtch_parser_callbacks = {
     150//      .keyboard = usb_lgtch_process_keycodes
     151//};
     152
     153///*----------------------------------------------------------------------------*/
     154
     155//static void usb_lgtch_process_keycodes(const uint8_t *key_codes, size_t count,
     156//    uint8_t report_id, void *arg)
     157//{
     158//      // TODO: checks
     159       
     160//      usb_log_debug(NAME " Got keys from parser (report id: %u): %s\n",
     161//          report_id, usb_debug_str_buffer(key_codes, count, 0));
     162//}
     163
     164/*----------------------------------------------------------------------------*/
     165/**
     166 * Processes key events.
     167 *
     168 * @note This function was copied from AT keyboard driver and modified to suit
     169 *       USB keyboard.
     170 *
     171 * @note Lock keys are not sent to the console, as they are completely handled
     172 *       in the driver. It may, however, be required later that the driver
     173 *       sends also these keys to application (otherwise it cannot use those
     174 *       keys at all).
     175 *
     176 * @param hid_dev
     177 * @param lgtch_dev
     178 * @param type Type of the event (press / release). Recognized values:
     179 *             KEY_PRESS, KEY_RELEASE
     180 * @param key Key code of the key according to HID Usage Tables.
     181 */
     182static void usb_lgtch_push_ev(usb_hid_dev_t *hid_dev, int type,
     183    unsigned int key)
     184{
     185        assert(hid_dev != NULL);
     186        assert(hid_dev->data != NULL);
     187       
     188        usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)hid_dev->data;
     189       
     190        console_event_t ev;
     191       
     192        ev.type = type;
     193        ev.key = key;
     194        ev.mods = 0;
     195
     196        ev.c = 0;
     197
     198        usb_log_debug2(NAME " Sending key %d to the console\n", ev.key);
     199        if (lgtch_dev->console_phone < 0) {
     200                usb_log_warning(
     201                    "Connection to console not ready, key discarded.\n");
     202                return;
     203        }
     204       
     205        async_msg_4(lgtch_dev->console_phone, KBD_EVENT, ev.type, ev.key,
     206            ev.mods, ev.c);
     207}
     208
     209/*----------------------------------------------------------------------------*/
     210
     211static void usb_lgtch_free(usb_lgtch_ultrax_t **lgtch_dev)
     212{
     213        if (lgtch_dev == NULL || *lgtch_dev == NULL) {
     214                return;
     215        }
     216       
     217        // hangup phone to the console
     218        async_hangup((*lgtch_dev)->console_phone);
     219       
     220//      if ((*lgtch_dev)->repeat_mtx != NULL) {
     221//              /* TODO: replace by some check and wait */
     222//              assert(!fibril_mutex_is_locked((*lgtch_dev)->repeat_mtx));
     223//              free((*lgtch_dev)->repeat_mtx);
     224//      }
     225       
     226        // free all buffers
     227        if ((*lgtch_dev)->keys != NULL) {
     228                free((*lgtch_dev)->keys);
     229        }
     230        if ((*lgtch_dev)->keys_old != NULL) {
     231                free((*lgtch_dev)->keys_old);
     232        }
     233
     234        free(*lgtch_dev);
     235        *lgtch_dev = NULL;
     236}
     237
     238/*----------------------------------------------------------------------------*/
     239
     240static int usb_lgtch_create_function(usb_hid_dev_t *hid_dev)
     241{
     242        /* Create the function exposed under /dev/devices. */
     243        ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed,
     244            NAME);
     245        if (fun == NULL) {
     246                usb_log_error("Could not create DDF function node.\n");
     247                return ENOMEM;
     248        }
     249       
     250        /*
     251         * Store the initialized HID device and HID ops
     252         * to the DDF function.
     253         */
     254        fun->ops = &lgtch_ultrax_ops;
     255        fun->driver_data = hid_dev;   // TODO: maybe change to hid_dev->data
     256       
     257        int rc = ddf_fun_bind(fun);
     258        if (rc != EOK) {
     259                usb_log_error("Could not bind DDF function: %s.\n",
     260                    str_error(rc));
     261                // TODO: Can / should I destroy the DDF function?
     262                ddf_fun_destroy(fun);
     263                return rc;
     264        }
     265       
     266        rc = ddf_fun_add_to_class(fun, "keyboard");
     267        if (rc != EOK) {
     268                usb_log_error(
     269                    "Could not add DDF function to class 'keyboard': %s.\n",
     270                    str_error(rc));
     271                // TODO: Can / should I destroy the DDF function?
     272                ddf_fun_destroy(fun);
     273                return rc;
     274        }
     275       
     276        return EOK;
     277}
     278
     279/*----------------------------------------------------------------------------*/
     280
     281int usb_lgtch_init(struct usb_hid_dev *hid_dev)
     282{
     283        if (hid_dev == NULL || hid_dev->usb_dev == NULL) {
     284                return EINVAL; /*! @todo Other return code? */
     285        }
     286       
     287        usb_log_debug(NAME " Initializing HID/lgtch_ultrax structure...\n");
     288       
     289        usb_lgtch_ultrax_t *lgtch_dev = (usb_lgtch_ultrax_t *)malloc(
     290            sizeof(usb_lgtch_ultrax_t));
     291        if (lgtch_dev == NULL) {
     292                return ENOMEM;
     293        }
     294       
     295        lgtch_dev->console_phone = -1;
     296       
     297        usb_hid_report_path_t *path = usb_hid_report_path();
     298        usb_hid_report_path_append_item(path, USB_HIDUT_PAGE_CONSUMER, 0);
     299       
     300        usb_hid_report_path_set_report_id(path, 1);
     301       
     302        lgtch_dev->key_count = usb_hid_report_input_length(
     303            hid_dev->report, path,
     304            USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY);
     305        usb_hid_report_path_free(path);
     306       
     307        usb_log_debug(NAME " Size of the input report: %zu\n",
     308            lgtch_dev->key_count);
     309       
     310        lgtch_dev->keys = (int32_t *)calloc(lgtch_dev->key_count,
     311            sizeof(int32_t));
     312       
     313        if (lgtch_dev->keys == NULL) {
     314                usb_log_fatal("No memory!\n");
     315                free(lgtch_dev);
     316                return ENOMEM;
     317        }
     318       
     319        lgtch_dev->keys_old =
     320                (int32_t *)calloc(lgtch_dev->key_count, sizeof(int32_t));
     321       
     322        if (lgtch_dev->keys_old == NULL) {
     323                usb_log_fatal("No memory!\n");
     324                free(lgtch_dev->keys);
     325                free(lgtch_dev);
     326                return ENOMEM;
     327        }
     328       
     329        /*! @todo Autorepeat */
     330       
     331        // save the KBD device structure into the HID device structure
     332        hid_dev->data = lgtch_dev;
     333       
     334        lgtch_dev->initialized = USB_LGTCH_STATUS_INITIALIZED;
     335        usb_log_debug(NAME " HID/lgtch_ultrax device structure initialized.\n");
     336       
     337        int rc = usb_lgtch_create_function(hid_dev);
     338        if (rc != EOK) {
     339                usb_lgtch_free(&lgtch_dev);
     340                return rc;
     341        }
     342       
     343        usb_log_debug(NAME " HID/lgtch_ultrax structure initialized.\n");
     344       
     345        return EOK;
     346}
     347
     348/*----------------------------------------------------------------------------*/
     349
     350void usb_lgtch_deinit(struct usb_hid_dev *hid_dev)
     351{
     352        if (hid_dev == NULL) {
     353                return;
     354        }
     355       
     356        if (hid_dev->data != NULL) {
     357                usb_lgtch_ultrax_t *lgtch_dev =
     358                    (usb_lgtch_ultrax_t *)hid_dev->data;
     359//              if (usb_kbd_is_initialized(kbd_dev)) {
     360//                      usb_kbd_mark_unusable(kbd_dev);
     361//              } else {
     362                        usb_lgtch_free(&lgtch_dev);
     363                        hid_dev->data = NULL;
     364//              }
     365        }
    66366}
    67367
     
    81381        usb_hid_report_path_t *path = usb_hid_report_path();
    82382        usb_hid_report_path_append_item(path, 0xc, 0);
    83         usb_hid_report_path_set_report_id(path, 1);
    84        
    85         int rc = usb_hid_parse_report(hid_dev->parser, buffer,
    86             buffer_size, path,
    87             USB_HID_PATH_COMPARE_END | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
    88             &usb_lgtch_parser_callbacks, hid_dev);
     383
     384        uint8_t report_id;
     385       
     386        int rc = usb_hid_parse_report(hid_dev->report, buffer, buffer_size,
     387            &report_id);
     388       
     389        if (rc != EOK) {
     390                usb_log_warning(NAME "Error in usb_hid_parse_report(): %s\n",
     391                    str_error(rc));
     392                return true;
     393        }
     394       
     395        usb_hid_report_path_set_report_id(path, report_id);
     396
     397        usb_hid_report_field_t *field = usb_hid_report_get_sibling(
     398            hid_dev->report, NULL, path, USB_HID_PATH_COMPARE_END
     399            | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
     400            USB_HID_REPORT_TYPE_INPUT);
     401       
     402        unsigned int key;
     403       
     404        /*! @todo Is this iterating OK if done multiple times?
     405         *  @todo The parsing is not OK
     406         */
     407        while (field != NULL) {
     408                usb_log_debug(NAME " KEY VALUE(%X) USAGE(%X)\n", field->value,
     409                    field->usage);
     410               
     411                key = usb_lgtch_map_usage(field->usage);
     412                usb_lgtch_push_ev(hid_dev, KEY_PRESS, key);
     413               
     414                field = usb_hid_report_get_sibling(
     415                    hid_dev->report, field, path, USB_HID_PATH_COMPARE_END
     416                    | USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY,
     417                    USB_HID_REPORT_TYPE_INPUT);
     418        }       
    89419
    90420        usb_hid_report_path_free(path);
    91        
    92         if (rc != EOK) {
    93                 usb_log_warning("Error in usb_hid_boot_keyboard_input_report():"
    94                     "%s\n", str_error(rc));
    95         }
    96421       
    97422        return true;
Note: See TracChangeset for help on using the changeset viewer.