[PATCH 5/5] keytable: show lirc device and make test show lirc scancodes

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

 



Now you can see what protocol any remote is using the following command.

$ ir-keytable -c -p all -t
Old keytable cleared
Protocols changed to lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp
Testing events. Please, press CTRL-C to abort.
2124.576099: lirc protocol(rc5): scancode = 0x1e11
2124.576143: event type EV_MSC(0x04): scancode = 0x1e11
2124.576143: event type EV_SYN(0x00).
2125.601002: lirc protocol(rc6_mce): scancode = 0x800f0410
2125.601051: event type EV_MSC(0x04): scancode = 0x800f0410
2125.601051: event type EV_SYN(0x00).

Signed-off-by: Sean Young <sean@xxxxxxxx>
---
 utils/keytable/keytable.c | 140 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 134 insertions(+), 6 deletions(-)

diff --git a/utils/keytable/keytable.c b/utils/keytable/keytable.c
index 5d12ec31..f0744c6a 100644
--- a/utils/keytable/keytable.c
+++ b/utils/keytable/keytable.c
@@ -18,13 +18,16 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <string.h>
 #include <linux/input.h>
+#include <linux/lirc.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <argp.h>
+#include <time.h>
 #include <stdbool.h>
 
 #include "parse.h"
@@ -270,6 +273,7 @@ static int sysfs = 0;
 struct rc_device {
 	char *sysfs_name;	/* Device sysfs node name */
 	char *input_name;	/* Input device file name */
+	char *lirc_name;	/* Lirc device file name */
 	char *drv_name;		/* Kernel driver that implements it */
 	char *keytable_name;	/* Keycode table name */
 
@@ -1016,15 +1020,33 @@ static int v2_set_protocols(struct rc_device *rc_dev)
 static int get_attribs(struct rc_device *rc_dev, char *sysfs_name)
 {
 	struct uevents  *uevent;
-	char		*input = "input", *event = "event";
+	char		*input = "input", *event = "event", *lirc = "lirc";
 	char		*DEV = "/dev/";
-	static struct sysfs_names *input_names, *event_names, *attribs, *cur;
+	static struct sysfs_names *input_names, *event_names, *attribs, *cur, *lirc_names;
 
 	/* Clean the attributes */
 	memset(rc_dev, 0, sizeof(*rc_dev));
 
 	rc_dev->sysfs_name = sysfs_name;
 
+	lirc_names = seek_sysfs_dir(rc_dev->sysfs_name, lirc);
+	if (lirc_names) {
+		uevent = read_sysfs_uevents(lirc_names->name);
+		free_names(lirc_names);
+		if (uevent) {
+			while (uevent->next) {
+				if (!strcmp(uevent->key, "DEVNAME")) {
+					rc_dev->lirc_name = malloc(strlen(uevent->value) + strlen(DEV) + 1);
+					strcpy(rc_dev->lirc_name, DEV);
+					strcat(rc_dev->lirc_name, uevent->value);
+					break;
+				}
+				uevent = uevent->next;
+			}
+			free_uevent(uevent);
+		}
+	}
+
 	input_names = seek_sysfs_dir(rc_dev->sysfs_name, input);
 	if (!input_names)
 		return EINVAL;
@@ -1262,16 +1284,119 @@ static char *get_event_name(struct parse_event *event, u_int16_t code)
 	return "";
 }
 
-static void test_event(int fd)
+static void print_scancodes(const struct lirc_scancode *scancodes, unsigned count)
+{
+	unsigned i;
+
+	for (i=0; i< count; i++)  {
+		const char *p;
+		switch (scancodes[i].rc_proto) {
+			case RC_PROTO_UNKNOWN: p = "unknown"; break;
+			case RC_PROTO_OTHER: p = "other"; break;
+			case RC_PROTO_RC5: p = "rc5"; break;
+			case RC_PROTO_RC5X_20: p = "rc5x_20"; break;
+			case RC_PROTO_RC5_SZ: p = "rc5_sz"; break;
+			case RC_PROTO_JVC: p = "jvc"; break;
+			case RC_PROTO_SONY12: p = "sony12"; break;
+			case RC_PROTO_SONY15: p = "sony15"; break;
+			case RC_PROTO_SONY20: p = "sony20"; break;
+			case RC_PROTO_NEC: p = "nec"; break;
+			case RC_PROTO_NECX: p = "necx"; break;
+			case RC_PROTO_NEC32: p = "nec32"; break;
+			case RC_PROTO_SANYO: p = "sanyo"; break;
+			case RC_PROTO_MCIR2_KBD: p = "mcir2_kbd"; break;
+			case RC_PROTO_MCIR2_MSE: p = "mcri2_mse"; break;
+			case RC_PROTO_RC6_0: p = "rc6_0"; break;
+			case RC_PROTO_RC6_6A_20: p = "rc6_6a_20"; break;
+			case RC_PROTO_RC6_6A_24: p = "rc6_6a_24"; break;
+			case RC_PROTO_RC6_6A_32: p = "rc6_6a_32"; break;
+			case RC_PROTO_RC6_MCE: p = "rc6_mce"; break;
+			case RC_PROTO_SHARP: p = "sharp"; break;
+			case RC_PROTO_XMP: p = "xmp"; break;
+			case RC_PROTO_CEC: p = "cec"; break;
+			default: p = NULL; break;
+		}
+		printf(_("%llu.%06llu: "),
+			scancodes[i].timestamp / 1000000000ull,
+			(scancodes[i].timestamp % 1000000000ull) / 1000ull);
+
+		if (p)
+			printf(_("lirc protocol(%s): scancode = 0x%llx"),
+				p, scancodes[i].scancode);
+		else
+			printf(_("lirc protocol(%d): scancode = 0x%llx"),
+				scancodes[i].rc_proto, scancodes[i].scancode);
+
+		if (scancodes[i].flags & LIRC_SCANCODE_FLAG_REPEAT)
+			printf(_(" repeat"));
+		if (scancodes[i].flags & LIRC_SCANCODE_FLAG_TOGGLE)
+			printf(_(" toggle=1"));
+
+		printf("\n");
+	}
+}
+
+static void test_event(struct rc_device *rc_dev, int fd)
 {
 	struct input_event ev[64];
-	int rd, i;
+	struct lirc_scancode sc[64];
+	int rd, i, lircfd = -1;
+
+	if (rc_dev->lirc_name) {
+		lircfd = open(rc_dev->lirc_name, O_RDONLY | O_NONBLOCK);
+		if (lircfd == -1) {
+			perror(_("Can't open lirc device"));
+			return;
+		}
+		unsigned features;
+		if (ioctl(lircfd, LIRC_GET_FEATURES, &features)) {
+			perror(_("Can't get lirc features"));
+			return;
+		}
+
+		if (!(features & LIRC_CAN_REC_SCANCODE)) {
+			close(lircfd);
+			lircfd = -1;
+		}
+		else {
+			unsigned mode = LIRC_MODE_SCANCODE;
+			if (ioctl(lircfd, LIRC_SET_REC_MODE, &mode)) {
+				perror(_("Can't set lirc mode"));
+				return;
+			}
+
+			mode = CLOCK_MONOTONIC;
+			ioctl(fd, EVIOCSCLOCKID, &mode);
+		}
+	}
+
 
 	printf (_("Testing events. Please, press CTRL-C to abort.\n"));
 	while (1) {
+		struct pollfd pollstruct[2] = {
+			{ .fd = fd, .events = POLLIN },
+			{ .fd = lircfd, .events = POLLIN },
+		};
+
+		poll(pollstruct, lircfd != -1 ? 2 : 1, -1);
+
+		if (lircfd != -1) {
+			rd = read(lircfd, sc, sizeof(sc));
+
+			if (rd != -1) {
+				print_scancodes(sc, rd / sizeof(struct lirc_scancode));
+			} else if (errno != EAGAIN) {
+				perror(_("Error reading lirc scancode"));
+				return;
+			}
+		}
+
 		rd = read(fd, ev, sizeof(ev));
 
 		if (rd < (int) sizeof(struct input_event)) {
+			if (errno == EAGAIN)
+				continue;
+
 			perror(_("Error reading event"));
 			return;
 		}
@@ -1455,6 +1580,9 @@ static int show_sysfs_attribs(struct rc_device *rc_dev, char *name)
 			fprintf(stderr, _("\tDriver %s, table %s\n"),
 				rc_dev->drv_name,
 				rc_dev->keytable_name);
+			if (rc_dev->lirc_name)
+				fprintf(stderr, _("\tLirc device: %s\n"),
+					rc_dev->lirc_name);
 			fprintf(stderr, _("\tSupported protocols: "));
 			write_sysfs_protocols(rc_dev->supported, stderr, "%s ");
 			fprintf(stderr, "\n\t");
@@ -1585,7 +1713,7 @@ int main(int argc, char *argv[])
 
 	if (debug)
 		fprintf(stderr, _("Opening %s\n"), devicename);
-	fd = open(devicename, O_RDONLY);
+	fd = open(devicename, O_RDONLY | O_NONBLOCK);
 	if (fd < 0) {
 		perror(devicename);
 		return -1;
@@ -1644,7 +1772,7 @@ int main(int argc, char *argv[])
 	}
 
 	if (test)
-		test_event(fd);
+		test_event(&rc_dev, fd);
 
 	return 0;
 }
-- 
2.13.5




[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