1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - OS
3   File:     os_alarm.c
4 
5   Copyright 2003-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 #include <nitro/os.h>
18 
19 //---- Timer control setting for alarm
20 #define OSi_ALARM_TIMERCONTROL      ( REG_OS_TM0CNT_H_E_MASK | REG_OS_TM0CNT_H_I_MASK | OS_TIMER_PRESCALER_64 )
21 
22 //---- Timer number alarm uses
23 #define OSi_ALARM_TIMER    OS_TIMER_1
24 
25 //---- Timer interrupt mask (must be same number with OSi_ALARM_TIMER)
26 #define OSi_ALARM_IE_TIMER OS_IE_TIMER1
27 
28 //---- Flag for initialization alarm
29 static u16 OSi_UseAlarm = FALSE;
30 
31 //---- Alarm queue
32 static struct OSiAlarmQueue OSi_AlarmQueue;
33 
34 
35 u16     OSi_IsTimerReserved(int timerNum);
36 void    OSi_SetTimerReserved(int timerNum);
37 void    OSi_UnsetTimerReserved(int timerNum);
38 
39 static void OSi_SetTimer(OSAlarm *alarm);
40 static void OSi_InsertAlarm(OSAlarm *alarm, OSTick fire);
41 
42 static void OSi_AlarmHandler(void *arg);
43 static void OSi_ArrangeTimer(void);
44 
45 
46 /*---------------------------------------------------------------------------*
47   Name:         OSi_SetTimer
48 
49   Description:  Sets timer.
50 
51   Arguments:    alarm:       Pointer to alarm to set timer
52 
53   Returns:      None.
54  *---------------------------------------------------------------------------*/
OSi_SetTimer(OSAlarm * alarm)55 static void OSi_SetTimer(OSAlarm *alarm)
56 {
57     s64     delta;
58     OSTick  tick = OS_GetTick();
59     u16     timerCount;
60 
61     //---- Let timer be disabled
62     OS_SetTimerControl(OSi_ALARM_TIMER, 0);
63 
64     delta = (s64)(alarm->fire - tick);
65 
66     //---- Set interrupt callback
67     OSi_EnterTimerCallback(OSi_ALARM_TIMER, OSi_AlarmHandler, NULL);
68 
69 
70     if (delta < 0)
71     {
72         timerCount = (u16)~1;
73     }
74     else if (delta < 0x10000)
75     {
76         timerCount = (u16)(~delta);
77     }
78     else
79     {
80         timerCount = 0;
81     }
82 
83 //OS_Printf( "**OSi_SetTimer  alarm=%x, fire=%llx  time=%llx delta=%lld timeCount=%x \n", alarm, alarm->fire, time, delta, (int)timerCount );
84 
85     //---- Set count and let timer be enabled
86     OS_SetTimerCount((OSTimer)OSi_ALARM_TIMER, timerCount);
87     OS_SetTimerControl(OSi_ALARM_TIMER, (u16)OSi_ALARM_TIMERCONTROL);
88 
89     //---- TIMER IRQ Enable
90     (void)OS_EnableIrqMask(OSi_ALARM_IE_TIMER);
91 }
92 
93 /*---------------------------------------------------------------------------*
94   Name:         OS_InitAlarm
95 
96   Description:  Initializes alarm system.
97 
98   Arguments:    None.
99 
100   Returns:      None.
101  *---------------------------------------------------------------------------*/
OS_InitAlarm(void)102 void OS_InitAlarm(void)
103 {
104     if (!OSi_UseAlarm)
105     {
106         OSi_UseAlarm = TRUE;
107 
108         //---- Check if tick system is available
109         SDK_ASSERTMSG(OS_IsTickAvailable(), "OS_InitAlarm: alarm system needs of tick system.");
110 
111         //---- OS reserves OSi_ALARM_TIMER
112         SDK_ASSERT(!OSi_IsTimerReserved(OSi_ALARM_TIMER));
113         OSi_SetTimerReserved(OSi_ALARM_TIMER);
114 
115         //---- Clear alarm list
116         OSi_AlarmQueue.head = NULL;
117         OSi_AlarmQueue.tail = NULL;
118 
119         //---- TIMER IRQ Disable
120         (void)OS_DisableIrqMask(OSi_ALARM_IE_TIMER);
121     }
122 }
123 
124 
125 /*---------------------------------------------------------------------------*
126   Name:         OS_EndAlarm
127 
128   Description:  Ends alarm system.
129 
130   Arguments:    None.
131 
132   Returns:      None.
133  *---------------------------------------------------------------------------*/
OS_EndAlarm(void)134 void OS_EndAlarm(void)
135 {
136     OSIntrMode enabled;
137 
138     SDK_ASSERT(OSi_UseAlarm);
139     enabled = OS_DisableInterrupts();
140 
141     //---- Check if any alarm exists
142     if (OSi_UseAlarm)
143     {
144         SDK_ASSERTMSG(!OSi_AlarmQueue.head,
145                       "OS_EndAlarm: Cannot end alarm system while using alarm.");
146 
147         //---- Unset timer reservation by OS
148         SDK_ASSERT(OSi_IsTimerReserved(OSi_ALARM_TIMER));
149         OSi_UnsetTimerReserved(OSi_ALARM_TIMER);
150 
151         OSi_UseAlarm = FALSE;
152     }
153 
154     (void)OS_RestoreInterrupts(enabled);
155 }
156 
157 
158 /*---------------------------------------------------------------------------*
159   Name:         OS_IsAlarmAvailable
160 
161   Description:  Checks alarm system is available.
162 
163   Arguments:    None.
164 
165   Returns:      If available, TRUE.
166  *---------------------------------------------------------------------------*/
OS_IsAlarmAvailable(void)167 BOOL OS_IsAlarmAvailable(void)
168 {
169     return OSi_UseAlarm;
170 }
171 
172 
173 /*---------------------------------------------------------------------------*
174   Name:         OS_CreateAlarm
175 
176   Description:  Creates alarm.
177 
178   Arguments:    alarm:       Pointer to alarm to be initialized
179 
180   Returns:      None.
181  *---------------------------------------------------------------------------*/
OS_CreateAlarm(OSAlarm * alarm)182 void OS_CreateAlarm(OSAlarm *alarm)
183 {
184     SDK_ASSERT(OSi_UseAlarm);
185     SDK_ASSERT(alarm);
186 
187     alarm->handler = 0;
188     alarm->tag = 0;
189 }
190 
191 
192 /*---------------------------------------------------------------------------*
193   Name:         OSi_InsertAlarm
194 
195   Description:  Inserts alarm. Needs to be called interrupts disabled.
196 
197   Arguments:    alarm:       Pointer to alarm to be set
198                 fire:        Tick to fire (only for one- shot alarm)
199 
200   Returns:      None.
201  *---------------------------------------------------------------------------*/
OSi_InsertAlarm(OSAlarm * alarm,OSTick fire)202 static void OSi_InsertAlarm(OSAlarm *alarm, OSTick fire)
203 {
204     OSAlarm *prev;
205     OSAlarm *next;
206 
207     //---- Calculate next fire for periodic alarm
208     if (alarm->period > 0)
209     {
210         OSTick  tick = OS_GetTick();
211 
212         fire = alarm->start;
213         if (alarm->start < tick)
214         {
215             fire += alarm->period * ((tick - alarm->start) / alarm->period + 1);
216         }
217     }
218 
219     //---- Set tick to fire
220     alarm->fire = fire;
221 
222     //---- Insert to list
223     for (next = OSi_AlarmQueue.head; next; next = next->next)
224     {
225 //        if ( next->fire <= fire )
226         if ((s64)(fire - next->fire) >= 0)
227         {
228             continue;
229         }
230 
231         //---- Insert alarm before 'next'
232         alarm->prev = next->prev;
233         next->prev = alarm;
234         alarm->next = next;
235         prev = alarm->prev;
236         if (prev)
237         {
238             prev->next = alarm;
239         }
240         else
241         {
242             OSi_AlarmQueue.head = alarm;
243             OSi_SetTimer(alarm);
244         }
245 
246         return;
247     }
248 
249     //---- Insert alarm after tail
250     alarm->next = 0;
251     prev = OSi_AlarmQueue.tail;
252     OSi_AlarmQueue.tail = alarm;
253     alarm->prev = prev;
254     if (prev)
255     {
256         prev->next = alarm;
257     }
258     else
259     {
260         OSi_AlarmQueue.head = OSi_AlarmQueue.tail = alarm;
261         OSi_SetTimer(alarm);
262     }
263 }
264 
265 
266 /*---------------------------------------------------------------------------*
267   Name:         OS_SetAlarm
268 
269   Description:  Sets alarm as a relative tick.
270 
271   Arguments:    alarm:       Pointer to alarm to be set
272                 tick:        Ticks to count before firing
273                 handler:     Alarm handler to be called
274                 arg:        Argument of handler
275 
276   Returns:      None.
277  *---------------------------------------------------------------------------*/
OS_SetAlarm(OSAlarm * alarm,OSTick tick,OSAlarmHandler handler,void * arg)278 void OS_SetAlarm(OSAlarm *alarm, OSTick tick, OSAlarmHandler handler, void *arg)
279 {
280     OSIntrMode enabled;
281 
282     //OS_Printf( "**OS_SetAlarm e=%x alarm=%x tick=%x  handler%x\n", enabled, alarm, tick, handler );
283     SDK_ASSERT(OSi_UseAlarm);
284     SDK_ASSERTMSG(handler, "OS_SetAlarm: handler must not be NULL.");
285     if (!alarm || alarm->handler)
286     {
287 #ifndef SDK_FINALROM
288         OS_Panic("alarm could be already used.");
289 #else
290         OS_Panic("");
291 #endif
292     }
293 
294     enabled = OS_DisableInterrupts();
295 
296     //---- Clear periodic info
297     alarm->period = 0;
298 
299     //---- Set handler
300     alarm->handler = handler;
301     alarm->arg = arg;
302 
303     //---- Insert alarm
304     OSi_InsertAlarm(alarm, OS_GetTick() + tick);
305 
306     (void)OS_RestoreInterrupts(enabled);
307 }
308 
309 /*---------------------------------------------------------------------------*
310   Name:         OS_SetPeriodicAlarm
311 
312   Description:  Sets periodic alarm.
313 
314   Arguments:    alarm:       Pointer to alarm to be set
315                 start:          Origin of the period in absolute tick
316                 period:         Ticks to count for each period
317                 handler:     Alarm handler to be called
318                 arg:         Argument of handler
319 
320   Returns:      None.
321  *---------------------------------------------------------------------------*/
OS_SetPeriodicAlarm(OSAlarm * alarm,OSTick start,OSTick period,OSAlarmHandler handler,void * arg)322 void OS_SetPeriodicAlarm(OSAlarm *alarm, OSTick start, OSTick period, OSAlarmHandler handler,
323                          void *arg)
324 {
325     u32     enabled;
326 
327     //OS_Printf( "**SetPeriodicAlarm s=%llx p=%llx\n", start, period );
328     SDK_ASSERT(OSi_UseAlarm);
329     SDK_ASSERTMSG(handler, "OS_SetPeriodicAlarm: handler must not be NULL\n");
330     SDK_ASSERTMSG(period > 0, "OS_SetPeriodicAlarm: bad period specified.");
331     if (!alarm || alarm->handler)
332     {
333 #ifndef SDK_FINALROM
334         OS_Panic("alarm could be already used.");
335 #else
336         OS_Panic("");
337 #endif
338     }
339 
340     enabled = OS_DisableInterrupts();
341 
342     //---- Set periodic info
343     alarm->period = period;
344     alarm->start = start;
345 
346     //---- Set handler
347     alarm->handler = handler;
348     alarm->arg = arg;
349 
350     //---- Insert periodic alarm
351     OSi_InsertAlarm(alarm, 0);
352 
353     (void)OS_RestoreInterrupts(enabled);
354 }
355 
356 /*---------------------------------------------------------------------------*
357   Name:         OS_CancelAlarm
358 
359   Description:  Cancels alarm.
360 
361   Arguments:    alarm:       Pointer to alarm to be canceled
362 
363   Returns:      None.
364  *---------------------------------------------------------------------------*/
OS_CancelAlarm(OSAlarm * alarm)365 void OS_CancelAlarm(OSAlarm *alarm)
366 {
367     OSAlarm *next;
368     u32     enabled;
369 
370     SDK_ASSERT(OSi_UseAlarm);
371     SDK_ASSERT(alarm);
372 
373     enabled = OS_DisableInterrupts();
374 
375     if (alarm->handler == NULL)
376     {
377         (void)OS_RestoreInterrupts(enabled);
378         return;
379     }
380 
381     //---- Remove alarm
382     next = alarm->next;
383     if (next == NULL)
384     {
385         OSi_AlarmQueue.tail = alarm->prev;
386     }
387     else
388     {
389         next->prev = alarm->prev;
390     }
391 
392     if (alarm->prev)
393     {
394         alarm->prev->next = next;
395     }
396     else
397     {
398         OSi_AlarmQueue.head = next;
399         if (next)
400         {
401             OSi_SetTimer(next);
402         }
403     }
404 
405     alarm->handler = NULL;
406     alarm->period = 0;                 // Not periodic alarm
407 
408     (void)OS_RestoreInterrupts(enabled);
409 }
410 
411 
412 /*---------------------------------------------------------------------------*
413   Name:         OSi_AlarmHandler
414 
415   Description:  Handler timer interrupt.
416 
417   Arguments:    arg:         Dummy
418 
419   Returns:      None.
420  *---------------------------------------------------------------------------*/
421 #include <nitro/code32.h>
OSi_AlarmHandler(void * arg)422 asm void OSi_AlarmHandler( void* arg )
423 {
424     stmfd     sp!, {r0, lr} /* 8-byte alignment of the call stack */
425     bl        OSi_ArrangeTimer
426     ldmfd     sp!, {r0, lr} /* 8-byte alignment of the call stack */
427     bx        lr
428 }
429 #include <nitro/codereset.h>
430 
431 
432 /*---------------------------------------------------------------------------*
433   Name:         OSi_ArrangeTimer
434 
435   Description:  Handler timer interrupt. Called from OSi_AlarmHandler.
436 
437   Arguments:    None.
438 
439   Returns:      None.
440  *---------------------------------------------------------------------------*/
OSi_ArrangeTimer(void)441 static void OSi_ArrangeTimer(void)
442 {
443     OSTick  tick;
444     OSAlarm *alarm;
445     OSAlarm *next;
446     OSAlarmHandler handler;
447 
448     //---- Let timer be disabled
449     OS_SetTimerControl(OSi_ALARM_TIMER, 0);
450 
451     //---- To be timer-irq Disable
452     (void)OS_DisableIrqMask(OSi_ALARM_IE_TIMER);
453 
454     //---- Set check flag timer interrupt
455     OS_SetIrqCheckFlag(OSi_ALARM_IE_TIMER);
456 
457 
458     tick = OS_GetTick();
459     alarm = OSi_AlarmQueue.head;
460 
461     //OS_Printf( "**Arrange  alarm=%x  time=%llx  file=%llx\n", alarm, time, alarm->fire );
462 
463     //---- No alarm
464     if (alarm == NULL)
465     {
466         return;
467     }
468 
469     //---- Not reach to time of top alarm
470     if (tick < alarm->fire)
471     {
472         OSi_SetTimer(alarm);
473         return;
474     }
475 
476     //---- Move next alarm to top
477     next = alarm->next;
478     OSi_AlarmQueue.head = next;
479 
480     if (next == NULL)
481     {
482         OSi_AlarmQueue.tail = NULL;
483     }
484     else
485     {
486         next->prev = NULL;
487     }
488 
489     //---- Call user alarm handler
490     handler = alarm->handler;
491 
492     if (alarm->period == 0)
493     {
494         alarm->handler = NULL;
495     }
496 
497     if (handler)
498     {
499         (handler) (alarm->arg);
500     }
501 
502     //---- If alarm is periodic, re-inter to list
503     if (alarm->period > 0)
504     {
505         alarm->handler = handler;
506         OSi_InsertAlarm(alarm, 0);
507     }
508 
509     //---- Set timer
510     if (OSi_AlarmQueue.head)
511     {
512         OSi_SetTimer(OSi_AlarmQueue.head);
513     }
514 }
515 
516 
517 /*---------------------------------------------------------------------------*
518   Name:         OS_SetAlarmTag
519 
520   Description:  Sets tag that is used OS_CancelAlarms.
521 
522   Arguments:    alarm:        Alarm to be set tag
523                 tag:          Tag number
524 
525   Returns:      None.
526  *---------------------------------------------------------------------------*/
OS_SetAlarmTag(OSAlarm * alarm,u32 tag)527 void OS_SetAlarmTag(OSAlarm *alarm, u32 tag)
528 {
529     SDK_ASSERT(OSi_UseAlarm);
530     SDK_ASSERT(alarm);
531     SDK_ASSERTMSG(tag > 0, "OS_SetAlarmTag: Tag must be >0.");
532 
533     alarm->tag = tag;
534 }
535 
536 
537 /*---------------------------------------------------------------------------*
538   Name:         OS_CancelAlarms
539 
540   Description:  Cancels alarms that have specified tag.
541 
542   Arguments:    tag:          Tag number to be cancelled. Not 0.
543 
544   Returns:      None.
545  *---------------------------------------------------------------------------*/
OS_CancelAlarms(u32 tag)546 void OS_CancelAlarms(u32 tag)
547 {
548     u32     enabled;
549     OSAlarm *alarm;
550     OSAlarm *next;
551 
552     SDK_ASSERT(OSi_UseAlarm);
553     SDK_ASSERTMSG(tag > 0, "OSCancelAlarms: Tag must be >0.");
554 
555     if (tag == 0)
556     {
557         return;
558     }
559 
560     enabled = OS_DisableInterrupts();
561 
562     for (alarm = OSi_AlarmQueue.head, next = alarm ? alarm->next : NULL;
563          alarm; alarm = next, next = alarm ? alarm->next : NULL)
564     {
565         if (alarm->tag == tag)
566         {
567             //---- Cancel alarm
568             OS_CancelAlarm(alarm);
569         }
570     }
571 
572     (void)OS_RestoreInterrupts(enabled);
573 }
574 
575 
576 /*---------------------------------------------------------------------------*
577   Name:         OS_CancelAllAlarms
578 
579   Description:  Cancels all alarms.
580 
581   Arguments:    None.
582 
583   Returns:      None.
584  *---------------------------------------------------------------------------*/
OS_CancelAllAlarms(void)585 void OS_CancelAllAlarms(void)
586 {
587     u32     enabled;
588     OSAlarm *alarm;
589     OSAlarm *next;
590 
591     SDK_ASSERT(OSi_UseAlarm);
592     enabled = OS_DisableInterrupts();
593 
594     for (alarm = OSi_AlarmQueue.head, next = alarm ? alarm->next : NULL;
595          alarm; alarm = next, next = alarm ? alarm->next : NULL)
596     {
597         //---- Cancel alarm
598         OS_CancelAlarm(alarm);
599     }
600 
601     (void)OS_RestoreInterrupts(enabled);
602 }
603 
604 /*---------------------------------------------------------------------------*
605   Name:         OSi_GetAlarmQueue
606 
607   Description:  Gets alarm queue.
608 
609   Arguments:    None.
610 
611   Returns:      Alarm queue.
612  *---------------------------------------------------------------------------*/
OSi_GetAlarmQueue(void)613 struct OSiAlarmQueue *OSi_GetAlarmQueue(void)
614 {
615     return &OSi_AlarmQueue;
616 }
617 
618 //================================================================================
619 //        FOR DEBUG
620 //================================================================================
621 /*---------------------------------------------------------------------------*
622   Name:         OS_GetNumberOfAlarm
623 
624   Description:  Gets number of alarm.
625 
626   Arguments:    None.
627 
628   Returns:      Number of alarm.
629  *---------------------------------------------------------------------------*/
OS_GetNumberOfAlarm(void)630 int OS_GetNumberOfAlarm(void)
631 {
632     OSIntrMode enabled = OS_DisableInterrupts();
633 	OSAlarm* p = OSi_AlarmQueue.head;
634 	int num = 0;
635 
636 	while(p)
637 	{
638 		num ++;
639 		p = p->next;
640 	}
641 
642     (void)OS_RestoreInterrupts(enabled);
643 	return num;
644 }
645 
646 /*---------------------------------------------------------------------------*
647   Name:         OS_GetAlarmResource
648 
649   Description:  Stores alarm resources to specified pointer.
650 
651   Arguments:    resource:       Pointer storing alarm resources
652 
653   Returns:      TRUE  ... success (always return this now).
654                 FALSE ... failure.
655  *---------------------------------------------------------------------------*/
OS_GetAlarmResource(OSAlarmResource * resource)656 BOOL    OS_GetAlarmResource(OSAlarmResource *resource)
657 {
658 	resource->num = OS_GetNumberOfAlarm();
659 
660 	return TRUE;
661 }
662