aboutsummaryrefslogblamecommitdiffstats
path: root/libgamepad_open_device.c
blob: 3c2a751f39027b3727d6316ed038ea923ff5dcd4 (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->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;
}