|
@@ -21,6 +21,9 @@
|
|
|
#define IR_TAB_MIN_SIZE 256
|
|
|
#define IR_TAB_MAX_SIZE 8192
|
|
|
|
|
|
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
|
|
|
+#define IR_KEYPRESS_TIMEOUT 250
|
|
|
+
|
|
|
/**
|
|
|
* ir_resize_table() - resizes a scancode table if necessary
|
|
|
* @rc_tab: the ir_scancode_table to resize
|
|
@@ -263,56 +266,124 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
|
|
|
|
|
|
/**
|
|
|
* ir_keyup() - generates input event to cleanup a key press
|
|
|
- * @input_dev: the struct input_dev descriptor of the device
|
|
|
+ * @ir: the struct ir_input_dev descriptor of the device
|
|
|
*
|
|
|
- * This routine is used by the input routines when a key is pressed at the
|
|
|
- * IR. It reports a keyup input event via input_report_key().
|
|
|
+ * This routine is used to signal that a key has been released on the
|
|
|
+ * remote control. It reports a keyup input event via input_report_key().
|
|
|
+ */
|
|
|
+static void ir_keyup(struct ir_input_dev *ir)
|
|
|
+{
|
|
|
+ if (!ir->keypressed)
|
|
|
+ return;
|
|
|
+
|
|
|
+ IR_dprintk(1, "keyup key 0x%04x\n", ir->last_keycode);
|
|
|
+ input_report_key(ir->input_dev, ir->last_keycode, 0);
|
|
|
+ input_sync(ir->input_dev);
|
|
|
+ ir->keypressed = false;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ir_timer_keyup() - generates a keyup event after a timeout
|
|
|
+ * @cookie: a pointer to struct ir_input_dev passed to setup_timer()
|
|
|
+ *
|
|
|
+ * This routine will generate a keyup event some time after a keydown event
|
|
|
+ * is generated when no further activity has been detected.
|
|
|
*/
|
|
|
-void ir_keyup(struct input_dev *dev)
|
|
|
+static void ir_timer_keyup(unsigned long cookie)
|
|
|
{
|
|
|
+ struct ir_input_dev *ir = (struct ir_input_dev *)cookie;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ir->keyup_jiffies is used to prevent a race condition if a
|
|
|
+ * hardware interrupt occurs at this point and the keyup timer
|
|
|
+ * event is moved further into the future as a result.
|
|
|
+ *
|
|
|
+ * The timer will then be reactivated and this function called
|
|
|
+ * again in the future. We need to exit gracefully in that case
|
|
|
+ * to allow the input subsystem to do its auto-repeat magic or
|
|
|
+ * a keyup event might follow immediately after the keydown.
|
|
|
+ */
|
|
|
+ spin_lock_irqsave(&ir->keylock, flags);
|
|
|
+ if (time_is_after_eq_jiffies(ir->keyup_jiffies))
|
|
|
+ ir_keyup(ir);
|
|
|
+ spin_unlock_irqrestore(&ir->keylock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ir_repeat() - notifies the IR core that a key is still pressed
|
|
|
+ * @dev: the struct input_dev descriptor of the device
|
|
|
+ *
|
|
|
+ * This routine is used by IR decoders when a repeat message which does
|
|
|
+ * not include the necessary bits to reproduce the scancode has been
|
|
|
+ * received.
|
|
|
+ */
|
|
|
+void ir_repeat(struct input_dev *dev)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
struct ir_input_dev *ir = input_get_drvdata(dev);
|
|
|
|
|
|
+ spin_lock_irqsave(&ir->keylock, flags);
|
|
|
+
|
|
|
if (!ir->keypressed)
|
|
|
- return;
|
|
|
+ goto out;
|
|
|
|
|
|
- IR_dprintk(1, "keyup key 0x%04x\n", ir->keycode);
|
|
|
- input_report_key(dev, ir->keycode, 0);
|
|
|
- input_sync(dev);
|
|
|
- ir->keypressed = 0;
|
|
|
+ ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
|
|
|
+ mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
|
|
|
+
|
|
|
+out:
|
|
|
+ spin_unlock_irqrestore(&ir->keylock, flags);
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(ir_keyup);
|
|
|
+EXPORT_SYMBOL_GPL(ir_repeat);
|
|
|
|
|
|
/**
|
|
|
* ir_keydown() - generates input event for a key press
|
|
|
- * @input_dev: the struct input_dev descriptor of the device
|
|
|
- * @scancode: the scancode that we're seeking
|
|
|
+ * @dev: the struct input_dev descriptor of the device
|
|
|
+ * @scancode: the scancode that we're seeking
|
|
|
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
|
|
|
+ * support toggle values, this should be set to zero)
|
|
|
*
|
|
|
* This routine is used by the input routines when a key is pressed at the
|
|
|
* IR. It gets the keycode for a scancode and reports an input event via
|
|
|
* input_report_key().
|
|
|
*/
|
|
|
-void ir_keydown(struct input_dev *dev, int scancode)
|
|
|
+void ir_keydown(struct input_dev *dev, int scancode, u8 toggle)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
struct ir_input_dev *ir = input_get_drvdata(dev);
|
|
|
|
|
|
u32 keycode = ir_g_keycode_from_table(dev, scancode);
|
|
|
|
|
|
- /* If already sent a keydown, do a keyup */
|
|
|
- if (ir->keypressed)
|
|
|
- ir_keyup(dev);
|
|
|
+ spin_lock_irqsave(&ir->keylock, flags);
|
|
|
|
|
|
- if (KEY_RESERVED == keycode)
|
|
|
- return;
|
|
|
+ /* Repeat event? */
|
|
|
+ if (ir->keypressed &&
|
|
|
+ ir->last_scancode == scancode &&
|
|
|
+ ir->last_toggle == toggle)
|
|
|
+ goto set_timer;
|
|
|
|
|
|
- ir->keycode = keycode;
|
|
|
- ir->keypressed = 1;
|
|
|
+ /* Release old keypress */
|
|
|
+ ir_keyup(ir);
|
|
|
|
|
|
- IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
|
|
|
- dev->name, keycode, scancode);
|
|
|
+ ir->last_scancode = scancode;
|
|
|
+ ir->last_toggle = toggle;
|
|
|
+ ir->last_keycode = keycode;
|
|
|
+
|
|
|
+ if (keycode == KEY_RESERVED)
|
|
|
+ goto out;
|
|
|
|
|
|
- input_report_key(dev, ir->keycode, 1);
|
|
|
+ /* Register a keypress */
|
|
|
+ ir->keypressed = true;
|
|
|
+ IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
|
|
|
+ dev->name, keycode, scancode);
|
|
|
+ input_report_key(dev, ir->last_keycode, 1);
|
|
|
input_sync(dev);
|
|
|
|
|
|
+set_timer:
|
|
|
+ ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
|
|
|
+ mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
|
|
|
+out:
|
|
|
+ spin_unlock_irqrestore(&ir->keylock, flags);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(ir_keydown);
|
|
|
|
|
@@ -365,8 +436,12 @@ int __ir_input_register(struct input_dev *input_dev,
|
|
|
input_dev->getkeycode = ir_getkeycode;
|
|
|
input_dev->setkeycode = ir_setkeycode;
|
|
|
input_set_drvdata(input_dev, ir_dev);
|
|
|
+ ir_dev->input_dev = input_dev;
|
|
|
|
|
|
spin_lock_init(&ir_dev->rc_tab.lock);
|
|
|
+ spin_lock_init(&ir_dev->keylock);
|
|
|
+ setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
|
|
|
+
|
|
|
ir_dev->rc_tab.name = rc_tab->name;
|
|
|
ir_dev->rc_tab.ir_type = rc_tab->ir_type;
|
|
|
ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
|
|
@@ -383,6 +458,8 @@ int __ir_input_register(struct input_dev *input_dev,
|
|
|
ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
|
|
|
|
|
|
set_bit(EV_KEY, input_dev->evbit);
|
|
|
+ set_bit(EV_REP, input_dev->evbit);
|
|
|
+
|
|
|
if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
|
|
|
rc = -ENOMEM;
|
|
|
goto out_table;
|
|
@@ -428,7 +505,7 @@ void ir_input_unregister(struct input_dev *dev)
|
|
|
return;
|
|
|
|
|
|
IR_dprintk(1, "Freed keycode table\n");
|
|
|
-
|
|
|
+ del_timer_sync(&ir_dev->timer_keyup);
|
|
|
rc_tab = &ir_dev->rc_tab;
|
|
|
rc_tab->size = 0;
|
|
|
kfree(rc_tab->scan);
|