aboutsummaryrefslogblamecommitdiffstats
path: root/libgamepad_drain__.c
blob: 38e898eefe82279550d4095f3d550a701baa4a2b (plain) (tree)






















































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

#define DEFER_EINTR(ERROR_CONDITION)\
	DEFER_EINTR_(device, ERROR_CONDITION, fail)


int
libgamepad_drain__(struct libgamepad_device *device)
{
	struct input_event buf[4 * 8];
	int flags, saved_errno = errno;
	ssize_t r;

	if (device->internals->deferred_error) {
		errno = device->internals->deferred_error;
		device->internals->deferred_error = 0;
		return -1;
	}

	flags = fcntl(device->fd, F_GETFL);
	if (flags < 0)
		return -1;

	if (!(flags & O_NONBLOCK))
		if (fcntl(device->fd, F_GETFL, flags | O_NONBLOCK) < 0)
			goto fail;

	for (;;) {
		r = read(device->fd, buf, sizeof(buf));
		if (r < (ssize_t)sizeof(buf)) {
			if (r > 0)
				break;
			else if (!r)
				goto nodev;
			else if (errno == EAGAIN)
				break;
			else if (errno == EINTR)
				device->internals->deferred_error = EINTR;
			else
				goto fail;
		}
	}

	if (!(flags & O_NONBLOCK))
		DEFER_EINTR(fcntl(device->fd, F_SETFL, flags) < 0);

	errno = saved_errno;
	return 0;

nodev:
	errno = ENODEV;
fail:
	return -1;
}