1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/* Copyright 2010 Stefan Tomanek <stefan.tomanek+th@wertarbyte.de>
* You have permission to copy, modify, and redistribute under the
* terms of the GPLv3 or any later version.
* For full license terms, see COPYING.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/hiddev.h>
#include <sys/ioctl.h>
#include <inttypes.h>
#include "devices.h"
#include "eventnames.h"
#define BITFIELD uint32_t
static device *device_list = NULL;
char *get_device_description(int fd) {
char descr[256] = "Unknown";
if(ioctl(fd, EVIOCGNAME(sizeof(descr)), descr) < 0) {
perror("evdev ioctl");
}
return strdup(descr);
}
static __inline__ int test_bit(int nr, BITFIELD * addr) {
BITFIELD mask;
addr += nr >> 5;
mask = 1 << (nr & 0x1f);
return ((mask & *addr) != 0);
}
int device_is_suitable(int fd) {
BITFIELD bits[32];
int rc = ioctl(fd, EVIOCGBIT(0,sizeof(bits)), bits);
return rc > 0 && (
/* we only consider devices with keys or switches suitable */
test_bit(EV_KEY, bits) || test_bit(EV_SW, bits)
);
}
void add_device(char *dev, int fd, int excl, char *tag) {
device **p = &device_list;
// find end of list
while (*p != NULL) {
p = &( (*p)->next );
}
if (fd < 0) {
fd = open( dev, O_RDONLY );
}
if (fd >= 0) {
if (! device_is_suitable(fd) ) {
fprintf(stderr, "Device %s not suitable.\n", dev);
close(fd);
return;
}
/* grab device exclusively */
if (excl) {
if (ioctl(fd, EVIOCGRAB, 1) == -1) {
fprintf(stderr, "Device %s cannot be grabbed exclusively.\n", dev);
close(fd);
return;
}
}
*p = malloc(sizeof(device));
if (*p == NULL) goto nomem_cleanup;
memset(*p, 0, sizeof(device));
(*p)->devname = strdup(dev);
if ((*p)->devname == NULL) goto nomem_cleanup;
(*p)->fd = fd;
(*p)->exclusive = excl;
if (tag) {
strncpy((*p)->tag, tag, TH_DEVICE_TAG_LENGTH);
(*p)->tag[TH_DEVICE_TAG_LENGTH-1] = '\0';
}
(*p)->next = NULL;
} else {
fprintf( stderr, "Error opening '%s': %s\n", dev, strerror(errno) );
}
return;
nomem_cleanup:
fprintf(stderr, "Unable to allocate memory for new device!\n");
if (*p) {
free( (*p)->devname );
}
free(*p);
*p = NULL;
}
int remove_device(char *dev) {
device **p = &device_list;
while (*p != NULL) {
if ( strcmp( (*p)->devname, dev ) == 0 ) {
device *copy = *p;
/* bypass the list item */
*p = copy->next;
close(copy->fd);
free(copy->devname);
free(copy);
return 1;
}
/* advance to the next node */
p = &( (*p)->next );
}
/* reached the end of the list */
return 0;
}
void clear_devices(void) {
device *p = device_list;
while (p != NULL) {
device *next = p->next;
close(p->fd);
free(p->devname);
free(p);
p = next;
}
device_list = NULL;
}
int count_devices(void) {
int n = 0;
device *p = device_list;
while (p != NULL) {
n++;
p = p->next;
}
return n;
}
void for_each_device( void(*func)(device*) ) {
device *p = device_list;
while (p != NULL) {
func( p );
p = p->next;
}
}
|