ir-keytable.c 6.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
/* ir-register.c - handle IR scancode->keycode tables
 *
 * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
 */

#include <linux/usb/input.h>

#include <media/ir-common.h>

10 11
#define IR_TAB_MIN_SIZE	32

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
/**
 * 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;
}

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/**
 * 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.
 */
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
 */

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++) {
89 90 91 92 93 94
		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++;
95 96 97
	}
	destin->size = j;

98
	IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
99 100 101 102

	return 0;
}

103 104 105 106 107 108 109 110 111 112 113 114
/**
 * 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,
			 int scancode, int *keycode)
{
115
	int elem;
116 117
	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);

118 119 120 121 122
	elem = ir_seek_table(rc_tab, scancode);
	if (elem >= 0) {
		*keycode = rc_tab->scan[elem].keycode;
		return 0;
	}
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

	return -EINVAL;
}

/**
 * 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,
			 int scancode, int keycode)
{
140
	int rc = 0;
141 142
	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
	struct ir_scancode *keymap = rc_tab->scan;
143
	unsigned long flags;
144 145

	/* Search if it is replacing an existing keycode */
146 147 148
	rc = ir_seek_table(rc_tab, scancode);
	if (rc <0)
		return rc;
149

150 151
	IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
		rc, scancode, keycode);
152

153 154 155 156 157 158 159 160 161
	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;
162 163 164 165
}

/**
 * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
166
 * @input_dev:	the struct input_dev descriptor of the device
167 168 169 170 171 172 173 174 175 176 177
 * @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_scancode_table *rc_tab = input_get_drvdata(dev);
	struct ir_scancode *keymap = rc_tab->scan;
178
	int elem;
179

180 181 182 183
	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);
184

185 186
		return rc_tab->scan[elem].keycode;
	}
187 188 189 190

	printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
	       dev->name, scancode);

191 192
	/* Reports userspace that an unknown keycode were got */
	return KEY_RESERVED;
193 194 195 196 197 198 199 200 201
}

/**
 * ir_set_keycode_table() - 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
202 203
 * an IR.
 * It should be called before registering the IR device.
204 205 206 207 208 209 210
 */
int ir_set_keycode_table(struct input_dev *input_dev,
			 struct ir_scancode_table *rc_tab)
{
	struct ir_scancode *keymap = rc_tab->scan;
	int i;

211 212
	spin_lock_init(&rc_tab->lock);

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	if (rc_tab->scan == NULL || !rc_tab->size)
		return -EINVAL;

	/* 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);
	}

	input_dev->getkeycode = ir_getkeycode;
	input_dev->setkeycode = ir_setkeycode;
	input_set_drvdata(input_dev, rc_tab);

	return 0;
}
230 231 232 233 234 235 236 237 238 239 240 241 242

void ir_input_free(struct input_dev *dev)
{
	struct ir_scancode_table *rc_tab = input_get_drvdata(dev);

	IR_dprintk(1, "Freed keycode table\n");

	rc_tab->size = 0;
	kfree(rc_tab->scan);
	rc_tab->scan = NULL;
}
EXPORT_SYMBOL_GPL(ir_input_free);