aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Euchner <florian.euchner@gmail.com>2016-05-04 18:59:18 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-05-04 19:00:54 -0400
commitc90a0f08fedc57e2b8ff871cc036cdbdde683de4 (patch)
treeb767f3e6ef1a3142d1f82716e6e5d883273d576c
parent5ad629a82de37cbcaffc17861e07b5ec68ab75f4 (diff)
Input: cm109 - fix handling of volume and mute buttons
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>
-rw-r--r--drivers/input/misc/cm109.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 9365535ba7f1..ee1bedd7c54c 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -76,8 +76,8 @@ enum {
76 76
77 BUZZER_ON = 1 << 5, 77 BUZZER_ON = 1 << 5,
78 78
79 /* up to 256 normal keys, up to 16 special keys */ 79 /* up to 256 normal keys, up to 15 special key combinations */
80 KEYMAP_SIZE = 256 + 16, 80 KEYMAP_SIZE = 256 + 15,
81}; 81};
82 82
83/* CM109 protocol packet */ 83/* CM109 protocol packet */
@@ -139,7 +139,7 @@ static unsigned short special_keymap(int code)
139{ 139{
140 if (code > 0xff) { 140 if (code > 0xff) {
141 switch (code - 0xff) { 141 switch (code - 0xff) {
142 case RECORD_MUTE: return KEY_MUTE; 142 case RECORD_MUTE: return KEY_MICMUTE;
143 case PLAYBACK_MUTE: return KEY_MUTE; 143 case PLAYBACK_MUTE: return KEY_MUTE;
144 case VOLUME_DOWN: return KEY_VOLUMEDOWN; 144 case VOLUME_DOWN: return KEY_VOLUMEDOWN;
145 case VOLUME_UP: return KEY_VOLUMEUP; 145 case VOLUME_UP: return KEY_VOLUMEUP;
@@ -312,6 +312,32 @@ static void report_key(struct cm109_dev *dev, int key)
312 input_sync(idev); 312 input_sync(idev);
313} 313}
314 314
315/*
316 * Converts data of special key presses (volume, mute) into events
317 * for the input subsystem, sends press-n-release for mute keys.
318 */
319static void cm109_report_special(struct cm109_dev *dev)
320{
321 static const u8 autorelease = RECORD_MUTE | PLAYBACK_MUTE;
322 struct input_dev *idev = dev->idev;
323 u8 data = dev->irq_data->byte[HID_IR0];
324 unsigned short keycode;
325 int i;
326
327 for (i = 0; i < 4; i++) {
328 keycode = dev->keymap[0xff + BIT(i)];
329 if (keycode == KEY_RESERVED)
330 continue;
331
332 input_report_key(idev, keycode, data & BIT(i));
333 if (data & autorelease & BIT(i)) {
334 input_sync(idev);
335 input_report_key(idev, keycode, 0);
336 }
337 }
338 input_sync(idev);
339}
340
315/****************************************************************************** 341/******************************************************************************
316 * CM109 usb communication interface 342 * CM109 usb communication interface
317 *****************************************************************************/ 343 *****************************************************************************/
@@ -357,10 +383,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
357 } 383 }
358 384
359 /* Special keys */ 385 /* Special keys */
360 if (dev->irq_data->byte[HID_IR0] & 0x0f) { 386 cm109_report_special(dev);
361 const int code = (dev->irq_data->byte[HID_IR0] & 0x0f);
362 report_key(dev, dev->keymap[0xff + code]);
363 }
364 387
365 /* Scan key column */ 388 /* Scan key column */
366 if (dev->keybit == 0xf) { 389 if (dev->keybit == 0xf) {