diff options
Diffstat (limited to 'package/libtapi/src')
| -rw-r--r-- | package/libtapi/src/Makefile | 27 | ||||
| -rw-r--r-- | package/libtapi/src/dialdetector.c | 109 | ||||
| -rw-r--r-- | package/libtapi/src/dialdetector.h | 109 | ||||
| -rw-r--r-- | package/libtapi/src/events.c | 58 | ||||
| -rw-r--r-- | package/libtapi/src/events.h | 18 | ||||
| -rw-r--r-- | package/libtapi/src/list.h | 601 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-device.c | 46 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-device.h | 25 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-ioctl.h | 20 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-port.c | 126 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-port.h | 66 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-session.c | 122 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-session.h | 14 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-stream.c | 42 | ||||
| -rw-r--r-- | package/libtapi/src/tapi-stream.h | 19 | ||||
| -rw-r--r-- | package/libtapi/src/tapidemo.c | 56 | ||||
| -rw-r--r-- | package/libtapi/src/timer_fd.c | 33 | ||||
| -rw-r--r-- | package/libtapi/src/timerfd.h | 61 | 
18 files changed, 1552 insertions, 0 deletions
diff --git a/package/libtapi/src/Makefile b/package/libtapi/src/Makefile new file mode 100644 index 000000000..70b46eb57 --- /dev/null +++ b/package/libtapi/src/Makefile @@ -0,0 +1,27 @@ +ifndef CFLAGS +CFLAGS = -O2 -g -I ../src +endif + +FPIC=-fPIC + +all: libtapi.so + +%.o: %.c +	$(CC) $(CFLAGS) -c -o $@ $^ $(FPIC) + +TAPI_OBJS = \ +	timer_fd.o \ +	events.o \ +	tapi-port.o \ +	tapi-device.o \ +	tapi-session.o \ +	tapi-stream.o + +tapidemo: tapidemo.o libtapi.so +	$(CC) $(LDFLAGS) -o $@ $^ + +libtapi.so: $(TAPI_OBJS) +	$(CC) $(LDFLAGS) -shared -o $@ $^ $(FPIC) + +clean: +	rm -rf *.o *.so diff --git a/package/libtapi/src/dialdetector.c b/package/libtapi/src/dialdetector.c new file mode 100644 index 000000000..ff91b37aa --- /dev/null +++ b/package/libtapi/src/dialdetector.c @@ -0,0 +1,109 @@ +#include <linux/input.h> +#include <sys/epoll.h> +#include <stdint.h> +#include <stdbool.h> + + +#include <stdlib.h> +#include <stdio.h> + +#include "events.h" +#include "timerfd.h" + +#include "tapi-port.h" +#include "dialdetector.h" + +static const struct itimerspec dialdetector_timeout = { +	.it_value.tv_sec = 3, +}; + +static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit) +{ +	printf("note digit: %d\n", d->num_digits); +	d->digits[d->num_digits] = digit; +	++d->num_digits; +} + +static void dialdetector_reset(struct dialdetector *d) +{ +	event_unregister(d->timer_fd); +	d->num_digits = 0; +	d->state = DIALDETECTOR_IDLE; +} + +static bool dialdetector_timeout_event(int events, void *data) +{ +	char num[20]; +	struct dialdetector *dialdetector = data; +	int i; + +	for (i = 0; i < dialdetector->num_digits; ++i) { +		num[i] = '0' + dialdetector->digits[i]; +	} +	num[i] = '\0'; + +	printf("Dialing: %s\n", num); +	dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits, +	dialdetector->digits); + +	dialdetector_reset(dialdetector); + +	return false; +} + +static void dialdetector_port_event(struct tapi_port *port, +	struct tapi_event *event, void *data) +{ +	struct dialdetector *d = data; + +	printf("port event: %d %d\n", d->state, event->hook.on); + +	switch (d->state) { +	case DIALDETECTOR_IDLE: +		if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) { +			d->state = DIALDETECTOR_WAIT_FOR_NUMBER; +			event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); +			timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); +		} +		break; +	case DIALDETECTOR_WAIT_FOR_NUMBER: +	case DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT: +		switch (event->type) { +		case TAPI_EVENT_TYPE_HOOK: +			if (event->hook.on == true) +				dialdetector_reset(d); +			break; +		case TAPI_EVENT_TYPE_DTMF: +			if (d->state == DIALDETECTOR_WAIT_FOR_NUMBER) +				event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); +			timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); +			d->state = DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT; +			dialdetector_note_digit(d, event->dtmf.code); +			break; +		default: +			break; +		} +	} +} + +struct dialdetector *dialdetector_alloc(struct tapi_port *port) +{ +	struct dialdetector *dialdetector; +	dialdetector = malloc(sizeof(*dialdetector)); + +	dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); +	dialdetector->port = port; +	dialdetector->num_digits = 0; +	dialdetector->state = DIALDETECTOR_IDLE; + +	dialdetector->timeout_cb.callback = dialdetector_timeout_event; +	dialdetector->timeout_cb.data = dialdetector; + +	dialdetector->port_listener.callback = dialdetector_port_event; +	dialdetector->port_listener.data = dialdetector; + +	tapi_port_register_event(port, &dialdetector->port_listener); + + +	return dialdetector; +} diff --git a/package/libtapi/src/dialdetector.h b/package/libtapi/src/dialdetector.h new file mode 100644 index 000000000..ff91b37aa --- /dev/null +++ b/package/libtapi/src/dialdetector.h @@ -0,0 +1,109 @@ +#include <linux/input.h> +#include <sys/epoll.h> +#include <stdint.h> +#include <stdbool.h> + + +#include <stdlib.h> +#include <stdio.h> + +#include "events.h" +#include "timerfd.h" + +#include "tapi-port.h" +#include "dialdetector.h" + +static const struct itimerspec dialdetector_timeout = { +	.it_value.tv_sec = 3, +}; + +static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit) +{ +	printf("note digit: %d\n", d->num_digits); +	d->digits[d->num_digits] = digit; +	++d->num_digits; +} + +static void dialdetector_reset(struct dialdetector *d) +{ +	event_unregister(d->timer_fd); +	d->num_digits = 0; +	d->state = DIALDETECTOR_IDLE; +} + +static bool dialdetector_timeout_event(int events, void *data) +{ +	char num[20]; +	struct dialdetector *dialdetector = data; +	int i; + +	for (i = 0; i < dialdetector->num_digits; ++i) { +		num[i] = '0' + dialdetector->digits[i]; +	} +	num[i] = '\0'; + +	printf("Dialing: %s\n", num); +	dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits, +	dialdetector->digits); + +	dialdetector_reset(dialdetector); + +	return false; +} + +static void dialdetector_port_event(struct tapi_port *port, +	struct tapi_event *event, void *data) +{ +	struct dialdetector *d = data; + +	printf("port event: %d %d\n", d->state, event->hook.on); + +	switch (d->state) { +	case DIALDETECTOR_IDLE: +		if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) { +			d->state = DIALDETECTOR_WAIT_FOR_NUMBER; +			event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); +			timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); +		} +		break; +	case DIALDETECTOR_WAIT_FOR_NUMBER: +	case DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT: +		switch (event->type) { +		case TAPI_EVENT_TYPE_HOOK: +			if (event->hook.on == true) +				dialdetector_reset(d); +			break; +		case TAPI_EVENT_TYPE_DTMF: +			if (d->state == DIALDETECTOR_WAIT_FOR_NUMBER) +				event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); +			timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); +			d->state = DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT; +			dialdetector_note_digit(d, event->dtmf.code); +			break; +		default: +			break; +		} +	} +} + +struct dialdetector *dialdetector_alloc(struct tapi_port *port) +{ +	struct dialdetector *dialdetector; +	dialdetector = malloc(sizeof(*dialdetector)); + +	dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); +	dialdetector->port = port; +	dialdetector->num_digits = 0; +	dialdetector->state = DIALDETECTOR_IDLE; + +	dialdetector->timeout_cb.callback = dialdetector_timeout_event; +	dialdetector->timeout_cb.data = dialdetector; + +	dialdetector->port_listener.callback = dialdetector_port_event; +	dialdetector->port_listener.data = dialdetector; + +	tapi_port_register_event(port, &dialdetector->port_listener); + + +	return dialdetector; +} diff --git a/package/libtapi/src/events.c b/package/libtapi/src/events.c new file mode 100644 index 000000000..36e9b62a0 --- /dev/null +++ b/package/libtapi/src/events.c @@ -0,0 +1,58 @@ +#include <stdbool.h> +#include <sys/epoll.h> +#include <stdlib.h> +#include <errno.h> + +#include <stdio.h> + +#include "events.h" + +struct event_callback *event_callbacks; + +static int event_epoll_fd = -1; + +int event_register(int fd, int events, struct event_callback *cb) +{ +	struct epoll_event ev; + +	if (event_epoll_fd == -1) +		event_epoll_fd = epoll_create(1); + +	ev.events = events; +	ev.data.ptr = cb; + +	cb->fd = fd; + +	return epoll_ctl(event_epoll_fd, EPOLL_CTL_ADD, fd, &ev); +} + +int	event_unregister(int fd) +{ +	return epoll_ctl(event_epoll_fd, EPOLL_CTL_DEL, fd, NULL); +} + +int tapi_mainloop(void) +{ +	struct epoll_event ev[10]; +	struct event_callback *cb; +	int ret; +	bool keep; +	int i; + +	if (event_epoll_fd == -1) +		event_epoll_fd = epoll_create(1); + +	while(true) { +		ret = epoll_wait(event_epoll_fd, ev, 10, -1); +		for(i = 0; i < ret; ++i) { +			cb = ev[i].data.ptr; +			keep = cb->callback(ev[i].events, cb->data); +			if (!keep) +				event_unregister(cb->fd); +		} +		if (ret < 0) +			printf("epoll: %d\n", errno); +	} + +	return 0; +} diff --git a/package/libtapi/src/events.h b/package/libtapi/src/events.h new file mode 100644 index 000000000..9912fac3a --- /dev/null +++ b/package/libtapi/src/events.h @@ -0,0 +1,18 @@ +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +struct event_callback { +	bool (*callback)(int events, void *data); +	void *data; +	int fd; +}; + +int event_register(int fd, int events, +	struct event_callback *callback); + +int event_unregister(int fd); + + +int tapi_mainloop(void); + +#endif diff --git a/package/libtapi/src/list.h b/package/libtapi/src/list.h new file mode 100644 index 000000000..2959a061d --- /dev/null +++ b/package/libtapi/src/list.h @@ -0,0 +1,601 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include <stddef.h> +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr:	the pointer to the member. + * @type:	the type of the container struct this is embedded in. + * @member:	the name of the member within the struct. + * + */ +#ifndef container_of +#define container_of(ptr, type, member) (			\ +	(type *)( (char *)ptr - offsetof(type,member) )) +#endif + + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { +	struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ +	struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ +	list->next = list; +	list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, +			      struct list_head *prev, +			      struct list_head *next) +{ +	next->prev = new; +	new->next = next; +	new->prev = prev; +	prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ +	__list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ +	__list_add(new, head->prev, head); +} + + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ +	next->prev = prev; +	prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ +	__list_del(entry->prev, entry->next); +	entry->next = NULL; +	entry->prev = NULL; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, +				struct list_head *new) +{ +	new->next = old->next; +	new->next->prev = new; +	new->prev = old->prev; +	new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, +					struct list_head *new) +{ +	list_replace(old, new); +	INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ +	__list_del(entry->prev, entry->next); +	INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ +	__list_del(list->prev, list->next); +	list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, +				  struct list_head *head) +{ +	__list_del(list->prev, list->next); +	list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, +				const struct list_head *head) +{ +	return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ +	return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ +	struct list_head *next = head->next; +	return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, +				 struct list_head *head) +{ +	struct list_head *first = list->next; +	struct list_head *last = list->prev; +	struct list_head *at = head->next; + +	first->prev = head; +	head->next = first; + +	last->next = at; +	at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ +	if (!list_empty(list)) +		__list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, +				    struct list_head *head) +{ +	if (!list_empty(list)) { +		__list_splice(list, head); +		INIT_LIST_HEAD(list); +	} +} + +/** + * list_entry - get the struct for this entry + * @ptr:	the &struct list_head pointer. + * @type:	the type of the struct this is embedded in. + * @member:	the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ +	container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr:	the list head to take the element from. + * @type:	the type of the struct this is embedded in. + * @member:	the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ +	list_entry((ptr)->next, type, member) + +/** + * list_for_each	-	iterate over a list + * @pos:	the &struct list_head to use as a loop cursor. + * @head:	the head for your list. + */ +#define list_for_each(pos, head) \ +	for (pos = (head)->next; pos != (head); \ +        	pos = pos->next) + +/** + * __list_for_each	-	iterate over a list + * @pos:	the &struct list_head to use as a loop cursor. + * @head:	the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ +	for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev	-	iterate over a list backwards + * @pos:	the &struct list_head to use as a loop cursor. + * @head:	the head for your list. + */ +#define list_for_each_prev(pos, head) \ +	for (pos = (head)->prev; pos != (head); \ +        	pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos:	the &struct list_head to use as a loop cursor. + * @n:		another &struct list_head to use as temporary storage + * @head:	the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ +	for (pos = (head)->next, n = pos->next; pos != (head); \ +		pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos:	the &struct list_head to use as a loop cursor. + * @n:		another &struct list_head to use as temporary storage + * @head:	the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ +	for (pos = (head)->prev, n = pos->prev; \ +	     pos != (head); \ +	     pos = n, n = pos->prev) + +/** + * list_for_each_entry	-	iterate over list of given type + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member)				\ +	for (pos = list_entry((head)->next, typeof(*pos), member);	\ +	     &pos->member != (head); 	\ +	     pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member)			\ +	for (pos = list_entry((head)->prev, typeof(*pos), member);	\ +	     &pos->member != (head); 	\ +	     pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos:	the type * to use as a start point + * @head:	the head of the list + * @member:	the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ +	((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) 		\ +	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\ +	     &pos->member != (head);	\ +	     pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member)		\ +	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\ +	     &pos->member != (head);	\ +	     pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) 			\ +	for (; &pos->member != (head);	\ +	     pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos:	the type * to use as a loop cursor. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member)			\ +	for (pos = list_entry((head)->next, typeof(*pos), member),	\ +		n = list_entry(pos->member.next, typeof(*pos), member);	\ +	     &pos->member != (head); 					\ +	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos:	the type * to use as a loop cursor. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) 		\ +	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\ +		n = list_entry(pos->member.next, typeof(*pos), member);		\ +	     &pos->member != (head);						\ +	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos:	the type * to use as a loop cursor. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) 			\ +	for (n = list_entry(pos->member.next, typeof(*pos), member);		\ +	     &pos->member != (head);						\ +	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos:	the type * to use as a loop cursor. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member)		\ +	for (pos = list_entry((head)->prev, typeof(*pos), member),	\ +		n = list_entry(pos->member.prev, typeof(*pos), member);	\ +	     &pos->member != (head); 					\ +	     pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { +	struct hlist_node *first; +}; + +struct hlist_node { +	struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ +	h->next = NULL; +	h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ +	return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ +	return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ +	struct hlist_node *next = n->next; +	struct hlist_node **pprev = n->pprev; +	*pprev = next; +	if (next) +		next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ +	__hlist_del(n); +	n->next = NULL; +	n->pprev = NULL; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ +	if (!hlist_unhashed(n)) { +		__hlist_del(n); +		INIT_HLIST_NODE(n); +	} +} + + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ +	struct hlist_node *first = h->first; +	n->next = first; +	if (first) +		first->pprev = &n->next; +	h->first = n; +	n->pprev = &h->first; +} + + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, +					struct hlist_node *next) +{ +	n->pprev = next->pprev; +	n->next = next; +	next->pprev = &n->next; +	*(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, +					struct hlist_node *next) +{ +	next->next = n->next; +	n->next = next; +	next->pprev = &n->next; + +	if(next->next) +		next->next->pprev  = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ +	for (pos = (head)->first; pos; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ +	for (pos = (head)->first; pos; pos = n) + +/** + * hlist_for_each_entry	- iterate over list of given type + * @tpos:	the type * to use as a loop cursor. + * @pos:	the &struct hlist_node to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member)			 \ +	for (pos = (head)->first; pos &&				 \ +		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +	     pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos:	the type * to use as a loop cursor. + * @pos:	the &struct hlist_node to use as a loop cursor. + * @member:	the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member)		\ +	for (pos = (pos)->next; pos &&					\ +	     ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});   \ +	     pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos:	the type * to use as a loop cursor. + * @pos:	the &struct hlist_node to use as a loop cursor. + * @member:	the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member)			 \ +	for (; pos &&			 \ +		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +	     pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos:	the type * to use as a loop cursor. + * @pos:	the &struct hlist_node to use as a loop cursor. + * @n:		another &struct hlist_node to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) 		 \ +	for (pos = (head)->first;					 \ +	     pos && ({ n = pos->next; 1; }) && 				 \ +		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ +	     pos = n) + +#endif diff --git a/package/libtapi/src/tapi-device.c b/package/libtapi/src/tapi-device.c new file mode 100644 index 000000000..66e4260a0 --- /dev/null +++ b/package/libtapi/src/tapi-device.c @@ -0,0 +1,46 @@ +#include <stdio.h> + +#include "tapi-device.h" +#include "tapi-ioctl.h" + +int tapi_device_open(unsigned int id, struct tapi_device *dev) +{ +	char path[100]; + +	snprintf(path, sizeof(path), "/dev/tapi%dC", id); +	dev->control_fd = open(path, 0); +	if (dev->control_fd < 0) +		return -1; + +	snprintf(dev->stream_path, 100, "/dev/tapi%dS", id); + +	dev->id = id; +	dev->num_ports = 2; + +	return 0; +} + +int tapi_link_alloc(struct tapi_device *dev, unsigned int ep1, unsigned int ep2) +{ +	return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_ALLOC, (ep1 << 16) | ep2); +} + +int tapi_link_free(struct tapi_device *dev, unsigned int link) +{ +	return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_FREE, link); +} + +int tapi_link_enable(struct tapi_device *dev, unsigned int link) +{ +	return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_ENABLE, link); +} + +int tapi_link_disable(struct tapi_device *dev, unsigned int link) +{ +	return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_DISABLE, link); +} + +int tapi_sync(struct tapi_device *dev) +{ +	return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_SYNC, 0); +} diff --git a/package/libtapi/src/tapi-device.h b/package/libtapi/src/tapi-device.h new file mode 100644 index 000000000..27658b9d8 --- /dev/null +++ b/package/libtapi/src/tapi-device.h @@ -0,0 +1,25 @@ +#ifndef __TAPI_DEVICE_H__ +#define __TAPI_DEVICE_H__ + +struct tapi_device { +	int control_fd; +	int stream_fd; +	struct tapi_port *ports; +	char stream_path[100]; + +	unsigned int id; + +	unsigned int num_ports; +}; + +struct tapi_endpoint; + +int tapi_device_open(unsigned int id, struct tapi_device *dev); + +int tapi_link_alloc(struct tapi_device *dev, unsigned int ep1, unsigned int ep2); +int tapi_link_free(struct tapi_device *dev, unsigned int link); +int tapi_link_enable(struct tapi_device *dev, unsigned int link); +int tapi_link_disable(struct tapi_device *dev, unsigned int link); +int tapi_sync(struct tapi_device *dev); + +#endif diff --git a/package/libtapi/src/tapi-ioctl.h b/package/libtapi/src/tapi-ioctl.h new file mode 100644 index 000000000..c43fac1e7 --- /dev/null +++ b/package/libtapi/src/tapi-ioctl.h @@ -0,0 +1,20 @@ + +#include <linux/ioctl.h> + +#define TAPI_MAGIC 't' +#define TAPI_IOCTL(x) _IO(TAPI_MAGIC, (x)) + +#define TAPI_CONTROL_IOCTL_LINK_ALLOC TAPI_IOCTL(0) +#define TAPI_CONTROL_IOCTL_LINK_FREE  TAPI_IOCTL(1) +#define TAPI_CONTROL_IOCTL_LINK_ENABLE TAPI_IOCTL(2) +#define TAPI_CONTROL_IOCTL_LINK_DISABLE TAPI_IOCTL(3) + +#define TAPI_CONTROL_IOCTL_SYNC TAPI_IOCTL(4) + +#define TAPI_PORT_IOCTL_GET_ENDPOINT TAPI_IOCTL(5) +#define TAPI_PORT_IOCTL_SET_RING TAPI_IOCTL(6) + +#define TAPI_STREAM_IOCTL_GET_ENDPOINT TAPI_IOCTL(7) +#define TAPI_STREAM_IOCTL_CONFIGURE TAPI_IOCTL(8) +#define TAPI_STREAM_IOCTL_START TAPI_IOCTL(9) +#define TAPI_STREAM_IOCTL_STOP TAPI_IOCTL(10) diff --git a/package/libtapi/src/tapi-port.c b/package/libtapi/src/tapi-port.c new file mode 100644 index 000000000..d06d946e1 --- /dev/null +++ b/package/libtapi/src/tapi-port.c @@ -0,0 +1,126 @@ +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/epoll.h> +#include <unistd.h> + +#include <linux/input.h> + +#include "tapi-ioctl.h" +#include "tapi-device.h" +#include "tapi-port.h" + +#include "events.h" +#include "list.h" + +static void tapi_port_event_dispatch(struct tapi_port *port, +	struct tapi_event *event) +{ +	struct tapi_port_event_listener *l; + +	list_for_each_entry(l, &port->event_listeners, head) { +		l->callback(port, event, l->data); +	} +} + +static bool tapi_port_input_event(int events, void *data) +{ +	struct tapi_port *port = data; +	struct input_event event; +	struct tapi_event tapi_event; +	int ret; + +	ret = read(port->input_fd, &event, sizeof(event)); +	if (ret < 0) { +		fprintf(stderr, "Port %d failed to read from input device: %d\n", +			port->id, errno); +		return true; +	} + +	if (!event.value) +		return true; + +	switch (event.code) { +	case KEY_NUMERIC_0 ... KEY_NUMERIC_9: +		tapi_event.type = TAPI_EVENT_TYPE_DTMF; +		tapi_event.dtmf.code = event.code - KEY_NUMERIC_0; +		break; +	case KEY_NUMERIC_POUND: +		tapi_event.type = TAPI_EVENT_TYPE_DTMF; +		tapi_event.dtmf.code = 10; +		break; +	case KEY_NUMERIC_STAR: +		tapi_event.type = TAPI_EVENT_TYPE_DTMF; +		tapi_event.dtmf.code = 11; +		break; +	case KEY_ESC: +		tapi_event.type = TAPI_EVENT_TYPE_HOOK; +		tapi_event.hook.on = true; +		break; +	case KEY_ENTER: +		tapi_event.type = TAPI_EVENT_TYPE_HOOK; +		tapi_event.hook.on = false; +		break; +	default: +		return true; +	} + +	if (tapi_event.type == TAPI_EVENT_TYPE_DTMF) +		tapi_event.dtmf.time = event.time; + +	tapi_port_event_dispatch(port, &tapi_event); + +	return true; +} + +int tapi_port_open(struct tapi_device *dev, unsigned int id, struct tapi_port *port) +{ +	int ret; +	char path[100]; + +	port->id = id; + +	snprintf(path, 100, "/dev/tapi%uP%u", dev->id, id); +	port->fd = open(path, 0); +	if (port->fd < 0) { +		printf("Failed to open %s: %d\n", path, errno); +		return errno; +	} + +	snprintf(path, 100, "/dev/event%u", id); +	port->input_fd = open(path, O_RDONLY); +	if (port->input_fd < 0) { +		printf("Failed to open %s: %d\n", path, errno); +		return errno; +	} + +	port->ep = ioctl(port->fd, TAPI_PORT_IOCTL_GET_ENDPOINT, 0); + +	INIT_LIST_HEAD(&port->event_listeners); + +	port->input_cb.callback = tapi_port_input_event; +	port->input_cb.data = port; + +	return event_register(port->input_fd, EPOLLIN, +		&port->input_cb); +} + +int tapi_port_set_ring(struct tapi_port *port, bool ring) +{ +	return ioctl(port->fd, TAPI_PORT_IOCTL_SET_RING, ring); +} + +int tapi_port_register_event(struct tapi_port *port, +	struct tapi_port_event_listener *cb) +{ +	list_add_tail(&cb->head, &port->event_listeners); +	return 0; +} + +void tapi_port_unregister_event(struct tapi_port *port, +	struct tapi_port_event_listener *cb) +{ +	list_del(&cb->head); +} diff --git a/package/libtapi/src/tapi-port.h b/package/libtapi/src/tapi-port.h new file mode 100644 index 000000000..a290a4002 --- /dev/null +++ b/package/libtapi/src/tapi-port.h @@ -0,0 +1,66 @@ +#ifndef __TAPI_PORT_H__ +#define __TAPI_PORT_H__ + +#include <sys/time.h> + +#include "list.h" +#include "events.h" + +struct tapi_port; +struct tapi_device; + +struct tapi_dtmf_event { +	struct timeval time; +	unsigned char code; +}; + +struct tapi_hook_event { +	bool on; +}; + +enum tapi_event_type { +	TAPI_EVENT_TYPE_DTMF, +	TAPI_EVENT_TYPE_HOOK, +}; + +struct tapi_event { +	enum tapi_event_type type; +	union { +		struct tapi_dtmf_event dtmf; +		struct tapi_hook_event hook; +	}; +}; + +struct tapi_port_event_listener { +	void (*callback)(struct tapi_port *, struct tapi_event *event, void *data); +	void *data; + +	struct list_head head; +}; + +struct tapi_port { +	int id; +	int fd; +	int input_fd; +	unsigned int ep; + +	struct event_callback input_cb; + +	struct list_head event_listeners; +}; + +int tapi_port_open(struct tapi_device *dev, unsigned int id, struct tapi_port +*port); +int tapi_port_set_ring(struct tapi_port *port, bool ring); +int tapi_port_register_event(struct tapi_port *port, +	struct tapi_port_event_listener *cb); + +void tapi_port_unregister_event(struct tapi_port *port, +	struct tapi_port_event_listener *cb); + +static inline int tapi_port_get_endpoint(struct tapi_port *port) +{ +	return port->ep; +} + +#endif diff --git a/package/libtapi/src/tapi-session.c b/package/libtapi/src/tapi-session.c new file mode 100644 index 000000000..8b1705311 --- /dev/null +++ b/package/libtapi/src/tapi-session.c @@ -0,0 +1,122 @@ +#include <stdlib.h> +#include <stdbool.h> +#include <stdint.h> + +#include "tapi-device.h" +#include "tapi-port.h" +#include "tapi-session.h" + +enum tapi_session_port_state { +	TAPI_SESSION_PORT_STATE_IDLE, +	TAPI_SESSION_PORT_STATE_RINGING, +	TAPI_SESSION_PORT_STATE_ACTIVE, +}; + +struct tapi_session_port { +	struct tapi_port *port; +	struct tapi_port_event_listener event_listener; + +	enum tapi_session_port_state state; +}; + +struct tapi_session { +	struct tapi_device *dev; +	struct tapi_session_port caller; +	struct tapi_session_port callee; + +	bool active; +	unsigned int link; + +	void (*release)(struct tapi_session *session, void *data); +}; + +static void tapi_session_terminate(struct tapi_session *session) +{ +	if (session->active) { +		tapi_link_enable(session->dev, session->link); +		tapi_sync(session->dev); +		tapi_link_free(session->dev, session->link); +	} + +	switch (session->callee.state) { +	case TAPI_SESSION_PORT_STATE_RINGING: +		tapi_port_set_ring(session->callee.port, false); +		break; +	default: +		break; +	} + +	session->active = false; +} + +static void tapi_session_caller_event(struct tapi_port *port, +	struct tapi_event *event, void *data) +{ +	struct tapi_session *session = data; + +	if (event->type != TAPI_EVENT_TYPE_HOOK) +		return; + +	if (event->hook.on) { +		tapi_session_terminate(session); +	} +} + +static void tapi_session_callee_event(struct tapi_port *port, +	struct tapi_event *event, void *data) +{ +	struct tapi_session *session = data; + +	if (event->type != TAPI_EVENT_TYPE_HOOK) +		return; + +	if (event->hook.on) { +		if (session->callee.state == TAPI_SESSION_PORT_STATE_ACTIVE) { +			tapi_session_terminate(session); +		} +	} else  { +		if (session->callee.state == TAPI_SESSION_PORT_STATE_RINGING) { +			tapi_port_set_ring(session->callee.port, false); +			session->link = tapi_link_alloc(session->dev, +				session->caller.port->ep, session->callee.port->ep); +			session->callee.state = TAPI_SESSION_PORT_STATE_ACTIVE; +			tapi_link_enable(session->dev, session->link); +			tapi_sync(session->dev); +			session->active = true; +		} +	} +} + +struct tapi_session *tapi_session_alloc(struct tapi_device *dev, +	struct tapi_port *caller, struct tapi_port *callee, +	void (*release)(struct tapi_session *session, void *data), void *release_data) +{ +	struct tapi_session *session; +	struct tapi_session_port *session_port; + +	session = malloc(sizeof(*session)); + +	session->dev = dev; + +	session->callee.port = callee; +	session->callee.state = TAPI_SESSION_PORT_STATE_RINGING; +	session->callee.event_listener.callback = tapi_session_callee_event; +	session->callee.event_listener.data = session; +	tapi_port_register_event(callee, &session->callee.event_listener); + +	session->caller.port = caller; +	session->caller.state = TAPI_SESSION_PORT_STATE_ACTIVE; +	session->caller.event_listener.callback = tapi_session_caller_event; +	session->caller.event_listener.data = session; +	tapi_port_register_event(caller, &session->caller.event_listener); + +	tapi_port_set_ring(callee, true); +} + +void tapi_session_free(struct tapi_session *session) +{ +	tapi_session_terminate(session); +	tapi_port_register_event(session->callee.port, &session->callee.event_listener); +	tapi_port_register_event(session->caller.port, &session->caller.event_listener); +	free(session); +} diff --git a/package/libtapi/src/tapi-session.h b/package/libtapi/src/tapi-session.h new file mode 100644 index 000000000..15d94735e --- /dev/null +++ b/package/libtapi/src/tapi-session.h @@ -0,0 +1,14 @@ +#ifndef __TAPI_SESSION_H__ +#define __TAPI_SESSION_H__ + +struct tapi_device; +struct tapi_port; +struct tapi_session; + +struct tapi_session *tapi_session_alloc(struct tapi_device *dev, +	struct tapi_port *caller, struct tapi_port *callee, +	void (*release)(struct tapi_session *session, void *data), void	*release_data); + +void tapi_session_free(struct tapi_session *session); + +#endif diff --git a/package/libtapi/src/tapi-stream.c b/package/libtapi/src/tapi-stream.c new file mode 100644 index 000000000..5ae44a163 --- /dev/null +++ b/package/libtapi/src/tapi-stream.c @@ -0,0 +1,42 @@ +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "tapi-device.h" +#include "tapi-stream.h" +#include "tapi-ioctl.h" + +struct tapi_stream *tapi_stream_alloc(struct tapi_device *dev) +{ +	struct tapi_stream *stream; + +	stream = malloc(sizeof(*stream)); +	if (!stream) +		return NULL; + +	stream->fd = open(dev->stream_path, O_RDWR); + +	if (stream->fd < 0) { +		free(stream); +		return NULL; +	} + +	stream->ep = ioctl(stream->fd, TAPI_STREAM_IOCTL_GET_ENDPOINT, 0); + +	if (stream->ep < 0) { +		close(stream->fd); +		free(stream); +		return NULL; +	} + +	return stream; +} + +void tapi_stream_free(struct tapi_stream *stream) +{ +	close(stream->fd); +	free(stream); +} diff --git a/package/libtapi/src/tapi-stream.h b/package/libtapi/src/tapi-stream.h new file mode 100644 index 000000000..0e3e04af2 --- /dev/null +++ b/package/libtapi/src/tapi-stream.h @@ -0,0 +1,19 @@ +#ifndef __TAPI_STREAM_H__ +#define __TAPI_STREAM_H__ + +struct tapi_device; + +struct tapi_stream { +	int fd; +	int ep; +}; + +struct tapi_stream *tapi_stream_alloc(struct tapi_device *); +void tapi_stream_free(struct tapi_stream *); + +static inline int tapi_stream_get_endpoint(struct tapi_stream *stream) +{ +	return stream->ep; +} + +#endif diff --git a/package/libtapi/src/tapidemo.c b/package/libtapi/src/tapidemo.c new file mode 100644 index 000000000..63098b89c --- /dev/null +++ b/package/libtapi/src/tapidemo.c @@ -0,0 +1,56 @@ + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <poll.h> + +#include <linux/input.h> +/*#include <sys/timerfd.h>*/ +#include "timerfd.h" +#include "dialdetector.h" + +#include "tapi-ioctl.h" + +#include "tapi-device.h" +#include "tapi-port.h" + +static struct tapi_device dev; +static struct tapi_port ports[2]; + +void dial_callback(struct tapi_port *port, size_t num_digits, const unsigned char *digits) +{ +	unsigned int link; + +	if (num_digits != 1) +		return; +	if (port->id == digits[0] || digits[0] > 1) +		return; + +	tapi_port_set_ring(&ports[digits[0]], true); + +	tapi_session_alloc(&dev, port, &ports[digits[0]]); +} + +int main(int argc, char *argv[]) +{ +	struct dialdetector *dd, *dd2; +	unsigned int link; +	unsigned char buf[1024]; +	int ret; + +	tapi_device_open(0, &dev); +	tapi_port_open(0, 0, &ports[0]); +	tapi_port_open(0, 1, &ports[1]); + +	dd = dialdetector_alloc(&ports[0]); +	dd->dial_callback = dial_callback; +	dd2 = dialdetector_alloc(&ports[1]); +	dd2->dial_callback = dial_callback; + +	tapi_mainloop(); + +	return 0; +} diff --git a/package/libtapi/src/timer_fd.c b/package/libtapi/src/timer_fd.c new file mode 100644 index 000000000..fbc951a9f --- /dev/null +++ b/package/libtapi/src/timer_fd.c @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: */ +/* + * timerfd_create() / timerfd_settime() / timerfd_gettime() for uClibc + * + * Copyright (C) 2009 Stephan Raue <stephan@openelec.tv> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <sys/syscall.h> +/*#include <sys/timerfd.h>*/ +#include "timerfd.h" + +/* + * timerfd_create() + */ +#ifdef __NR_timerfd_create +int timerfd_create(int clockid, int flags) +{ +	return syscall(__NR_timerfd_create, clockid, flags); +} +#endif + +/* + * timerfd_settime() + */ +#ifdef __NR_timerfd_settime +int timerfd_settime(int ufd, int flags, const struct itimerspec *umtr, struct itimerspec *otmr) +{ +	return syscall(__NR_timerfd_settime, ufd, flags, umtr, otmr); +} +#endif + diff --git a/package/libtapi/src/timerfd.h b/package/libtapi/src/timerfd.h new file mode 100644 index 000000000..f17bc798a --- /dev/null +++ b/package/libtapi/src/timerfd.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library 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 +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef	_SYS_TIMERFD_H +#define	_SYS_TIMERFD_H	1 + +#include <time.h> + + +/* Bits to be set in the FLAGS parameter of `timerfd_create'.  */ +enum +  { +    TFD_CLOEXEC = 02000000, +#define TFD_CLOEXEC TFD_CLOEXEC +    TFD_NONBLOCK = 04000 +#define TFD_NONBLOCK TFD_NONBLOCK +  }; + + +/* Bits to be set in the FLAGS parameter of `timerfd_settime'.  */ +enum +  { +    TFD_TIMER_ABSTIME = 1 << 0 +#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME +  }; + + +__BEGIN_DECLS + +/* Return file descriptor for new interval timer source.  */ +extern int timerfd_create (clockid_t __clock_id, int __flags) __THROW; + +/* Set next expiration time of interval timer source UFD to UTMR.  If +   FLAGS has the TFD_TIMER_ABSTIME flag set the timeout value is +   absolute.  Optionally return the old expiration time in OTMR.  */ +extern int timerfd_settime (int __ufd, int __flags, +			    __const struct itimerspec *__utmr, +			    struct itimerspec *__otmr) __THROW; + +/* Return the next expiration time of UFD.  */ +extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW; + +__END_DECLS + +#endif /* sys/timerfd.h */ +  | 
