aboutsummaryrefslogtreecommitdiffstats
path: root/libgamepad_open_device.c
blob: 3c2a751f39027b3727d6316ed038ea923ff5dcd4 (plain) (blame)
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
/* 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->internals = NULL;
	devicep->buttons = NULL;
	devicep->absolute_axes = NULL;
	devicep->relative_axes = NULL;
	memset(devicep->force_feedback_support, 0, sizeof(devicep->force_feedback_support));

	devicep->internals = calloc(1, sizeof(*devicep->internals));
	if (!devicep->internals)
		return -1;

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

	if (ioctl(devicep->fd, EVIOCGID, &id)) {
		libgamepad_close_device(devicep);
		return -1;
	}

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

	devicep->name              = libevdev_get_name(devicep->internals->dev);
	devicep->unique_id         = libevdev_get_uniq(devicep->internals->dev);
	devicep->physical_location = libevdev_get_phys(devicep->internals->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->internals->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->internals->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->internals->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->internals->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;
}