diff options
Diffstat (limited to 'drivers/input/misc/cm109.c')
-rw-r--r-- | drivers/input/misc/cm109.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 9365535ba..9cc6d057c 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -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 */ @@ -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; @@ -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 *****************************************************************************/ @@ -340,6 +366,7 @@ static void cm109_urb_irq_callback(struct urb *urb) struct cm109_dev *dev = urb->context; const int status = urb->status; int error; + unsigned long flags; dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n", dev->irq_data->byte[0], @@ -357,10 +384,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) { @@ -381,7 +405,7 @@ static void cm109_urb_irq_callback(struct urb *urb) out: - spin_lock(&dev->ctl_submit_lock); + spin_lock_irqsave(&dev->ctl_submit_lock, flags); dev->irq_urb_pending = 0; @@ -405,7 +429,7 @@ static void cm109_urb_irq_callback(struct urb *urb) __func__, error); } - spin_unlock(&dev->ctl_submit_lock); + spin_unlock_irqrestore(&dev->ctl_submit_lock, flags); } static void cm109_urb_ctl_callback(struct urb *urb) @@ -413,6 +437,7 @@ static void cm109_urb_ctl_callback(struct urb *urb) struct cm109_dev *dev = urb->context; const int status = urb->status; int error; + unsigned long flags; dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n", dev->ctl_data->byte[0], @@ -427,7 +452,7 @@ static void cm109_urb_ctl_callback(struct urb *urb) __func__, status); } - spin_lock(&dev->ctl_submit_lock); + spin_lock_irqsave(&dev->ctl_submit_lock, flags); dev->ctl_urb_pending = 0; @@ -448,7 +473,7 @@ static void cm109_urb_ctl_callback(struct urb *urb) } } - spin_unlock(&dev->ctl_submit_lock); + spin_unlock_irqrestore(&dev->ctl_submit_lock, flags); } static void cm109_toggle_buzzer_async(struct cm109_dev *dev) |