1/*
2 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 *
16 * Low resolution timer interface linux specific implementation.
17 *
18 * $Id: linux_timer.c 342502 2012-07-03 03:08:12Z $
19 */
20
21/*
22* debug facilities
23*/
24#define TIMER_DEBUG	0 /* Turn off the debug */
25#if TIMER_DEBUG
26#define TIMERDBG(fmt, args...) printf("%s: " fmt "\n", __FUNCTION__ , ## args)
27#else
28#define TIMERDBG(fmt, args...)
29#endif
30
31
32/*
33 * POSIX timer support for Linux. Taken from linux_timer.c in upnp
34 */
35
36#define __USE_GNU
37
38
39#include <stdlib.h>	    // for malloc, free, etc.
40#include <string.h>	    // for memset, strncasecmp, etc.
41#include <assert.h>	    // for assert, of course.
42#include <signal.h>	    // for sigemptyset, etc.
43#include <stdio.h>	    // for printf, etc.
44#include <sys/time.h>
45#include <time.h>
46
47/* define TIMER_PROFILE to enable code which guages how accurate the timer functions are.
48 * For each expiring timer the code will print the expected time interval and the actual time
49 * interval.
50 * #define TIMER_PROFILE
51 */
52#undef TIMER_PROFILE
53
54/*
55timer_cancel( ) - cancel a timer
56timer_connect( ) - connect a user routine to the timer signal
57timer_create( ) - allocate a timer using the specified clock for a timing base (POSIX)
58timer_delete( ) - remove a previously created timer (POSIX)
59timer_gettime( ) - get the remaining time before expiration and the reload value (POSIX)
60timer_getoverrun( ) - return the timer expiration overrun (POSIX)
61timer_settime( ) - set the time until the next expiration and arm timer (POSIX)
62nanosleep( ) - suspend the current task until the time interval elapses (POSIX)
63*/
64
65#define MS_PER_SEC 1000		/* 1000ms per second */
66#define US_PER_SEC 1000000	/* 1000000us per second */
67#define US_PER_MS  1000		/* 1000us per ms */
68#define UCLOCKS_PER_SEC 1000000 /* Clock ticks per second */
69
70typedef void (*event_callback_t)(timer_t, int);
71
72#ifdef BCMQT
73uint htclkratio = 50;
74static void TIMESPEC_TO_TIMEVAL(struct timeval *tv, const struct timespec *ts)
75{
76	uint ms = (ts->tv_sec * 1000 + ts->tv_nsec / 1000000) * htclkratio;
77	tv->tv_sec = ms / 1000;
78	tv->tv_usec = (ms % 1000) * 1000;
79}
80static void TIMEVAL_TO_TIMESPEC(const struct timeval *tv, struct timespec *ts)
81{
82	uint ms = (tv->tv_sec * 1000 + tv->tv_usec / 1000) / htclkratio;
83	ts->tv_sec = ms / 1000;
84	ts->tv_nsec = (ms % 1000) * 1000000;
85}
86#else	/* BCMQT */
87#ifndef TIMESPEC_TO_TIMEVAL
88# define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
89	(tv)->tv_sec = (ts)->tv_sec;                                    \
90	(tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
91}
92#endif
93
94#ifndef TIMEVAL_TO_TIMESPEC
95# define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
96	(ts)->tv_sec = (tv)->tv_sec;                                    \
97	(ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
98}
99#endif
100#endif	/* !BCMQT */
101
102#define ROUNDUP(x, y) ((((x)+(y)-1)/(y))*(y))
103
104#define timerroundup(t, g) \
105	do { \
106		if (!timerisset(t)) (t)->tv_usec = 1; \
107		if ((t)->tv_sec == 0) (t)->tv_usec = ROUNDUP((t)->tv_usec, g); \
108	} while (0)
109
110typedef long uclock_t;
111
112#define TFLAG_NONE	0
113#define TFLAG_CANCELLED	(1<<0)
114#define TFLAG_DELETED	(1<<1)
115
116struct event {
117    struct timeval it_interval;
118    struct timeval it_value;
119    event_callback_t func;
120    int arg;
121    unsigned short flags;
122    struct event *next;
123#ifdef TIMER_PROFILE
124    uint expected_ms;
125    uclock_t start;
126#endif
127};
128
129void timer_cancel(timer_t timerid);
130
131static void alarm_handler(int i);
132static void check_event_queue();
133static void print_event_queue();
134static void check_timer();
135#if THIS_FINDS_USE
136static int count_queue(struct event *);
137#endif
138static int timer_change_settime(timer_t timer_id, const struct itimerspec *timer_spec);
139void block_timer();
140void unblock_timer();
141
142static struct event *event_queue = NULL;
143static struct event *event_freelist;
144static uint g_granularity;
145static int g_maxevents = 0;
146
147uclock_t uclock()
148{
149	struct timeval tv;
150
151	gettimeofday(&tv, NULL);
152	return ((tv.tv_sec * US_PER_SEC) + tv.tv_usec);
153}
154
155
156void init_event_queue(int n)
157{
158	int i;
159	struct itimerval tv;
160
161	g_maxevents = n;
162	event_freelist = (struct event *) malloc(n * sizeof(struct event));
163	memset(event_freelist, 0, n * sizeof(struct event));
164
165	for (i = 0; i < (n-1); i++)
166		event_freelist[i].next = &event_freelist[i+1];
167
168	event_freelist[i].next = NULL;
169
170	tv.it_interval.tv_sec = 0;
171	tv.it_interval.tv_usec = 1;
172	tv.it_value.tv_sec = 0;
173	tv.it_value.tv_usec = 0;
174
175	setitimer(ITIMER_REAL, &tv, 0);
176	setitimer(ITIMER_REAL, 0, &tv);
177
178	if (tv.it_interval.tv_usec == 0)
179		tv.it_interval.tv_usec = 1;
180
181	g_granularity = tv.it_interval.tv_usec;
182	signal(SIGALRM, alarm_handler);
183}
184
185int clock_gettime(
186	clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
187	struct timespec * tp        /* where to store current time */
188)
189{
190	struct timeval tv;
191	int n;
192
193
194	n = gettimeofday(&tv, NULL);
195	TIMEVAL_TO_TIMESPEC(&tv, tp);
196
197	return n;
198}
199
200
201int timer_create(
202	clockid_t         clock_id, /* clock ID (always CLOCK_REALTIME) */
203	struct sigevent * evp,      /* user event handler */
204	timer_t *         pTimer    /* ptr to return value */
205)
206{
207	struct event *event;
208
209	if (clock_id != CLOCK_REALTIME) {
210		TIMERDBG("timer_create can only support clock id CLOCK_REALTIME");
211		exit(1);
212	}
213
214	if (evp != NULL) {
215		if (evp->sigev_notify != SIGEV_SIGNAL || evp->sigev_signo != SIGALRM) {
216			TIMERDBG("timer_create can only support signalled alarms using SIGALRM");
217			exit(1);
218		}
219	}
220
221	event = event_freelist;
222	if (event == NULL) {
223		print_event_queue();
224	}
225	assert(event != NULL);
226
227	event->flags = TFLAG_NONE;
228
229	event_freelist = event->next;
230	event->next = NULL;
231
232	check_event_queue();
233
234	*pTimer = (timer_t) event;
235
236	return 0;
237}
238
239int timer_delete(
240	timer_t timerid /* timer ID */
241)
242{
243	struct event *event = (struct event *) timerid;
244
245	if (event->flags & TFLAG_DELETED) {
246		TIMERDBG("Cannot delete a deleted event");
247		return 1;
248	}
249
250	timer_cancel(timerid);
251
252	event->flags |= TFLAG_DELETED;
253
254	event->next = event_freelist;
255	event_freelist = event;
256
257	return 0;
258}
259
260int timer_connect
261(
262	timer_t     timerid, /* timer ID */
263	void (*routine)(timer_t, int), /* user routine */
264	int         arg      /* user argument */
265)
266{
267	struct event *event = (struct event *) timerid;
268
269	assert(routine != NULL);
270	event->func = routine;
271	event->arg = arg;
272
273	return 0;
274}
275
276/*
277 * Please Call this function only from the call back functions of the alarm_handler.
278 * This is just a hack
279 */
280int timer_change_settime
281(
282	timer_t                   timerid, /* timer ID */
283	const struct itimerspec * value   /* time to be set */
284)
285{
286	struct event *event = (struct event *) timerid;
287
288	TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
289	TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
290
291	return 1;
292}
293
294int timer_settime
295(
296	timer_t                   timerid, /* timer ID */
297	int                       flags,   /* absolute or relative */
298	const struct itimerspec * value,   /* time to be set */
299	struct itimerspec *       ovalue   /* previous time set (NULL=no result) */
300)
301{
302	struct itimerval itimer;
303	struct event *event = (struct event *) timerid;
304	struct event **ppevent;
305
306	TIMESPEC_TO_TIMEVAL(&event->it_interval, &value->it_interval);
307	TIMESPEC_TO_TIMEVAL(&event->it_value, &value->it_value);
308
309	/* if .it_value is zero, the timer is disarmed */
310	if (!timerisset(&event->it_value)) {
311		timer_cancel(timerid);
312		return 0;
313	}
314
315	block_timer();
316
317#ifdef TIMER_PROFILE
318	event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) + (event->it_value.tv_usec /
319	                                                              US_PER_MS);
320	event->start = uclock();
321#endif
322	if (event->next) {
323		TIMERDBG("calling timer_settime with a timer that is already on the queue.");
324	}
325
326
327	/* We always want to make sure that the event at the head of the
328	 * queue has a timeout greater than the itimer granularity.
329	 * Otherwise we end up with the situation that the time remaining
330	 * on an itimer is greater than the time at the head of the queue
331	 * in the first place.
332	 */
333	timerroundup(&event->it_value, g_granularity);
334
335	timerclear(&itimer.it_value);
336	getitimer(ITIMER_REAL, &itimer);
337	if (timerisset(&itimer.it_value)) {
338		/* reset the top timer to have an interval equal to the remaining interval
339		 * when the timer was cancelled.
340		 */
341		if (event_queue) {
342			/* CSTYLED */
343			if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
344				/* it is an error if the amount of time remaining is more than the
345				 * amount of time requested by the top event.
346				 */
347				TIMERDBG("timer_settime: TIMER ERROR!");
348
349			} else {
350				/* some portion of the top event has already expired.
351				 * Reset the interval of the top event to remaining
352				 * time left in that interval.
353				 */
354				event_queue->it_value = itimer.it_value;
355
356				/* if we were the earliest timer before now, we are still the
357				 * earliest timer now. we do not need to reorder the list.
358				 */
359			}
360		}
361	}
362
363	/* Now, march down the list, decrementing the new timer by the
364	 * current it_value of each event on the queue.
365	 */
366	ppevent = &event_queue;
367	while (*ppevent) {
368		/* CSTYLED */
369		if (timercmp(&(event->it_value), &((*ppevent)->it_value), <)) {
370			/* if the proposed event will trigger sooner than the next event
371			 * in the queue, we will insert the new event just before the next one.
372			 * we also need to adjust the delta value to the next event.
373			 */
374			timersub(&((*ppevent)->it_value), &(event->it_value),
375			         &((*ppevent)->it_value));
376			break;
377		}
378		/* subtract the interval of the next event from the proposed interval. */
379		timersub(&(event->it_value), &((*ppevent)->it_value), &(event->it_value));
380
381		ppevent = &((*ppevent)->next);
382	}
383
384	/* we have found our proper place in the queue, */
385	/* link our new event into the pending event queue. */
386	event->next = *ppevent;
387	*ppevent = event;
388
389	check_event_queue();
390
391	/* if our new event ended up at the front of the queue, reissue the timer. */
392	if (event == event_queue) {
393		timerroundup(&event_queue->it_value, g_granularity);
394		timerclear(&itimer.it_interval);
395		itimer.it_value = event_queue->it_value;
396
397		/* we want to be sure to never turn off the timer completely, */
398		/* so if the next interval is zero, set it to some small value. */
399		if (!timerisset(&(itimer.it_value)))
400			itimer.it_value = (struct timeval) { 0, 1 };
401
402		assert(!timerisset(&itimer.it_interval));
403		assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >= g_granularity);
404		assert(event_queue->it_value.tv_sec > 0 || event_queue->it_value.tv_usec >=
405		       g_granularity);
406		setitimer(ITIMER_REAL, &itimer, NULL);
407		check_timer();
408	}
409
410	event->flags &= ~TFLAG_CANCELLED;
411
412	unblock_timer();
413
414	return 0;
415}
416
417static void check_timer()
418{
419	struct itimerval itimer;
420
421	getitimer(ITIMER_REAL, &itimer);
422	if (timerisset(&itimer.it_interval)) {
423		TIMERDBG("ERROR timer interval is set.");
424	}
425	/* CSTYLED */
426	if (timercmp(&(itimer.it_value), &(event_queue->it_value), >)) {
427		TIMERDBG("ERROR timer expires later than top event.");
428	}
429}
430
431
432static void check_event_queue()
433{
434	struct timeval sum;
435	struct event *event;
436	int i = 0;
437
438#ifdef notdef
439	int nfree = 0;
440	struct event *p;
441	for (p = event_freelist; p; p = p->next)
442	nfree++;
443	printf("%d free events\n", nfree);
444#endif
445
446	timerclear(&sum);
447	for (event = event_queue; event; event = event->next) {
448		if (i > g_maxevents) {
449			TIMERDBG("timer queue looks like it loops back on itself!");
450			print_event_queue();
451			exit(1);
452		}
453		i++;
454	}
455}
456
457#if THIS_FINDS_USE
458/* The original upnp version has this unused function, so I left it in
459 * to maintain the resemblance.
460 */
461static int count_queue(struct event *event_queue)
462{
463	struct event *event;
464	int i = 0;
465	for (event = event_queue; event; event = event->next)
466		i++;
467	return i;
468}
469#endif
470
471static void print_event_queue()
472{
473	struct event *event;
474	int i = 0;
475
476	for (event = event_queue; event; event = event->next) {
477		printf("#%d (0x%x)->0x%x: \t%d sec %d usec\t%p\n",
478		       i++, (unsigned int) event, (unsigned int) event->next, (int)
479		       event->it_value.tv_sec,
480		       (int) event->it_value.tv_usec, event->func);
481		if (i > g_maxevents) {
482			printf("...(giving up)\n");
483			break;
484		}
485	}
486}
487
488/* The top element of the event queue must have expired. */
489/* Remove that element, run its function, and reset the timer. */
490/* if there is no interval, recycle the event structure. */
491static void alarm_handler(int i)
492{
493	struct event *event, **ppevent;
494	struct itimerval itimer;
495	struct timeval small_interval = { 0, g_granularity/2 };
496#ifdef TIMER_PROFILE
497	uint junk;
498	uclock_t end;
499	uint actual;
500#endif
501
502	block_timer();
503
504	/* Loop through the event queue and remove the first event plus any */
505	/* subsequent events that will expire very soon thereafter (within 'small_interval'}. */
506	/* */
507	if (!event_queue) {
508		unblock_timer();
509		return;
510	}
511
512	do {
513		/* remove the top event. */
514		event = event_queue;
515		event_queue = event_queue->next;
516		event->next = NULL;
517
518#ifdef TIMER_PROFILE
519		end = uclock();
520		actual = ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000));
521		if (actual < 0)
522			junk = end;
523		TIMERDBG("expected %d ms actual %d ms", event->expected_ms,
524		         ((end-event->start)/((uclock_t)UCLOCKS_PER_SEC/1000)));
525#endif
526
527		/* call the event callback function */
528		(*(event->func))((timer_t) event, (int)event->arg);
529
530		/* If the event has been cancelled, do NOT put it back on the queue. */
531		if (!(event->flags & TFLAG_CANCELLED)) {
532
533			/* if the event is a recurring event, reset the timer and
534			 * find its correct place in the sorted list of events.
535			 */
536			if (timerisset(&event->it_interval)) {
537				/* event is recurring... */
538				event->it_value = event->it_interval;
539#ifdef TIMER_PROFILE
540				event->expected_ms = (event->it_value.tv_sec * MS_PER_SEC) +
541				        (event->it_value.tv_usec / US_PER_MS);
542				event->start = uclock();
543#endif
544				timerroundup(&event->it_value, g_granularity);
545
546				/* Now, march down the list, decrementing the new timer by the */
547				/* current delta of each event on the queue. */
548				ppevent = &event_queue;
549				while (*ppevent) {
550					if (timercmp(&(event->it_value), &((*ppevent)->it_value),
551						     /* CSTYLED */
552						     <)) {
553						/* if the proposed event will trigger sooner than
554						 * the next event
555						 * in the queue, we will insert the new event just
556						 * before the next one.
557						 * we also need to adjust the delta value to the
558						 * next event.
559						 */
560						timersub(&((*ppevent)->it_value),
561						         &(event->it_value),
562						         &((*ppevent)->it_value));
563						break;
564					}
565					timersub(&(event->it_value), &((*ppevent)->it_value),
566					         &(event->it_value));
567					ppevent = &((*ppevent)->next);
568				}
569
570				/* we have found our proper place in the queue, */
571				/* link our new event into the pending event queue. */
572				event->next = *ppevent;
573				*ppevent = event;
574			} else {
575				/* there is no interval, so recycle the event structure.
576				 * timer_delete((timer_t) event);
577				 */
578			}
579		}
580
581		check_event_queue();
582
583		/* CSTYLED */
584	} while (event_queue && timercmp(&event_queue->it_value, &small_interval, <));
585
586	/* re-issue the timer... */
587	if (event_queue) {
588		timerroundup(&event_queue->it_value, g_granularity);
589
590		timerclear(&itimer.it_interval);
591		itimer.it_value = event_queue->it_value;
592		/* we want to be sure to never turn off the timer completely, */
593		/* so if the next interval is zero, set it to some small value. */
594		if (!timerisset(&(itimer.it_value)))
595			itimer.it_value = (struct timeval) { 0, 1 };
596
597		setitimer(ITIMER_REAL, &itimer, NULL);
598		check_timer();
599	} else {
600		TIMERDBG("There are no events in the queue - timer not reset.");
601	}
602
603	unblock_timer();
604}
605
606static int block_count = 0;
607
608void block_timer()
609{
610	sigset_t set;
611
612	if (block_count++ == 0) {
613		sigemptyset(&set);
614		sigaddset(&set, SIGALRM);
615		sigprocmask(SIG_BLOCK, &set, NULL);
616	}
617}
618
619void unblock_timer()
620{
621	sigset_t set;
622
623	if (--block_count == 0) {
624		sigemptyset(&set);
625		sigaddset(&set, SIGALRM);
626		sigprocmask(SIG_UNBLOCK, &set, NULL);
627	}
628}
629
630void timer_cancel_all()
631{
632	struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
633	struct event *event;
634	struct event **ppevent;
635
636	setitimer(ITIMER_REAL, &timeroff, NULL);
637
638	ppevent = &event_queue;
639	while (*ppevent) {
640		event = *ppevent;
641		*ppevent = event->next;
642		event->next = NULL;
643	}
644}
645
646
647void timer_cancel(timer_t timerid)
648{
649	struct itimerval itimer;
650	struct itimerval timeroff = { { 0, 0 }, { 0, 0} };
651	struct event *event = (struct event *) timerid;
652	struct event **ppevent;
653
654	if (event->flags & TFLAG_CANCELLED) {
655		TIMERDBG("Cannot cancel a cancelled event");
656		return;
657	}
658
659	block_timer();
660
661	ppevent = &event_queue;
662	while (*ppevent) {
663		if (*ppevent == event) {
664
665			/* RACE CONDITION - if the alarm goes off while we are in
666			 * this loop, and if the timer we want to cancel is the
667			 * next to expire, the alarm will end up firing
668			 * after this routine is complete, causing it to go off early.
669			 */
670
671			/* If the cancelled timer is the next to expire,
672			 * we need to do something special to clean up correctly.
673			 */
674			if (event == event_queue && event->next != NULL) {
675				timerclear(&itimer.it_value);
676				getitimer(ITIMER_REAL, &itimer);
677
678				/* subtract the time that has already passed while waiting for this
679				 * timer...
680				 */
681				timersub(&(event->it_value), &(itimer.it_value),
682				         &(event->it_value));
683
684				/* and add any remainder to the next timer in the list */
685				timeradd(&(event->next->it_value), &(event->it_value),
686				         &(event->next->it_value));
687			}
688
689			*ppevent = event->next;
690			event->next = NULL;
691
692			if (event_queue) {
693				timerroundup(&event_queue->it_value, g_granularity);
694				timerclear(&itimer.it_interval);
695				itimer.it_value = event_queue->it_value;
696
697				/* We want to be sure to never turn off the timer
698				 * completely if there are more events on the queue,
699				 * so if the next interval is zero, set it to some
700				 * small value.
701				 */
702
703				if (!timerisset(&(itimer.it_value)))
704					itimer.it_value = (struct timeval) { 0, 1 };
705
706				assert(itimer.it_value.tv_sec > 0 || itimer.it_value.tv_usec >=
707				       g_granularity);
708				assert(event_queue->it_value.tv_sec > 0 ||
709				       event_queue->it_value.tv_usec >=
710				       g_granularity);
711				setitimer(ITIMER_REAL, &itimer, NULL);
712				check_timer();
713			} else {
714				setitimer(ITIMER_REAL, &timeroff, NULL);
715			}
716			break;
717		}
718		ppevent = &((*ppevent)->next);
719	}
720
721	event->flags |= TFLAG_CANCELLED;
722
723	unblock_timer();
724}
725
726/*
727* timer related headers
728*/
729#include "bcmtimer.h"
730
731/*
732* locally used global variables and constants
733*/
734
735/*
736* Initialize internal resources used in the timer module. It must be called
737* before any other timer function calls. The param 'timer_entries' is used
738* to pre-allocate fixed number of timer entries.
739*/
740int bcm_timer_module_init(int timer_entries, bcm_timer_module_id *module_id)
741{
742	init_event_queue(timer_entries);
743	*module_id = (bcm_timer_module_id)event_freelist;
744	return 0;
745}
746
747/*
748* Cleanup internal resources used by this timer module. It deletes all
749* pending timer entries from the backend timer system as well.
750*/
751int bcm_timer_module_cleanup(bcm_timer_module_id module_id)
752{
753	module_id = 0;
754	return 0;
755}
756
757/* Enable/Disable timer module */
758int bcm_timer_module_enable(bcm_timer_module_id module_id, int enable)
759{
760	if (enable)
761		unblock_timer();
762	else
763		block_timer();
764	return 0;
765}
766
767int bcm_timer_create(bcm_timer_module_id module_id, bcm_timer_id *timer_id)
768{
769	module_id = 0;
770	return timer_create(CLOCK_REALTIME, NULL, (timer_t *)timer_id);
771}
772
773int bcm_timer_delete(bcm_timer_id timer_id)
774{
775	return timer_delete((timer_t)timer_id);
776}
777
778int bcm_timer_gettime(bcm_timer_id timer_id, struct itimerspec *timer_spec)
779{
780	return -1;
781}
782
783int bcm_timer_settime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
784{
785	return timer_settime((timer_t)timer_id, 0, timer_spec, NULL);
786}
787
788int bcm_timer_connect(bcm_timer_id timer_id, bcm_timer_cb func, int data)
789{
790	return timer_connect((timer_t)timer_id, (void *)func, data);
791}
792
793int bcm_timer_cancel(bcm_timer_id timer_id)
794{
795	timer_cancel((timer_t)timer_id);
796	return 0;
797}
798int bcm_timer_change_expirytime(bcm_timer_id timer_id, const struct itimerspec *timer_spec)
799{
800	timer_change_settime((timer_t)timer_id, timer_spec);
801	return 1;
802}
803