ir-keytable.c 12.5 KB
Newer Older
1 2 3
/* ir-register.c - handle IR scancode->keycode tables
 *
 * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 5 6 7 8 9 10 11 12
 *
 * 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.
13 14 15
 */


16
#include <linux/input.h>
17
#include <linux/slab.h>
18 19
#include <media/ir-common.h>

20 21 22
/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
#define IR_TAB_MIN_SIZE	256
#define IR_TAB_MAX_SIZE	8192
23

24
/**
25 26 27
 * ir_resize_table() - resizes a scancode table if necessary
 * @rc_tab:	the ir_scancode_table to resize
 * @return:	zero on success or a negative error code
28
 *
29 30
 * This routine will shrink the ir_scancode_table if it has lots of
 * unused entries and grow it if it is full.
31
 */
32
static int ir_resize_table(struct ir_scancode_table *rc_tab)
33
{
34 35 36 37 38 39 40 41 42
	unsigned int oldalloc = rc_tab->alloc;
	unsigned int newalloc = oldalloc;
	struct ir_scancode *oldscan = rc_tab->scan;
	struct ir_scancode *newscan;

	if (rc_tab->size == rc_tab->len) {
		/* All entries in use -> grow keytable */
		if (rc_tab->alloc >= IR_TAB_MAX_SIZE)
			return -ENOMEM;
43

44 45 46
		newalloc *= 2;
		IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
	}
47

48 49 50 51 52
	if ((rc_tab->len * 3 < rc_tab->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
		/* Less than 1/3 of entries in use -> shrink keytable */
		newalloc /= 2;
		IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
	}
53

54 55
	if (newalloc == oldalloc)
		return 0;
56

57 58 59 60 61
	newscan = kmalloc(newalloc, GFP_ATOMIC);
	if (!newscan) {
		IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
		return -ENOMEM;
	}
62

63 64 65 66 67 68
	memcpy(newscan, rc_tab->scan, rc_tab->len * sizeof(struct ir_scancode));
	rc_tab->scan = newscan;
	rc_tab->alloc = newalloc;
	rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
	kfree(oldscan);
	return 0;
69 70
}

71
/**
72 73 74 75 76 77 78
 * ir_do_setkeycode() - internal function to set a keycode in the
 *			scancode->keycode table
 * @dev:	the struct input_dev device descriptor
 * @rc_tab:	the struct ir_scancode_table to set the keycode in
 * @scancode:	the scancode for the ir command
 * @keycode:	the keycode for the ir command
 * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
79
 *
80 81
 * This routine is used internally to manipulate the scancode->keycode table.
 * The caller has to hold @rc_tab->lock.
82
 */
83 84 85
static int ir_do_setkeycode(struct input_dev *dev,
			    struct ir_scancode_table *rc_tab,
			    unsigned scancode, unsigned keycode)
86
{
87 88 89 90 91 92 93 94 95 96
	unsigned int i;
	int old_keycode = KEY_RESERVED;

	/* First check if we already have a mapping for this ir command */
	for (i = 0; i < rc_tab->len; i++) {
		/* Keytable is sorted from lowest to highest scancode */
		if (rc_tab->scan[i].scancode > scancode)
			break;
		else if (rc_tab->scan[i].scancode < scancode)
			continue;
97

98 99
		old_keycode = rc_tab->scan[i].keycode;
		rc_tab->scan[i].keycode = keycode;
100

101 102
		/* Did the user wish to remove the mapping? */
		if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
103 104
			IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
				   i, scancode);
105 106 107 108
			rc_tab->len--;
			memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
				(rc_tab->len - i) * sizeof(struct ir_scancode));
		}
109

110 111 112 113
		/* Possibly shrink the keytable, failure is not a problem */
		ir_resize_table(rc_tab);
		break;
	}
114

115 116 117 118
	if (old_keycode == KEY_RESERVED) {
		/* No previous mapping found, we might need to grow the table */
		if (ir_resize_table(rc_tab))
			return -ENOMEM;
119

120 121 122
		IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
			   i, scancode, keycode);

123 124 125 126 127 128 129 130
		/* i is the proper index to insert our new keycode */
		memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
			(rc_tab->len - i) * sizeof(struct ir_scancode));
		rc_tab->scan[i].scancode = scancode;
		rc_tab->scan[i].keycode = keycode;
		rc_tab->len++;
		set_bit(keycode, dev->keybit);
	} else {
131 132
		IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
			   i, scancode, keycode);
133 134 135 136 137 138 139 140 141
		/* A previous mapping was updated... */
		clear_bit(old_keycode, dev->keybit);
		/* ...but another scancode might use the same keycode */
		for (i = 0; i < rc_tab->len; i++) {
			if (rc_tab->scan[i].keycode == old_keycode) {
				set_bit(old_keycode, dev->keybit);
				break;
			}
		}
142 143 144 145 146
	}

	return 0;
}

147
/**
148
 * ir_setkeycode() - set a keycode in the scancode->keycode table
149 150
 * @dev:	the struct input_dev device descriptor
 * @scancode:	the desired scancode
151 152
 * @keycode:	result
 * @return:	-EINVAL if the keycode could not be inserted, otherwise zero.
153
 *
154
 * This routine is used to handle evdev EVIOCSKEY ioctl.
155
 */
156 157
static int ir_setkeycode(struct input_dev *dev,
			 unsigned int scancode, unsigned int keycode)
158
{
159 160
	int rc;
	unsigned long flags;
161 162
	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
163

164 165 166 167
	spin_lock_irqsave(&rc_tab->lock, flags);
	rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode);
	spin_unlock_irqrestore(&rc_tab->lock, flags);
	return rc;
168 169 170
}

/**
171 172 173 174 175
 * ir_setkeytable() - sets several entries in the scancode->keycode table
 * @dev:	the struct input_dev device descriptor
 * @to:		the struct ir_scancode_table to copy entries to
 * @from:	the struct ir_scancode_table to copy entries from
 * @return:	-EINVAL if all keycodes could not be inserted, otherwise zero.
176
 *
177
 * This routine is used to handle table initialization.
178
 */
179 180 181
static int ir_setkeytable(struct input_dev *dev,
			  struct ir_scancode_table *to,
			  const struct ir_scancode_table *from)
182
{
183 184
	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
185
	unsigned long flags;
186 187
	unsigned int i;
	int rc = 0;
188 189

	spin_lock_irqsave(&rc_tab->lock, flags);
190 191 192 193 194
	for (i = 0; i < from->size; i++) {
		rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
				      from->scan[i].keycode);
		if (rc)
			break;
195 196
	}
	spin_unlock_irqrestore(&rc_tab->lock, flags);
197
	return rc;
198 199 200
}

/**
201
 * ir_getkeycode() - get a keycode from the scancode->keycode table
202 203
 * @dev:	the struct input_dev device descriptor
 * @scancode:	the desired scancode
204 205
 * @keycode:	used to return the keycode, if found, or KEY_RESERVED
 * @return:	always returns zero.
206
 *
207
 * This routine is used to handle evdev EVIOCGKEY ioctl.
208
 */
209 210
static int ir_getkeycode(struct input_dev *dev,
			 unsigned int scancode, unsigned int *keycode)
211
{
212 213 214
	int start, end, mid;
	unsigned long flags;
	int key = KEY_RESERVED;
215 216
	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
	struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
217

218 219 220 221 222 223 224 225 226 227 228 229 230
	spin_lock_irqsave(&rc_tab->lock, flags);
	start = 0;
	end = rc_tab->len - 1;
	while (start <= end) {
		mid = (start + end) / 2;
		if (rc_tab->scan[mid].scancode < scancode)
			start = mid + 1;
		else if (rc_tab->scan[mid].scancode > scancode)
			end = mid - 1;
		else {
			key = rc_tab->scan[mid].keycode;
			break;
		}
231
	}
232
	spin_unlock_irqrestore(&rc_tab->lock, flags);
233

234 235 236 237
	if (key == KEY_RESERVED)
		IR_dprintk(1, "unknown key for scancode 0x%04x\n",
			   scancode);

238
	*keycode = key;
239
	return 0;
240 241 242 243
}

/**
 * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
244
 * @input_dev:	the struct input_dev descriptor of the device
245 246 247 248
 * @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.
249
 * If the key is not found, it returns KEY_RESERVED. Otherwise, returns the
250 251 252 253
 * corresponding keycode from the table.
 */
u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
{
254
	int keycode;
255

256
	ir_getkeycode(dev, scancode, &keycode);
257 258 259
	if (keycode != KEY_RESERVED)
		IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
			   dev->name, scancode, keycode);
260
	return keycode;
261
}
262
EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
263

264 265 266 267 268 269 270 271 272 273 274 275 276 277
/**
 * ir_keyup() - generates input event to cleanup a key press
 * @input_dev:	the struct input_dev descriptor of the device
 *
 * This routine is used by the input routines when a key is pressed at the
 * IR. It reports a keyup input event via input_report_key().
 */
void ir_keyup(struct input_dev *dev)
{
	struct ir_input_dev *ir = input_get_drvdata(dev);

	if (!ir->keypressed)
		return;

278
	IR_dprintk(1, "keyup key 0x%04x\n", ir->keycode);
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
	input_report_key(dev, ir->keycode, 0);
	input_sync(dev);
	ir->keypressed = 0;
}
EXPORT_SYMBOL_GPL(ir_keyup);

/**
 * ir_keydown() - generates input event for a key press
 * @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. It gets the keycode for a scancode and reports an input event via
 * input_report_key().
 */
void ir_keydown(struct input_dev *dev, int scancode)
{
	struct ir_input_dev *ir = input_get_drvdata(dev);

	u32 keycode = ir_g_keycode_from_table(dev, scancode);

	/* If already sent a keydown, do a keyup */
	if (ir->keypressed)
		ir_keyup(dev);

	if (KEY_RESERVED == keycode)
		return;

	ir->keycode = keycode;
	ir->keypressed = 1;

	IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
		dev->name, keycode, scancode);

	input_report_key(dev, ir->keycode, 1);
	input_sync(dev);

}
EXPORT_SYMBOL_GPL(ir_keydown);

319 320 321 322 323 324 325 326 327 328 329 330 331
static int ir_open(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);

	return ir_dev->props->open(ir_dev->props->priv);
}

static void ir_close(struct input_dev *input_dev)
{
	struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);

	ir_dev->props->close(ir_dev->props->priv);
}
332

333
/**
334
 * __ir_input_register() - sets the IR keycode table and add the handlers
335 336 337 338
 *			    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
 *
339 340 341 342
 * 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
343
 */
344
int __ir_input_register(struct input_dev *input_dev,
345
		      const struct ir_scancode_table *rc_tab,
346 347
		      const struct ir_dev_props *props,
		      const char *driver_name)
348
{
349
	struct ir_input_dev *ir_dev;
350
	int rc;
351 352 353 354

	if (rc_tab->scan == NULL || !rc_tab->size)
		return -EINVAL;

355 356 357 358
	ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL);
	if (!ir_dev)
		return -ENOMEM;

359 360 361 362 363
	ir_dev->driver_name = kasprintf(GFP_KERNEL, "%s", driver_name);
	if (!ir_dev->driver_name) {
		rc = -ENOMEM;
		goto out_dev;
	}
364

365 366 367 368 369
	input_dev->getkeycode = ir_getkeycode;
	input_dev->setkeycode = ir_setkeycode;
	input_set_drvdata(input_dev, ir_dev);

	spin_lock_init(&ir_dev->rc_tab.lock);
370
	ir_dev->rc_tab.name = rc_tab->name;
371 372 373 374 375 376
	ir_dev->rc_tab.ir_type = rc_tab->ir_type;
	ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
						  sizeof(struct ir_scancode));
	ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
	ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);

377
	if (!ir_dev->rc_tab.scan) {
378 379
		rc = -ENOMEM;
		goto out_name;
380
	}
381

382 383 384 385 386 387 388 389
	IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
		   ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);

	set_bit(EV_KEY, input_dev->evbit);
	if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
		rc = -ENOMEM;
		goto out_table;
	}
390

391
	ir_dev->props = props;
392 393 394 395
	if (props && props->open)
		input_dev->open = ir_open;
	if (props && props->close)
		input_dev->close = ir_close;
396

397
	rc = ir_register_class(input_dev);
398
	if (rc < 0)
399
		goto out_table;
400

401 402 403
	IR_dprintk(1, "Registered input device on %s for %s remote.\n",
		   driver_name, rc_tab->name);

404 405
	return 0;

406 407 408 409 410
out_table:
	kfree(ir_dev->rc_tab.scan);
out_name:
	kfree(ir_dev->driver_name);
out_dev:
411
	kfree(ir_dev);
412
	return rc;
413
}
414
EXPORT_SYMBOL_GPL(__ir_input_register);
415

416 417 418 419 420 421
/**
 * 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.
 */
422
void ir_input_unregister(struct input_dev *dev)
423
{
424
	struct ir_input_dev *ir_dev = input_get_drvdata(dev);
425
	struct ir_scancode_table *rc_tab;
426

427
	if (!ir_dev)
428 429
		return;

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

432
	rc_tab = &ir_dev->rc_tab;
433 434 435
	rc_tab->size = 0;
	kfree(rc_tab->scan);
	rc_tab->scan = NULL;
436

437 438
	ir_unregister_class(dev);

439
	kfree(ir_dev->driver_name);
440
	kfree(ir_dev);
441
}
442
EXPORT_SYMBOL_GPL(ir_input_unregister);
443

444 445 446 447 448 449
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");