| /* ir-register.c - handle IR scancode->keycode tables | 
 |  * | 
 |  * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com> | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  *  it under the terms of the GNU General Public License as published by | 
 |  *  the Free Software Foundation version 2 of the License. | 
 |  * | 
 |  *  This program is distributed in the hope that it will be useful, | 
 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  *  GNU General Public License for more details. | 
 |  */ | 
 |  | 
 |  | 
 | #include <linux/input.h> | 
 | #include <media/ir-common.h> | 
 |  | 
 | #define IR_TAB_MIN_SIZE	32 | 
 | #define IR_TAB_MAX_SIZE	1024 | 
 |  | 
 | /** | 
 |  * ir_seek_table() - returns the element order on the table | 
 |  * @rc_tab:	the ir_scancode_table with the keymap to be used | 
 |  * @scancode:	the scancode that we're seeking | 
 |  * | 
 |  * This routine is used by the input routines when a key is pressed at the | 
 |  * IR. The scancode is received and needs to be converted into a keycode. | 
 |  * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the | 
 |  * corresponding keycode from the table. | 
 |  */ | 
 | static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode) | 
 | { | 
 | 	int rc; | 
 | 	unsigned long flags; | 
 | 	struct ir_scancode *keymap = rc_tab->scan; | 
 |  | 
 | 	spin_lock_irqsave(&rc_tab->lock, flags); | 
 |  | 
 | 	/* FIXME: replace it by a binary search */ | 
 |  | 
 | 	for (rc = 0; rc < rc_tab->size; rc++) | 
 | 		if (keymap[rc].scancode == scancode) | 
 | 			goto exit; | 
 |  | 
 | 	/* Not found */ | 
 | 	rc = -EINVAL; | 
 |  | 
 | exit: | 
 | 	spin_unlock_irqrestore(&rc_tab->lock, flags); | 
 | 	return rc; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_roundup_tablesize() - gets an optimum value for the table size | 
 |  * @n_elems:		minimum number of entries to store keycodes | 
 |  * | 
 |  * This routine is used to choose the keycode table size. | 
 |  * | 
 |  * In order to have some empty space for new keycodes, | 
 |  * and knowing in advance that kmalloc allocates only power of two | 
 |  * segments, it optimizes the allocated space to have some spare space | 
 |  * for those new keycodes by using the maximum number of entries that | 
 |  * will be effectively be allocated by kmalloc. | 
 |  * In order to reduce the quantity of table resizes, it has a minimum | 
 |  * table size of IR_TAB_MIN_SIZE. | 
 |  */ | 
 | static int ir_roundup_tablesize(int n_elems) | 
 | { | 
 | 	size_t size; | 
 |  | 
 | 	if (n_elems < IR_TAB_MIN_SIZE) | 
 | 		n_elems = IR_TAB_MIN_SIZE; | 
 |  | 
 | 	/* | 
 | 	 * As kmalloc only allocates sizes of power of two, get as | 
 | 	 * much entries as possible for the allocated memory segment | 
 | 	 */ | 
 | 	size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode)); | 
 | 	n_elems = size / sizeof(struct ir_scancode); | 
 |  | 
 | 	return n_elems; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_copy_table() - copies a keytable, discarding the unused entries | 
 |  * @destin:	destin table | 
 |  * @origin:	origin table | 
 |  * | 
 |  * Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED | 
 |  * Also copies table size and table protocol. | 
 |  * NOTE: It shouldn't copy the lock field | 
 |  */ | 
 |  | 
 | static int ir_copy_table(struct ir_scancode_table *destin, | 
 | 		 const struct ir_scancode_table *origin) | 
 | { | 
 | 	int i, j = 0; | 
 |  | 
 | 	for (i = 0; i < origin->size; i++) { | 
 | 		if (origin->scan[i].keycode == KEY_UNKNOWN || | 
 | 		   origin->scan[i].keycode == KEY_RESERVED) | 
 | 			continue; | 
 |  | 
 | 		memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode)); | 
 | 		j++; | 
 | 	} | 
 | 	destin->size = j; | 
 | 	destin->ir_type = origin->ir_type; | 
 |  | 
 | 	IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table | 
 |  * @dev:	the struct input_dev device descriptor | 
 |  * @scancode:	the desired scancode | 
 |  * @keycode:	the keycode to be retorned. | 
 |  * | 
 |  * This routine is used to handle evdev EVIOCGKEY ioctl. | 
 |  * If the key is not found, returns -EINVAL, otherwise, returns 0. | 
 |  */ | 
 | static int ir_getkeycode(struct input_dev *dev, | 
 | 			 unsigned int scancode, unsigned int *keycode) | 
 | { | 
 | 	int elem; | 
 | 	struct ir_input_dev *ir_dev = input_get_drvdata(dev); | 
 | 	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | 
 |  | 
 | 	elem = ir_seek_table(rc_tab, scancode); | 
 | 	if (elem >= 0) { | 
 | 		*keycode = rc_tab->scan[elem].keycode; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Scancode not found and table can't be expanded | 
 | 	 */ | 
 | 	if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE) | 
 | 		return -EINVAL; | 
 |  | 
 | 	/* | 
 | 	 * If is there extra space, returns KEY_RESERVED, | 
 | 	 * otherwise, input core won't let ir_setkeycode to work | 
 | 	 */ | 
 | 	*keycode = KEY_RESERVED; | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_is_resize_needed() - Check if the table needs rezise | 
 |  * @table:		keycode table that may need to resize | 
 |  * @n_elems:		minimum number of entries to store keycodes | 
 |  * | 
 |  * Considering that kmalloc uses power of two storage areas, this | 
 |  * routine detects if the real alloced size will change. If not, it | 
 |  * just returns without doing nothing. Otherwise, it will extend or | 
 |  * reduce the table size to meet the new needs. | 
 |  * | 
 |  * It returns 0 if no resize is needed, 1 otherwise. | 
 |  */ | 
 | static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems) | 
 | { | 
 | 	int cur_size = ir_roundup_tablesize(table->size); | 
 | 	int new_size = ir_roundup_tablesize(n_elems); | 
 |  | 
 | 	if (cur_size == new_size) | 
 | 		return 0; | 
 |  | 
 | 	/* Resize is needed */ | 
 | 	return 1; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_delete_key() - remove a keycode from the table | 
 |  * @rc_tab:		keycode table | 
 |  * @elem:		element to be removed | 
 |  * | 
 |  */ | 
 | static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem) | 
 | { | 
 | 	unsigned long flags = 0; | 
 | 	int newsize = rc_tab->size - 1; | 
 | 	int resize = ir_is_resize_needed(rc_tab, newsize); | 
 | 	struct ir_scancode *oldkeymap = rc_tab->scan; | 
 | 	struct ir_scancode *newkeymap = NULL; | 
 |  | 
 | 	if (resize) | 
 | 		newkeymap = kzalloc(ir_roundup_tablesize(newsize) * | 
 | 				    sizeof(*newkeymap), GFP_ATOMIC); | 
 |  | 
 | 	/* There's no memory for resize. Keep the old table */ | 
 | 	if (!resize || !newkeymap) { | 
 | 		newkeymap = oldkeymap; | 
 |  | 
 | 		/* We'll modify the live table. Lock it */ | 
 | 		spin_lock_irqsave(&rc_tab->lock, flags); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Copy the elements before the one that will be deleted | 
 | 	 * if (!resize), both oldkeymap and newkeymap points | 
 | 	 * to the same place, so, there's no need to copy | 
 | 	 */ | 
 | 	if (resize && elem > 0) | 
 | 		memcpy(newkeymap, oldkeymap, | 
 | 		       elem * sizeof(*newkeymap)); | 
 |  | 
 | 	/* | 
 | 	 * Copy the other elements overwriting the element to be removed | 
 | 	 * This operation applies to both resize and non-resize case | 
 | 	 */ | 
 | 	if (elem < newsize) | 
 | 		memcpy(&newkeymap[elem], &oldkeymap[elem + 1], | 
 | 		       (newsize - elem) * sizeof(*newkeymap)); | 
 |  | 
 | 	if (resize) { | 
 | 		/* | 
 | 		 * As the copy happened to a temporary table, only here | 
 | 		 * it needs to lock while replacing the table pointers | 
 | 		 * to use the new table | 
 | 		 */ | 
 | 		spin_lock_irqsave(&rc_tab->lock, flags); | 
 | 		rc_tab->size = newsize; | 
 | 		rc_tab->scan = newkeymap; | 
 | 		spin_unlock_irqrestore(&rc_tab->lock, flags); | 
 |  | 
 | 		/* Frees the old keytable */ | 
 | 		kfree(oldkeymap); | 
 | 	} else { | 
 | 		rc_tab->size = newsize; | 
 | 		spin_unlock_irqrestore(&rc_tab->lock, flags); | 
 | 	} | 
 | } | 
 |  | 
 | /** | 
 |  * ir_insert_key() - insert a keycode at the table | 
 |  * @rc_tab:		keycode table | 
 |  * @scancode:	the desired scancode | 
 |  * @keycode:	the keycode to be retorned. | 
 |  * | 
 |  */ | 
 | static int ir_insert_key(struct ir_scancode_table *rc_tab, | 
 | 			  int scancode, int keycode) | 
 | { | 
 | 	unsigned long flags; | 
 | 	int elem = rc_tab->size; | 
 | 	int newsize = rc_tab->size + 1; | 
 | 	int resize = ir_is_resize_needed(rc_tab, newsize); | 
 | 	struct ir_scancode *oldkeymap = rc_tab->scan; | 
 | 	struct ir_scancode *newkeymap; | 
 |  | 
 | 	if (resize) { | 
 | 		newkeymap = kzalloc(ir_roundup_tablesize(newsize) * | 
 | 				    sizeof(*newkeymap), GFP_ATOMIC); | 
 | 		if (!newkeymap) | 
 | 			return -ENOMEM; | 
 |  | 
 | 		memcpy(newkeymap, oldkeymap, | 
 | 		       rc_tab->size * sizeof(*newkeymap)); | 
 | 	} else | 
 | 		newkeymap  = oldkeymap; | 
 |  | 
 | 	/* Stores the new code at the table */ | 
 | 	IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n", | 
 | 		   rc_tab->size, scancode, keycode); | 
 |  | 
 | 	spin_lock_irqsave(&rc_tab->lock, flags); | 
 | 	rc_tab->size = newsize; | 
 | 	if (resize) { | 
 | 		rc_tab->scan = newkeymap; | 
 | 		kfree(oldkeymap); | 
 | 	} | 
 | 	newkeymap[elem].scancode = scancode; | 
 | 	newkeymap[elem].keycode  = keycode; | 
 | 	spin_unlock_irqrestore(&rc_tab->lock, flags); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_setkeycode() - set a keycode at the evdev scancode ->keycode table | 
 |  * @dev:	the struct input_dev device descriptor | 
 |  * @scancode:	the desired scancode | 
 |  * @keycode:	the keycode to be retorned. | 
 |  * | 
 |  * This routine is used to handle evdev EVIOCSKEY ioctl. | 
 |  * There's one caveat here: how can we increase the size of the table? | 
 |  * If the key is not found, returns -EINVAL, otherwise, returns 0. | 
 |  */ | 
 | static int ir_setkeycode(struct input_dev *dev, | 
 | 			 unsigned int scancode, unsigned int keycode) | 
 | { | 
 | 	int rc = 0; | 
 | 	struct ir_input_dev *ir_dev = input_get_drvdata(dev); | 
 | 	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | 
 | 	struct ir_scancode *keymap = rc_tab->scan; | 
 | 	unsigned long flags; | 
 |  | 
 | 	/* | 
 | 	 * Handle keycode table deletions | 
 | 	 * | 
 | 	 * If userspace is adding a KEY_UNKNOWN or KEY_RESERVED, | 
 | 	 * deal as a trial to remove an existing scancode attribution | 
 | 	 * if table become too big, reduce it to save space | 
 | 	 */ | 
 | 	if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) { | 
 | 		rc = ir_seek_table(rc_tab, scancode); | 
 | 		if (rc < 0) | 
 | 			return 0; | 
 |  | 
 | 		IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode); | 
 | 		clear_bit(keymap[rc].keycode, dev->keybit); | 
 | 		ir_delete_key(rc_tab, rc); | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Handle keycode replacements | 
 | 	 * | 
 | 	 * If the scancode exists, just replace by the new value | 
 | 	 */ | 
 | 	rc = ir_seek_table(rc_tab, scancode); | 
 | 	if (rc >= 0) { | 
 | 		IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n", | 
 | 			rc, scancode, keycode); | 
 |  | 
 | 		clear_bit(keymap[rc].keycode, dev->keybit); | 
 |  | 
 | 		spin_lock_irqsave(&rc_tab->lock, flags); | 
 | 		keymap[rc].keycode = keycode; | 
 | 		spin_unlock_irqrestore(&rc_tab->lock, flags); | 
 |  | 
 | 		set_bit(keycode, dev->keybit); | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Handle new scancode inserts | 
 | 	 * | 
 | 	 * reallocate table if needed and insert a new keycode | 
 | 	 */ | 
 |  | 
 | 	/* Avoid growing the table indefinitely */ | 
 | 	if (rc_tab->size + 1 > IR_TAB_MAX_SIZE) | 
 | 		return -EINVAL; | 
 |  | 
 | 	rc = ir_insert_key(rc_tab, scancode, keycode); | 
 | 	if (rc < 0) | 
 | 		return rc; | 
 | 	set_bit(keycode, dev->keybit); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode | 
 |  * @input_dev:	the struct input_dev descriptor of the device | 
 |  * @scancode:	the scancode that we're seeking | 
 |  * | 
 |  * This routine is used by the input routines when a key is pressed at the | 
 |  * IR. The scancode is received and needs to be converted into a keycode. | 
 |  * If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the | 
 |  * corresponding keycode from the table. | 
 |  */ | 
 | u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) | 
 | { | 
 | 	struct ir_input_dev *ir_dev = input_get_drvdata(dev); | 
 | 	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; | 
 | 	struct ir_scancode *keymap = rc_tab->scan; | 
 | 	int elem; | 
 |  | 
 | 	elem = ir_seek_table(rc_tab, scancode); | 
 | 	if (elem >= 0) { | 
 | 		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n", | 
 | 			   dev->name, scancode, keymap[elem].keycode); | 
 |  | 
 | 		return rc_tab->scan[elem].keycode; | 
 | 	} | 
 |  | 
 | 	printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n", | 
 | 	       dev->name, scancode); | 
 |  | 
 | 	/* Reports userspace that an unknown keycode were got */ | 
 | 	return KEY_RESERVED; | 
 | } | 
 | EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); | 
 |  | 
 | /** | 
 |  * ir_input_register() - sets the IR keycode table and add the handlers | 
 |  *			    for keymap table get/set | 
 |  * @input_dev:	the struct input_dev descriptor of the device | 
 |  * @rc_tab:	the struct ir_scancode_table table of scancode/keymap | 
 |  * | 
 |  * This routine is used to initialize the input infrastructure | 
 |  * to work with an IR. | 
 |  * It will register the input/evdev interface for the device and | 
 |  * register the syfs code for IR class | 
 |  */ | 
 | int ir_input_register(struct input_dev *input_dev, | 
 | 		      const struct ir_scancode_table *rc_tab, | 
 | 		      const struct ir_dev_props *props) | 
 | { | 
 | 	struct ir_input_dev *ir_dev; | 
 | 	struct ir_scancode  *keymap    = rc_tab->scan; | 
 | 	int i, rc; | 
 |  | 
 | 	if (rc_tab->scan == NULL || !rc_tab->size) | 
 | 		return -EINVAL; | 
 |  | 
 | 	ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL); | 
 | 	if (!ir_dev) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	spin_lock_init(&ir_dev->rc_tab.lock); | 
 |  | 
 | 	ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size); | 
 | 	ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size * | 
 | 				    sizeof(struct ir_scancode), GFP_KERNEL); | 
 | 	if (!ir_dev->rc_tab.scan) { | 
 | 		kfree(ir_dev); | 
 | 		return -ENOMEM; | 
 | 	} | 
 |  | 
 | 	IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", | 
 | 		ir_dev->rc_tab.size, | 
 | 		ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan)); | 
 |  | 
 | 	ir_copy_table(&ir_dev->rc_tab, rc_tab); | 
 | 	ir_dev->props = props; | 
 |  | 
 | 	/* set the bits for the keys */ | 
 | 	IR_dprintk(1, "key map size: %d\n", rc_tab->size); | 
 | 	for (i = 0; i < rc_tab->size; i++) { | 
 | 		IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n", | 
 | 			i, keymap[i].keycode); | 
 | 		set_bit(keymap[i].keycode, input_dev->keybit); | 
 | 	} | 
 | 	clear_bit(0, input_dev->keybit); | 
 |  | 
 | 	set_bit(EV_KEY, input_dev->evbit); | 
 |  | 
 | 	input_dev->getkeycode = ir_getkeycode; | 
 | 	input_dev->setkeycode = ir_setkeycode; | 
 | 	input_set_drvdata(input_dev, ir_dev); | 
 |  | 
 | 	rc = input_register_device(input_dev); | 
 | 	if (rc < 0) | 
 | 		goto err; | 
 |  | 
 | 	rc = ir_register_class(input_dev); | 
 | 	if (rc < 0) { | 
 | 		input_unregister_device(input_dev); | 
 | 		goto err; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 |  | 
 | err: | 
 | 	kfree(rc_tab->scan); | 
 | 	kfree(ir_dev); | 
 | 	input_set_drvdata(input_dev, NULL); | 
 | 	return rc; | 
 | } | 
 | EXPORT_SYMBOL_GPL(ir_input_register); | 
 |  | 
 | /** | 
 |  * ir_input_unregister() - unregisters IR and frees resources | 
 |  * @input_dev:	the struct input_dev descriptor of the device | 
 |  | 
 |  * This routine is used to free memory and de-register interfaces. | 
 |  */ | 
 | void ir_input_unregister(struct input_dev *dev) | 
 | { | 
 | 	struct ir_input_dev *ir_dev = input_get_drvdata(dev); | 
 | 	struct ir_scancode_table *rc_tab; | 
 |  | 
 | 	if (!ir_dev) | 
 | 		return; | 
 |  | 
 | 	IR_dprintk(1, "Freed keycode table\n"); | 
 |  | 
 | 	rc_tab = &ir_dev->rc_tab; | 
 | 	rc_tab->size = 0; | 
 | 	kfree(rc_tab->scan); | 
 | 	rc_tab->scan = NULL; | 
 |  | 
 | 	ir_unregister_class(dev); | 
 |  | 
 | 	kfree(ir_dev); | 
 | 	input_unregister_device(dev); | 
 | } | 
 | EXPORT_SYMBOL_GPL(ir_input_unregister); | 
 |  | 
 | int ir_core_debug;    /* ir_debug level (0,1,2) */ | 
 | EXPORT_SYMBOL_GPL(ir_core_debug); | 
 | module_param_named(debug, ir_core_debug, int, 0644); | 
 |  | 
 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | 
 | MODULE_LICENSE("GPL"); |