using two keyboards at the same time
Norbert Koch
NKoch at demig.de
Thu Dec 16 00:53:24 PST 2004
Hello.
I know, the syscons driver does not allow to have
two keyboards attached at the same time.
So my idea was to have a userland application
which polls the keyboard(s) currently _not_
attached to syscons using select(2) or poll(2)
and then switching to an active keyboard.
>From reading the source code under /sys/dev/kbd
I thought this should work.
I made this simple test: I attached syscons to
/dev/kbd1 and ran "cat /dev/kbd0".
As expected I saw characters
coming from both keyboards.
Then I wrote a program to do the selecting and switching.
Well, it does not work (under FreeBSD 4.10).
Select never returns. As I understand
it a device driver should return immediately
if it does not support poll.
Does anyone have an idea?
May be I just made some stupid mistake.
Thank you.
>--------------------------------------------
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <machine/console.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define MAX_DEVICES 5
#define TEST
#define STR(x) #x
#define XSTR(x) STR (x)
static void usage (void)
{
fprintf (stderr,
"usage: autosw [ -D ] [ -d ] [ [ -f <device>] ... ]\n"
" -D : do not detach\n"
" -d : enable debug output\n"
" -f : specify keyboard device (up to " XSTR (MAX_DEVICES) ")\n"
" if no keyboard devices specified\n"
" /dev/kbd0 and /dev/kbd1 are polled\n");
exit (1);
}
/*
* borrowed from /usr/src/usr.sbin/kbdcontrol/kbdcontrol.c
*/
static int set_keyboard_fd (int fd)
{
keyboard_info_t info;
if (ioctl (fd, KDGKBINFO, & info) == -1)
{
close (fd);
return -1;
};
ioctl (fd, CONS_RELKBD, 0);
close (fd);
if (ioctl (0, CONS_SETKBD, info.kb_index) == -1)
{
return -1;
};
return 0;
}
static int set_keyboard (char * device)
{
int fd;
fd = open (device, O_RDONLY);
if (fd < 0)
{
return -1;
};
return set_keyboard_fd (fd);
}
int main (int argc, char ** argv)
{
char * devices[MAX_DEVICES];
fd_set ifds, ofds;
int ch, i, fd, maxfd, no_devices = 0, debug = 0, detach = 1, detached = 0;
struct stat sb;
while ((ch = getopt (argc, argv, "Ddf:h")) != -1)
{
switch (ch)
{
case 'D':
detach = 0;
break;
case 'd':
++ debug;
break;
case 'f':
if (no_devices >= MAX_DEVICES)
{
fprintf (stderr, "too many devices\n");
exit (1);
};
if (stat (optarg, & sb) < 0)
{
fprintf (stderr, "cannot stat %s: %s\n", optarg, strerror
(errno));
exit (1);
};
if ((sb.st_mode & S_IFCHR) == 0)
{
fprintf (stderr, "not a character device: %s\n", optarg);
exit (1);
};
devices[no_devices ++] = strdup (optarg);
continue;
case 'h':
case '?':
default:
usage ();
}
};
/*
* no devices specified, use default
*/
if (no_devices == 0)
{
devices[0] = "/dev/kbd0";
devices[1] = "/dev/kbd1";
no_devices = 2;
if (debug)
{
fprintf (stderr, "using default devices\n");
};
};
/*
* switch syscons to first keyboard
*/
#ifndef TEST
for (i = -1; ++ i < no_devices;)
#else
for (i = 1; i == 1; ++ i)
#endif
{
if (set_keyboard (devices[i]) == 0)
{
if (debug)
{
fprintf (stderr, "selecting keyboard %s\n", devices[i]);
};
break;
}
};
for (;;)
{
/*
* try to open all devices for select
*/
FD_ZERO (& ifds);
maxfd = -1;
#ifndef TEST
for (i = -1; ++ i < no_devices;)
#else
for (i = 0; i == 0; ++ i)
#endif
{
fd = open (devices[i], O_RDONLY|O_NONBLOCK);
if (fd >= 0)
{
if (debug)
{
fprintf (stderr, "polling %s", devices[i]);
};
if (debug >= 2)
{
fprintf (stderr, " fd=%u", fd);
};
if (debug)
{
fprintf (stderr, "\n");
};
FD_SET (fd, & ifds);
if (fd > maxfd)
{
maxfd = fd;
}
}
};
if (maxfd < 0)
{
fprintf (stderr, "could not open any device\n");
exit (1);
};
if (detach && ! detached && ! debug)
{
daemon (0, 0);
detached = 1;
};
ofds = ifds;
if (debug >= 2)
{
fprintf (stderr, "polling maxfd=%u\n", maxfd);
};
/*
***** !!! never returns !!!
*/
if (select (maxfd, & ofds, NULL, NULL, NULL) == -1)
{
/*
* got signal
*/
exit (0);
};
if (debug)
{
fprintf (stderr, "polled successfully\n");
};
/*
* find first keyboard where select returned some activity
*/
for (fd = -1; ++ fd < maxfd; ++ fd)
{
if (FD_ISSET (fd, & ofds))
{
if (debug)
{
fprintf (stderr, "switching keyboard\n");
};
if (debug >= 2)
{
fprintf (stderr, " fd=%u", fd);
};
if (debug)
{
fprintf (stderr, "\n");
};
/*
* switch to keyboard with activity
*/
set_keyboard_fd (fd);
FD_ZERO (& ofds);
}
else if (FD_ISSET (fd, & ifds))
{
if (debug >= 2)
{
fprintf (stderr, "closing fd=%u\n", fd);
};
close (fd);
}
}
}
}
More information about the freebsd-hackers
mailing list