diff options
author | kraxel <kraxel> | 2004-04-21 11:55:44 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2004-04-21 11:55:44 +0000 |
commit | c4d7dacb41039e087d20b8889a4d13bd4c9928f2 (patch) | |
tree | 0aef1f53f2e8cd55c4db8915d9d9a1265dd97adc | |
download | input-c4d7dacb41039e087d20b8889a4d13bd4c9928f2.tar.gz |
Initial revision
-rw-r--r-- | GNUmakefile | 62 | ||||
-rw-r--r-- | INSTALL | 59 | ||||
-rw-r--r-- | README | 82 | ||||
-rw-r--r-- | input-events.c | 132 | ||||
-rw-r--r-- | input-kbd.c | 260 | ||||
-rw-r--r-- | input-recv.c | 87 | ||||
-rw-r--r-- | input-send.c | 234 | ||||
-rw-r--r-- | input.c | 132 | ||||
-rw-r--r-- | input.h | 30 | ||||
-rw-r--r-- | linux-input.h | 927 | ||||
-rwxr-xr-x | lirc.sh | 18 | ||||
-rw-r--r-- | list.h | 169 | ||||
-rw-r--r-- | lsinput.c | 35 | ||||
-rw-r--r-- | mk/Autoconf.mk | 124 | ||||
-rw-r--r-- | mk/Compile.mk | 84 | ||||
-rw-r--r-- | mk/Maintainer.mk | 47 | ||||
-rw-r--r-- | mk/Variables.mk | 33 | ||||
-rwxr-xr-x | name.sh | 10 | ||||
-rw-r--r-- | tcp.c | 153 | ||||
-rw-r--r-- | tcp.h | 11 |
20 files changed, 2689 insertions, 0 deletions
diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..0479955 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,62 @@ +# config +-include Make.config +include mk/Variables.mk + +# add our flags + libs +CFLAGS += -DVERSION='"$(VERSION)"' +LDLIBS += -lm + +# build +TARGETS := lsinput input-events input-kbd input-send input-recv lircd.conf +HEADERS := EV.h REL.h KEY.h BTN.h BUS.h + +# default target +all: build + + +################################################################# +# poor man's autoconf ;-) + +include mk/Autoconf.mk + +define make-config +LIB := $(LIB) +endef + + +######################################################################## +# rules + +build: $(TARGETS) + +$(HEADERS): name.sh + sh name.sh $* > $@ + +lircd.conf: lirc.sh + sh lirc.sh > $@ + +lsinput: lsinput.o input.o +input-events: input-events.o input.o +input-kbd: input-kbd.o input.o +input-send: input-send.o input.o tcp.o +input-recv: input-recv.o input.o tcp.o + +input.o: input.c $(HEADERS) + +install: build + install -d $(bindir) + install -s lsinput input-events input-kbd input-send input-recv $(bindir) + +clean: + -rm -f *.o $(depfiles) + +realclean distclean: clean + -rm -f Make.config + -rm -f $(TARGETS) $(HEADERS) *~ xpm/*~ *.bak + +############################################# + +include mk/Compile.mk +include mk/Maintainer.mk +-include $(depfiles) + @@ -0,0 +1,59 @@ + +howto compile and install this package +====================================== + + +really short install instructions +--------------------------------- + + $ make + $ su -c "make install" + + + +the more detailed version +------------------------- + +Make sure you use GNU make. The file name "GNUmakefile" isn't a joke, +this package really requires GNU make. + +As first step make will do some config checks on your system and write +the results to Make.config. If you want to have a look at Make.config +before the actual build starts you can run this step separately using +"make config". + +The Makefiles use the usual GNU-ish Makefile conventions for variable +names and default values, i.e. prefix=/usr/local, ... + +The values for some frequently adapted variables are initialized from +the enviroment. Thus you can change the defaults simply by setting +environment variables: + + $ prefix="/usr" + $ CFLAGS="-O3 -mcpu=i686" + $ export prefix CFLAGS + +Almost any variable can be overridden on the make command line. It is +often used this way to install into some buildroot for packaging ... + + $ su -c "make DESTDIR=/tmp/buildroot install" + +... but it works for most other variables equally well. There are +some exceptions through, it usually does _not_ work for CFLAGS for +example. + +Try "make verbose=yes" if you want to see the complete command lines +executed by make instead of the short messages (for trouble shooting, +because you like this way, for whatever reason ...). This also makes +the config checks performed by "make config" more verbose. + +If you don't trust my Makefiles you can run "make -n install" to see +what "make install" would do on your system. It will produce +human-readable output (unlike automake ...). + +Have fun, + + Gerd + +-- +Gerd Knorr <kraxel@bytesex.org> @@ -0,0 +1,82 @@ + +This is a small collection of input layer utilities. I wrote them +mainly for testing and debugging, but maybe others find them useful +too :-) + + +lsinput +======= + +probe and list all devices + + +input-event +=========== + +listen for events and print them. Expects a device number as argument +(0 == /dev/input/event0, ...). + + -t <sec> set timeout, quits after <sec> seconds without input. + default is 10 + -g grab device using EVIOCGRAB, i.e. get exclusive access to + the device + + +input-kbd +========= + +read/write keyboard maps (scancode => linux keycode). Also expects a +device number as argument. + +If the input device supports maps, it will print them to stdout. +Looks like this (AT Keyboard): + + 0x0001 = 67 # KEY_F9 + 0x0002 = 65 # KEY_F7 + 0x0003 = 63 # KEY_F5 + 0x0004 = 61 # KEY_F3 + [ ... ] + +If the device doesn't support maps the utility just prints the keys +and/or buttons supported by the device (my mouse): + + bits: BTN_LEFT + bits: BTN_RIGHT + bits: BTN_MIDDLE + +If you pass a map file via -f switch the utility will parse it and +reconfigure the device. Syntax is identical to the maps printed out, +i.e. you can dump the current map to some file, edit it and then apply +the changes. The key names are also accepted, i.e. both this ... + + 0x0001 = 67 + +... and this ... + + 0x0001 = KEY_F9 + +... works. + + +input-send +========== + +small daemon which reads from a input device and sends it over the +network to everyone who connects. Listens on tcp port 1234. + + +input-recv +========== + +the receiving end for the send utility. Connects to localhost:1234 +right now and prints stuff to stderr. Plan is to put events into +/dev/input/uinput some day which basically gives you a remote input +device. + + +Have fun, + + Gerd + +-- +Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] diff --git a/input-events.c b/input-events.c new file mode 100644 index 0000000..c525757 --- /dev/null +++ b/input-events.c @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/select.h> + +#include "input.h" + +/* ------------------------------------------------------------------ */ + +static void show_events(int nr, int timeout, int grab) +{ + struct input_event event; + struct timeval tv; + int fd, quit; + fd_set set; + + fd = device_open(nr,1); + if (-1 == fd) + return; + device_info(fd); + + if (grab) { + if (-1 == ioctl(fd,EVIOCGRAB,1)) { + perror("ioctl EVIOCGRAB(1)"); + close(fd); + return; + } + fprintf(stderr,"grabbed input device\n"); + } + + fprintf(stderr,"waiting for events\n"); + quit = 0; + for (;;) { + /* wait for input */ + FD_ZERO(&set); + FD_SET(fd,&set); + tv.tv_sec = timeout; + tv.tv_usec = 0; + switch (select(fd+1,&set,NULL,NULL,&tv)) { + case -1: + perror("select"); + quit = 1; + break; + case 0: + fprintf(stderr,"timeout, quitting\n"); + quit = 1; + break; + } + if (quit) + break; + + /* read input */ + if (FD_ISSET(fd,&set)) { + switch (read(fd,&event,sizeof(event))) { + case -1: + perror("read"); + quit = 1; + break; + case 0: + fprintf(stderr,"EOF\n"); + quit = 1; + break; + default: + print_event(&event); + break; + } + } + if (quit) + break; + } + + if (grab) { + if (-1 == ioctl(fd,EVIOCGRAB,0)) { + perror("ioctl EVIOCGRAB(0)"); + close(fd); + return; + } + fprintf(stderr,"released input device\n"); + } + close(fd); +} + +static int usage(char *prog, int error) +{ + fprintf(error ? stderr : stdout, + "usage: %s" + " [ -g ] [ -t <sec> ]" + " devnr\n", + prog); + exit(error); +} + +int main(int argc, char *argv[]) +{ + int timeout = 10; + int grab = 0; + int c,devnr; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "hgt:"))) + break; + switch (c) { + case 't': + timeout = atoi(optarg); + break; + case 'g': + grab = 1; + break; + case 'h': + usage(argv[0],0); + default: + usage(argv[0],1); + } + } + + if (optind == argc) + usage(argv[0],1); + + devnr = atoi(argv[optind]); + show_events(devnr,timeout,grab); + return 0; +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/input-kbd.c b/input-kbd.c new file mode 100644 index 0000000..fbe3f27 --- /dev/null +++ b/input-kbd.c @@ -0,0 +1,260 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/select.h> + +#include "input.h" + +struct kbd_entry { + int scancode; + int keycode; +}; + +struct kbd_map { + struct kbd_entry *map; + int keys; + int size; + int alloc; +}; + +/* ------------------------------------------------------------------ */ + +static struct kbd_map* kbd_map_read(int fd) +{ + struct kbd_entry entry; + struct kbd_map *map; + int rc; + + map = malloc(sizeof(*map)); + memset(map,0,sizeof(*map)); + for (map->size = 0; map->size < 65536; map->size++) { + entry.scancode = map->size; + entry.keycode = KEY_RESERVED; + rc = ioctl(fd, EVIOCGKEYCODE, &entry); + if (rc < 0) { + map->size--; + break; + } + if (map->size >= map->alloc) { + map->alloc += 64; + map->map = realloc(map->map, map->alloc * sizeof(entry)); + } + map->map[map->size] = entry; + + if (KEY_RESERVED != entry.keycode) + map->keys++; + } + if (map->keys) { + fprintf(stderr,"map: %d keys, size: %d/%d\n", + map->keys, map->size, map->alloc); + return map; + } else { + free(map); + return NULL; + } +} + +static int kbd_map_write(int fh, struct kbd_map *map) +{ + int i,rc; + + for (i = 0; i < map->size; i++) { + rc = ioctl(fh, EVIOCSKEYCODE, &map->map[i]); + if (0 != rc) { + fprintf(stderr,"ioctl EVIOCSKEYCODE(%d,%d): %s\n", + map->map[i].scancode,map->map[i].keycode, + strerror(errno)); + return -1; + } + } + return 0; +} + +static void kbd_key_print(FILE *fp, int scancode, int keycode) +{ + fprintf(fp, "0x%04x = %3d # %s\n", + scancode, keycode, key_name(keycode)); +} + +static void kbd_map_print(FILE *fp, struct kbd_map *map, int complete) +{ + int i; + + for (i = 0; i < map->size; i++) { + if (!complete && KEY_RESERVED == map->map[i].keycode) + continue; + kbd_key_print(fp,map->map[i].scancode,map->map[i].keycode); + } +} + +static int kbd_map_parse(FILE *fp, struct kbd_map *map) +{ + struct kbd_entry entry; + char line[80],scancode[80],keycode[80]; + int i; + + while (NULL != fgets(line,sizeof(line),fp)) { + if (2 != sscanf(line," %80s = %80s", scancode, keycode)) { + fprintf(stderr,"parse error: %s",line); + return -1; + } + + /* parse scancode */ + if (0 == strncasecmp(scancode,"0x",2)) { + entry.scancode = strtol(scancode, NULL, 16); + } else { + entry.scancode = strtol(scancode, NULL, 10); + } + if (entry.scancode < 0 || + entry.scancode >= map->size) { + fprintf(stderr,"scancode %d out of range (0-%d)\n", + entry.scancode,map->size); + return -1; + } + + /* parse keycode */ + for (i = 0; i < KEY_MAX; i++) { + if (!KEY_NAME[i]) + continue; + if (0 == strcmp(keycode,KEY_NAME[i])) + break; + } + if (i == KEY_MAX) + entry.keycode = atoi(keycode); + else + entry.keycode = i; + + fprintf(stderr,"set: "); + kbd_key_print(stderr,entry.scancode,entry.keycode); + map->map[entry.scancode] = entry; + } + return 0; +} + +/* ------------------------------------------------------------------ */ + +static void kbd_print_bits(int fd) +{ + BITFIELD bits[KEY_MAX/sizeof(BITFIELD)]; + int rc,bit; + + rc = ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(bits)),bits); + if (rc < 0) + return; + for (bit = 0; bit < rc*8 && bit < KEY_MAX; bit++) { + if (!test_bit(bit,bits)) + continue; + if (KEY_NAME[bit]) { + fprintf(stderr,"bits: %s\n", KEY_NAME[bit]); + } else { + fprintf(stderr,"bits: unknown [%d]\n", bit); + } + } +} + +static void show_kbd(int nr) +{ + struct kbd_map *map; + int fd; + + fd = device_open(nr,1); + if (-1 == fd) + return; + device_info(fd); + + map = kbd_map_read(fd); + if (NULL != map) { + kbd_map_print(stdout,map,0); + } else { + kbd_print_bits(fd); + } + + close(fd); +} + +static int set_kbd(int nr, char *mapfile) +{ + struct kbd_map *map; + FILE *fp; + int fd; + + fd = device_open(nr,1); + if (-1 == fd) + return -1; + + map = kbd_map_read(fd); + if (NULL == map) { + fprintf(stderr,"device has no map\n"); + close(fd); + return -1; + } + + if (0 == strcmp(mapfile,"-")) + fp = stdin; + else { + fp = fopen(mapfile,"r"); + if (NULL == fp) { + fprintf(stderr,"open %s: %s\n",mapfile,strerror(errno)); + close(fd); + return -1; + } + } + + if (0 != kbd_map_parse(fp,map) || + 0 != kbd_map_write(fd,map)) { + close(fd); + return -1; + } + + close(fd); + return 0; +} + +static int usage(char *prog, int error) +{ + fprintf(error ? stderr : stdout, + "usage: %s [ -f file ] devnr\n", + prog); + exit(error); +} + +int main(int argc, char *argv[]) +{ + int c,devnr; + char *mapfile = NULL; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "hf:"))) + break; + switch (c) { + case 'f': + mapfile = optarg; + break; + case 'h': + usage(argv[0],0); + default: + usage(argv[0],1); + } + } + + if (optind == argc) + usage(argv[0],1); + + devnr = atoi(argv[optind]); + if (mapfile) { + set_kbd(devnr,mapfile); + } else { + show_kbd(devnr); + } + return 0; +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/input-recv.c b/input-recv.c new file mode 100644 index 0000000..4a59f3c --- /dev/null +++ b/input-recv.c @@ -0,0 +1,87 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "input.h" +#include "tcp.h" + +/* ------------------------------------------------------------------ */ + +static int usage(char *prog, int error) +{ + fprintf(error ? stderr : stdout, + "usage: %s" + "\n", + prog); + exit(error); +} + +int main(int argc, char *argv[]) +{ + char *addr = NULL; + char *port = NULL; + char *host = "localhost"; + char *serv = "1234"; + struct addrinfo ask; + int c,sock; + + memset(&ask,0,sizeof(ask)); + ask.ai_family = PF_UNSPEC; + ask.ai_socktype = SOCK_STREAM; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "h"))) + break; + switch (c) { + case 'h': + usage(argv[0],0); + default: + usage(argv[0],1); + } + } + + tcp_verbose = 1; + sock = tcp_connect(&ask,addr,port,host,serv); + if (-1 == sock) + exit(1); + + for (;;) { + struct input_event ev; + fd_set set; + int rc; + + FD_ZERO(&set); + FD_SET(sock,&set); + rc = select(sock+1,&set,NULL,NULL,NULL); + if (1 != rc) { + perror("select"); + exit(1); + } + + rc = read(sock,&ev,sizeof(ev)); + if (rc != sizeof(ev)) { + fprintf(stderr,"read ret=%d (expected %d), errno=%s\n", + rc,(int)sizeof(ev),strerror(errno)); + exit(1); + } + + /* convert from network byte order ... */ + ev.time.tv_sec = ntohl(ev.time.tv_sec); + ev.time.tv_usec = ntohl(ev.time.tv_usec); + ev.type = ntohs(ev.type); + ev.code = ntohs(ev.code); + ev.value = ntohl(ev.value); + + print_event(&ev); + } + + return 0; +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/input-send.c b/input-send.c new file mode 100644 index 0000000..946832f --- /dev/null +++ b/input-send.c @@ -0,0 +1,234 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> + +#include "list.h" +#include "input.h" +#include "tcp.h" + +struct connection { + int socket; + struct sockaddr_storage peer; + struct list_head list; + char peerhost[INET6_ADDRSTRLEN+1]; + char peerserv[33]; +}; + +/* ------------------------------------------------------------------ */ + +int debug = 0; +int timeout = 10; +int slisten; +int input; +LIST_HEAD(connections); + +static void conn_new(void) +{ + struct connection *conn; + int len; + + conn = malloc(sizeof(conn)); + memset(conn,0,sizeof(conn)); + len = sizeof(conn->peer); + conn->socket = accept(slisten,(struct sockaddr*)&conn->peer,&len); + if (-1 == conn->socket) { + if (tcp_verbose) + perror("accept"); + free(conn); + return; + } + if (tcp_verbose) { + getnameinfo((struct sockaddr*)&conn->peer,len, + conn->peerhost,INET6_ADDRSTRLEN, + conn->peerserv,32, + NI_NUMERICHOST | NI_NUMERICSERV); + fprintf(stderr,"connect from [%s]\n",conn->peerhost); + } + fcntl(conn->socket,F_SETFL,O_NONBLOCK); + + /* FIXME: access control */ + list_add_tail(&conn->list,&connections); +} + +static void conn_del(struct connection *conn) +{ + if (tcp_verbose) + fprintf(stderr,"connection from [%s] closed\n",conn->peerhost); + close(conn->socket); + list_del(&conn->list); + free(conn); +} + +static void input_bcast(struct input_event *ev) +{ + struct connection *conn; + struct list_head *item; + struct list_head *safe; + int rc; + + if (debug) + print_event(ev); + + /* convert to network byte order ... */ + ev->time.tv_sec = htonl(ev->time.tv_sec); + ev->time.tv_usec = htonl(ev->time.tv_usec); + ev->type = htons(ev->type); + ev->code = htons(ev->code); + ev->value = htonl(ev->value); + + /* send out */ + list_for_each_safe(item,safe,&connections) { + conn = list_entry(item, struct connection, list); + rc = write(conn->socket,ev,sizeof(*ev)); + if (rc != sizeof(*ev)) + conn_del(conn); + } +} + +static void loop(void) +{ + struct connection *conn; + struct list_head *item; + struct list_head *safe; + fd_set set; + struct timeval tv; + int max,rc; + + for (;;) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO(&set); + FD_SET(slisten,&set); + max = slisten; + + FD_SET(input,&set); + if (max < input) + max = input; + + list_for_each(item,&connections) { + conn = list_entry(item, struct connection, list); + FD_SET(conn->socket,&set); + if (max < conn->socket) + max = conn->socket; + } + + rc = select(max+1,&set,NULL,NULL,&tv); + if (rc < 0) { + /* Huh? */ + perror("select"); + exit(1); + } + if (0 == rc) { + /* timeout */ + continue; + } + + list_for_each_safe(item,safe,&connections) { + conn = list_entry(item, struct connection, list); + if (FD_ISSET(conn->socket,&set)) { + char dummy[16]; + rc = read(conn->socket,dummy,sizeof(dummy)); + if (rc <= 0) + conn_del(conn); + } + } + + if (FD_ISSET(input,&set)) { + struct input_event ev; + rc = read(input,&ev,sizeof(ev)); + if (rc != sizeof(ev)) + exit(1); + input_bcast(&ev); + } + + if (FD_ISSET(slisten,&set)) + conn_new(); + } +} + +/* ------------------------------------------------------------------ */ + +static void daemonize(void) +{ + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + close(0); close(1); close(2); + setsid(); + open("/dev/null",O_RDWR); dup(0); dup(0); + break; + default: + exit(0); + } +} + +static int usage(char *prog, int error) +{ + fprintf(error ? stderr : stdout, + "usage: %s" + " [ -t <sec> ] [ -g ]" + " devnr\n", + prog); + exit(error); +} + +int main(int argc, char *argv[]) +{ + int grab = 0; + char *addr = NULL; + char *port = "1234"; + int c,devnr; + struct addrinfo ask; + + memset(&ask,0,sizeof(ask)); + ask.ai_family = PF_UNSPEC; + ask.ai_socktype = SOCK_STREAM; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "hdgt:"))) + break; + switch (c) { + case 'd': + debug = 1; + tcp_verbose = 1; + break; + case 't': + timeout = atoi(optarg); + break; + case 'g': + grab = 1; + break; + case 'h': + usage(argv[0],0); + default: + usage(argv[0],1); + } + } + + if (optind == argc) + usage(argv[0],1); + devnr = atoi(argv[optind]); + input = device_open(devnr,debug); + if (-1 == input) + exit(1); + + slisten = tcp_listen(&ask,addr,port); + if (-1 == slisten) + exit(1); + + if (!debug) + daemonize(); + loop(); + return 0; +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> + +#include "input.h" + +/* ------------------------------------------------------------------ */ + +char *EV_NAME[EV_MAX] = { +#include "EV.h" +}; + +char *REL_NAME[REL_MAX] = { +#include "REL.h" +}; + +char *KEY_NAME[KEY_MAX] = { +#include "KEY.h" +#include "BTN.h" +}; + +char *BUS_NAME[] = { +#include "BUS.h" +}; + +/* ------------------------------------------------------------------ */ + +int device_open(int nr, int verbose) +{ + char filename[32]; + int fd, version; + + snprintf(filename,sizeof(filename), + "/dev/input/event%d",nr); + fd = open(filename,O_RDONLY); + if (-1 == fd) { + fprintf(stderr,"open %s: %s\n", + filename,strerror(errno)); + return -1; + } + if (verbose) + fprintf(stderr,"%s\n",filename); + + if (-1 == ioctl(fd,EVIOCGVERSION,&version)) { + perror("ioctl EVIOCGVERSION"); + close(fd); + return -1; + } + if (EV_VERSION != version) { + fprintf(stderr, "protocol version mismatch (expected %d, got %d)\n", + EV_VERSION, version); + close(fd); + return -1; + } + return fd; +} + +void device_info(int fd) +{ + struct input_id id; + BITFIELD bits[32]; + char buf[32]; + int rc,bit; + + rc = ioctl(fd,EVIOCGID,&id); + if (rc >= 0) + fprintf(stderr, + " bustype : %s\n" + " vendor : 0x%x\n" + " product : 0x%x\n" + " version : %d\n", + BUS_NAME[id.bustype], + id.vendor, id.product, id.version); + rc = ioctl(fd,EVIOCGNAME(sizeof(buf)),buf); + if (rc >= 0) + fprintf(stderr," name : \"%.*s\"\n",rc,buf); + rc = ioctl(fd,EVIOCGPHYS(sizeof(buf)),buf); + if (rc >= 0) + fprintf(stderr," phys : \"%.*s\"\n",rc,buf); + rc = ioctl(fd,EVIOCGUNIQ(sizeof(buf)),buf); + if (rc >= 0) + fprintf(stderr," uniq : \"%.*s\"\n",rc,buf); + rc = ioctl(fd,EVIOCGBIT(0,sizeof(bits)),bits); + if (rc >= 0) { + fprintf(stderr," bits ev :"); + for (bit = 0; bit < rc*8 && bit < EV_MAX; bit++) { + if (test_bit(bit,bits)) + fprintf(stderr," %s", EV_NAME[bit]); + } + fprintf(stderr,"\n"); + } + fprintf(stderr,"\n"); +} + +/* ------------------------------------------------------------------ */ + +void print_event(struct input_event *event) +{ + char ts[32]; + time_t t; + + t = event->time.tv_sec; + strftime(ts,sizeof(ts),"%H:%M:%S",localtime(&t)); + fprintf(stderr,"%s.%06ld: %s",ts,event->time.tv_usec, + EV_NAME[event->type]); + switch (event->type) { + case EV_KEY: + fprintf(stderr," %s %s", + KEY_NAME[event->code], + event->value ? "pressed" : "released"); + break; + case EV_REL: + fprintf(stderr," %s %d", + REL_NAME[event->code], event->value); + break; + default: + fprintf(stderr," code=%u value=%d", + (unsigned int)event->code, event->value); + } + fprintf(stderr,"\n"); +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ @@ -0,0 +1,30 @@ +#include <inttypes.h> + +#include <sys/ioctl.h> +#include "linux-input.h" + +#define ev_name(code) ((code) < EV_MAX && EV_NAME[code] ? EV_NAME[code] : "???") +#define rel_name(code) ((code) < REL_MAX && REL_NAME[code] ? REL_NAME[code] : "???") +#define key_name(code) ((code) < KEY_MAX && KEY_NAME[code] ? KEY_NAME[code] : "???") + +#define BITFIELD uint32_t + +extern char *EV_NAME[EV_MAX]; +extern char *REL_NAME[REL_MAX]; +extern char *KEY_NAME[KEY_MAX]; +extern char *BUS_NAME[]; + +static __inline__ int test_bit(int nr, BITFIELD * addr) +{ + BITFIELD mask; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *addr) != 0); +} + +/* ------------------------------------------------------------------ */ + +int device_open(int nr, int verbose); +void device_info(int fd); +void print_event(struct input_event *event); diff --git a/linux-input.h b/linux-input.h new file mode 100644 index 0000000..8c5b194 --- /dev/null +++ b/linux-input.h @@ -0,0 +1,927 @@ +/* from 2.6.0-test3 */ + +#ifndef _INPUT_H +#define _INPUT_H + +/* + * Copyright (c) 1999-2002 Vojtech Pavlik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifdef __KERNEL__ +#include <linux/time.h> +#include <linux/list.h> +#else +#include <sys/time.h> +#include <sys/ioctl.h> +#include <asm/types.h> +#endif + +/* + * The event structure itself + */ + +struct input_event { + struct timeval time; + __u16 type; + __u16 code; + __s32 value; +}; + +/* + * Protocol version. + */ + +#define EV_VERSION 0x010000 + +/* + * IOCTLs (0x00 - 0x7f) + */ + +struct input_id { + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; +}; + +struct input_absinfo { + __s32 value; + __s32 minimum; + __s32 maximum; + __s32 fuzz; + __s32 flat; +}; + +#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ +#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ +#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */ +#define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */ +#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ +#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ + +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ +#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */ +#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */ + +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ +#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ +#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ + +#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ + +/* + * Event types + */ + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f + +/* + * Synchronization events. + */ + +#define SYN_REPORT 0 +#define SYN_CONFIG 1 + +/* + * Keys and buttons + */ + +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_103RD 84 +#define KEY_F13 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_F14 89 +#define KEY_F15 90 +#define KEY_F16 91 +#define KEY_F17 92 +#define KEY_F18 93 +#define KEY_F19 94 +#define KEY_F20 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_F21 120 +#define KEY_F22 121 +#define KEY_F23 122 +#define KEY_F24 123 +#define KEY_KPCOMMA 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 +#define KEY_AGAIN 129 +#define KEY_PROPS 130 +#define KEY_UNDO 131 +#define KEY_FRONT 132 +#define KEY_COPY 133 +#define KEY_OPEN 134 +#define KEY_PASTE 135 +#define KEY_FIND 136 +#define KEY_CUT 137 +#define KEY_HELP 138 +#define KEY_MENU 139 +#define KEY_CALC 140 +#define KEY_SETUP 141 +#define KEY_SLEEP 142 +#define KEY_WAKEUP 143 +#define KEY_FILE 144 +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 +#define KEY_COMPUTER 157 +#define KEY_BACK 158 +#define KEY_FORWARD 159 +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 +#define KEY_ISO 170 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 + +#define KEY_INTL1 181 +#define KEY_INTL2 182 +#define KEY_INTL3 183 +#define KEY_INTL4 184 +#define KEY_INTL5 185 +#define KEY_INTL6 186 +#define KEY_INTL7 187 +#define KEY_INTL8 188 +#define KEY_INTL9 189 +#define KEY_LANG1 190 +#define KEY_LANG2 191 +#define KEY_LANG3 192 +#define KEY_LANG4 193 +#define KEY_LANG5 194 +#define KEY_LANG6 195 +#define KEY_LANG7 196 +#define KEY_LANG8 197 +#define KEY_LANG9 198 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_UNKNOWN 240 + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 +#define KEY_TV 0x179 +#define KEY_TV2 0x17a +#define KEY_VCR 0x17b +#define KEY_VCR2 0x17c +#define KEY_SAT 0x17d +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f +#define KEY_TAPE 0x180 +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 +#define KEY_VIDEO 0x189 +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 +#define KEY_CHANNELDOWN 0x193 +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_MAX 0x1ff + +/* + * Relative axes + */ + +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f + +/* + * Absolute axes + */ + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f + +/* + * Misc events + */ + +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_MAX 0x07 + +/* + * LEDs + */ + +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_SLEEP 0x05 +#define LED_SUSPEND 0x06 +#define LED_MUTE 0x07 +#define LED_MISC 0x08 +#define LED_MAX 0x0f + +/* + * Autorepeat values + */ + +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 + +/* + * Sounds + */ + +#define SND_CLICK 0x00 +#define SND_BELL 0x01 +#define SND_TONE 0x02 +#define SND_MAX 0x07 + +/* + * IDs. + */ + +#define ID_BUS 0 +#define ID_VENDOR 1 +#define ID_PRODUCT 2 +#define ID_VERSION 3 + +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 + +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 + +/* + * Values describing the status of an effect + */ +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 + +/* + * Structures used in ioctls to upload effects to a device + * The first structures are not passed directly by using ioctls. + * They are sub-structures of the actually sent structure (called ff_effect) + */ + +struct ff_replay { + __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */ + __u16 delay; /* Time to wait before to start playing an effect */ +}; + +struct ff_trigger { + __u16 button; /* Number of button triggering an effect */ + __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ +}; + +struct ff_envelope { + __u16 attack_length; /* Duration of attack (ms) */ + __u16 attack_level; /* Level at beginning of attack */ + __u16 fade_length; /* Duration of fade (ms) */ + __u16 fade_level; /* Level at end of fade */ +}; + +/* FF_CONSTANT */ +struct ff_constant_effect { + __s16 level; /* Strength of effect. Negative values are OK */ + struct ff_envelope envelope; +}; + +/* FF_RAMP */ +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; + +/* FF_SPRING of FF_FRICTION */ +struct ff_condition_effect { + __u16 right_saturation; /* Max level when joystick is on the right */ + __u16 left_saturation; /* Max level when joystick in on the left */ + + __s16 right_coeff; /* Indicates how fast the force grows when the + joystick moves to the right */ + __s16 left_coeff; /* Same for left side */ + + __u16 deadband; /* Size of area where no force is produced */ + __s16 center; /* Position of dead zone */ + +}; + +/* FF_PERIODIC */ +struct ff_periodic_effect { + __u16 waveform; /* Kind of wave (sine, square...) */ + __u16 period; /* in ms */ + __s16 magnitude; /* Peak value */ + __s16 offset; /* Mean value of wave (roughly) */ + __u16 phase; /* 'Horizontal' shift */ + + struct ff_envelope envelope; + +/* Only used if waveform == FF_CUSTOM */ + __u32 custom_len; /* Number of samples */ + __s16 *custom_data; /* Buffer of samples */ +/* Note: the data pointed by custom_data is copied by the driver. You can + * therefore dispose of the memory after the upload/update */ +}; + +/* FF_RUMBLE */ +/* Some rumble pads have two motors of different weight. + strong_magnitude represents the magnitude of the vibration generated + by the heavy motor. +*/ +struct ff_rumble_effect { + __u16 strong_magnitude; /* Magnitude of the heavy motor */ + __u16 weak_magnitude; /* Magnitude of the light one */ +}; + +/* + * Structure sent through ioctl from the application to the driver + */ +struct ff_effect { + __u16 type; +/* Following field denotes the unique id assigned to an effect. + * If user sets if to -1, a new effect is created, and its id is returned in the same field + * Else, the user sets it to the effect id it wants to update. + */ + __s16 id; + + __u16 direction; /* Direction. 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + + struct ff_trigger trigger; + struct ff_replay replay; + + union { + struct ff_constant_effect constant; + struct ff_ramp_effect ramp; + struct ff_periodic_effect periodic; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; + } u; +}; + +/* + * Force feedback effect types + */ + +#define FF_RUMBLE 0x50 +#define FF_PERIODIC 0x51 +#define FF_CONSTANT 0x52 +#define FF_SPRING 0x53 +#define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 + +/* + * Force feedback periodic effect types + */ + +#define FF_SQUARE 0x58 +#define FF_TRIANGLE 0x59 +#define FF_SINE 0x5a +#define FF_SAW_UP 0x5b +#define FF_SAW_DOWN 0x5c +#define FF_CUSTOM 0x5d + +/* + * Set ff device properties + */ + +#define FF_GAIN 0x60 +#define FF_AUTOCENTER 0x61 + +#define FF_MAX 0x7f + +#ifdef __KERNEL__ + +/* + * In-kernel definitions. + */ + +#include <linux/fs.h> +#include <linux/timer.h> + +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define LONG(x) ((x)/BITS_PER_LONG) + +#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \ + ((dev->keycodesize == 1) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode]))) + +#define init_input_dev(dev) do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0) + +struct input_dev { + + void *private; + + char *name; + char *phys; + char *uniq; + struct input_id id; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + int ff_effects_max; + + unsigned int keycodemax; + unsigned int keycodesize; + void *keycode; + + unsigned int repeat_key; + struct timer_list timer; + + struct pm_dev *pm_dev; + struct pt_regs *regs; + int state; + + int sync; + + int abs[ABS_MAX + 1]; + int rep[REP_MAX + 1]; + + unsigned long key[NBITS(KEY_MAX)]; + unsigned long led[NBITS(LED_MAX)]; + unsigned long snd[NBITS(SND_MAX)]; + + int absmax[ABS_MAX + 1]; + int absmin[ABS_MAX + 1]; + int absfuzz[ABS_MAX + 1]; + int absflat[ABS_MAX + 1]; + + int (*open)(struct input_dev *dev); + void (*close)(struct input_dev *dev); + int (*accept)(struct input_dev *dev, struct file *file); + int (*flush)(struct input_dev *dev, struct file *file); + int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); + int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); + int (*erase_effect)(struct input_dev *dev, int effect_id); + + struct input_handle *grab; + + struct list_head h_list; + struct list_head node; +}; + +/* + * Structure for hotplug & device<->driver matching. + */ + +#define INPUT_DEVICE_ID_MATCH_BUS 1 +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 +#define INPUT_DEVICE_ID_MATCH_VERSION 8 + +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010 +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020 +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040 +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080 +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100 +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200 +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400 +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800 + +#define INPUT_DEVICE_ID_MATCH_DEVICE\ + (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) +#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ + (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) + +struct input_device_id { + + unsigned long flags; + + struct input_id id; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + + unsigned long driver_info; +}; + +struct input_handle; + +struct input_handler { + + void *private; + + void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); + void (*disconnect)(struct input_handle *handle); + + struct file_operations *fops; + int minor; + char *name; + + struct input_device_id *id_table; + + struct list_head h_list; + struct list_head node; +}; + +struct input_handle { + + void *private; + + int open; + char *name; + + struct input_dev *dev; + struct input_handler *handler; + + struct list_head d_node; + struct list_head h_node; +}; + +#define to_dev(n) container_of(n,struct input_dev,node) +#define to_handler(n) container_of(n,struct input_handler,node); +#define to_handle(n) container_of(n,struct input_handle,d_node) +#define to_handle_h(n) container_of(n,struct input_handle,h_node) + +void input_register_device(struct input_dev *); +void input_unregister_device(struct input_dev *); + +void input_register_handler(struct input_handler *); +void input_unregister_handler(struct input_handler *); + +int input_grab_device(struct input_handle *); +void input_release_device(struct input_handle *); + +int input_open_device(struct input_handle *); +void input_close_device(struct input_handle *); + +int input_accept_process(struct input_handle *handle, struct file *file); +int input_flush_device(struct input_handle* handle, struct file* file); + +void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) +#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) +#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) +#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) +#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c) + +#define input_regs(a,b) do { (a)->regs = (b); } while (0) +#define input_sync(a) do { input_event(a, EV_SYN, SYN_REPORT, 0); (a)->regs = NULL; } while (0) + +extern struct class input_class; + +#endif +#endif @@ -0,0 +1,18 @@ +#!/bin/sh +INPUT="linux-input.h" +cat <<EOF +begin remote + name linux-input-layer + begin codes +EOF +awk " + /_MAX/ { next }; + /KEY_RESERVED/ { next }; + /#define (KEY|BTN)_/ { gsub(/KEY_/,\"\",\$2); + printf(\"\t\t%-20s 0x%04x\n\", + \$2,0x10000+strtonum(\$3)) } +" < $INPUT +cat <<EOF + end codes +end remote +EOF @@ -0,0 +1,169 @@ +#ifndef _LIST_H +#define _LIST_H 1 + +/* + * Simple doubly linked list implementation. + * -- shameless stolen from the linux kernel sources + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a item entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_add(struct list_head * item, + struct list_head * prev, + struct list_head * next) +{ + next->prev = item; + item->next = next; + item->prev = prev; + prev->next = item; +} + +/** + * list_add - add a item entry + * @item: item entry to be added + * @head: list head to add it after + * + * Insert a item entry after the specified head. + * This is good for implementing stacks. + */ +static __inline__ void list_add(struct list_head *item, struct list_head *head) +{ + __list_add(item, head, head->next); +} + +/** + * list_add_tail - add a item entry + * @item: item entry to be added + * @head: list head to add it before + * + * Insert a item entry before the specified head. + * This is useful for implementing queues. + */ +static __inline__ void list_add_tail(struct list_head *item, struct list_head *head) +{ + __list_add(item, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_del(struct list_head * prev, + struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static __inline__ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static __inline__ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static __inline__ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_splice - join two lists + * @list: the item list to add. + * @head: the place to add it in the first list. + */ +static __inline__ void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev - iterate over a list in reverse order + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +#endif /* _LIST_H */ diff --git a/lsinput.c b/lsinput.c new file mode 100644 index 0000000..45f50e5 --- /dev/null +++ b/lsinput.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> + +#include "input.h" + +/* ------------------------------------------------------------------ */ + +static void list_devices(void) +{ + int i,fd; + + for (i = 0; i < 32; i++) { + /* try to open */ + fd = device_open(i,1); + if (-1 == fd) + return; + device_info(fd); + close(fd); + } + return; +} + +int main(int argc, char *argv[]) +{ + list_devices(); + exit(0); +} + +/* --------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/mk/Autoconf.mk b/mk/Autoconf.mk new file mode 100644 index 0000000..646e47b --- /dev/null +++ b/mk/Autoconf.mk @@ -0,0 +1,124 @@ +# +# simple autoconf system for GNU make +# +# (c) 2002,2003 Gerd Knorr <kraxel@bytesex.org> +# +# credits for creating this one go to the autotools people because +# they managed it to annoy lots of developers and users (including +# me) with version incompatibilities. +# +# This file is public domain. No warranty. If it breaks you keep +# both pieces. +# +######################################################################## + +# verbose yes/no +verbose ?= no + +# some stuff used by the tests +ifneq ($(verbose),no) + # verbose (for debug) + ac_init = echo "checking $(1) ... " >&2; rc=no + ac_b_cmd = echo "run: $(1)" >&2; $(1) >/dev/null && rc=yes + ac_s_cmd = echo "run: $(1)" >&2; rc=`$(1)` + ac_fini = echo "... result is $${rc}" >&2; echo >&2; echo "$${rc}" +else + # normal + ac_init = echo -ne "checking $(1) ... " >&2; rc=no + ac_b_cmd = $(1) >/dev/null 2>&1 && rc=yes + ac_s_cmd = rc=`$(1) 2>/dev/null` + ac_fini = echo "$${rc}" >&2; echo "$${rc}" +endif + +# some helpers to build cflags and related variables +ac_def_cflags_1 = $(if $(filter yes,$($(1))),-D$(1)) +ac_lib_cflags = $(foreach lib,$(1),$(call ac_def_cflags_1,HAVE_LIB$(lib))) +ac_inc_cflags = $(foreach inc,$(1),$(call ac_def_cflags_1,HAVE_$(inc))) +ac_lib_mkvar_1 = $(if $(filter yes,$(HAVE_LIB$(1))),$($(1)_$(2))) +ac_lib_mkvar = $(foreach lib,$(1),$(call ac_lib_mkvar_1,$(lib),$(2))) + + +######################################################################## +# the tests ... + +# get uname +ac_uname = $(shell \ + $(call ac_init,for system);\ + $(call ac_s_cmd,uname -s | tr 'A-Z' 'a-z');\ + $(call ac_fini)) + +# check for some header file +ac_header = $(shell \ + $(call ac_init,for $(1));\ + $(call ac_b_cmd,echo '\#include <$(1)>' |\ + $(CC) $(CFLAGS) -E -);\ + $(call ac_fini)) + +# check for some library +ac_lib = $(shell \ + $(call ac_init,for $(1) in $(2));\ + echo 'void $(1)(void); int main(void) {$(1)();return 0;}' \ + > __actest.c;\ + $(call ac_b_cmd,$(CC) $(CFLAGS) $(LDFLAGS) -o \ + __actest __actest.c -l$(2) $(3));\ + rm -f __actest __actest.c;\ + $(call ac_fini)) + +# check if some compiler flag works +ac_cflag = $(shell \ + $(call ac_init,if $(CC) supports $(1));\ + echo 'int main() {return 0;}' > __actest.c;\ + $(call ac_b_cmd,$(CC) $(CFLAGS) $(1) $(LDFLAGS) -o \ + __actest __actest.c);\ + rm -f __actest __actest.c;\ + $(call ac_fini)) + +# check for some binary +ac_binary = $(shell \ + $(call ac_init,for $(1));\ + $(call ac_s_cmd,which $(1));\ + bin="$$rc";rc="no";\ + $(call ac_b_cmd,test -x "$$$$bin");\ + $(call ac_fini)) + +# check if lib64 is used +ac_lib64 = $(shell \ + $(call ac_init,for libdir name);\ + $(call ac_s_cmd,$(CC) -print-search-dirs | grep -q lib64 &&\ + echo "lib64" || echo "lib");\ + $(call ac_fini)) + +# check for x11 ressource dir prefix +ac_resdir = $(shell \ + $(call ac_init,for X11 app-defaults prefix);\ + $(call ac_s_cmd, test -d /etc/X11/app-defaults &&\ + echo "/etc/X11" || echo "/usr/X11R6/lib/X11");\ + $(call ac_fini)) + + +######################################################################## +# build Make.config + +define newline + + +endef +make-config-q = $(subst $(newline),\n,$(make-config)) + +ifeq ($(filter config,$(MAKECMDGOALS)),config) +.PHONY: Make.config + LIB := $(call ac_lib64) +else + LIB ?= $(call ac_lib64) + LIB := $(LIB) +endif +.PHONY: config +config: Make.config + @true + +Make.config: GNUmakefile + @echo -e "$(make-config-q)" > $@ + @echo + @echo "Make.config written, edit if needed" + @echo + diff --git a/mk/Compile.mk b/mk/Compile.mk new file mode 100644 index 0000000..75dadde --- /dev/null +++ b/mk/Compile.mk @@ -0,0 +1,84 @@ +# +# some rules to compile stuff ... +# +# (c) 2002 Gerd Knorr <kraxel@bytesex.org> +# +# main features: +# * autodependencies via "cpp -MD" +# * fancy, non-verbose output +# +# This file is public domain. No warranty. If it breaks you keep +# both pieces. +# +######################################################################## + +# verbose yes/no +verbose ?= no + +# dependency files +tmpdep = mk/$(subst /,_,$*).tmp +depfile = mk/$(subst /,_,$*).dep +depfiles = mk/*.dep + +compile_c = $(CC) $(CFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< +compile_cc = $(CXX) $(CXXFLAGS) -Wp,-MD,$(tmpdep) -c -o $@ $< +fixup_deps = sed -e "s|.*\.o:|$@:|" < $(tmpdep) > $(depfile) && rm -f $(tmpdep) + +link_app = $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) +link_so = $(CC) $(LDFLAGS) -shared -Wl,-soname,$(@F) -o $@ $^ $(LDLIBS) +ar_lib = rm -f $@ && ar -r $@ $^ && ranlib $@ + +moc_h = $(MOC) $< -o $@ +msgfmt_po = msgfmt -o $@ $< + +# non-verbose output +ifeq ($(verbose),no) + echo_compile_c = echo " CC " $@ + echo_compile_cc = echo " CXX " $@ + echo_link_app = echo " LD " $@ + echo_link_so = echo " LD " $@ + echo_ar_lib = echo " AR " $@ + echo_moc_h = echo " MOC " $@ + echo_msgfmt_po = echo " MSGFMT " $@ +else + echo_compile_c = echo $(compile_c) + echo_compile_cc = echo $(compile_cc) + echo_link_app = echo $(link_app) + echo_link_so = echo $(link_so) + echo_ar_lib = echo $(ar_lib) + echo_moc_h = echo $(moc_h) + echo_msgfmt_po = echo $(msgfmt_po) +endif + +%.o: %.c + @$(echo_compile_c) + @$(compile_c) + @$(fixup_deps) + +%.o: %.cc + @$(echo_compile_cc) + @$(compile_cc) + @$(fixup_deps) + +%.o: %.cpp + @$(echo_compile_cc) + @$(compile_cc) + @$(fixup_deps) + + +%.so: %.o + @$(echo_link_so) + @$(link_so) + +%: %.o + @$(echo_link_app) + @$(link_app) + +%.moc : %.h + @$(echo_moc_h) + @$(moc_h) + +%.mo : %.po + @$(echo_msgfmt_po) + @$(msgfmt_po) + diff --git a/mk/Maintainer.mk b/mk/Maintainer.mk new file mode 100644 index 0000000..f5ff691 --- /dev/null +++ b/mk/Maintainer.mk @@ -0,0 +1,47 @@ +# just some maintainer stuff for me ... +######################################################################## + +make-sync-dir = $(HOME)/src/gnu-make +pbuilder-dir = /work/pbuilder/result +snapshot-dir = $(HOME)/snapshot +snapshot-date = $(shell date +%Y%m%d) +snapshot-name = $(snapshot-dir)/$(PACKAGE)-$(snapshot-date).tar.gz + +deb-version = $(shell dpkg-parsechangelog | sed -n 's/^Version: \(.*:\|\)//p') +deb-arch := $(shell uname -m | sed \ + -e 's/i.86/i386/' \ + -e 's/ppc/powerpc/') +deb-dsc := ../$(PACKAGE)_$(VERSION).dsc +deb-changes := $(pbuilder-dir)/$(PACKAGE)_$(VERSION)_$(deb-arch).changes + + +.PHONY: sync checkit release port tarball dist rpm +sync:: distclean + test -d $(make-sync-dir) + rm -f INSTALL mk/*.mk + cp -v $(make-sync-dir)/INSTALL . + cp -v $(make-sync-dir)/*.mk mk + chmod 444 INSTALL mk/*.mk + + +dsc source $(deb-dsc): clean + test "$(VERSION)" = "$(deb-version)" + dpkg-buildpackage -S -us -uc -rfakeroot + +debs pbuild $(deb-changes): $(deb-dsc) + sudo /usr/sbin/pbuilder build $(deb-dsc) + -lintian -i $(deb-changes) + +release: $(deb-changes) + debsign $(deb-changes) + + +tarball dist: realclean + (cd ..; tar czf $(TARBALL) $(DIR)) + +snapshot snap: realclean + (cd ..; tar czf $(snapshot-name) $(DIR)) + +rpm: tarball + rpm -ta ../$(TARBALL) + diff --git a/mk/Variables.mk b/mk/Variables.mk new file mode 100644 index 0000000..4449d81 --- /dev/null +++ b/mk/Variables.mk @@ -0,0 +1,33 @@ +# common variables ... +######################################################################## + +# package + version +empty := +space := $(empty) $(empty) +PWD := $(shell pwd) +DIR := $(patsubst $(dir $(PWD))%,%,$(PWD)) +PACKAGE := $(word 1,$(subst -,$(space),$(DIR))) +VERSION := $(word 2,$(subst -,$(space),$(DIR))) +TARBALL := $(PACKAGE)_$(VERSION).tar.gz + +# directories +DESTDIR = +prefix ?= /usr/local +bindir = $(DESTDIR)$(prefix)/bin +mandir = $(DESTDIR)$(prefix)/share/man +locdir = $(DESTDIR)$(prefix)/share/locale + +# programs +CC ?= gcc +CXX ?= g++ +MOC ?= $(if $(QTDIR),$(QTDIR)/bin/moc,moc) +INSTALL ?= install +INSTALL_BINARY := $(INSTALL) -s +INSTALL_SCRIPT := $(INSTALL) +INSTALL_DATA := $(INSTALL) -m 644 +INSTALL_DIR := $(INSTALL) -d + +# cflags +CFLAGS ?= -g -O2 +CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes \ + -Wpointer-arith -Wunused @@ -0,0 +1,10 @@ +#!/bin/sh + +TYPE="$1" +INPUT="linux-input.h" + +awk " + /EV_VERSION/ { next }; + /_MAX/ { next }; + /#define $1_/ { printf(\"\t[ %-16s ] = \\\"%s\\\",\n\", \$2, \$2); } +" < $INPUT
\ No newline at end of file @@ -0,0 +1,153 @@ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "tcp.h" + +int tcp_verbose; + +/* ------------------------------------------------------------------ */ + +static char *strfamily(int family) +{ + switch (family) { + case PF_INET6: return "ipv6"; + case PF_INET: return "ipv4"; + case PF_UNIX: return "unix"; + } + return "????"; +} + +int tcp_connect(struct addrinfo *ai, + char *addr, char *port, + char *host, char *serv) +{ + struct addrinfo *res,*e; + struct addrinfo *lres, ask; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + char uhost[INET6_ADDRSTRLEN+1]; + char userv[33]; + int sock,rc,opt=1; + + /* lookup peer */ + ai->ai_flags = AI_CANONNAME; + if (0 != (rc = getaddrinfo(host, serv, ai, &res))) { + if (tcp_verbose) + fprintf(stderr,"getaddrinfo (peer): %s\n",gai_strerror(rc)); + return -1; + } + for (e = res; e != NULL; e = e->ai_next) { + if (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uhost,INET6_ADDRSTRLEN,userv,32, + NI_NUMERICHOST | NI_NUMERICSERV)) { + if (tcp_verbose) + fprintf(stderr,"getnameinfo (peer): oops\n"); + continue; + } + if (-1 == (sock = socket(e->ai_family, e->ai_socktype, + e->ai_protocol))) { + if (tcp_verbose) + fprintf(stderr,"socket (%s): %s\n", + strfamily(e->ai_family),strerror(errno)); + continue; + } + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); + if (NULL != addr || NULL != port) { + /* bind local port */ + memset(&ask,0,sizeof(ask)); + ask.ai_flags = AI_PASSIVE; + ask.ai_family = e->ai_family; + ask.ai_socktype = e->ai_socktype; + if (0 != (rc = getaddrinfo(addr, port, &ask, &lres))) { + if (tcp_verbose) + fprintf(stderr,"getaddrinfo (local): %s\n", + gai_strerror(rc)); + continue; + } + if (0 != getnameinfo((struct sockaddr*)lres->ai_addr, + lres->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV)) { + if (tcp_verbose) + fprintf(stderr,"getnameinfo (local): oops\n"); + continue; + } + if (-1 == bind(sock, lres->ai_addr, lres->ai_addrlen)) { + if (tcp_verbose) + fprintf(stderr,"%s [%s] %s bind: %s\n", + strfamily(lres->ai_family),uaddr,uport, + strerror(errno)); + continue; + } + } + /* connect to peer */ + if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) { + if (tcp_verbose) + fprintf(stderr,"%s %s [%s] %s connect: %s\n", + strfamily(e->ai_family),e->ai_canonname,uhost,userv, + strerror(errno)); + close(sock); + continue; + } + if (tcp_verbose) + fprintf(stderr,"%s %s [%s] %s open\n", + strfamily(e->ai_family),e->ai_canonname,uhost,userv); + fcntl(sock,F_SETFL,O_NONBLOCK); + return sock; + } + return -1; +} + +int tcp_listen(struct addrinfo *ai, char *addr, char *port) +{ + struct addrinfo *res,*e; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + int slisten,rc,opt=1; + + /* lookup */ + ai->ai_flags = AI_PASSIVE; + if (0 != (rc = getaddrinfo(addr, port, ai, &res))) { + if (tcp_verbose) + fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rc)); + exit(1); + } + + /* create socket + bind */ + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN,uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + if (-1 == (slisten = socket(e->ai_family, e->ai_socktype, + e->ai_protocol))) { + if (tcp_verbose) + fprintf(stderr,"socket (%s): %s\n", + strfamily(e->ai_family),strerror(errno)); + continue; + } + opt = 1; + setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); + if (-1 == bind(slisten, e->ai_addr, e->ai_addrlen)) { + if (tcp_verbose) + fprintf(stderr,"%s [%s] %s bind: %s\n", + strfamily(e->ai_family),uaddr,uport, + strerror(errno)); + continue; + } + listen(slisten,1); + break; + } + if (NULL == e) + return -1; + + /* wait for a incoming connection */ + if (tcp_verbose) + fprintf(stderr,"listen on %s [%s] %s ...\n", + strfamily(e->ai_family),uaddr,uport); + fcntl(slisten,F_SETFL,O_NONBLOCK); + return slisten; +} @@ -0,0 +1,11 @@ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +extern int tcp_verbose; + +int tcp_connect(struct addrinfo *ai, + char *addr, char *port, + char *host, char *serv); + +int tcp_listen(struct addrinfo *ai, char *addr, char *port); |