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