Re: [PATCH 4/4] ir-keytable: allow protocol for scancode-keycode mappings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em Mon, 06 Apr 2015 13:26:18 +0200
David Härdeman <david@xxxxxxxxxxx> escreveu:

> Introduce a list of "kernel" ir protocols (e.g. "sony12" instead of "sony")
> and extend the set-key command to ir-keytable to allow for a mapping of the
> form "protocol:scancode=keycode" in addition to the old "scancode=keycode"
> format. The code automatically falls back to the old behaviour if the
> kernel doesn't support the new approach with protocols.
> 
> The read command is also updated to show the protocol information if the
> kernel supports it.


I applied patches 1 to 3 of this series, as they are not based on any
new feature.

This patch, however, needs to wait for the Kernel patch to be acked, and
may be modified, depending on the review process.

I'll mark it at patchwork as RFC. Please re-submit after we merge the
Kernel changes.

Thanks,
Mauro

> 
> Signed-off-by: David Härdeman <david@xxxxxxxxxxx>
> ---
>  utils/keytable/keytable.c |  288 ++++++++++++++++++++++++++++++++-------------
>  1 file changed, 202 insertions(+), 86 deletions(-)
> 
> diff --git a/utils/keytable/keytable.c b/utils/keytable/keytable.c
> index 63eea2e..fd50095 100644
> --- a/utils/keytable/keytable.c
> +++ b/utils/keytable/keytable.c
> @@ -55,13 +55,22 @@ struct input_keymap_entry_v2 {
>  #define EVIOCSKEYCODE_V2	_IOW('E', 0x04, struct input_keymap_entry_v2)
>  #endif
>  
> -struct keytable_entry {
> -	u_int32_t scancode;
> -	u_int32_t keycode;
> -	struct keytable_entry *next;
> +struct rc_scancode {
> +	u_int16_t protocol;
> +	u_int16_t reserved[3];
> +	u_int64_t scancode;
>  };
>  
> -struct keytable_entry *keytable = NULL;
> +struct rc_keymap_entry {
> +	u_int8_t  flags;
> +	u_int8_t  len;
> +	u_int16_t index;
> +	u_int32_t keycode;
> +	union {
> +		struct rc_scancode rc;
> +		u_int8_t raw[32];
> +	};
> +};
>  
>  struct uevents {
>  	char		*key;
> @@ -109,41 +118,76 @@ enum sysfs_protocols {
>  	SYSFS_INVALID		= 0,
>  };
>  
> +enum kernel_protocol {
> +	KERN_UNKNOWN		= 0,    /* Protocol not known */
> +	KERN_OTHER		= 1,    /* Protocol known but proprietary */
> +	KERN_LIRC		= 2,    /* Pass raw IR to lirc userspace */
> +	KERN_RC5		= 3,    /* Philips RC5 protocol */
> +	KERN_RC5X		= 4,    /* Philips RC5x protocol */
> +	KERN_RC5_SZ		= 5,    /* StreamZap variant of RC5 */
> +	KERN_JVC		= 6,    /* JVC protocol */
> +	KERN_SONY12		= 7,    /* Sony 12 bit protocol */
> +	KERN_SONY15		= 8,    /* Sony 15 bit protocol */
> +	KERN_SONY20		= 9,    /* Sony 20 bit protocol */
> +	KERN_NEC		= 10,   /* NEC protocol */
> +	KERN_SANYO		= 11,   /* Sanyo protocol */
> +	KERN_MCE_KBD		= 12,   /* RC6-ish MCE keyboard/mouse */
> +	KERN_RC6_0		= 13,   /* Philips RC6-0-16 protocol */
> +	KERN_RC6_6A_20		= 14,   /* Philips RC6-6A-20 protocol */
> +	KERN_RC6_6A_24		= 15,   /* Philips RC6-6A-24 protocol */
> +	KERN_RC6_6A_32		= 16,   /* Philips RC6-6A-32 protocol */
> +	KERN_RC6_MCE		= 17,   /* MCE (Philips RC6-6A-32 subtype) protocol */
> +	KERN_SHARP		= 18,   /* Sharp protocol */
> +	KERN_XMP		= 19,   /* XMP protocol */
> +	KERN_INVALID		= 31,	/* internal, no real protocol number */
> +};
> +
>  struct protocol_map_entry {
>  	const char *name;
>  	const char *sysfs1_name;
>  	enum sysfs_protocols sysfs_protocol;
> +	enum kernel_protocol kernel_protocol;
>  };
>  
>  const struct protocol_map_entry protocol_map[] = {
> -	{ "unknown",	NULL,		SYSFS_UNKNOWN	},
> -	{ "other",	NULL,		SYSFS_OTHER	},
> -	{ "lirc",	NULL,		SYSFS_LIRC	},
> -	{ "rc-5",	"/rc5_decoder",	SYSFS_RC5	},
> -	{ "rc5",	NULL,		SYSFS_RC5	},
> -	{ "rc-5x",	NULL,		SYSFS_INVALID	},
> -	{ "rc5x",	NULL,		SYSFS_INVALID	},
> -	{ "jvc",	"/jvc_decoder",	SYSFS_JVC	},
> -	{ "sony",	"/sony_decoder",SYSFS_SONY	},
> -	{ "sony12",	NULL,		SYSFS_INVALID	},
> -	{ "sony15",	NULL,		SYSFS_INVALID	},
> -	{ "sony20",	NULL,		SYSFS_INVALID	},
> -	{ "nec",	"/nec_decoder",	SYSFS_NEC	},
> -	{ "sanyo",	NULL,		SYSFS_SANYO	},
> -	{ "mce-kbd",	NULL,		SYSFS_MCE_KBD	},
> -	{ "mce_kbd",	NULL,		SYSFS_MCE_KBD	},
> -	{ "rc-6",	"/rc6_decoder",	SYSFS_RC6	},
> -	{ "rc6",	NULL,		SYSFS_RC6	},
> -	{ "rc-6-0",	NULL,		SYSFS_INVALID	},
> -	{ "rc-6-6a-20",	NULL,		SYSFS_INVALID	},
> -	{ "rc-6-6a-24",	NULL,		SYSFS_INVALID	},
> -	{ "rc-6-6a-32",	NULL,		SYSFS_INVALID	},
> -	{ "rc-6-mce",	NULL,		SYSFS_INVALID	},
> -	{ "sharp",	NULL,		SYSFS_SHARP	},
> -	{ "xmp",	"/xmp_decoder",	SYSFS_XMP	},
> -	{ NULL,		NULL,		SYSFS_INVALID	},
> +	{ "unknown",	NULL,		SYSFS_UNKNOWN,	KERN_UNKNOWN	},
> +	{ "other",	NULL,		SYSFS_OTHER,	KERN_OTHER	},
> +	{ "lirc",	NULL,		SYSFS_LIRC,	KERN_LIRC	},
> +	{ "rc-5",	"/rc5_decoder",	SYSFS_RC5,	KERN_RC5	},
> +	{ "rc5",	NULL,		SYSFS_RC5,	KERN_RC5	},
> +	{ "rc-5x",	NULL,		SYSFS_INVALID,	KERN_RC5X	},
> +	{ "rc5x",	NULL,		SYSFS_INVALID,	KERN_RC5X	},
> +	{ "jvc",	"/jvc_decoder",	SYSFS_JVC,	KERN_JVC	},
> +	{ "sony",	"/sony_decoder",SYSFS_SONY,	KERN_INVALID	},
> +	{ "sony12",	NULL,		SYSFS_INVALID,	KERN_SONY12	},
> +	{ "sony15",	NULL,		SYSFS_INVALID,	KERN_SONY15	},
> +	{ "sony20",	NULL,		SYSFS_INVALID,	KERN_SONY20	},
> +	{ "nec",	"/nec_decoder",	SYSFS_NEC,	KERN_NEC	},
> +	{ "sanyo",	NULL,		SYSFS_SANYO,	KERN_SANYO	},
> +	{ "mce-kbd",	NULL,		SYSFS_MCE_KBD,	KERN_MCE_KBD	},
> +	{ "mce_kbd",	NULL,		SYSFS_MCE_KBD,	KERN_MCE_KBD	},
> +	{ "rc-6",	"/rc6_decoder",	SYSFS_RC6,	KERN_INVALID	},
> +	{ "rc6",	NULL,		SYSFS_RC6,	KERN_INVALID 	},
> +	{ "rc-6-0",	NULL,		SYSFS_INVALID,	KERN_RC6_0	},
> +	{ "rc-6-6a-20",	NULL,		SYSFS_INVALID,	KERN_RC6_6A_20	},
> +	{ "rc-6-6a-24",	NULL,		SYSFS_INVALID,	KERN_RC6_6A_24	},
> +	{ "rc-6-6a-32",	NULL,		SYSFS_INVALID,	KERN_RC6_6A_32	},
> +	{ "rc-6-mce",	NULL,		SYSFS_INVALID,	KERN_RC6_MCE	},
> +	{ "sharp",	NULL,		SYSFS_SHARP,	KERN_SHARP	},
> +	{ "xmp",	"/xmp_decoder",	SYSFS_XMP,	KERN_XMP	},
> +	{ NULL,		NULL,		SYSFS_INVALID,	KERN_INVALID	},
> +};
> +
> +struct keytable_entry {
> +	u_int32_t scancode;
> +	u_int32_t keycode;
> +	enum kernel_protocol protocol;
> +	struct keytable_entry *next;
>  };
>  
> +struct keytable_entry *keytable = NULL;
> +
> +
>  static enum sysfs_protocols parse_sysfs_protocol(const char *name, bool all_allowed)
>  {
>  	const struct protocol_map_entry *pme;
> @@ -162,6 +206,21 @@ static enum sysfs_protocols parse_sysfs_protocol(const char *name, bool all_allo
>  	return SYSFS_INVALID;
>  }
>  
> +static enum kernel_protocol parse_kernel_protocol(const char *name)
> +{
> +	const struct protocol_map_entry *pme;
> +
> +	if (!name)
> +		return KERN_INVALID;
> +
> +	for (pme = protocol_map; pme->name; pme++) {
> +		if (!strcasecmp(name, pme->name))
> +			return pme->kernel_protocol;
> +	}
> +
> +	return KERN_INVALID;
> +}
> +
>  static void write_sysfs_protocols(enum sysfs_protocols protocols, FILE *fp, const char *fmt)
>  {
>  	const struct protocol_map_entry *pme;
> @@ -197,6 +256,7 @@ static const char doc[] = N_(
>  	"  SYSDEV   - the ir class as found at /sys/class/rc\n"
>  	"  TABLE    - a file with a set of scancode=keycode value pairs\n"
>  	"  SCANKEY  - a set of scancode1=keycode1,scancode2=keycode2.. value pairs\n"
> +	"             or (experimentally) a list of protocol1:scancode1=keycode1,protocol2:scancode2=keycode2...triplets\n"
>  	"  PROTOCOL - protocol name (nec, rc-5, rc-6, jvc, sony, sanyo, rc-5-sz, lirc,\n"
>  	"                            sharp, mce_kbd, xmp, other, all) to be enabled\n"
>  	"  DELAY    - Delay before repeating a keystroke\n"
> @@ -447,7 +507,6 @@ err_einval:
>  static error_t parse_opt(int k, char *arg, struct argp_state *state)
>  {
>  	char *p;
> -	long key;
>  	int rc;
>  
>  	switch (k) {
> @@ -492,51 +551,69 @@ static error_t parse_opt(int k, char *arg, struct argp_state *state)
>  		break;
>  	}
>  	case 'k':
> -		p = strtok(arg, ":=");
> -		do {
> +		for (p = strtok(arg, ",;"); p; p = strtok(NULL, ",;")) {
> +			char *protocol_str;
> +			enum kernel_protocol protocol = KERN_INVALID;
> +			long long int scancode;
> +			char *keycode_str;
> +			long keycode;
>  			struct keytable_entry *ke;
>  
> -			if (!p)
> -				goto err_inval;
> -
> -			ke = calloc(1, sizeof(*ke));
> -			if (!ke) {
> -				perror(_("No memory!\n"));
> -				return ENOMEM;
> +			errno = 0;
> +			/* New format - protocol:scancode=keycode */
> +			if (sscanf(p, " %m[^:] : %lli = %ms", &protocol_str, &scancode, &keycode_str) != 3) {
> +			       if (errno != 0) {
> +				       fprintf(stderr, _("sscanf failed!\n"));
> +				       return errno;
> +			       }
> +
> +			       /* Old format - scancode=keycode */
> +			       protocol_str = NULL;
> +			       if (sscanf(p, " %lli = %ms", &scancode, &keycode_str) != 2) {
> +				       if (errno != 0) {
> +					       fprintf(stderr, _("sscanf failed!\n"));
> +					       return errno;
> +				       }
> +				       goto err_inval;
> +			       }
>  			}
>  
> -			ke->scancode = strtoul(p, NULL, 0);
> -			if (errno) {
> -				free(ke);
> -				goto err_inval;
> +			keycode = parse_code(keycode_str);
> +			if (keycode == -1) {
> +				errno = 0;
> +				keycode = strtoul(keycode_str, NULL, 0);
> +				if (errno)
> +					keycode = -1;
>  			}
> +			free(keycode_str);
>  
> -			p = strtok(NULL, ",;");
> -			if (!p) {
> -				free(ke);
> -				goto err_inval;
> -			}
> +			if (protocol_str) {
> +				protocol = parse_kernel_protocol(protocol_str);
> +				free(protocol_str);
>  
> -			key = parse_code(p);
> -			if (key == -1) {
> -				key = strtol(p, NULL, 0);
> -				if (errno) {
> -					free(ke);
> +				if (protocol == KERN_INVALID)
>  					goto err_inval;
> -				}
>  			}
>  
> -			ke->keycode = key;
> +			if (keycode == -1 || scancode < 0)
> +				goto err_inval;
>  
> -			if (debug)
> -				fprintf(stderr, _("scancode 0x%04x=%u\n"),
> -					ke->scancode, ke->keycode);
> +			ke = calloc(1, sizeof(*ke));
> +			if (!ke) {
> +				perror(_("No memory!\n"));
> +				return ENOMEM;
> +			}
>  
> +			ke->scancode = scancode;
> +			ke->keycode = keycode;
> +			ke->protocol = protocol;
>  			ke->next = keytable;
>  			keytable = ke;
>  
> -			p = strtok(NULL, ":=");
> -		} while (p);
> +			if (debug)
> +				fprintf(stderr, _("scancode %i:0x%04x=%u\n"),
> +					ke->protocol, ke->scancode, ke->keycode);
> +		}
>  		break;
>  	case 'p':
>  		for (p = strtok(arg, ",;"); p; p = strtok(NULL, ",;")) {
> @@ -579,21 +656,24 @@ static struct argp argp = {
>  	.doc = doc,
>  };
>  
> -static void prtcode(int *codes)
> +static void print_mapping(enum kernel_protocol protocol, unsigned scancode, unsigned keycode)
>  {
>  	struct parse_event *p;
>  
> +	if (protocol != KERN_INVALID)
> +		printf(_("protocol 0x%04x, "), protocol);
> +
>  	for (p = key_events; p->name != NULL; p++) {
> -		if (p->value == (unsigned)codes[1]) {
> -			printf(_("scancode 0x%04x = %s (0x%02x)\n"), codes[0], p->name, codes[1]);
> +		if (p->value == keycode) {
> +			printf(_("scancode 0x%04x = %s (0x%02x)\n"), scancode, p->name, keycode);
>  			return;
>  		}
>  	}
>  
> -	if (isprint (codes[1]))
> -		printf(_("scancode 0x%04x = '%c' (0x%02x)\n"), codes[0], codes[1], codes[1]);
> +	if (isprint(keycode))
> +		printf(_("scancode 0x%04x = '%c' (0x%02x)\n"), scancode, keycode, keycode);
>  	else
> -		printf(_("scancode 0x%04x = 0x%02x\n"), codes[0], codes[1]);
> +		printf(_("scancode 0x%04x = 0x%02x\n"), scancode, keycode);
>  }
>  
>  static void free_names(struct sysfs_names *names)
> @@ -1201,12 +1281,30 @@ static int add_keys(int fd)
>  	int write_cnt = 0;
>  	struct keytable_entry *ke;
>  	unsigned codes[2];
> +	struct rc_keymap_entry rke;
>  
>  	for (ke = keytable; ke; ke = ke->next) {
>  		write_cnt++;
>  		if (debug)
> -			fprintf(stderr, "\t%04x=%04x\n",
> -				ke->scancode, ke->keycode);
> +			fprintf(stderr, "\t%u:%04x=%04x\n",
> +				ke->protocol, ke->scancode, ke->keycode);
> +
> +		if (ke->protocol != KERN_INVALID) {
> +			memset(&rke, '\0', sizeof(rke));
> +			rke.len = sizeof(rke.rc);
> +			rke.keycode = ke->keycode;
> +			rke.rc.protocol = ke->protocol;
> +			rke.rc.scancode = ke->scancode;
> +
> +			if (debug)
> +				fprintf(stderr, _("Attempting new EVIOCSKEYCODE_V2 ioctl\n"));
> +
> +			if (ioctl(fd, EVIOCSKEYCODE_V2, &rke) == 0)
> +				continue;
> +
> +			if (debug)
> +				fprintf(stderr, _("New EVIOCSKEYCODE_V2 ioctl failed\n"));
> +		}
>  
>  		codes[0] = ke->scancode;
>  		codes[1] = ke->keycode;
> @@ -1329,7 +1427,7 @@ static void display_table_v1(struct rc_device *rc_dev, int fd)
>  			if (ioctl(fd, EVIOCGKEYCODE, codes) == -1)
>  				perror("EVIOCGKEYCODE");
>  			else if (codes[1] != KEY_RESERVED)
> -				prtcode(codes);
> +				print_mapping(KERN_INVALID, codes[0], codes[1]);
>  		}
>  	}
>  	display_proto(rc_dev);
> @@ -1337,27 +1435,45 @@ static void display_table_v1(struct rc_device *rc_dev, int fd)
>  
>  static void display_table_v2(struct rc_device *rc_dev, int fd)
>  {
> +	struct input_keymap_entry_v2 ike;
> +	struct rc_keymap_entry rke;
> +	bool first = true, rke_supported = true;
> +	u_int32_t scancode;
>  	int i;
> -	struct input_keymap_entry_v2 entry;
> -	int codes[2];
>  
> -	memset(&entry, '\0', sizeof(entry));
> -	i = 0;
> -	do {
> -		entry.flags = KEYMAP_BY_INDEX;
> -		entry.index = i;
> -		entry.len = sizeof(u_int32_t);
> +	for (i = 0; ; i++) {
> +		if (first || rke_supported) {
> +			memset(&rke, '\0', sizeof(rke));
> +			rke.flags = KEYMAP_BY_INDEX;
> +			rke.index = i;
> +			rke.len = sizeof(rke.rc);
>  
> -		if (ioctl(fd, EVIOCGKEYCODE_V2, &entry) == -1)
> +			if (ioctl(fd, EVIOCGKEYCODE_V2, &rke) == -1) {
> +				if (first)
> +					rke_supported = false;
> +				else
> +					break;
> +			}
> +
> +			first = false;
> +			if (rke_supported) {
> +				print_mapping(rke.rc.protocol, rke.rc.scancode, rke.keycode);
> +				continue;
> +			}
> +		}
> +
> +		memset(&ike, '\0', sizeof(ike));
> +		ike.flags = KEYMAP_BY_INDEX;
> +		ike.index = i;
> +		ike.len = sizeof(scancode);
> +
> +		if (ioctl(fd, EVIOCGKEYCODE_V2, &ike) == -1)
>  			break;
>  
>  		/* FIXME: Extend it to support scancodes > 32 bits */
> -		memcpy(&codes[0], entry.scancode, sizeof(codes[0]));
> -		codes[1] = entry.keycode;
> -
> -		prtcode(codes);
> -		i++;
> -	} while (1);
> +		memcpy(&scancode, ike.scancode, sizeof(scancode));
> +		print_mapping(KERN_INVALID, scancode, ike.keycode);
> +	}
>  	display_proto(rc_dev);
>  }
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux