Skip to content

Commit

Permalink
Input: cm109 - fix handling of volume and mute buttons
Browse files Browse the repository at this point in the history
The CM109 driver reported key press events of volume up / down and
record / playback mute buttons, but no release events. Report those events
properly by handling volume and mute keys seperately. For the record and
playback mute buttons, only presses are registered by the CM109, therefore
simulate press-n-release. This fixes the volume control buttons of various
USB headsets.

Signed-off-by: Florian Euchner <florian.euchner@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Florian Euchner authored and Dmitry Torokhov committed May 4, 2016
1 parent 5ad629a commit c90a0f0
Showing 1 changed file with 30 additions and 7 deletions.
37 changes: 30 additions & 7 deletions drivers/input/misc/cm109.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ enum {

BUZZER_ON = 1 << 5,

/* up to 256 normal keys, up to 16 special keys */
KEYMAP_SIZE = 256 + 16,
/* up to 256 normal keys, up to 15 special key combinations */
KEYMAP_SIZE = 256 + 15,
};

/* CM109 protocol packet */
Expand Down Expand Up @@ -139,7 +139,7 @@ static unsigned short special_keymap(int code)
{
if (code > 0xff) {
switch (code - 0xff) {
case RECORD_MUTE: return KEY_MUTE;
case RECORD_MUTE: return KEY_MICMUTE;
case PLAYBACK_MUTE: return KEY_MUTE;
case VOLUME_DOWN: return KEY_VOLUMEDOWN;
case VOLUME_UP: return KEY_VOLUMEUP;
Expand Down Expand Up @@ -312,6 +312,32 @@ static void report_key(struct cm109_dev *dev, int key)
input_sync(idev);
}

/*
* Converts data of special key presses (volume, mute) into events
* for the input subsystem, sends press-n-release for mute keys.
*/
static void cm109_report_special(struct cm109_dev *dev)
{
static const u8 autorelease = RECORD_MUTE | PLAYBACK_MUTE;
struct input_dev *idev = dev->idev;
u8 data = dev->irq_data->byte[HID_IR0];
unsigned short keycode;
int i;

for (i = 0; i < 4; i++) {
keycode = dev->keymap[0xff + BIT(i)];
if (keycode == KEY_RESERVED)
continue;

input_report_key(idev, keycode, data & BIT(i));
if (data & autorelease & BIT(i)) {
input_sync(idev);
input_report_key(idev, keycode, 0);
}
}
input_sync(idev);
}

/******************************************************************************
* CM109 usb communication interface
*****************************************************************************/
Expand Down Expand Up @@ -357,10 +383,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
}

/* Special keys */
if (dev->irq_data->byte[HID_IR0] & 0x0f) {
const int code = (dev->irq_data->byte[HID_IR0] & 0x0f);
report_key(dev, dev->keymap[0xff + code]);
}
cm109_report_special(dev);

/* Scan key column */
if (dev->keybit == 0xf) {
Expand Down

0 comments on commit c90a0f0

Please sign in to comment.