HelenOS sources

root/uspace/drv/hid/usbhid/kbd/kbdrepeat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usb_kbd_repeat_loop
  2. usb_kbd_repeat_fibril
  3. usb_kbd_repeat_start
  4. usb_kbd_repeat_stop

/*
 * Copyright (c) 2011 Lubos Slovak
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup drvusbhid
 * @{
 */
/**
 * @file
 * USB HID keyboard autorepeat facilities
 */

#include <fibril_synch.h>
#include <io/kbd_event.h>
#include <io/keycode.h>
#include <errno.h>

#include <usb/debug.h>

#include "kbdrepeat.h"
#include "kbddev.h"

/**
 * Main loop handling the auto-repeat of keys.
 *
 * This functions periodically checks if there is some key to be auto-repeated.
 *
 * If a new key is to be repeated, it uses the delay before first repeat stored
 * in the keyboard structure to wait until the key has to start repeating.
 *
 * If the same key is still pressed, it uses the delay between repeats stored
 * in the keyboard structure to wait until the key should be repeated.
 *
 * If the currently repeated key is not pressed any more (
 * usb_kbd_repeat_stop() was called), it stops repeating it and starts
 * checking again.
 *
 * @note For accessing the keyboard device auto-repeat information a fibril
 *       mutex (repeat_mtx) from the @a kbd structure is used.
 *
 * @param kbd Keyboard device structure.
 */
static void usb_kbd_repeat_loop(usb_kbd_t *kbd)
{
        unsigned int delay = 0;

        usb_log_debug("Starting autorepeat loop.");

        while (true) {
                /* Check if the kbd structure is usable. */
                if (!usb_kbd_is_initialized(kbd)) {
                        usb_log_warning("kbd not ready, exiting autorepeat.");
                        return;
                }

                fibril_mutex_lock(&kbd->repeat_mtx);

                if (kbd->repeat.key_new > 0) {
                        if (kbd->repeat.key_new == kbd->repeat.key_repeated) {
                                usb_log_debug2("Repeating key: %u.",
                                    kbd->repeat.key_repeated);
                                usb_kbd_push_ev(kbd, KEY_PRESS,
                                    kbd->repeat.key_repeated);
                                delay = kbd->repeat.delay_between;
                        } else {
                                usb_log_debug2("New key to repeat: %u.",
                                    kbd->repeat.key_new);
                                kbd->repeat.key_repeated = kbd->repeat.key_new;
                                delay = kbd->repeat.delay_before;
                        }
                } else {
                        if (kbd->repeat.key_repeated > 0) {
                                usb_log_debug2("Stopping to repeat key: %u.",
                                    kbd->repeat.key_repeated);
                                kbd->repeat.key_repeated = 0;
                        }
                        delay = CHECK_DELAY;
                }
                fibril_mutex_unlock(&kbd->repeat_mtx);
                fibril_usleep(delay);
        }
}

/**
 * Main routine to be executed by a fibril for handling auto-repeat.
 *
 * Starts the loop for checking changes in auto-repeat.
 *
 * @param arg User-specified argument. Expects pointer to the keyboard device
 *            structure representing the keyboard.
 *
 * @retval EOK if the routine has finished.
 * @retval EINVAL if no argument is supplied.
 */
errno_t usb_kbd_repeat_fibril(void *arg)
{
        usb_log_debug("Autorepeat fibril spawned.");

        if (arg == NULL) {
                usb_log_error("No device!");
                return EINVAL;
        }

        usb_kbd_t *kbd = arg;

        usb_kbd_repeat_loop(kbd);

        return EOK;
}

/**
 * Start repeating particular key.
 *
 * @note Only one key is repeated at any time, so calling this function
 *       effectively cancels auto-repeat of the current repeated key (if any)
 *       and 'schedules' another key for auto-repeat.
 *
 * @param kbd Keyboard device structure.
 * @param key Key to start repeating.
 */
void usb_kbd_repeat_start(usb_kbd_t *kbd, unsigned int key)
{
        fibril_mutex_lock(&kbd->repeat_mtx);
        kbd->repeat.key_new = key;
        fibril_mutex_unlock(&kbd->repeat_mtx);
}

/**
 * Stop repeating particular key.
 *
 * @note Only one key is repeated at any time, but this function may be called
 *       even with key that is not currently repeated (in that case nothing
 *       happens).
 *
 * @param kbd Keyboard device structure.
 * @param key Key to stop repeating.
 */
void usb_kbd_repeat_stop(usb_kbd_t *kbd, unsigned int key)
{
        fibril_mutex_lock(&kbd->repeat_mtx);
        if (key == kbd->repeat.key_new) {
                kbd->repeat.key_new = 0;
        }
        fibril_mutex_unlock(&kbd->repeat_mtx);
}
/**
 * @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub