Current section

Files

Jump to
input_event src input_enum.c
Raw

src/input_enum.c

/*
* Copyright 2016 Justin Schneck
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "input_enum.h"
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <stdlib.h>
#include <dirent.h>
#include <inttypes.h>
#include "utils.h"
#include "erlcmd.h"
static const char response_id = 'r';
struct device_info *device_info_alloc()
{
struct device_info *info = (struct device_info *) malloc(sizeof(struct device_info));
memset(info, 0, sizeof(struct device_info));
return info;
}
void device_info_free(struct device_info *info)
{
// Free any data
if (info->fd)
free(info->fd);
if (info->name)
free(info->name);
// Reset the fields
memset(info, 0, sizeof(struct device_info));
}
void device_info_free_list(struct device_info *info)
{
while (info) {
struct device_info *next = info->next;
device_info_free(info);
free(info);
info = next;
}
}
/**
* Filter for the AutoDevProbe scandir on /dev/input.
*
* @param dir The current directory entry provided by scandir.
*
* @return Non-zero if the given directory entry starts with "event", or zero
* otherwise.
*/
static int is_event_device(const struct dirent *dir) {
return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
}
int enum_devices() {
if (getuid() != 0)
fprintf(stderr, "Not running as root, no devices may be available.\n");
struct device_info *device_list = find_input_devices();
int device_list_len = 0;
for (struct device_info *device = device_list;
device != NULL;
device = device->next)
device_list_len++;
debug("Found %d devices", device_list_len);
char resp[4096];
int resp_index = sizeof(uint16_t); // Space for payload size
resp[resp_index++] = response_id;
ei_encode_version(resp, &resp_index);
ei_encode_list_header(resp, &resp_index, device_list_len);
for (struct device_info *device = device_list;
device != NULL;
device = device->next) {
ei_encode_tuple_header(resp, &resp_index, 2);
ei_encode_binary(resp, &resp_index, device->fd, strlen(device->fd));
ei_encode_binary(resp, &resp_index, device->name,strlen(device->name));
}
ei_encode_empty_list(resp, &resp_index);
erlcmd_send(resp, resp_index);
device_info_free_list(device_list);
return 0;
}
struct device_info *find_input_devices() {
struct dirent **namelist;
int i, ndev, devnum;
char *filename;
struct device_info *info = NULL;
ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort);
if (ndev <= 0)
return info;
for (i = 0; i < ndev; i++)
{
char fname[64];
int fd = -1;
char name[256] = "???";
snprintf(fname, sizeof(fname),
"%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
fd = open(fname, O_RDONLY);
if (fd < 0)
continue;
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
close(fd);
struct device_info *new_info = device_info_alloc();
new_info->fd = strdup(fname);
new_info->name = strdup(name);
new_info->next = info;
info = new_info;
free(namelist[i]);
}
free(namelist);
return info;
}