Skip to content

Commit

Permalink
V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keyco…
Browse files Browse the repository at this point in the history
…de table

V4L drivers use an static keycode vector with 128 entries, where the scancode
indexes the keycode. While this works, it limits the scancodes to have only
7 bits, not allowing for example full RC5 codes.

Instead of implementing the same code on every V4L driver, provide a common
infrastructure to handle the bigger tables, minimizing the changes inside
each driver.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Mauro Carvalho Chehab committed Dec 5, 2009
1 parent 4e89217 commit ef53a11
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 2 deletions.
2 changes: 1 addition & 1 deletion drivers/media/common/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
saa7146-objs := saa7146_i2c.o saa7146_core.o
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
ir-common-objs := ir-functions.o ir-keymaps.o ir-keytable.o

obj-y += tuners/
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
Expand Down
156 changes: 156 additions & 0 deletions drivers/media/common/ir-keytable.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* 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>

/**
* 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)
{
int i;
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
struct ir_scancode *keymap = rc_tab->scan;

/* See if we can match the raw key code. */
for (i = 0; i < rc_tab->size; i++)
if (keymap[i].scancode == scancode) {
*keycode = keymap[i].keycode;
return 0;
}

/*
* If is there extra space, returns KEY_RESERVED,
* otherwise, input core won't let ir_setkeycode
* to work
*/
for (i = 0; i < rc_tab->size; i++)
if (keymap[i].keycode == KEY_RESERVED ||
keymap[i].keycode == KEY_UNKNOWN) {
*keycode = KEY_RESERVED;
return 0;
}

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)
{
int i;
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
struct ir_scancode *keymap = rc_tab->scan;

/* Search if it is replacing an existing keycode */
for (i = 0; i < rc_tab->size; i++)
if (keymap[i].scancode == scancode) {
keymap[i].keycode = keycode;
return 0;
}

/* Search if is there a clean entry. If so, use it */
for (i = 0; i < rc_tab->size; i++)
if (keymap[i].keycode == KEY_RESERVED ||
keymap[i].keycode == KEY_UNKNOWN) {
keymap[i].scancode = scancode;
keymap[i].keycode = keycode;
return 0;
}

/*
* FIXME: Currently, it is not possible to increase the size of
* scancode table. For it to happen, one possibility
* would be to allocate a table with key_map_size + 1,
* copying data, appending the new key on it, and freeing
* the old one - or maybe just allocating some spare space
*/

return -EINVAL;
}

/**
* ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
* @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.
*/
u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
{
int i;
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
struct ir_scancode *keymap = rc_tab->scan;

for (i = 0; i < rc_tab->size; i++)
if (keymap[i].scancode == scancode) {
IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
dev->name, scancode, keymap[i].keycode);

return keymap[i].keycode;
}

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

return KEY_UNKNOWN;
}
EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);

/**
* 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
* an IR. It requires that the caller initializes the input_dev struct with
* some fields: name,
*/
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;

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;
}
EXPORT_SYMBOL_GPL(ir_set_keycode_table);
12 changes: 11 additions & 1 deletion include/media/ir-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ struct card_ir {
struct tasklet_struct tlet;
};

/* Routines from ir-functions.c */

void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
int ir_type, struct ir_scancode_table *ir_codes);
void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir);
Expand All @@ -120,7 +122,15 @@ u32 ir_rc5_decode(unsigned int code);
void ir_rc5_timer_end(unsigned long data);
void ir_rc5_timer_keyup(unsigned long data);

/* Keymaps to be used by other modules */
/* Routines from ir-keytable.c */

u32 ir_g_keycode_from_table(struct input_dev *input_dev,
u32 scancode);

int ir_set_keycode_table(struct input_dev *input_dev,
struct ir_scancode_table *rc_tab);

/* scancode->keycode map tables from ir-keymaps.c */

extern struct ir_scancode_table ir_codes_empty_table;
extern struct ir_scancode_table ir_codes_avermedia_table;
Expand Down

0 comments on commit ef53a11

Please sign in to comment.