LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 10-06-2011, 10:07 PM   #1
Litch84
LQ Newbie
 
Registered: Nov 2009
Posts: 4

Rep: Reputation: 0
Get /dev/input/eventX from VID:PID (C/C++)


I have a known USB HID device XYZ, which has a known VID:PID (It's an RFID Scanner that acts like a keyboard).

I need to know (once it's plugged in) how to get the /dev/input/eventX path by just knowing it's VID:PID...

(Solution in C/C++)

Any ideas?
Does the linux event subsystem have an enumeration function?
 
Old 10-08-2011, 06:49 AM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942Reputation: 942
Each event interface is listed in /sys/class/input/ as a directory. USB devices will have the vendor ID in hexadecimal in /sys/class/input/eventX/device/id/vendor and product ID in /sys/class/input/eventX/device/id/product. You can rely on /sys being mounted, since otherwise a lot of programs (and even some GNU C library functions) may stop working.

The implementation depends on your approach, but here is a thread-safe example in C99:
Code:
#define  _POSIX_C_SOURCE 200808L
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

static char *strmerge(const char *const s1, const char *const s2)
{
	const size_t	 n1 = s1 ? strlen(s1) : 0;
	const size_t	 n2 = s2 ? strlen(s2) : 0;
	char		*s;

	if (!n1 && !n2) {
		errno = EINVAL;
		return NULL;
	}

	s = malloc(n1 + n2 + 1);
	if (!s) {
		errno = ENOMEM;
		return NULL;
	}

	if (n1)	memcpy(s, s1, n1);
	if (n2)	memcpy(s + n1, s2, n2);
	s[n1 + n2] = 0;

	return s;
}

static int read_hex(const char *const filename)
{
	FILE		*in;
	unsigned int	 value;

	in = fopen(filename, "rb");
	if (!in)
		return -1;

	if (fscanf(in, "%x", &value) == 1) {
		fclose(in);
		return (int)value;
	}

	fclose(in);
	return -1;
}

static int vendor_id(const char *const event)
{
	if (event && *event) {
		char	filename[256];
		int	result;

		result = snprintf(filename, sizeof(filename), "/sys/class/input/%s/device/id/vendor", event);
		if (result < 1 || result >= sizeof(filename))
			return -1;

		return read_hex(filename);
	}
	return -1;
}

static int product_id(const char *const event)
{
	if (event && *event) {
		char	filename[256];
		int	result;

		result = snprintf(filename, sizeof(filename), "/sys/class/input/%s/device/id/product", event);
		if (result < 1 || result >= sizeof(filename))
			return -1;

		return read_hex(filename);
	}
	return -1;
}

char *find_event(const int vendor, const int product)
{
	DIR		*dir;
	struct dirent	*cache, *entry;
	char		*name;
	long		 maxlen;
	int		 result;

	maxlen = pathconf("/sys/class/input/", _PC_NAME_MAX);
	if (maxlen == -1L)
		return NULL;

	dir = opendir("/sys/class/input");
	if (!dir)
		return NULL;

	cache = malloc(offsetof(struct dirent, d_name) + maxlen + 1);
	if (!cache) {
		closedir(dir);
		errno = ENOMEM;
		return NULL;
	}

	while (1) {

		entry = NULL;
		result = readdir_r(dir, cache, &entry);
		if (result) {
			free(cache);
			closedir(dir);
			errno = result;
			return NULL;
		}

		if (!entry) {
			free(cache);
			closedir(dir);
			errno = ENOENT;
			return NULL;
		}

		if (vendor_id(entry->d_name) == vendor &&
		    product_id(entry->d_name) == product) {
			name = strmerge("/dev/input/", entry->d_name);
			free(cache);
			closedir(dir);
			if (name)
				return name;
			errno = ENOMEM;
			return NULL;
		}

	}
}

int main(int argc, char *argv[])
{
	int		 arg, status;
	unsigned int	 vendor, product;
	char		*event;
	char		 dummy;

	if (argc < 2) {
		fprintf(stderr, "\nUsage: %s vendor:product\n\n", argv[0]);
		return 0;
	}

	status = 0;

	for (arg = 1; arg < argc; arg++)
		if (sscanf(argv[arg], "%x:%x %c", &vendor, &product, &dummy) == 2) {
			event = find_event((int)vendor, (int)product);
			if (event) {
				fprintf(stdout, "%s (%s)\n", event, argv[arg]);
				fflush(stdout);
				free(event);
			} else {
				fprintf(stderr, "%s not found.\n", argv[arg]);
				fflush(stderr);
				status |= 2;
			}
		} else {
			fprintf(stderr, "%s is not a valid vendor:product.\n", argv[arg]);
			fflush(stderr);
			status |= 1;
		}

	return status;
}
The function find_event() will return the path to the event device, if it finds a matching vendorroduct input device. Note the careful error handling, and use of re-entrant readdir_r() (for threaded programs). I supplied the main() too for testing, so you can compile and run it as a standalone program first. I am sure this could be written in a much cleaner manner, and I would not be surprised if something like this is already available in a library, but this should do for an example.

Hope you find it useful,
 
  


Reply

Tags
event, hid, input, usb


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
HAL vs Xserver (/dev/input/mice?): convincing X to *not* use a given input device? stuartnlevy Linux - Desktop 6 01-24-2012 05:06 PM
Mouse going back and forth between /dev/input/event3 and /dev/input/event4 Linux.tar.gz Linux - Hardware 2 03-05-2011 05:46 PM
using libusb find device VID & PID on Solaris xwhbin Solaris / OpenSolaris 2 05-19-2010 02:05 AM
[SOLVED] Touchscreen input device not appearing in /dev/input rohshall Linux - Embedded & Single-board computer 4 08-21-2009 11:39 AM
usb bluetooth modify vid & pid scan73 Linux - Newbie 1 02-11-2008 11:35 PM


All times are GMT -5. The time now is 11:20 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration