linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: R0b0t1 <r030t1@gmail.com>
To: linux-input@vger.kernel.org, linux-usb@vger.kernel.org
Subject: UHID Device Reports Do Not Generate OS Activity
Date: Sat, 10 Feb 2018 03:33:41 -0600	[thread overview]
Message-ID: <CAAD4mYj0pUUbwX8mKDP2qTn=QZM9ubk3f9FsabefK4xntY7bFA@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 559 bytes --]

Hello,

I am trying to simulate a keyboard using the uhid interface. The fake
device shows up in dmesg, but attempting to press the "a" key does
nothing I can see. No input appears in the active terminal, nor in an
xev window.

The program receives UHID_OPEN, UHID_START, and UHID_CLOSE.

Many different report descriptors were tried. The one currently
uncommented is the one distributed with the USB implementor forum's
HID report descriptor tool. The other is one found in a description of
a boot device compatible keyboard.

Thanks in advance,
     R0b0t1

[-- Attachment #2: kbd.c --]
[-- Type: text/x-csrc, Size: 4931 bytes --]

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>

#include <errno.h>
#include <fcntl.h>
#include <poll.h>

#include <sys/ioctl.h>
#include <linux/uhid.h>

#define handle_error(m) \
	do { perror(m); exit(EXIT_FAILURE); } while (0)

static unsigned char rdesc[] = {
	0x05, 0x01,
	0x09, 0x06,
	0xa1, 0x01,

	0x05, 0x07,
	0x19, 0xe0,
	0x29, 0xe7,
	0x15, 0x00,
	0x25, 0x01,
	0x75, 0x01,
	0x95, 0x08,
	0x81, 0x02,

	0x95, 0x01,
	0x75, 0x08,
	0x81, 0x03,

	0x95, 0x05,
	0x75, 0x01,
	0x05, 0x08,
	0x19, 0x01,
	0x29, 0x05,
	0x91, 0x02,

	0x95, 0x01,
	0x75, 0x03,
	0x91, 0x03,

	0x95, 0x06,
	0x75, 0x08,
	0x15, 0x00,
	0x25, 0x65,
	0x05, 0x07,
	0x19, 0x00,
	0x29, 0x65,
	0x81, 0x00,

	0xc0
};

/*
static unsigned char rdesc[] = {
	0x05, 0x01, // Usage Page (Generic Desktop)
	0x09, 0x06, // Usage (Keyboard)

	0xa1, 0x01, // Collection (Application)
	
	// Modifier report.
	0x75, 0x01, // Report Size (1)
	0x95, 0x08, // Report Count (8)
	0x05, 0x07, // Usage Page (Key Codes)
	0x19, 0xe0, // Usage Minimum (224)
	0x29, 0xe7, // Usage Maximum (231)
	0x15, 0x00, // Logical Minimum (0) - Shorten (0x14)?
	0x25, 0x01, // Logical Maximum (1)
	0x81, 0x02, // Input (Data, Variable, Absolute)

	// Reserved byte.
	0x95, 0x01, // Report Count (1)
	0x75, 0x08, // Report Size (8)
	0x81, 0x01, // Input (Constant)

	// LED report.
	0x95, 0x05, // Report Count (5)
	0x75, 0x01, // Report Size (1)
	0x05, 0x08, // Usage Page (LEDs)
	0x19, 0x01, // Usage Minimum (1)
	0x29, 0x05, // Usage Maximum (5)
	0x91, 0x02, // Output (Data, Variable, Absolute)

	// LED report padding.
	0x95, 0x01, // Report Count (1)
	0x75, 0x03, // Report Size (3)
	0x91, 0x01, // Output (Constant)

	// Key code report.
	0x95, 0x06, // Report Count (6)
	0x75, 0x08, // Report Size (8)
	0x15, 0x00, // Logical Minimum (0)
	0x26, 0xff, 0x00, // Logical Maximum (255)
	0x05, 0x07, // Usage Page (Key Codes)
	0x19, 0x00, // Usage Minimum (0)
	0x29, 0xff, // Usage Maximum (255)
	0x81, 0x00, // Input (Data, Array)

	0xc0		// End Collection
};
*/


static int
uhid_write(int fd, const struct uhid_event *he)
{
	ssize_t r = write(fd, he, sizeof(*he));
	if (r < 0) {
		fprintf(stderr, "write: cannot write to uhid: %m\n");
		return -errno;
	} else if (r != sizeof(*he)) {
		fprintf(stderr, "write: wrong size written to uhid: %ld != %lu\n",
				r, sizeof(*he));
		return -EFAULT;
	} else return 0;
}

static int
uhid_event(int fd)
{
	struct uhid_event he;
	ssize_t sz;
	if ((sz = read(fd, &he, sizeof(he))) == -1)
		handle_error("read");

	switch (he.type) {
	case UHID_START:
		fprintf(stderr, "UHID_START from uhid-dev.\n");
		break;
	case UHID_STOP:
		fprintf(stderr, "UHID_STOP from uhid-dev.\n");
		break;
	case UHID_OPEN:
		fprintf(stderr, "UHID_OPEN from uhid-dev.\n");
		return 0;
	case UHID_CLOSE:
		fprintf(stderr, "UHID_CLOSE from uhid-dev.\n");
		break;
	case UHID_OUTPUT:
		fprintf(stderr, "UHID_OUTPUT from uhid-dev.\n");
		// TODO: Handle output.
		break;
	case UHID_OUTPUT_EV:
		fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev.\n");
		break;
	default:
		fprintf(stderr, "Invalid event from uhid-dev: %u.\n", he.type);
	}

	return 1;
}

int
main(int argc, char *argv[])
{
	int fd;
	ssize_t sz;
	struct uhid_event he;

	if ((fd = open("/dev/uhid", O_RDWR | O_CLOEXEC)) == -1)
		handle_error("open");

	struct pollfd fds[1] = {
		{.fd = fd, .events = POLLIN}
	};

	memset(&he, 0, sizeof(he));
	he.type = UHID_CREATE2;
	strcpy((char *)he.u.create.name, "kb-daemon-device");
	memcpy(he.u.create2.rd_data, rdesc, sizeof(rdesc));
	he.u.create2.rd_size = sizeof(rdesc);
	he.u.create2.bus = BUS_USB;
	he.u.create2.vendor = 0x15d9;
	he.u.create2.product = 0x0a37;
	he.u.create2.version = 0;
	he.u.create2.country = 0;
	if (uhid_write(fd, &he))
		handle_error("uhid_write");

	char cont = 1;
	while (cont) {
		int n = ppoll(fds, sizeof(fds), NULL, NULL);
		if (n == -1)
			handle_error("ppoll");

		for (int i = 0; i < n; i++) {
			if (fds[i].fd == fd &&
				fds[i].revents & POLLIN)
				cont = uhid_event(fds[i].fd);
		}
	}

	memset(&he, 0, sizeof(he));
	he.type = UHID_INPUT2;
	he.u.input2.size = 8;
	he.u.input2.data[0] = 0x00;
	he.u.input2.data[1] = 0x00;
	he.u.input2.data[2] = 0x04;
	he.u.input2.data[3] = 0x00;
	he.u.input2.data[4] = 0x00;
	he.u.input2.data[5] = 0x00;
	he.u.input2.data[6] = 0x00;
	he.u.input2.data[7] = 0x00;
	if (uhid_write(fd, &he))
		handle_error("uhid_write");

	memset(&he, 0, sizeof(he));
	he.type = UHID_INPUT2;
	he.u.input2.size = 8;
	he.u.input2.data[0] = 0x00;
	he.u.input2.data[1] = 0x00;
	he.u.input2.data[2] = 0x00;
	he.u.input2.data[3] = 0x00;
	he.u.input2.data[4] = 0x00;
	he.u.input2.data[5] = 0x00;
	he.u.input2.data[6] = 0x00;
	he.u.input2.data[7] = 0x00;
	if (uhid_write(fd, &he))
		handle_error("uhid_write");
	
	memset(&he, 0, sizeof(he));
	he.type = UHID_DESTROY;
	if (uhid_write(fd, &he))
		handle_error("uhid_write");
	uhid_event(fd);


	return EXIT_SUCCESS;
}

             reply	other threads:[~2018-02-10  9:33 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-10  9:33 R0b0t1 [this message]
2018-02-11 19:46 ` UHID Device Reports Do Not Generate OS Activity Roderick Colenbrander
     [not found]   ` <CAEc3jaAyQiNDLbOvNkT65n-Vju-LOHjoSuiOqDunBFna0YDaBQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2018-02-11 20:22     ` R0b0t1

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAAD4mYj0pUUbwX8mKDP2qTn=QZM9ubk3f9FsabefK4xntY7bFA@mail.gmail.com' \
    --to=r030t1@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).