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