Merge commit 'v2.6.32-rc5' into for-linus
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 3 Nov 2009 06:10:07 +0000 (22:10 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 3 Nov 2009 06:10:07 +0000 (22:10 -0800)
1  2 
drivers/input/input.c
drivers/input/keyboard/atkbd.c

diff --combined drivers/input/input.c
@@@ -17,6 -17,7 +17,7 @@@
  #include <linux/random.h>
  #include <linux/major.h>
  #include <linux/proc_fs.h>
+ #include <linux/sched.h>
  #include <linux/seq_file.h>
  #include <linux/poll.h>
  #include <linux/device.h>
@@@ -781,29 -782,10 +782,29 @@@ static unsigned int input_proc_devices_
        return 0;
  }
  
 +union input_seq_state {
 +      struct {
 +              unsigned short pos;
 +              bool mutex_acquired;
 +      };
 +      void *p;
 +};
 +
  static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
  {
 -      if (mutex_lock_interruptible(&input_mutex))
 -              return NULL;
 +      union input_seq_state *state = (union input_seq_state *)&seq->private;
 +      int error;
 +
 +      /* We need to fit into seq->private pointer */
 +      BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
 +
 +      error = mutex_lock_interruptible(&input_mutex);
 +      if (error) {
 +              state->mutex_acquired = false;
 +              return ERR_PTR(error);
 +      }
 +
 +      state->mutex_acquired = true;
  
        return seq_list_start(&input_dev_list, *pos);
  }
@@@ -813,12 -795,9 +814,12 @@@ static void *input_devices_seq_next(str
        return seq_list_next(v, &input_dev_list, pos);
  }
  
 -static void input_devices_seq_stop(struct seq_file *seq, void *v)
 +static void input_seq_stop(struct seq_file *seq, void *v)
  {
 -      mutex_unlock(&input_mutex);
 +      union input_seq_state *state = (union input_seq_state *)&seq->private;
 +
 +      if (state->mutex_acquired)
 +              mutex_unlock(&input_mutex);
  }
  
  static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
@@@ -882,7 -861,7 +883,7 @@@ static int input_devices_seq_show(struc
  static const struct seq_operations input_devices_seq_ops = {
        .start  = input_devices_seq_start,
        .next   = input_devices_seq_next,
 -      .stop   = input_devices_seq_stop,
 +      .stop   = input_seq_stop,
        .show   = input_devices_seq_show,
  };
  
@@@ -902,49 -881,40 +903,49 @@@ static const struct file_operations inp
  
  static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
  {
 -      if (mutex_lock_interruptible(&input_mutex))
 -              return NULL;
 +      union input_seq_state *state = (union input_seq_state *)&seq->private;
 +      int error;
 +
 +      /* We need to fit into seq->private pointer */
 +      BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
 +
 +      error = mutex_lock_interruptible(&input_mutex);
 +      if (error) {
 +              state->mutex_acquired = false;
 +              return ERR_PTR(error);
 +      }
 +
 +      state->mutex_acquired = true;
 +      state->pos = *pos;
  
 -      seq->private = (void *)(unsigned long)*pos;
        return seq_list_start(&input_handler_list, *pos);
  }
  
  static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
 -      seq->private = (void *)(unsigned long)(*pos + 1);
 -      return seq_list_next(v, &input_handler_list, pos);
 -}
 +      union input_seq_state *state = (union input_seq_state *)&seq->private;
  
 -static void input_handlers_seq_stop(struct seq_file *seq, void *v)
 -{
 -      mutex_unlock(&input_mutex);
 +      state->pos = *pos + 1;
 +      return seq_list_next(v, &input_handler_list, pos);
  }
  
  static int input_handlers_seq_show(struct seq_file *seq, void *v)
  {
        struct input_handler *handler = container_of(v, struct input_handler, node);
 +      union input_seq_state *state = (union input_seq_state *)&seq->private;
  
 -      seq_printf(seq, "N: Number=%ld Name=%s",
 -                 (unsigned long)seq->private, handler->name);
 +      seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
        if (handler->fops)
                seq_printf(seq, " Minor=%d", handler->minor);
        seq_putc(seq, '\n');
  
        return 0;
  }
 +
  static const struct seq_operations input_handlers_seq_ops = {
        .start  = input_handlers_seq_start,
        .next   = input_handlers_seq_next,
 -      .stop   = input_handlers_seq_stop,
 +      .stop   = input_seq_stop,
        .show   = input_handlers_seq_show,
  };
  
@@@ -1176,7 -1146,7 +1177,7 @@@ static struct attribute_group input_dev
        .attrs  = input_dev_caps_attrs,
  };
  
- static struct attribute_group *input_dev_attr_groups[] = {
+ static const struct attribute_group *input_dev_attr_groups[] = {
        &input_dev_attr_group,
        &input_dev_id_attr_group,
        &input_dev_caps_attr_group,
@@@ -1304,6 -1274,7 +1305,7 @@@ static int input_dev_uevent(struct devi
                }                                               \
        } while (0)
  
+ #ifdef CONFIG_PM
  static void input_dev_reset(struct input_dev *dev, bool activate)
  {
        if (!dev->event)
        }
  }
  
- #ifdef CONFIG_PM
  static int input_dev_suspend(struct device *dev)
  {
        struct input_dev *input_dev = to_input_dev(dev);
@@@ -1358,14 -1328,14 +1359,14 @@@ static struct device_type input_dev_typ
  #endif
  };
  
- static char *input_nodename(struct device *dev)
+ static char *input_devnode(struct device *dev, mode_t *mode)
  {
        return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
  }
  
  struct class input_class = {
        .name           = "input",
-       .nodename       = input_nodename,
+       .devnode        = input_devnode,
  };
  EXPORT_SYMBOL_GPL(input_class);
  
@@@ -229,11 -229,10 +229,11 @@@ struct atkbd 
  };
  
  /*
-  * System-specific ketymap fixup routine
+  * System-specific keymap fixup routine
   */
  static void (*atkbd_platform_fixup)(struct atkbd *, const void *data);
  static void *atkbd_platform_fixup_data;
 +static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int);
  
  static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
                                ssize_t (*handler)(struct atkbd *, char *));
@@@ -394,9 -393,6 +394,9 @@@ static irqreturn_t atkbd_interrupt(stru
  
        input_event(dev, EV_MSC, MSC_RAW, code);
  
 +      if (atkbd_platform_scancode_fixup)
 +              code = atkbd_platform_scancode_fixup(atkbd, code);
 +
        if (atkbd->translated) {
  
                if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
@@@ -578,22 -574,11 +578,22 @@@ static void atkbd_event_work(struct wor
  
        mutex_lock(&atkbd->event_mutex);
  
 -      if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
 -              atkbd_set_leds(atkbd);
 +      if (!atkbd->enabled) {
 +              /*
 +               * Serio ports are resumed asynchronously so while driver core
 +               * thinks that device is already fully operational in reality
 +               * it may not be ready yet. In this case we need to keep
 +               * rescheduling till reconnect completes.
 +               */
 +              schedule_delayed_work(&atkbd->event_work,
 +                                      msecs_to_jiffies(100));
 +      } else {
 +              if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
 +                      atkbd_set_leds(atkbd);
  
 -      if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
 -              atkbd_set_repeat_rate(atkbd);
 +              if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
 +                      atkbd_set_repeat_rate(atkbd);
 +      }
  
        mutex_unlock(&atkbd->event_mutex);
  }
@@@ -785,30 -770,6 +785,30 @@@ static int atkbd_select_set(struct atkb
        return 3;
  }
  
 +static int atkbd_reset_state(struct atkbd *atkbd)
 +{
 +        struct ps2dev *ps2dev = &atkbd->ps2dev;
 +      unsigned char param[1];
 +
 +/*
 + * Set the LEDs to a predefined state (all off).
 + */
 +
 +      param[0] = 0;
 +      if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
 +              return -1;
 +
 +/*
 + * Set autorepeat to fastest possible.
 + */
 +
 +      param[0] = 0;
 +      if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
 +              return -1;
 +
 +      return 0;
 +}
 +
  static int atkbd_activate(struct atkbd *atkbd)
  {
        struct ps2dev *ps2dev = &atkbd->ps2dev;
@@@ -890,6 -851,29 +890,6 @@@ static unsigned int atkbd_hp_forced_rel
        0x94, -1U
  };
  
 -/*
 - * Inventec system with broken key release on volume keys
 - */
 -static unsigned int atkbd_inventec_forced_release_keys[] = {
 -      0xae, 0xb0, -1U
 -};
 -
 -/*
 - * Perform fixup for HP Pavilion ZV6100 laptop that doesn't generate release
 - * for its volume buttons
 - */
 -static unsigned int atkbd_hp_zv6100_forced_release_keys[] = {
 -      0xae, 0xb0, -1U
 -};
 -
 -/*
 - * Perform fixup for HP (Compaq) Presario R4000 R4100 R4200 that don't generate
 - * release for their volume buttons
 - */
 -static unsigned int atkbd_hp_r4000_forced_release_keys[] = {
 -      0xae, 0xb0, -1U
 -};
 -
  /*
   * Samsung NC10,NC20 with Fn+F? key release not working
   */
@@@ -897,6 -881,14 +897,6 @@@ static unsigned int atkbd_samsung_force
        0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
  };
  
 -/*
 - * The volume up and volume down special keys on a Fujitsu Amilo PA 1510 laptop
 - * do not generate release events so we have to do it ourselves.
 - */
 -static unsigned int atkbd_amilo_pa1510_forced_release_keys[] = {
 -      0xb0, 0xae, -1U
 -};
 -
  /*
   * Amilo Pi 3525 key release for Fn+Volume keys not working
   */
@@@ -918,30 -910,6 +918,30 @@@ static unsigned int atkdb_soltech_ta12_
        0xa0, 0xae, 0xb0, -1U
  };
  
 +/*
 + * Many notebooks don't send key release event for volume up/down
 + * keys, with key list below common among them
 + */
 +static unsigned int atkbd_volume_forced_release_keys[] = {
 +      0xae, 0xb0, -1U
 +};
 +
 +/*
 + * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas
 + * they should be generating e4-e6 (0x80 | code).
 + */
 +static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
 +                                                  unsigned int code)
 +{
 +      if (atkbd->translated && atkbd->emul == 1 &&
 +          (code == 0x64 || code == 0x65 || code == 0x66)) {
 +              atkbd->emul = 0;
 +              code |= 0x80;
 +      }
 +
 +      return code;
 +}
 +
  /*
   * atkbd_set_keycode_table() initializes keyboard's keycode table
   * according to the selected scancode set
@@@ -1119,7 -1087,6 +1119,7 @@@ static int atkbd_connect(struct serio *
                }
  
                atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
 +              atkbd_reset_state(atkbd);
                atkbd_activate(atkbd);
  
        } else {
@@@ -1300,7 -1267,6 +1300,7 @@@ static ssize_t atkbd_set_extra(struct a
  
                atkbd->dev = new_dev;
                atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
 +              atkbd_reset_state(atkbd);
                atkbd_activate(atkbd);
                atkbd_set_keycode_table(atkbd);
                atkbd_set_device_attrs(atkbd);
@@@ -1547,13 -1513,6 +1547,13 @@@ static int __init atkbd_setup_forced_re
        return 0;
  }
  
 +static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
 +{
 +      atkbd_platform_scancode_fixup = id->driver_data;
 +
 +      return 0;
 +}
 +
  static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
        {
                .ident = "Dell Laptop",
                        DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_hp_zv6100_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "HP Presario R4000",
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_hp_r4000_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "HP Presario R4100",
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_hp_r4000_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "HP Presario R4200",
                        DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_hp_r4000_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "Inventec Symphony",
                        DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_inventec_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "Samsung NC10",
                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"),
                },
                .callback = atkbd_setup_forced_release,
 -              .driver_data = atkbd_amilo_pa1510_forced_release_keys,
 +              .driver_data = atkbd_volume_forced_release_keys,
        },
        {
                .ident = "Fujitsu Amilo Pi 3525",
                .callback = atkbd_setup_forced_release,
                .driver_data = atkdb_soltech_ta12_forced_release_keys,
        },
 +      {
 +              .ident = "OQO Model 01+",
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
 +              },
 +              .callback = atkbd_setup_scancode_fixup,
 +              .driver_data = atkbd_oqo_01plus_scancode_fixup,
 +      },
        { }
  };