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