diff options
Diffstat (limited to 'events.c')
-rw-r--r-- | events.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/events.c b/events.c new file mode 100644 index 0000000..461e641 --- /dev/null +++ b/events.c @@ -0,0 +1,175 @@ +/* + * OMAP3 generic events handling + * + * Copyright (C) 2010-2012 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _BSD_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/select.h> + +#include "isp/list.h" +#include "isp/omap3isp.h" +#include "isp/tools.h" + +#include "events.h" + +#define SELECT_TIMEOUT 2000 /* in milliseconds */ + +struct event_fd { + struct list_entry list; + + int fd; + enum omap3_isp_event_type type; + void (*callback)(void *priv); + void *priv; +}; + +void events_watch_fd(struct events *events, int fd, + enum omap3_isp_event_type type, + void(*callback)(void *), void *priv) +{ + struct event_fd *event; + + event = malloc(sizeof *event); + if (event == NULL) + return; + + event->fd = fd; + event->type = type; + event->callback = callback; + event->priv = priv; + + switch (event->type) { + case OMAP3_ISP_EVENT_READ: + FD_SET(fd, &events->rfds); + break; + case OMAP3_ISP_EVENT_WRITE: + FD_SET(fd, &events->wfds); + break; + } + + events->maxfd = max(events->maxfd, fd); + + list_append(&event->list, &events->events); +} + +void events_unwatch_fd(struct events *events, int fd) +{ + struct event_fd *event = NULL; + struct event_fd *entry; + int maxfd = 0; + + list_for_each_entry(entry, &events->events, list) { + if (entry->fd == fd) + event = entry; + else + maxfd = max(maxfd, entry->fd); + } + + if (event == NULL) + return; + + switch (event->type) { + case OMAP3_ISP_EVENT_READ: + FD_CLR(fd, &events->rfds); + break; + case OMAP3_ISP_EVENT_WRITE: + FD_CLR(fd, &events->wfds); + break; + } + + events->maxfd = maxfd; + + list_remove(&event->list); + free(event); +} + +static void events_dispatch(struct events *events, const fd_set *rfds, + const fd_set *wfds) +{ + struct event_fd *event; + + list_for_each_entry(event, &events->events, list) { + if (event->type == OMAP3_ISP_EVENT_READ && + FD_ISSET(event->fd, rfds)) + event->callback(event->priv); + if (event->type == OMAP3_ISP_EVENT_WRITE && + FD_ISSET(event->fd, wfds)) + event->callback(event->priv); + } +} + +bool events_loop(struct events *events) +{ + while (!events->done) { + struct timeval timeout; + fd_set rfds; + fd_set wfds; + int ret; + + timeout.tv_sec = SELECT_TIMEOUT / 1000; + timeout.tv_usec = (SELECT_TIMEOUT % 1000) * 1000; + rfds = events->rfds; + wfds = events->wfds; + + ret = select(events->maxfd + 1, &rfds, &wfds, NULL, &timeout); + if (ret < 0) { + /* EINTR means that a signal has been received, continue + * to the next iteration in that case. + */ + if (errno == EINTR) + continue; + + printf("error: select failed with %d\n", errno); + break; + } + if (ret == 0) { + /* select() should never time out as the ISP is supposed + * to capture images continuously. A timeout is thus + * considered as a fatal error. + */ + printf("error: select timeout\n"); + break; + } + + events_dispatch(events, &rfds, &wfds); + } + + return !events->done; +} + +void events_stop(struct events *events) +{ + events->done = true; +} + +void events_init(struct events *events) +{ + memset(events, 0, sizeof *events); + + FD_ZERO(&events->rfds); + FD_ZERO(&events->wfds); + events->maxfd = 0; + list_init(&events->events); +} |