diff mbox

Handling of large keycodes

Message ID 20100731091936.GA22253@core.coreip.homeip.net (mailing list archive)
State New, archived
Headers show

Commit Message

Dmitry Torokhov July 31, 2010, 9:19 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 54109dc..4dd9fb0 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -175,8 +175,7 @@  EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
  */
 
 struct getset_keycode_data {
-	unsigned int scancode;
-	unsigned int keycode;
+	struct keymap_entry ke;
 	int error;
 };
 
@@ -184,32 +183,50 @@  static int getkeycode_helper(struct input_handle *handle, void *data)
 {
 	struct getset_keycode_data *d = data;
 
-	d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
+	d->error = input_get_keycode(handle->dev, &d->ke);
 
 	return d->error == 0; /* stop as soon as we successfully get one */
 }
 
 int getkeycode(unsigned int scancode)
 {
-	struct getset_keycode_data d = { scancode, 0, -ENODEV };
+	struct getset_keycode_data d = {
+		.ke	= {
+			.by_index	= false,
+			.len		= sizeof(scancode),
+			.keycode	= 0,
+		},
+		.error	= -ENODEV,
+	};
+
+	memcpy(d.ke.scancode, &scancode, sizeof(scancode));
 
 	input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
 
-	return d.error ?: d.keycode;
+	return d.error ?: d.ke.keycode;
 }
 
 static int setkeycode_helper(struct input_handle *handle, void *data)
 {
 	struct getset_keycode_data *d = data;
 
-	d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
+	d->error = input_set_keycode(handle->dev, &d->ke);
 
 	return d->error == 0; /* stop as soon as we successfully set one */
 }
 
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	struct getset_keycode_data d = { scancode, keycode, -ENODEV };
+	struct getset_keycode_data d = {
+		.ke	= {
+			.by_index	= false,
+			.len		= sizeof(scancode),
+			.keycode	= keycode,
+		},
+		.error	= -ENODEV,
+	};
+
+	memcpy(d.ke.scancode, &scancode, sizeof(scancode));
 
 	input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
 
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 783cdd3..9c7a97b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -534,6 +534,80 @@  static int handle_eviocgbit(struct input_dev *dev,
 }
 #undef OLD_KEY_MAX
 
+static int evdev_handle_get_keycode(struct input_dev *dev,
+				    void __user *p, size_t size)
+{
+	struct keymap_entry ke;
+	int error;
+
+	memset(&ke, 0, sizeof(ke));
+
+	if (size == sizeof(unsigned int[2])) {
+		/* legacy case */
+		int __user *ip = (int __user *)p;
+
+		if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+			return -EFAULT;
+
+		ke.len = sizeof(unsigned int);
+		ke.by_index = false;
+
+		error = input_get_keycode(dev, &ke);
+		if (error)
+			return error;
+
+		if (put_user(ke.keycode, ip + 1))
+			return -EFAULT;
+
+	} else {
+		size = min(size, sizeof(ke));
+
+		if (copy_from_user(&ke, p, size))
+			return -EFAULT;
+
+		error = input_get_keycode(dev, &ke);
+		if (error)
+			return error;
+
+		if (copy_to_user(p, &ke, size))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int evdev_handle_set_keycode(struct input_dev *dev,
+				    void __user *p, size_t size)
+{
+	struct keymap_entry ke;
+
+	memset(&ke, 0, sizeof(ke));
+
+	if (size == sizeof(unsigned int[2])) {
+		/* legacy case */
+		int __user *ip = (int __user *)p;
+
+		if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
+			return -EFAULT;
+
+		if (get_user(ke.keycode, ip + 1))
+			return -EFAULT;
+
+		ke.len = sizeof(unsigned int);
+		ke.by_index = false;
+
+	} else {
+		size = min(size, sizeof(ke));
+
+		if (copy_from_user(&ke, p, size))
+			return -EFAULT;
+
+		if (ke.len > sizeof(ke.scancode))
+			return -EINVAL;
+	}
+
+	return input_set_keycode(dev, &ke);
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 			   void __user *p, int compat_mode)
 {
@@ -543,8 +617,6 @@  static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 	struct input_absinfo abs;
 	struct ff_effect effect;
 	int __user *ip = (int __user *)p;
-	struct keycode_table_entry kt, *kt_p = p;
-	char scancode[16];
 	unsigned int i, t, u, v;
 	unsigned int size;
 	int error;
@@ -582,62 +654,6 @@  static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
 		return 0;
 
-	case EVIOCGKEYCODE:
-		if (get_user(t, ip))
-			return -EFAULT;
-
-		error = input_get_keycode(dev, t, &v);
-		if (error)
-			return error;
-
-		if (put_user(v, ip + 1))
-			return -EFAULT;
-
-		return 0;
-
-	case EVIOCSKEYCODE:
-		if (get_user(t, ip) || get_user(v, ip + 1))
-			return -EFAULT;
-
-		return input_set_keycode(dev, t, v);
-
-	case EVIOCGKEYCODEBIG:
-		if (copy_from_user(&kt, kt_p, sizeof(kt)))
-			return -EFAULT;
-
-		if (kt.len > sizeof(scancode))
-			return -EINVAL;
-
-		kt.scancode = scancode;
-
-		error = input_get_keycode_big(dev, &kt);
-		if (error)
-			return error;
-
-		if (copy_to_user(kt_p, &kt, sizeof(kt)))
-			return -EFAULT;
-
-		/* FIXME: probably need some compat32 code */
-		if (copy_to_user(kt_p->scancode, kt.scancode, kt.len))
-			return -EFAULT;
-
-		return 0;
-
-	case EVIOCSKEYCODEBIG:
-		if (copy_from_user(&kt, kt_p, sizeof(kt)))
-			return -EFAULT;
-
-		if (kt.len > sizeof(scancode))
-			return -EINVAL;
-
-		kt.scancode = scancode;
-
-		/* FIXME: probably need some compat32 code */
-		if (copy_from_user(kt.scancode, kt_p->scancode, kt.len))
-			return -EFAULT;
-
-		return input_set_keycode_big(dev, &kt);
-
 	case EVIOCRMFF:
 		return input_ff_erase(dev, (int)(unsigned long) p, file);
 
@@ -659,7 +675,6 @@  static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 
 	/* Now check variable-length commands */
 #define EVIOC_MASK_SIZE(nr)	((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
-
 	switch (EVIOC_MASK_SIZE(cmd)) {
 
 	case EVIOCGKEY(0):
@@ -693,6 +708,12 @@  static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 			return -EFAULT;
 
 		return error;
+
+	case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
+		return evdev_handle_get_keycode(dev, p, size);
+
+	case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
+		return evdev_handle_set_keycode(dev, p, size);
 	}
 
 	/* Multi-number variable-length handlers */
diff --git a/drivers/input/input.c b/drivers/input/input.c
index bbb95c1..4408913 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -634,131 +634,141 @@  static void input_disconnect_device(struct input_dev *dev)
 	spin_unlock_irq(&dev->event_lock);
 }
 
-/*
- * Those routines handle the default case where no [gs]etkeycode() is
- * defined. In this case, an array indexed by the scancode is used.
+/**
+ * input_scancode_to_scalar() - converts scancode in &struct keymap_entry
+ * @ke: keymap entry containing scancode to be converted.
+ * @scancode: pointer to the location where converted scancode should
+ *	be stored.
+ *
+ * This function is used to convert scancode stored in &struct keymap_entry
+ * into scalar form understood by legacy keymap handling methods. These
+ * methods expect scancodes to be represented as 'unsigned int'.
  */
-
-static int input_fetch_keycode(struct input_dev *dev, int scancode)
+int input_scancode_to_scalar(const struct keymap_entry *ke,
+			     unsigned int *scancode)
 {
-	switch (dev->keycodesize) {
-		case 1:
-			return ((u8 *)dev->keycode)[scancode];
+	switch (ke->len) {
+	case 1:
+		*scancode = *((u8 *)ke->scancode);
+		break;
 
-		case 2:
-			return ((u16 *)dev->keycode)[scancode];
+	case 2:
+		*scancode = *((u16 *)ke->scancode);
+		break;
+
+	case 4:
+		*scancode = *((u32 *)ke->scancode);
+		break;
 
-		default:
-			return ((u32 *)dev->keycode)[scancode];
+	default:
+		return -EINVAL;
 	}
+
+	return 0;
 }
+EXPORT_SYMBOL(input_scancode_to_scalar);
 
 /*
- * Supports only 8, 16 and 32 bit scancodes. It wouldn't be that
- * hard to write some machine-endian logic to support 24 bit scancodes,
- * but it seemed overkill. It should also be noticed that, since there
- * are, in general, less than 256 scancodes sparsed into the scancode
- * space, even with 16 bits, the codespace is sparsed, with leads into
- * memory and code ineficiency, when retrieving the entire scancode
- * space.
- * So, it is highly recommended to implement getkeycodebig/setkeycodebig
- * instead of using a normal table approach, when more than 8 bits is
- * needed for the scancode.
+ * Those routines handle the default case where no [gs]etkeycode() is
+ * defined. In this case, an array indexed by the scancode is used.
  */
-static int input_fetch_scancode(struct keycode_table_entry *kt_entry,
-				u32 *scancode)
+
+static unsigned int input_fetch_keycode(struct input_dev *dev,
+					unsigned int index)
 {
-	switch (kt_entry->len) {
+	switch (dev->keycodesize) {
 	case 1:
-		*scancode = *((u8 *)kt_entry->scancode);
-		break;
+		return ((u8 *)dev->keycode)[index];
+
 	case 2:
-		*scancode = *((u16 *)kt_entry->scancode);
-		break;
-	case 4:
-		*scancode = *((u32 *)kt_entry->scancode);
-		break;
+		return ((u16 *)dev->keycode)[index];
+
 	default:
-		return -EINVAL;
+		return ((u32 *)dev->keycode)[index];
 	}
-	return 0;
 }
 
-
-static int input_default_getkeycode_from_index(struct input_dev *dev,
-				    struct keycode_table_entry *kt_entry)
+static int input_default_getkeycode(struct input_dev *dev,
+				    struct keymap_entry *ke)
 {
-	u32 scancode = kt_entry->index;
+	unsigned int index;
+	int error;
 
 	if (!dev->keycodesize)
 		return -EINVAL;
 
-	if (scancode >= dev->keycodemax)
+	if (ke->by_index)
+		index = ke->index;
+	else {
+		error = input_scancode_to_scalar(ke, &index);
+		if (error)
+			return error;
+	}
+
+	if (index >= dev->keycodemax)
 		return -EINVAL;
 
-	kt_entry->keycode = input_fetch_keycode(dev, scancode);
-	memcpy(kt_entry->scancode, &scancode, 4);
+	ke->keycode = input_fetch_keycode(dev, index);
+	ke->index = index;
+	ke->len = sizeof(index);
+	memcpy(ke->scancode, &index, sizeof(index));
 
 	return 0;
 }
 
-static int input_default_getkeycode_from_scancode(struct input_dev *dev,
-				    struct keycode_table_entry *kt_entry)
-{
-	if (input_fetch_scancode(kt_entry, &kt_entry->index))
-		return -EINVAL;
-
-	return input_default_getkeycode_from_index(dev, kt_entry);
-}
-
-
 static int input_default_setkeycode(struct input_dev *dev,
-				    struct keycode_table_entry *kt_entry)
+				    const struct keymap_entry *ke,
+				    unsigned int *old_keycode)
 {
-	u32 old_keycode;
+	unsigned int index;
+	int error;
 	int i;
-	u32 scancode;
 
-	if (input_fetch_scancode(kt_entry, &scancode))
+	if (!dev->keycodesize)
 		return -EINVAL;
 
-	if (scancode >= dev->keycodemax)
-		return -EINVAL;
+	if (ke->by_index) {
+		index = ke->index;
+	} else {
+		error = input_scancode_to_scalar(ke, &index);
+		if (error)
+			return error;
+	}
 
-	if (!dev->keycodesize)
+	if (index >= dev->keycodemax)
 		return -EINVAL;
 
 	if (dev->keycodesize < sizeof(dev->keycode) &&
-	    (kt_entry->keycode >> (dev->keycodesize * 8)))
+			(ke->keycode >> (dev->keycodesize * 8)))
 		return -EINVAL;
 
 	switch (dev->keycodesize) {
 		case 1: {
 			u8 *k = (u8 *)dev->keycode;
-			old_keycode = k[scancode];
-			k[scancode] = kt_entry->keycode;
+			*old_keycode = k[index];
+			k[index] = ke->keycode;
 			break;
 		}
 		case 2: {
 			u16 *k = (u16 *)dev->keycode;
-			old_keycode = k[scancode];
-			k[scancode] = kt_entry->keycode;
+			*old_keycode = k[index];
+			k[index] = ke->keycode;
 			break;
 		}
 		default: {
 			u32 *k = (u32 *)dev->keycode;
-			old_keycode = k[scancode];
-			k[scancode] = kt_entry->keycode;
+			*old_keycode = k[index];
+			k[index] = ke->keycode;
 			break;
 		}
 	}
 
-	__clear_bit(old_keycode, dev->keybit);
-	__set_bit(kt_entry->keycode, dev->keybit);
+	__clear_bit(*old_keycode, dev->keybit);
+	__set_bit(ke->keycode, dev->keybit);
 
 	for (i = 0; i < dev->keycodemax; i++) {
-		if (input_fetch_keycode(dev, i) == old_keycode) {
-			__set_bit(old_keycode, dev->keybit);
+		if (input_fetch_keycode(dev, i) == *old_keycode) {
+			__set_bit(*old_keycode, dev->keybit);
 			break; /* Setting the bit twice is useless, so break */
 		}
 	}
@@ -767,215 +777,90 @@  static int input_default_setkeycode(struct input_dev *dev,
 }
 
 /**
- * input_get_keycode_big - retrieve keycode currently mapped to a given scancode
+ * input_get_keycode - retrieve keycode currently mapped to a given scancode
  * @dev: input device which keymap is being queried
- * @kt_entry: keytable entry
+ * @ke: keymap entry
  *
  * This function should be called by anyone interested in retrieving current
  * keymap. Presently evdev handlers use it.
  */
-int input_get_keycode_big(struct input_dev *dev,
-			  struct keycode_table_entry *kt_entry)
-{
-	if (dev->getkeycode) {
-		u32 scancode = kt_entry->index;
-
-		/*
-		 * Support for legacy drivers, that don't implement the new
-		 * ioctls
-		 */
-		memcpy(kt_entry->scancode, &scancode, 4);
-		return dev->getkeycode(dev, scancode,
-				       &kt_entry->keycode);
-	} else
-		return dev->getkeycodebig_from_index(dev, kt_entry);
-}
-EXPORT_SYMBOL(input_get_keycode_big);
-
-/**
- * input_set_keycode_big - attribute a keycode to a given scancode
- * @dev: input device which keymap is being queried
- * @kt_entry: keytable entry
- *
- * This function should be called by anyone needing to update current
- * keymap. Presently keyboard and evdev handlers use it.
- */
-int input_set_keycode_big(struct input_dev *dev,
-			  struct keycode_table_entry *kt_entry)
+int input_get_keycode(struct input_dev *dev, struct keymap_entry *ke)
 {
 	unsigned long flags;
-	int old_keycode;
-	int retval = -EINVAL;
-	u32 uninitialized_var(scancode);
-
-	if (kt_entry->keycode < 0 || kt_entry->keycode > KEY_MAX)
-		return -EINVAL;
+	int retval;
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
-	/*
-	 * We need to know the old scancode, in order to generate a
-	 * keyup effect, if the set operation happens successfully
-	 */
 	if (dev->getkeycode) {
 		/*
 		 * Support for legacy drivers, that don't implement the new
 		 * ioctls
 		 */
-		if (!dev->setkeycode)
-			goto out;
-
-		retval = input_fetch_scancode(kt_entry, &scancode);
-		if (retval)
-			goto out;
+		u32 scancode = ke->index;
 
-		retval = dev->getkeycode(dev, scancode,
-					 &old_keycode);
+		memcpy(ke->scancode, &scancode, sizeof(scancode));
+		ke->len = sizeof(scancode);
+		retval = dev->getkeycode(dev, scancode, &ke->keycode);
 	} else {
-		int new_keycode = kt_entry->keycode;
-
-		retval = dev->getkeycodebig_from_scancode(dev, kt_entry);
-		old_keycode = kt_entry->keycode;
-		kt_entry->keycode = new_keycode;
+		retval = dev->getkeycode_new(dev, ke);
 	}
 
-	if (retval)
-		goto out;
-
-	if (dev->getkeycode)
-		retval = dev->setkeycode(dev, scancode,
-					 kt_entry->keycode);
-	else
-		retval = dev->setkeycodebig(dev, kt_entry);
-	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_big);
-
-/**
- * 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,
-		      unsigned int scancode, unsigned int *keycode)
-{
-	unsigned long flags;
-
-	if (dev->getkeycode) {
-		/*
-		 * Use the legacy calls
-		 */
-		return dev->getkeycode(dev, scancode, keycode);
-	} else {
-		int retval;
-		struct keycode_table_entry kt_entry;
-
-		/*
-		 * Userspace is using a legacy call with a driver ported
-		 * to the new way. This is a bad idea with long sparsed
-		 * tables, since lots of the retrieved values will be in
-		 * blank. Also, it makes sense only if the table size is
-		 * lower than 2^32.
-		 */
-		memset(&kt_entry, 0, sizeof(kt_entry));
-		kt_entry.len = 4;
-		kt_entry.index = scancode;
-		kt_entry.scancode = (char *)&scancode;
-
-		spin_lock_irqsave(&dev->event_lock, flags);
-		retval = dev->getkeycodebig_from_index(dev, &kt_entry);
-		spin_unlock_irqrestore(&dev->event_lock, flags);
-
-		*keycode = kt_entry.keycode;
-		return retval;
-	}
-}
 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
+ * input_set_keycode - attribute a keycode to a given scancode
+ * @dev: input device which keymap is being queried
+ * @ke: keymap entry
+ * @old_keycode: keycode previously 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,
-		      unsigned int scancode, unsigned int keycode)
+int input_set_keycode(struct input_dev *dev, const struct keymap_entry *ke)
 {
 	unsigned long flags;
 	unsigned int old_keycode;
 	int retval;
 
-	if (keycode > KEY_MAX)
+	if (ke->keycode > KEY_MAX)
 		return -EINVAL;
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
-	if (dev->getkeycode) {
+	if (dev->setkeycode) {
 		/*
-		 * Use the legacy calls
+		 * Support for legacy drivers, that don't implement the new
+		 * ioctls
 		 */
-		retval = dev->getkeycode(dev, scancode, &old_keycode);
-		if (retval)
-			goto out;
+		unsigned int scancode;
 
-		retval = dev->setkeycode(dev, scancode, keycode);
+		retval = input_scancode_to_scalar(ke, &scancode);
 		if (retval)
 			goto out;
-	} else {
-		struct keycode_table_entry kt_entry;
 
 		/*
-		 * Userspace is using a legacy call with a driver ported
-		 * to the new way. This is a bad idea with long sparsed
-		 * tables, since lots of the retrieved values will be in
-		 * blank. Also, it makes sense only if the table size is
-		 * lower than 2^32.
+		 * We need to know the old scancode, in order to generate a
+		 * keyup effect, if the set operation happens successfully
 		 */
-		memset(&kt_entry, 0, sizeof(kt_entry));
-		kt_entry.len = 4;
-		kt_entry.scancode = (char *)&scancode;
-
-		retval = dev->getkeycodebig_from_scancode(dev, &kt_entry);
-		if (retval)
+		if (!dev->getkeycode) {
+			retval = -EINVAL;
 			goto out;
+		}
 
-		old_keycode = kt_entry.keycode;
-		kt_entry.keycode = keycode;
-
-		retval = dev->setkeycodebig(dev, &kt_entry);
+		retval = dev->getkeycode(dev, scancode, &old_keycode);
 		if (retval)
 			goto out;
+
+		retval = dev->setkeycode(dev, scancode, ke->keycode);
+	} else {
+		retval = dev->setkeycode_new(dev, ke, &old_keycode);
 	}
 
-	/* Make sure KEY_RESERVED did not get enabled. */
-	__clear_bit(KEY_RESERVED, dev->keybit);
+	if (retval)
+		goto out;
 
 	/*
 	 * Simulate keyup event if keycode is not present
@@ -1960,17 +1845,11 @@  int input_register_device(struct input_dev *dev)
 		dev->rep[REP_PERIOD] = 33;
 	}
 
-	if (!dev->getkeycode) {
-		if (!dev->getkeycodebig_from_index)
-			dev->getkeycodebig_from_index = input_default_getkeycode_from_index;
-		if (!dev->getkeycodebig_from_scancode)
-			dev->getkeycodebig_from_scancode = input_default_getkeycode_from_scancode;
-	}
+	if (!dev->getkeycode && !dev->getkeycode_new)
+		dev->getkeycode_new = input_default_getkeycode;
 
-	if (!dev->setkeycode) {
-		if (!dev->setkeycodebig)
-			dev->setkeycodebig = input_default_setkeycode;
-	}
+	if (!dev->setkeycode && !dev->setkeycode_new)
+		dev->setkeycode_new = input_default_setkeycode;
 
 	dev_set_name(&dev->dev, "input%ld",
 		     (unsigned long) atomic_inc_return(&input_no) - 1);
diff --git a/include/linux/input.h b/include/linux/input.h
index 8d6de8c..e090169 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -56,22 +56,35 @@  struct input_absinfo {
 	__s32 resolution;
 };
 
-struct keycode_table_entry {
-	__u32 keycode;		/* e.g. KEY_A */
-	__u32 index;            /* Index for the given scan/key table, on EVIOCGKEYCODEBIG */
-	__u32 len;		/* Length of the scancode */
-	__u32 reserved[2];	/* Reserved for future usage */
-	char *scancode;		/* scancode, in machine-endian */
+/**
+ * struct keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls
+ * @scancode: scancode represented in machine-endian form.
+ * @len: length of the scancode that resides in @scancode buffer.
+ * @index: index in the keymap, may be used instead of scancode
+ * @by_index: boolean value indicating that kernel should perform
+ *	lookup in keymap by @index instead of @scancode
+ * @keycode: key code assigned to this scancode
+ *
+ * The structure is used to retrieve and modify keymap data. Users have
+ * of performing lookup either by @scancode itself or by @index in
+ * keymap entry. EVIOCGKEYCODE will also return scancode or index
+ * (depending on which element was used to perform lookup).
+ */
+struct keymap_entry {
+	__u8  len;
+	__u8  by_index;
+	__u16 index;
+	__u32 keycode;
+	__u8  scancode[32];
 };
 
 #define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
 #define EVIOCGID		_IOR('E', 0x02, struct input_id)	/* get device ID */
 #define EVIOCGREP		_IOR('E', 0x03, unsigned int[2])	/* get repeat settings */
 #define EVIOCSREP		_IOW('E', 0x03, unsigned int[2])	/* set repeat settings */
-#define EVIOCGKEYCODE		_IOR('E', 0x04, unsigned int[2])	/* get keycode */
-#define EVIOCSKEYCODE		_IOW('E', 0x04, unsigned int[2])	/* set keycode */
-#define EVIOCGKEYCODEBIG	_IOR('E', 0x04, struct keycode_table_entry) /* get keycode */
-#define EVIOCSKEYCODEBIG	_IOW('E', 0x04, struct keycode_table_entry) /* set keycode */
+
+#define EVIOCGKEYCODE		_IOR('E', 0x04, struct keymap_entry)	/* get keycode */
+#define EVIOCSKEYCODE		_IOW('E', 0x04, struct keymap_entry)	/* set keycode */
 
 #define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
 #define EVIOCGPHYS(len)		_IOC(_IOC_READ, 'E', 0x07, len)		/* get physical location */
@@ -1098,22 +1111,13 @@  struct input_mt_slot {
  * @keycodemax: size of keycode table
  * @keycodesize: size of elements in keycode table
  * @keycode: map of scancodes to keycodes for this device
- * @setkeycode: optional legacy method to alter current keymap, used to
- *	implement sparse keymaps. Shouldn't be used in new drivers
  * @getkeycode: optional legacy method to retrieve current keymap.
- *	Shouldn't be used on new drivers.
- * @setkeycodebig: optional method to alter current keymap, used to implement
+ * @setkeycode: optional method to alter current keymap, used to implement
  *	sparse keymaps. If not supplied default mechanism will be used.
  *	The method is being called while holding event_lock and thus must
  *	not sleep
- * @getkeycodebig_from_index: optional method to retrieve current keymap from
- *	an array index. If not supplied default mechanism will be used.
- *	The method is being called while holding event_lock and thus must
- *	not sleep
- * @getkeycodebig_from_scancode: optional method to retrieve current keymap
- *	from an scancode. If not supplied default mechanism will be used.
- *	The method is being called while holding event_lock and thus must
- *	not sleep
+ * @getkeycode_new: transition method
+ * @setkeycode_new: transition method
  * @ff: force feedback structure associated with the device if device
  *	supports force feedback effects
  * @repeat_key: stores key code of the last key pressed; used to implement
@@ -1187,16 +1191,15 @@  struct input_dev {
 	unsigned int keycodemax;
 	unsigned int keycodesize;
 	void *keycode;
+
 	int (*setkeycode)(struct input_dev *dev,
 			  unsigned int scancode, unsigned int keycode);
 	int (*getkeycode)(struct input_dev *dev,
 			  unsigned int scancode, unsigned int *keycode);
-	int (*setkeycodebig)(struct input_dev *dev,
-			     struct keycode_table_entry *kt_entry);
-	int (*getkeycodebig_from_index)(struct input_dev *dev,
-			     struct keycode_table_entry *kt_entry);
-	int (*getkeycodebig_from_scancode)(struct input_dev *dev,
-			     struct keycode_table_entry *kt_entry);
+	int (*setkeycode_new)(struct input_dev *dev,
+			      const struct keymap_entry *ke,
+			      unsigned int *old_keycode);
+	int (*getkeycode_new)(struct input_dev *dev, struct keymap_entry *ke);
 
 	struct ff_device *ff;
 
@@ -1503,14 +1506,11 @@  INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz)
 INPUT_GENERATE_ABS_ACCESSORS(flat, flat)
 INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
 
-int input_get_keycode(struct input_dev *dev,
-		      unsigned int scancode, unsigned int *keycode);
-int input_set_keycode(struct input_dev *dev,
-		      unsigned int scancode, unsigned int keycode);
-int input_get_keycode_big(struct input_dev *dev,
-			  struct keycode_table_entry *kt_entry);
-int input_set_keycode_big(struct input_dev *dev,
-			  struct keycode_table_entry *kt_entry);
+int input_scancode_to_scalar(const struct keymap_entry *ke,
+			     unsigned int *scancode);
+
+int input_get_keycode(struct input_dev *dev, struct keymap_entry *ke);
+int input_set_keycode(struct input_dev *dev, const struct keymap_entry *ke);
 
 extern struct class input_class;