]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2009 21:00:17 +0000 (13:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Nov 2009 21:00:17 +0000 (13:00 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: psmouse - remove unneeded '\n' from psmouse.proto parameter
  Input: atkbd - restore LED state at reconnect
  Input: force LED reset on resume
  Input: fix locking in memoryless force-feedback devices

drivers/input/ff-core.c
drivers/input/ff-memless.c
drivers/input/input.c
drivers/input/keyboard/atkbd.c
drivers/input/mouse/psmouse-base.c
include/linux/input.h

index 72c63e5dd630709ddffccf8dc945147857bf41ba..38df81fcdc3a90bdb4f812a02a4d064e6d657f2d 100644 (file)
@@ -337,16 +337,16 @@ int input_ff_create(struct input_dev *dev, int max_effects)
        dev->ff = ff;
        dev->flush = flush_effects;
        dev->event = input_ff_event;
-       set_bit(EV_FF, dev->evbit);
+       __set_bit(EV_FF, dev->evbit);
 
        /* Copy "true" bits into ff device bitmap */
        for (i = 0; i <= FF_MAX; i++)
                if (test_bit(i, dev->ffbit))
-                       set_bit(i, ff->ffbit);
+                       __set_bit(i, ff->ffbit);
 
        /* we can emulate RUMBLE with periodic effects */
        if (test_bit(FF_PERIODIC, ff->ffbit))
-               set_bit(FF_RUMBLE, dev->ffbit);
+               __set_bit(FF_RUMBLE, dev->ffbit);
 
        return 0;
 }
@@ -362,12 +362,14 @@ EXPORT_SYMBOL_GPL(input_ff_create);
  */
 void input_ff_destroy(struct input_dev *dev)
 {
-       clear_bit(EV_FF, dev->evbit);
-       if (dev->ff) {
-               if (dev->ff->destroy)
-                       dev->ff->destroy(dev->ff);
-               kfree(dev->ff->private);
-               kfree(dev->ff);
+       struct ff_device *ff = dev->ff;
+
+       __clear_bit(EV_FF, dev->evbit);
+       if (ff) {
+               if (ff->destroy)
+                       ff->destroy(ff);
+               kfree(ff->private);
+               kfree(ff);
                dev->ff = NULL;
        }
 }
index 2d1415e1683467ae55de53ba3fb273996ba7a795..b483b2995fa9918ad9cec432b37f0248517c45af 100644 (file)
@@ -61,7 +61,6 @@ struct ml_device {
        struct ml_effect_state states[FF_MEMLESS_EFFECTS];
        int gain;
        struct timer_list timer;
-       spinlock_t timer_lock;
        struct input_dev *dev;
 
        int (*play_effect)(struct input_dev *dev, void *data,
@@ -368,38 +367,38 @@ static void ml_effect_timer(unsigned long timer_data)
 {
        struct input_dev *dev = (struct input_dev *)timer_data;
        struct ml_device *ml = dev->ff->private;
+       unsigned long flags;
 
        debug("timer: updating effects");
 
-       spin_lock(&ml->timer_lock);
+       spin_lock_irqsave(&dev->event_lock, flags);
        ml_play_effects(ml);
-       spin_unlock(&ml->timer_lock);
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
+/*
+ * Sets requested gain for FF effects. Called with dev->event_lock held.
+ */
 static void ml_ff_set_gain(struct input_dev *dev, u16 gain)
 {
        struct ml_device *ml = dev->ff->private;
        int i;
 
-       spin_lock_bh(&ml->timer_lock);
-
        ml->gain = gain;
 
        for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
                __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags);
 
        ml_play_effects(ml);
-
-       spin_unlock_bh(&ml->timer_lock);
 }
 
+/*
+ * Start/stop specified FF effect. Called with dev->event_lock held.
+ */
 static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
 {
        struct ml_device *ml = dev->ff->private;
        struct ml_effect_state *state = &ml->states[effect_id];
-       unsigned long flags;
-
-       spin_lock_irqsave(&ml->timer_lock, flags);
 
        if (value > 0) {
                debug("initiated play");
@@ -425,8 +424,6 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
                ml_play_effects(ml);
        }
 
-       spin_unlock_irqrestore(&ml->timer_lock, flags);
-
        return 0;
 }
 
@@ -436,7 +433,7 @@ static int ml_ff_upload(struct input_dev *dev,
        struct ml_device *ml = dev->ff->private;
        struct ml_effect_state *state = &ml->states[effect->id];
 
-       spin_lock_bh(&ml->timer_lock);
+       spin_lock_irq(&dev->event_lock);
 
        if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
                __clear_bit(FF_EFFECT_PLAYING, &state->flags);
@@ -448,7 +445,7 @@ static int ml_ff_upload(struct input_dev *dev,
                ml_schedule_timer(ml);
        }
 
-       spin_unlock_bh(&ml->timer_lock);
+       spin_unlock_irq(&dev->event_lock);
 
        return 0;
 }
@@ -482,7 +479,6 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
        ml->private = data;
        ml->play_effect = play_effect;
        ml->gain = 0xffff;
-       spin_lock_init(&ml->timer_lock);
        setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
 
        set_bit(FF_GAIN, dev->ffbit);
index cc763c96fadadf0565048a2a897d0f6202d81f09..2266ecbfbc010789390c9a5ebb36b72d0960526e 100644 (file)
@@ -1292,17 +1292,24 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
        return 0;
 }
 
-#define INPUT_DO_TOGGLE(dev, type, bits, on)                   \
-       do {                                                    \
-               int i;                                          \
-               if (!test_bit(EV_##type, dev->evbit))           \
-                       break;                                  \
-               for (i = 0; i < type##_MAX; i++) {              \
-                       if (!test_bit(i, dev->bits##bit) ||     \
-                           !test_bit(i, dev->bits))            \
-                               continue;                       \
-                       dev->event(dev, EV_##type, i, on);      \
-               }                                               \
+#define INPUT_DO_TOGGLE(dev, type, bits, on)                           \
+       do {                                                            \
+               int i;                                                  \
+               bool active;                                            \
+                                                                       \
+               if (!test_bit(EV_##type, dev->evbit))                   \
+                       break;                                          \
+                                                                       \
+               for (i = 0; i < type##_MAX; i++) {                      \
+                       if (!test_bit(i, dev->bits##bit))               \
+                               continue;                               \
+                                                                       \
+                       active = test_bit(i, dev->bits);                \
+                       if (!active && !on)                             \
+                               continue;                               \
+                                                                       \
+                       dev->event(dev, EV_##type, i, on ? active : 0); \
+               }                                                       \
        } while (0)
 
 #ifdef CONFIG_PM
index 4452eabbee6d66f14482271c35943a3125721aa6..28e6110d1ff8a51c3eed113f49f6410a1db8784d 100644 (file)
@@ -1174,6 +1174,18 @@ static int atkbd_reconnect(struct serio *serio)
                        return -1;
 
                atkbd_activate(atkbd);
+
+               /*
+                * Restore LED state and repeat rate. While input core
+                * will do this for us at resume time reconnect may happen
+                * because user requested it via sysfs or simply because
+                * keyboard was unplugged and plugged in again so we need
+                * to do it ourselves here.
+                */
+               atkbd_set_leds(atkbd);
+               if (!atkbd->softrepeat)
+                       atkbd_set_repeat_rate(atkbd);
+
        }
 
        atkbd_enable(atkbd);
@@ -1422,6 +1434,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
 
                atkbd->dev = new_dev;
                atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
+               atkbd_reset_state(atkbd);
                atkbd_activate(atkbd);
                atkbd_set_keycode_table(atkbd);
                atkbd_set_device_attrs(atkbd);
index 690aed90543694e0c4d94cf6e8234bbef228843e..5bd64841bf1c393963f7076676aaa24f6b609387 100644 (file)
@@ -1673,7 +1673,7 @@ static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 {
        int type = *((unsigned int *)kp->arg);
 
-       return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
+       return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
 }
 
 static int __init psmouse_init(void)
index 0ccfc30cd40f7696e0b9e863272f82fb8e42e0f0..c2b1a7d244d918f9127aaf557b6127a2b12486c7 100644 (file)
@@ -1377,6 +1377,10 @@ extern struct class input_class;
  * methods; erase() is optional. set_gain() and set_autocenter() need
  * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
  * bits.
+ *
+ * Note that playback(), set_gain() and set_autocenter() are called with
+ * dev->event_lock spinlock held and interrupts off and thus may not
+ * sleep.
  */
 struct ff_device {
        int (*upload)(struct input_dev *dev, struct ff_effect *effect,