Skip to content

Commit

Permalink
media: rc: make scancodes 64 bit
Browse files Browse the repository at this point in the history
There are many protocols that encode more than 32 bit. We want 64 bit
support so that BPF IR decoders can decode more than 32 bit. None of
the existing kernel IR decoders/encoders support 64 bit, for now.

The MSC_SCAN event can only contain 32 bit scancodes, so we only generate
MSC_SCAN events if the scancode fits into 32 bits. The full 64 bit
scancode can be read from the lirc chardev.

Signed-off-by: Sean Young <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
  • Loading branch information
seanyoung authored and mchehab committed Mar 12, 2020
1 parent 00c4308 commit e6c6d7d
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 39 deletions.
5 changes: 0 additions & 5 deletions drivers/media/rc/bpf-lirc.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ static const struct bpf_func_proto rc_repeat_proto = {
.arg1_type = ARG_PTR_TO_CTX,
};

/*
* Currently rc-core does not support 64-bit scancodes, but there are many
* known protocols with more than 32 bits. So, define the interface as u64
* as a future-proof.
*/
BPF_CALL_4(bpf_rc_keydown, u32*, sample, u32, protocol, u64, scancode,
u32, toggle)
{
Expand Down
7 changes: 1 addition & 6 deletions drivers/media/rc/lirc_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
goto out_unlock;
}

/*
* The scancode field in lirc_scancode is 64-bit simply
* to future-proof it, since there are IR protocols encode
* use more than 32 bits. For now only 32-bit protocols
* are supported.
*/
/* We only have encoders for 32-bit protocols. */
if (scan.scancode > U32_MAX ||
!rc_validate_scancode(scan.rc_proto, scan.scancode)) {
ret = -EINVAL;
Expand Down
80 changes: 58 additions & 22 deletions drivers/media/rc/rc-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,41 @@ static struct rc_map_list empty_map = {
}
};

/**
* scancode_to_u64() - converts scancode in &struct input_keymap_entry
* @ke: keymap entry containing scancode to be converted.
* @scancode: pointer to the location where converted scancode should
* be stored.
*
* This function is a version of input_scancode_to_scalar specialized for
* rc-core.
*/
static int scancode_to_u64(const struct input_keymap_entry *ke, u64 *scancode)
{
switch (ke->len) {
case 1:
*scancode = *((u8 *)ke->scancode);
break;

case 2:
*scancode = *((u16 *)ke->scancode);
break;

case 4:
*scancode = *((u32 *)ke->scancode);
break;

case 8:
*scancode = *((u64 *)ke->scancode);
break;

default:
return -EINVAL;
}

return 0;
}

/**
* ir_create_table() - initializes a scancode table
* @dev: the rc_dev device
Expand Down Expand Up @@ -285,13 +320,13 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,

/* Did the user wish to remove the mapping? */
if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n",
dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04llx\n",
index, rc_map->scan[index].scancode);
rc_map->len--;
memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
(rc_map->len - index) * sizeof(struct rc_map_table));
} else {
dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n",
dev_dbg(&dev->dev, "#%d: %s scan 0x%04llx with key 0x%04x\n",
index,
old_keycode == KEY_RESERVED ? "New" : "Replacing",
rc_map->scan[index].scancode, new_keycode);
Expand Down Expand Up @@ -334,8 +369,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
*/
static unsigned int ir_establish_scancode(struct rc_dev *dev,
struct rc_map *rc_map,
unsigned int scancode,
bool resize)
u64 scancode, bool resize)
{
unsigned int i;

Expand Down Expand Up @@ -394,7 +428,7 @@ static int ir_setkeycode(struct input_dev *idev,
struct rc_dev *rdev = input_get_drvdata(idev);
struct rc_map *rc_map = &rdev->rc_map;
unsigned int index;
unsigned int scancode;
u64 scancode;
int retval = 0;
unsigned long flags;

Expand All @@ -407,7 +441,7 @@ static int ir_setkeycode(struct input_dev *idev,
goto out;
}
} else {
retval = input_scancode_to_scalar(ke, &scancode);
retval = scancode_to_u64(ke, &scancode);
if (retval)
goto out;

Expand All @@ -434,8 +468,7 @@ static int ir_setkeycode(struct input_dev *idev,
*
* return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
*/
static int ir_setkeytable(struct rc_dev *dev,
const struct rc_map *from)
static int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
{
struct rc_map *rc_map = &dev->rc_map;
unsigned int i, index;
Expand Down Expand Up @@ -466,7 +499,7 @@ static int ir_setkeytable(struct rc_dev *dev,

static int rc_map_cmp(const void *key, const void *elt)
{
const unsigned int *scancode = key;
const u64 *scancode = key;
const struct rc_map_table *e = elt;

if (*scancode < e->scancode)
Expand All @@ -487,7 +520,7 @@ static int rc_map_cmp(const void *key, const void *elt)
* return: index in the table, -1U if not found
*/
static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
unsigned int scancode)
u64 scancode)
{
struct rc_map_table *res;

Expand Down Expand Up @@ -516,15 +549,15 @@ static int ir_getkeycode(struct input_dev *idev,
struct rc_map_table *entry;
unsigned long flags;
unsigned int index;
unsigned int scancode;
u64 scancode;
int retval;

spin_lock_irqsave(&rc_map->lock, flags);

if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
index = ke->index;
} else {
retval = input_scancode_to_scalar(ke, &scancode);
retval = scancode_to_u64(ke, &scancode);
if (retval)
goto out;

Expand All @@ -538,7 +571,6 @@ static int ir_getkeycode(struct input_dev *idev,
ke->keycode = entry->keycode;
ke->len = sizeof(entry->scancode);
memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));

} else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
/*
* We do not really know the valid range of scancodes
Expand Down Expand Up @@ -570,7 +602,7 @@ static int ir_getkeycode(struct input_dev *idev,
*
* return: the corresponding keycode, or KEY_RESERVED
*/
u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
u32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode)
{
struct rc_map *rc_map = &dev->rc_map;
unsigned int keycode;
Expand All @@ -586,7 +618,7 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
spin_unlock_irqrestore(&rc_map->lock, flags);

if (keycode != KEY_RESERVED)
dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n",
dev_dbg(&dev->dev, "%s: scancode 0x%04llx keycode 0x%02x\n",
dev->device_name, scancode, keycode);

return keycode;
Expand Down Expand Up @@ -719,8 +751,11 @@ void rc_repeat(struct rc_dev *dev)

spin_lock_irqsave(&dev->keylock, flags);

input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
input_sync(dev->input_dev);
if (dev->last_scancode <= U32_MAX) {
input_event(dev->input_dev, EV_MSC, MSC_SCAN,
dev->last_scancode);
input_sync(dev->input_dev);
}

if (dev->keypressed) {
dev->keyup_jiffies = jiffies + timeout;
Expand All @@ -743,7 +778,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
* called with keylock held.
*/
static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
u32 scancode, u32 keycode, u8 toggle)
u64 scancode, u32 keycode, u8 toggle)
{
bool new_event = (!dev->keypressed ||
dev->last_protocol != protocol ||
Expand All @@ -761,7 +796,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
if (new_event && dev->keypressed)
ir_do_keyup(dev, false);

input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
if (scancode <= U32_MAX)
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);

dev->last_protocol = protocol;
dev->last_scancode = scancode;
Expand All @@ -772,7 +808,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
/* Register a keypress */
dev->keypressed = true;

dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
dev->device_name, keycode, protocol, scancode);
input_report_key(dev->input_dev, keycode, 1);

Expand Down Expand Up @@ -809,7 +845,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
* This routine is used to signal that a key has been pressed on the
* remote control.
*/
void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode,
void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode,
u8 toggle)
{
unsigned long flags;
Expand Down Expand Up @@ -840,7 +876,7 @@ EXPORT_SYMBOL_GPL(rc_keydown);
* remote control. The driver must manually call rc_keyup() at a later stage.
*/
void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,
u32 scancode, u8 toggle)
u64 scancode, u8 toggle)
{
unsigned long flags;
u32 keycode = rc_g_keycode_from_table(dev, scancode);
Expand Down
8 changes: 4 additions & 4 deletions include/media/rc-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ struct rc_dev {
struct timer_list timer_repeat;
u32 last_keycode;
enum rc_proto last_protocol;
u32 last_scancode;
u64 last_scancode;
u8 last_toggle;
u32 timeout;
u32 min_timeout;
Expand Down Expand Up @@ -284,12 +284,12 @@ int devm_rc_register_device(struct device *parent, struct rc_dev *dev);
void rc_unregister_device(struct rc_dev *dev);

void rc_repeat(struct rc_dev *dev);
void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode,
void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode,
u8 toggle);
void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,
u32 scancode, u8 toggle);
u64 scancode, u8 toggle);
void rc_keyup(struct rc_dev *dev);
u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode);
u32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode);

/*
* From rc-raw.c
Expand Down
4 changes: 2 additions & 2 deletions include/media/rc-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@
/**
* struct rc_map_table - represents a scancode/keycode pair
*
* @scancode: scan code (u32)
* @scancode: scan code (u64)
* @keycode: Linux input keycode
*/
struct rc_map_table {
u32 scancode;
u64 scancode;
u32 keycode;
};

Expand Down

0 comments on commit e6c6d7d

Please sign in to comment.