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), &param);
367                 /* OBJ text */
368                 src = LoadImage(IMAGE_NOTES_DIGIT, &size);
369                 param.srcNum = (u16)size;
370                 SVC_UnpackBits(src, (u32 *)(HW_DB_OBJ_VRAM), &param);
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