kqueue(2) + /dev/sysmouse

1

Witam,

sprawa może i głupia, bo zainspirowana filmikiem: , ale pytania będą raczej do ekspertów.

Rozważmy następujący blokujący (i działający) kod:

#include <sys/types.h>
#include <sys/mouse.h>

#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


struct mouse_event {
	uint8_t buttons;
	int8_t hdx;
	int8_t hdy;
	int8_t ldx;
	int8_t ldy;
	int8_t hdz;
	int8_t ldz;
	int8_t ext_buttons;
};

int
main(int argc, char **argv)
{
	int error, fd;
	short dx, dy, dz;
	struct mouse_event ev;

	fd = open("/dev/sysmouse", O_RDONLY);
	if (fd < 0)
		err(1, "open(2) failed");

	for (;;) {
		if (read(fd, &ev, sizeof(ev)) != sizeof(ev))
			err(1, "read(2) failed");

		dx = ev.hdx + ev.ldx;
		dy = ev.hdy + ev.ldy;
		dz = ev.hdz + ev.ldz;

		printf("%c %c %c x=%d y=%d z=%d\n",
		    ev.buttons & 0x4 ? ' ' : 'L', 
		    ev.buttons & 0x2 ? ' ' : 'M', 
		    ev.buttons & 0x1 ? ' ' : 'R', 
		    dx, dy, dz);
	}

	return (0);
}

Z różnych względów chciałbym go sobie przerobić na wersję nieblokującą:

#include <sys/types.h>
#include <sys/event.h>
#include <sys/mouse.h>

#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


/*
 * W razie wątpliwości patrz: man 4 mouse
 */
struct mouse_event {
	uint8_t buttons;
	int8_t hdx;
	int8_t hdy;
	int8_t ldx;
	int8_t ldy;
	int8_t hdz;
	int8_t ldz;
	int8_t ext_buttons;
};

/*
 * Wyciągnięcie tylko po to, żeby nie zaciemnić kodu main().
 */
static void
handle_mouse(int fd)
{
	short dx, dy, dz;
	struct mouse_event ev;

	if (read(fd, &ev, sizeof(ev)) != sizeof(ev))
		err(1, "read(2) failed");

	dx = ev.hdx + ev.ldx;
	dy = ev.hdy + ev.ldy;
	dz = ev.hdz + ev.ldz;

	printf("%c %c %c x=%d y=%d z=%d\n", ev.buttons & 0x4 ? ' ' : 'L', 
	    ev.buttons & 0x2 ? ' ' : 'M', ev.buttons & 0x1 ? ' ' : 'R', 
	    dx, dy, dz);
}

int
main(int argc, char **argv)
{
	int error, fd, kq;
	struct kevent kev;

	fd = open("/dev/sysmouse", O_RDONLY | O_NONBLOCK);
	if (fd < 0)
		err(1, "open(2) failed");

	kq = kqueue();
	if (kq < 0)
		err(1, "kevent(2) failed");

	/*
	 * Rejestracja eventów.
	 */
	EV_SET(&kev, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
	error = kevent(kq, &kev, 1, NULL, 0, NULL);
	if (error < 0)
		err(1, "kevent(2) failed");

	EV_SET(&kev, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0);
	error = kevent(kq, &kev, 1, NULL, 0, NULL);
	if (error < 0)
		err(1, "kevent(2) failed");

	for (;;) {
		error = kevent(kq, NULL, 0, &kev, 1, NULL);
		if (error < 0)
			err(1, "kevent(2) failed");

		/* 
		 * Timeout jest niedopuszczalny, więc możemy dostać co najwyżej
		 * jeden event.
		 * */
		assert(error == 1);
		if (kev.filter == EVFILT_READ && kev.ident == fd) {
			handle_mouse(fd);
		} else if (kev.filter == EVFILT_SIGNAL &&
		    kev.ident == SIGTERM) {
			break;
		} else {
			fprintf(stderr, "WTF!?: %d %lu\n", kev.filter,
			    kev.ident);
		}
	}

	close(fd);
	return (0);
}

Która to z kolei kończy się takim oto nieciekawym komunikatem:
mouse-nblk: kevent(2) failed: Operation not supported by device

Teraz pytania:

  1. Czy wszystkie urządzenia w katalogu /dev/ nie wspierają kevent(2)?
  2. Czy jest to tylko kwestia mojego sterownika do myszy (/sys/dev/vt/vt_sysmouse.c)?

Jeśli na pytanie (2) odpowiedź jest twierdząca:

Czy wystarczyłoby przeczytać kqueue(9), aby doimplementować brakującą obsługę zdarzeń w sterowniku myszy? Sensem pytania jest: czy to tylko kwestia wsparcia w sterowniku, czy trzeba modyfikować coś więcej?

Ukłony.

0

Ok, doszedłem do problemu:

  1. Tak, na starszym sterowniku do myszy to działa bez problemu.
  2. Sterownik do myszy z nowego vt jest walnięty i trzeba go trochę przerobić, żeby zadziałał.

1 użytkowników online, w tym zalogowanych: 0, gości: 1