1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos - OS - forChina-fs
3 File: os_china_override.c
4
5 Copyright 2005-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-10-02 #$
14 $Rev: 8827 $
15 $Author: yosizaki $
16 *---------------------------------------------------------------------------*/
17
18
19 #include <nitro.h>
20
21
22 /*---------------------------------------------------------------------------*/
23 /* Constants */
24
25 /* Startup display fade and stop frame count */
26 #define OSi_FORCHINA_FADE_SPAN 32
27 #define OSi_FORCHINA_DISP_SPAN 64
28
29 /* Index to data images managed by using table */
30 typedef enum
31 {
32 IMAGE_NOTES_CHR,
33 IMAGE_NOTES_SCR,
34 IMAGE_NOTES_DIGIT,
35 IMAGE_LOGO_CHR,
36 IMAGE_LOGO_SCR,
37 IMAGE_LOGO_PAL,
38 IMAGE_LOGO_VOICE,
39 IMAGE_MAX
40 }
41 ImageIndex;
42
43
44 /*---------------------------------------------------------------------------*/
45 /* Declarations */
46
47 static u8 *LoadImage(ImageIndex index, u32 *p_size);
48 static void WaitForNextFrame(void);
49 static void VBlankIntr(void);
50 static void SetISBNString(const char **isbn);
51
52
53 /*---------------------------------------------------------------------------*/
54 /* Functions */
55
56 /*---------------------------------------------------------------------------*
57 Name: LoadImage
58
59 Description: Allocates memory of sufficient size and loads the specified file.
60
61 Arguments: index - Index to the file to load.
62 p_size - Pointer to u32 that stores the file size.
63 If not needed, you can specify NULL and it will be ignored.
64
65 Returns: Memory that is allocated inside the call and where the file is loaded.
66 When OS_ShowAttentionChina ends, each heap is destroyed with OS_ClearAlloc so you don't need to explicitly deallocate the memory returned here.
67
68
69 *---------------------------------------------------------------------------*/
LoadImage(ImageIndex index,u32 * p_size)70 static u8 *LoadImage(ImageIndex index, u32 *p_size)
71 {
72 void *ptr = NULL;
73 /* *INDENT-OFF* */
74 static const char *(path_table[IMAGE_MAX]) =
75 {
76 "notes_forChina_chrData.bin",
77 "notes_forChina_scrData.bin",
78 "digit_chrData.bin",
79 "logo_forChina_chrData.bin",
80 "logo_forChina_scrData.bin",
81 "logo_forChina_palData.bin",
82 "logo_forChina_voice.bin",
83 };
84 /* *INDENT-ON* */
85 const char *path = path_table[index];
86
87 FSFile file[1];
88
89 FS_InitFile(file);
90 if (!FS_OpenFileEx(file, path, FS_FILEMODE_R))
91 {
92 OS_TPanic("failed to open file \"%s\"", path);
93 }
94 else
95 {
96 u32 len = FS_GetFileLength(file);
97 ptr = OS_Alloc(len);
98 if (!ptr)
99 {
100 OS_TPanic("failed to allocate memory for image \"%s\"", path);
101 }
102 else
103 {
104 if (p_size)
105 {
106 *p_size = len;
107 }
108 if (FS_ReadFile(file, ptr, (int)len) != len)
109 {
110 OS_TPanic("failed to read file \"%s\"", path);
111 }
112 }
113 (void)FS_CloseFile(file);
114 }
115
116 return (u8 *)ptr;
117 }
118
119 /*---------------------------------------------------------------------------*
120 Name: WaitForNextFrame
121
122 Description: Processing when system is opened and closed, V-Blank wait, and sound update processing.
123
124 Arguments: None.
125
126 Returns: None.
127 *---------------------------------------------------------------------------*/
WaitForNextFrame(void)128 static void WaitForNextFrame(void)
129 {
130 /* Confirm that cover is closed */
131 if (PAD_DetectFold())
132 {
133 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
134 }
135 OS_WaitVBlankIntr();
136 }
137
138 /*---------------------------------------------------------------------------*
139 Name: VBlankIntr
140
141 Description: V-Blank interrupt vector in exclusive startup control screen.
142
143 Arguments: None.
144
145 Returns: None.
146 *---------------------------------------------------------------------------*/
VBlankIntr(void)147 static void VBlankIntr(void)
148 {
149 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
150 }
151
152 /*---------------------------------------------------------------------------*
153 Name: SetISBNString
154
155 Description: Reflect the ISBN number etc. in a prescribed location in the screen data.
156
157 Arguments: isbn: Character string array relating to the ISBN number, etc.
158
159 Returns: None.
160 *---------------------------------------------------------------------------*/
SetISBNString(const char ** isbn)161 static void SetISBNString(const char **isbn)
162 {
163 s32 i, j;
164 struct
165 {
166 u8 x, y; /* Leading display offset */
167 u8 length; /* Display character count */
168 }
169 pos[] =
170 {
171 {
172 80, 144, 13}
173 , /* ISBN */
174 {
175 120, 158, 12}
176 , /* Joint registration number */
177 {
178 103, 175, 4}
179 , /* New sound output tube (left) */
180 {
181 144, 175, 4}
182 , /* New sound output tube (right) */
183 }
184 ;
185 const int count = sizeof(pos) / sizeof(*pos); /* Total number of lines */
186 const int digit_id = 0; /* Digit display character lead ID ("0123456789-") */
187
188 GXOamAttr *dst = (GXOamAttr *)HW_DB_OAM;
189 for (i = 0; i < count; i++)
190 {
191 for (j = 0; j < pos[i].length; ++j)
192 {
193 dst->attr01 = (u32)(((pos[i].x + j * 8) << 16) | (pos[i].y << 0));
194 if (isbn[i][j] == '-')
195 {
196 dst->attr2 = (u16)(digit_id + 10);
197 }
198 else if ((isbn[i][j] >= '0') && (isbn[i][j] <= '9'))
199 {
200 dst->attr2 = (u16)(digit_id + isbn[i][j] - '0');
201 }
202 else
203 {
204 dst->attr2 = (u16)(digit_id + 11);
205 }
206 ++dst;
207 }
208 }
209 }
210
211 /*---------------------------------------------------------------------------*
212 Name: OS_ShowAttentionChina
213
214 Description: Displays logo for China and warning screen for prescribed time.
215
216 Arguments: isbn: Character string array relating to the ISBN number, etc.
217
218 Returns: None.
219 *---------------------------------------------------------------------------*/
OS_ShowAttentionChina(const char ** isbn)220 void OS_ShowAttentionChina(const char **isbn)
221 {
222 /* Structure for saving register */
223 struct
224 {
225 u32 gx_dispcnt;
226 u32 gxs_dispcnt;
227 u16 gx_powcnt;
228 u16 gx_dispstat;
229 u16 gx_bright;
230 u16 gxs_bright;
231 u16 gx_bg0cnt;
232 u16 gxs_bg0cnt;
233 u32 gx_bg0ofs;
234 u32 gxs_bg0ofs;
235 u8 gx_vramcnt_a;
236 u8 gx_vramcnt_c;
237 u8 gx_vramcnt_d;
238 u8 reserved[1];
239
240 OSIrqFunction irqFunction;
241 OSIrqMask irqMask;
242 BOOL irq;
243 OSIntrMode interrupts;
244
245 }
246 shelter;
247
248 /* Pre-processing */
249 {
250 /* Save each register */
251 shelter.gx_dispstat = reg_GX_DISPSTAT;
252 shelter.gx_dispcnt = reg_GX_DISPCNT;
253 shelter.gxs_dispcnt = reg_GXS_DB_DISPCNT;
254 shelter.gx_bright = reg_GX_MASTER_BRIGHT;
255 shelter.gxs_bright = reg_GXS_DB_MASTER_BRIGHT;
256 shelter.gx_powcnt = reg_GX_POWCNT;
257 shelter.gx_vramcnt_a = reg_GX_VRAMCNT_A;
258 shelter.gx_vramcnt_c = reg_GX_VRAMCNT_C;
259 shelter.gx_vramcnt_d = reg_GX_VRAMCNT_D;
260 shelter.gx_bg0cnt = reg_G2_BG0CNT;
261 shelter.gxs_bg0cnt = reg_G2S_DB_BG0CNT;
262 shelter.gx_bg0ofs = reg_G2_BG0OFS;
263 shelter.gxs_bg0ofs = reg_G2S_DB_BG0OFS;
264
265 /* Stop display */
266 reg_GX_DISPCNT = 0;
267 reg_GXS_DB_DISPCNT = 0;
268
269 /* Initialize power control */
270 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
271 {
272 /* When changing LCD enable from OFF to ON, wait 100ms */
273 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
274 }
275 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
276 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
277
278 /* Initialization of master brightness */
279 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) | 16);
280 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
281
282 /* Initialization of memory management and FS */
283 {
284 void *tmp;
285 OSHeapHandle hh;
286 tmp = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
287 OS_SetArenaLo(OS_ARENA_MAIN, tmp);
288 hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
289 hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
290 FS_Init(FS_DMA_NOT_USE);
291 }
292
293 /* Prepare display of logo screen */
294 {
295 reg_GX_VRAMCNT_A =
296 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
297 reg_G2_BG0CNT =
298 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
299 (GX_BG_COLORMODE_256 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
300 <<
301 REG_G2_BG0CNT_SCREENBASE_SHIFT)
302 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
303 <<
304 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
305 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
306 reg_G2_BG0OFS = 0;
307 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
308 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
309
310 /* Load character data into VRAM */
311 {
312 void *const src = LoadImage(IMAGE_LOGO_CHR, NULL);
313 MI_UncompressLZ16(src, (u32 *)HW_BG_VRAM);
314 }
315 /* Load screen data into VRAM */
316 {
317 u8 *const src = LoadImage(IMAGE_LOGO_SCR, NULL);
318 s32 i;
319 s32 j;
320 u16 temp;
321
322 SVC_CpuClearFast(0, (u32 *)(HW_BG_VRAM + 0xf000), 1536);
323 for (i = 0; i < 12; i++)
324 {
325 for (j = 0; j < 12; j++)
326 {
327 temp = (u16)(src[(i * 12) + j]);
328 *(u16 *)(HW_BG_VRAM + 0xf194 + (i * 64) + (j * 2)) = temp;
329 }
330 }
331 }
332 /* Load palette data into VRAM */
333 {
334 u32 size;
335 void *const src = LoadImage(IMAGE_LOGO_PAL, &size);
336 SVC_CpuCopyFast(src, (u32 *)(HW_BG_PLTT), size);
337 }
338 }
339
340 /* Prepare to display Notes screen */
341 {
342 reg_GX_VRAMCNT_C =
343 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
344 reg_GX_VRAMCNT_D =
345 (u8)((4 << REG_GX_VRAMCNT_D_MST_SHIFT) | (1 << REG_GX_VRAMCNT_D_E_SHIFT));
346 reg_G2S_DB_BG0CNT =
347 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
348 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) |
349 (GX_BG_SCRBASE_0xf000 << REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT) |
350 (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) |
351 (GX_BG_EXTPLTT_01 << REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT) | (0 <<
352 REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
353 reg_G2S_DB_BG0OFS = 0;
354 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
355 ((GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ) <<
356 REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
357
358 /* Load character data into VRAM */
359 {
360 u32 size;
361 void *src;
362 MIUnpackBitsParam param = { 0, 1, 4, 0, 0 };
363 /* BG text */
364 src = LoadImage(IMAGE_NOTES_CHR, &size);
365 param.srcNum = (u16)size;
366 SVC_UnpackBits(src, (u32 *)(HW_DB_BG_VRAM), ¶m);
367 /* OBJ text */
368 src = LoadImage(IMAGE_NOTES_DIGIT, &size);
369 param.srcNum = (u16)size;
370 SVC_UnpackBits(src, (u32 *)(HW_DB_OBJ_VRAM), ¶m);
371 SVC_CpuClear(0xC0, (void *)HW_DB_OAM, HW_OAM_SIZE, 32);
372 }
373 /* Load screen data into VRAM */
374 {
375 void *const src = LoadImage(IMAGE_NOTES_SCR, NULL);
376 MI_UncompressLZ16(src, (u32 *)(HW_DB_BG_VRAM + 0xf000));
377 }
378 SetISBNString(isbn);
379 /* Edit palette */
380 *((u16 *)(HW_DB_BG_PLTT + 0)) = 0x0000;
381 *((u16 *)(HW_DB_BG_PLTT + 2)) = 0x7fff;
382 *((u16 *)(HW_DB_OBJ_PLTT + 0)) = 0x7fff;
383 *((u16 *)(HW_DB_OBJ_PLTT + 2)) = 0x0000;
384 }
385
386 /* Start display */
387 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
388 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
389
390 /* Interrupt settings */
391 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
392 shelter.irqFunction = OS_GetIrqFunction(OS_IE_V_BLANK);
393 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
394 shelter.irqMask = OS_EnableIrqMask(OS_IE_V_BLANK);
395 shelter.irq = OS_EnableIrq();
396 shelter.interrupts = OS_EnableInterrupts();
397
398 }
399
400 /* Main process */
401 {
402 s32 i;
403 u16 pad_old;
404 u16 pad;
405
406 /* Fade in */
407 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
408 {
409 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
410 16 - ((i + 1) * 16 / OSi_FORCHINA_FADE_SPAN));
411 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
412 WaitForNextFrame();
413 }
414
415 /* Skip based on button input */
416 pad_old = PAD_Read();
417 for (i = 0; i < OSi_FORCHINA_DISP_SPAN; i++)
418 {
419 pad = PAD_Read();
420 if (~pad_old & pad)
421 {
422 /* If any button push trigger was detected, skip */
423 break;
424 }
425 pad_old = pad;
426 WaitForNextFrame();
427 }
428
429 /* Fade out */
430 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
431 {
432 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
433 (i + 1) * 16 / OSi_FORCHINA_FADE_SPAN);
434 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
435 WaitForNextFrame();
436 }
437 }
438
439 /* Post-processing */
440 {
441
442 /* End FS and memory management */
443 {
444 FS_End();
445 OS_ClearAlloc(OS_ARENA_MAIN);
446 }
447
448 /* Stop display */
449 reg_GX_DISPCNT &= ~(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
450 reg_GXS_DB_DISPCNT &= ~REG_GXS_DB_DISPCNT_MODE_MASK;
451
452 /* Restore interrupt-related items */
453 (void)OS_RestoreInterrupts(shelter.interrupts);
454 (void)OS_RestoreIrq(shelter.irq);
455 (void)OS_SetIrqMask(shelter.irqMask);
456 OS_SetIrqFunction(OS_IE_V_BLANK, shelter.irqFunction);
457 reg_GX_DISPSTAT &= ~REG_GX_DISPSTAT_VBI_MASK;
458
459 /* Clear used VRAM (cannot restore initial values because the size is too big) */
460 SVC_CpuClearFast(0, (u32 *)HW_BG_VRAM, 0x10000);
461 SVC_CpuClearFast(0, (u32 *)HW_BG_PLTT, 0x200);
462 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_VRAM, 0x10000);
463 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_PLTT, 0x04);
464 SVC_CpuClearFast(0, (u32 *)HW_DB_OAM, HW_OAM_SIZE);
465
466 /* Restore each register */
467 reg_G2S_DB_BG0OFS = shelter.gxs_bg0ofs;
468 reg_G2_BG0OFS = shelter.gx_bg0ofs;
469 reg_G2S_DB_BG0CNT = shelter.gxs_bg0cnt;
470 reg_G2_BG0CNT = shelter.gx_bg0cnt;
471 reg_GX_VRAMCNT_D = shelter.gx_vramcnt_d;
472 reg_GX_VRAMCNT_C = shelter.gx_vramcnt_c;
473 reg_GX_VRAMCNT_A = shelter.gx_vramcnt_a;
474 reg_GX_POWCNT = shelter.gx_powcnt;
475 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
476 {
477 /* When changing LCD enable from ON to OFF, wait 100ms */
478 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
479 }
480 reg_GXS_DB_MASTER_BRIGHT = shelter.gxs_bright;
481 reg_GX_MASTER_BRIGHT = shelter.gx_bright;
482 reg_GXS_DB_DISPCNT = shelter.gxs_dispcnt;
483 reg_GX_DISPCNT = shelter.gx_dispcnt;
484 reg_GX_DISPSTAT = shelter.gx_dispstat;
485 }
486 }
487
488 /*---------------------------------------------------------------------------*
489 End of file
490 *---------------------------------------------------------------------------*/
491