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