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 */
 {
        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;
        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
  *****************************************************************************/
        }
 
        /* 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) {