#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/rcupdate.h>
+#include <linux/smp_lock.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
/*
* Pass event through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled. Because of that we
- * do not need to use rcu_read_lock() here although we are using RCU
- * to access handle list. Note that because of that write-side uses
- * synchronize_sched() instead of synchronize_ru().
+ * dev->event_lock held and interrupts disabled.
*/
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
- struct input_handle *handle = rcu_dereference(dev->grab);
+ struct input_handle *handle;
+
+ rcu_read_lock();
+ handle = rcu_dereference(dev->grab);
if (handle)
handle->handler->event(handle, type, code, value);
else
if (handle->open)
handle->handler->event(handle,
type, code, value);
+ rcu_read_unlock();
}
/*
if (value >= 0)
disposition = INPUT_PASS_TO_ALL;
break;
+
+ case EV_PWR:
+ disposition = INPUT_PASS_TO_ALL;
+ break;
}
- if (type != EV_SYN)
+ if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
dev->sync = 0;
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
if (is_event_supported(type, dev->evbit, EV_MAX)) {
spin_lock_irqsave(&dev->event_lock, flags);
+ rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);
+ rcu_read_unlock();
spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
rcu_assign_pointer(dev->grab, handle);
- /*
- * Not using synchronize_rcu() because read-side is protected
- * by a spinlock with interrupts off instead of rcu_read_lock().
- */
- synchronize_sched();
+ synchronize_rcu();
out:
mutex_unlock(&dev->mutex);
if (dev->grab == handle) {
rcu_assign_pointer(dev->grab, NULL);
/* Make sure input_pass_event() notices that grab is gone */
- synchronize_sched();
+ synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open && handle->handler->start)
* Make sure we are not delivering any more events
* through this handle
*/
- synchronize_sched();
+ synchronize_rcu();
}
}
if (!--handle->open) {
/*
- * synchronize_sched() makes sure that input_pass_event()
+ * synchronize_rcu() makes sure that input_pass_event()
* completed and that no more input events are delivered
* through this handle
*/
- synchronize_sched();
+ synchronize_rcu();
}
mutex_unlock(&dev->mutex);
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
- test_bit(code, dev->key)) {
+ __test_and_clear_bit(code, dev->key)) {
input_pass_event(dev, EV_KEY, code, 0);
}
}
if (!dev->keycodesize)
return -EINVAL;
- if (scancode < 0 || scancode >= dev->keycodemax)
+ if (scancode >= dev->keycodemax)
return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode);
int old_keycode;
int i;
- if (scancode < 0 || scancode >= dev->keycodemax)
- return -EINVAL;
-
- if (keycode < 0 || keycode > KEY_MAX)
+ if (scancode >= dev->keycodemax)
return -EINVAL;
if (!dev->keycodesize)
return 0;
}
+/**
+ * input_get_keycode - retrieve keycode currently mapped to a given scancode
+ * @dev: input device which keymap is being queried
+ * @scancode: scancode (or its equivalent for device in question) for which
+ * keycode is needed
+ * @keycode: result
+ *
+ * This function should be called by anyone interested in retrieving current
+ * keymap. Presently keyboard and evdev handlers use it.
+ */
+int input_get_keycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ if (scancode < 0)
+ return -EINVAL;
+
+ return dev->getkeycode(dev, scancode, keycode);
+}
+EXPORT_SYMBOL(input_get_keycode);
+
+/**
+ * input_get_keycode - assign new keycode to a given scancode
+ * @dev: input device which keymap is being updated
+ * @scancode: scancode (or its equivalent for device in question)
+ * @keycode: new keycode to be assigned to the scancode
+ *
+ * This function should be called by anyone needing to update current
+ * keymap. Presently keyboard and evdev handlers use it.
+ */
+int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
+{
+ unsigned long flags;
+ int old_keycode;
+ int retval;
+
+ if (scancode < 0)
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+
+ retval = dev->getkeycode(dev, scancode, &old_keycode);
+ if (retval)
+ goto out;
+
+ retval = dev->setkeycode(dev, scancode, keycode);
+ if (retval)
+ goto out;
+
+ /*
+ * Simulate keyup event if keycode is not present
+ * in the keymap anymore
+ */
+ if (test_bit(EV_KEY, dev->evbit) &&
+ !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
+ __test_and_clear_bit(old_keycode, dev->key)) {
+
+ input_pass_event(dev, EV_KEY, old_keycode, 0);
+ if (dev->sync)
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
+
+ out:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(input_set_keycode);
#define MATCH_BIT(bit, max) \
- for (i = 0; i < NBITS(max); i++) \
+ for (i = 0; i < BITS_TO_LONGS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
- if (i != NBITS(max)) \
+ if (i != BITS_TO_LONGS(max)) \
continue;
static const struct input_device_id *input_match_device(const struct input_device_id *id,
{
int i;
- for (i = NBITS(max) - 1; i > 0; i--)
+ for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
return 0;
}
-static struct seq_operations input_devices_seq_ops = {
+static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
.stop = input_devices_seq_stop,
return 0;
}
-static struct seq_operations input_handlers_seq_ops = {
+static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
.stop = input_handlers_seq_stop,
{
struct proc_dir_entry *entry;
- proc_bus_input_dir = proc_mkdir("input", proc_bus);
+ proc_bus_input_dir = proc_mkdir("bus/input", NULL);
if (!proc_bus_input_dir)
return -ENOMEM;
proc_bus_input_dir->owner = THIS_MODULE;
- entry = create_proc_entry("devices", 0, proc_bus_input_dir);
+ entry = proc_create("devices", 0, proc_bus_input_dir,
+ &input_devices_fileops);
if (!entry)
goto fail1;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_devices_fileops;
-
- entry = create_proc_entry("handlers", 0, proc_bus_input_dir);
+ entry = proc_create("handlers", 0, proc_bus_input_dir,
+ &input_handlers_fileops);
if (!entry)
goto fail2;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_handlers_fileops;
-
return 0;
fail2: remove_proc_entry("devices", proc_bus_input_dir);
- fail1: remove_proc_entry("input", proc_bus);
+ fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
{
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
- remove_proc_entry("input", proc_bus);
+ remove_proc_entry("bus/input", NULL);
}
#else /* !CONFIG_PROC_FS */
len += snprintf(buf, max(size, 0), "%c", name);
for (i = min_bit; i < max_bit; i++)
- if (bm[LONG(i)] & BIT(i))
+ if (bm[BIT_WORD(i)] & BIT_MASK(i))
len += snprintf(buf + len, max(size - len, 0), "%X,", i);
return len;
}
int i;
int len = 0;
- for (i = NBITS(max) - 1; i > 0; i--)
+ for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
* Input uevent interface - loading event handlers based on
* device bitfields.
*/
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
const char *name, unsigned long *bitmap, int max)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "%s=", name))
return -ENOMEM;
- *cur_len += input_print_bitmap(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- bitmap, max, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_bitmap(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ bitmap, max, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
struct input_dev *dev)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
- "MODALIAS=");
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- *cur_len += input_print_modalias(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- dev, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ dev, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \
do { \
- int err = input_add_uevent_bm_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- name, bm, max); \
+ int err = input_add_uevent_bm_var(env, name, bm, max); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \
do { \
- int err = input_add_uevent_modalias_var(envp, \
- num_envp, &i, \
- buffer, buffer_size, &len, \
- dev); \
+ int err = input_add_uevent_modalias_var(env, dev); \
if (err) \
return err; \
} while (0)
-static int input_dev_uevent(struct device *device, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct input_dev *dev = to_input_dev(device);
- int i = 0;
- int len = 0;
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
- envp[i] = NULL;
return 0;
}
__set_bit(code, dev->ffbit);
break;
+ case EV_PWR:
+ /* do nothing */
+ break;
+
default:
printk(KERN_ERR
"input_set_capability: unknown type %u (code %u)\n",
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
- if (dev->cdev.dev)
- dev->dev.parent = dev->cdev.dev;
-
error = device_add(&dev->dev);
if (error)
return error;
return error;
list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex);
- /*
- * We don't use synchronize_rcu() here because we rely
- * on dev->event_lock to protect read-side critical
- * section in input_pass_event().
- */
- synchronize_sched();
+ synchronize_rcu();
/*
* Since we are supposed to be called from ->connect()
mutex_lock(&dev->mutex);
list_del_rcu(&handle->d_node);
mutex_unlock(&dev->mutex);
- synchronize_sched();
+ synchronize_rcu();
}
EXPORT_SYMBOL(input_unregister_handle);
static int input_open_file(struct inode *inode, struct file *file)
{
- struct input_handler *handler = input_table[iminor(inode) >> 5];
+ struct input_handler *handler;
const struct file_operations *old_fops, *new_fops = NULL;
int err;
+ lock_kernel();
/* No load-on-demand here? */
- if (!handler || !(new_fops = fops_get(handler->fops)))
- return -ENODEV;
+ handler = input_table[iminor(inode) >> 5];
+ if (!handler || !(new_fops = fops_get(handler->fops))) {
+ err = -ENODEV;
+ goto out;
+ }
/*
* That's _really_ odd. Usually NULL ->open means "nothing special",
*/
if (!new_fops->open) {
fops_put(new_fops);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
old_fops = file->f_op;
file->f_op = new_fops;
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
+out:
+ unlock_kernel();
return err;
}