aboutsummaryrefslogblamecommitdiffstats
path: root/libgamepad_open_device.c
blob: cce013313c5779f7931d0f4e3145376a8971d548 (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                                                                                                
                           







                                      
                                                                                            







                                                        
                                                



                                              









                                                               





                                                                     



                                                              





















                                                                                           



                                                                                          
































                                                                                                          
/* See LICENSE file for copyright and license details. */
#include "common.h"


int
libgamepad_open_device(struct libgamepad_device *devicep, int dirfd, const char *path, int mode)
{
	int err;
	unsigned int i;
	uint16_t n;
	struct input_id id;

	devicep->fd = dirfd;
	devicep->close_fd = 0;
	devicep->require_sync = 0;
	devicep->dev = NULL;
	devicep->buttons = NULL;
	devicep->absolute_axes = NULL;
	devicep->relative_axes = NULL;
	memset(devicep->force_feedback_support, 0, sizeof(devicep->force_feedback_support));

	if (path && *path) {
		devicep->fd = openat(dirfd, path, mode);
		if (devicep->fd < 0)
			return -1;
		devicep->close_fd = 1;
	}

	if (ioctl(devicep->fd, EVIOCGID, &id)) {
		if (devicep->close_fd) {
			close(devicep->fd);
			devicep->close_fd = 0;
		}
		return -1;
	}

	err = libevdev_new_from_fd(devicep->fd, &devicep->dev);
	if (err < 0) {
		if (devicep->close_fd) {
			close(devicep->fd);
			devicep->close_fd = 0;
		}
		errno = -err;
		return -1;
	}

	devicep->name              = libevdev_get_name(devicep->dev);
	devicep->unique_id         = libevdev_get_uniq(devicep->dev);
	devicep->physical_location = libevdev_get_phys(devicep->dev);
	devicep->bus_type          = (unsigned int)id.bustype;
	devicep->vendor            = (unsigned int)id.vendor;
	devicep->product           = (unsigned int)id.product;
	devicep->version           = (unsigned int)id.version;

	devicep->nbuttons = 0;
	for (i = 0; i < KEY_CNT; i++) {
		devicep->button_map[i] = -1;
		if (libevdev_has_event_code(devicep->dev, EV_KEY, i))
			devicep->button_map[i] = (int16_t)devicep->nbuttons++;
	}

	devicep->nabsolute_axes = 0;
	for (i = 0; i < ABS_CNT; i++) {
		devicep->absolute_axis_map[i] = -1;
		if (libevdev_has_event_code(devicep->dev, EV_ABS, i))
			devicep->absolute_axis_map[i] = (int16_t)devicep->nabsolute_axes++;
	}

	devicep->nrelative_axes = 0;
	for (i = 0; i < REL_CNT; i++) {
		devicep->relative_axis_map[i] = -1;
		if (libevdev_has_event_code(devicep->dev, EV_REL, i))
			devicep->relative_axis_map[i] = (int16_t)devicep->nrelative_axes++;
	}

	for (i = 0; i < FF_CNT; i++)
		if (libevdev_has_event_code(devicep->dev, EV_FF, i))
			devicep->force_feedback_support[i / 8] |= (uint8_t)(1 << (i & 7));

	if (devicep->nbuttons) {
		devicep->buttons = calloc(devicep->nbuttons, sizeof(*devicep->buttons));
		if (!devicep->buttons)
			goto fail;
		for (i = 0, n = 0; i < KEY_CNT; i++)
			if (devicep->button_map[i] >= 0)
				devicep->buttons[n++] = (uint16_t)i;
	}

	if (devicep->nabsolute_axes) {
		devicep->absolute_axes = calloc(devicep->nabsolute_axes, sizeof(*devicep->absolute_axes));
		if (!devicep->absolute_axes)
			goto fail;
		for (i = 0, n = 0; i < ABS_CNT; i++)
			if (devicep->absolute_axis_map[i] >= 0)
				devicep->absolute_axes[n++] = (uint16_t)i;
	}

	if (devicep->nrelative_axes) {
		devicep->relative_axes = calloc(devicep->nrelative_axes, sizeof(*devicep->relative_axes));
		if (!devicep->relative_axes)
			goto fail;
		for (i = 0, n = 0; i < REL_CNT; i++)
			if (devicep->relative_axis_map[i] >= 0)
				devicep->relative_axes[n++] = (uint16_t)i;
	}

	return 0;

fail:
	libgamepad_close_device(devicep);
	return -1;
}