1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - OS
3 File: os_china.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: 10638 $
15 $Author: mizutani_nakaba $
16 *---------------------------------------------------------------------------*/
17
18 #include <nitro/os.h>
19 #include <nitro/gx.h>
20 #include <nitro/spi.h>
21 #include <nitro/pad.h>
22 #include <nitro/os/ARM9/china.h>
23
24 #include <nitro/version_begin.h>
25 static char checkString[] = OS_BURY_STRING_FORCHINA;
26 #include <nitro/version_end.h>
27
28 #if defined(SDK_ARM9) && defined(SDK_TWLLTD)
29 #include <os_attention.h>
30 #endif
31
32
33
34 /*****************************************************************************/
35 /* Constants */
36
37 /* Display fade and stop frame count */
38 #define OSi_FORCHINA_FADE_SPAN 32
39 #define OSi_FORCHINA_DISP_SPAN 128
40
41 /* Index to data images managed by using table */
42 typedef enum
43 {
44 IMAGE_NOTES_CHR,
45 IMAGE_NOTES_SCR,
46 IMAGE_NOTES_DIGIT,
47 IMAGE_LOGO_CHR,
48 IMAGE_LOGO_SCR,
49 IMAGE_LOGO_PAL,
50 IMAGE_MAX
51 }
52 ImageIndex;
53
54 /* ONLY_FORCHINA setting */
55 #define OSi_ONLY_FORCHINA_CHAR_WIDTH 15
56 #define OSi_ONLY_FORCHINA_CHAR_HEIGHT 2
57 #define OSi_ONLY_FORCHINA_DOT_WIDTH 117
58 #define OSi_ONLY_FORCHINA_DOT_HEIGHT 16
59 #define OSi_ONLY_FORCHINA_CHAR_SIZE 240
60
61 /* Character data for startup limitation screen (0-fixed pack of 3 bits into 4 bits) */
62 static u8 only_forChina_charData[OSi_ONLY_FORCHINA_CHAR_SIZE] ATTRIBUTE_ALIGN(4) =
63 {
64 0x00, 0x7c, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x8c, 0x8c, 0x9c, 0x9c, 0xbc, 0xbc, 0xec,
65 0x00, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x00, 0xc3, 0xc3, 0x66, 0x66, 0x3c,
66 0x3c, 0x18, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xcf, 0xef, 0x60,
67 0x60, 0x60, 0x67, 0x67, 0x00, 0xc7, 0xcf, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x0f,
68 0x1f, 0x18, 0x18, 0x18, 0x1f, 0x0f, 0x00, 0x60, 0x60, 0x00, 0x00, 0x60, 0x60, 0x60,
69 0x00, 0x7c, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x8c, 0x8c, 0x8c,
70 0x8c, 0x8c, 0x00, 0x00, 0x00, 0xf1, 0xf9, 0x19, 0x19, 0xf9, 0x00, 0xc0, 0xc0, 0xc1,
71 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x87, 0xcf, 0xdc, 0xd8, 0xd8, 0xd8, 0x98, 0x00, 0x0f,
72 0x0f, 0x00, 0x00, 0x00, 0x07, 0x0f, 0xc6, 0xc6, 0xc6, 0xfe, 0x7c, 0x00, 0x00, 0x00,
73 0xec, 0xcc, 0xcc, 0x8c, 0x8c, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0xf9, 0xf9, 0x00,
74 0x00, 0x00, 0x18, 0x18, 0x18, 0x19, 0x19, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0,
75 0xc0, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0xcc, 0xcc,
76 0xcc, 0xcf, 0xc7, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x00, 0x00, 0x00,
77 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xfe, 0x7c, 0xe0,
78 0xc0, 0x00, 0x8c, 0x8c, 0x8c, 0xfc, 0xf8, 0x01, 0x01, 0x00, 0xf9, 0x19, 0x19, 0xf9,
79 0xf1, 0x00, 0x00, 0x00, 0xc3, 0xc0, 0xc0, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x18, 0x18,
80 0x1c, 0xcf, 0xc7, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0f, 0x07, 0x00, 0x00, 0x00};
81
82 /*****************************************************************************/
83 /* Declaration */
84 extern void OSi_InitCommon(void); // os_init.c
85
86 static u8* LoadImage(ImageIndex index, u32 *p_size);
87 static void WaitForNextFrame(void);
88 static void VBlankIntr(void);
89 static void SetISBNString(const char **isbn, BOOL disp_isbn);
90
91 static void CheckLanguageCode(void);
92 static void CheckDetectFold(void);
93 static void DispExclusiveMessage(void);
94 static void DispLogoAndNotes(const char **isbn);
95
96
97 /*****************************************************************************/
98 /* Functions */
99
100 /*---------------------------------------------------------------------------*
101 Name: LoadImage
102
103 Description: Allocates memory of sufficient size and loads the specified file.
104
105 Arguments: index: Index to the file to load
106 p_size: Pointer to u32 that stores the file size
107 If not needed, you can specify NULL and it will be ignored.
108
109 Returns: Memory that is allocated inside the call and where the file is loaded.
110 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.
111
112
113 *---------------------------------------------------------------------------*/
LoadImage(ImageIndex index,u32 * p_size)114 static u8 *LoadImage(ImageIndex index, u32 *p_size)
115 {
116 void *ptr = NULL;
117 #if defined(SDK_CHINA_DATA_FROM_FILE)
118
119 /* *INDENT-OFF* */
120 static const char *(path_table[IMAGE_MAX]) =
121 {
122 "notes_forChina_chrData.bin",
123 "notes_forChina_scrData.bin",
124 "digit_chrData.bin",
125 "logo_forChina_chrData.bin",
126 "logo_forChina_scrData.bin",
127 "logo_forChina_palData.bin",
128 };
129 /* *INDENT-ON* */
130 const char *path = path_table[index];
131
132 FSFile file[1];
133
134 FS_InitFile(file);
135 if (!FS_OpenFileEx(file, path, FS_FILEMODE_R))
136 {
137 OS_TPanic("failed to open file \"%s\"", path);
138 }
139 else
140 {
141 u32 len = FS_GetFileLength(file);
142 ptr = OS_Alloc(len);
143 if (!ptr)
144 {
145 OS_TPanic("failed to allocate memory for image \"%s\"", path);
146 }
147 else
148 {
149 if (p_size)
150 {
151 *p_size = len;
152 }
153 if (FS_ReadFile(file, ptr, (int)len) != len)
154 {
155 OS_TPanic("failed to read file \"%s\"", path);
156 }
157 }
158 (void)FS_CloseFile(file);
159 }
160
161 #else
162
163 extern u8 _binary_notes_forChina_chrData_bin[];
164 extern u8 _binary_notes_forChina_chrData_bin_end[];
165 extern u8 _binary_notes_forChina_scrData_bin[];
166 extern u8 _binary_notes_forChina_scrData_bin_end[];
167 extern u8 _binary_digit_chrData_bin[];
168 extern u8 _binary_digit_chrData_bin_end[];
169 extern u8 _binary_logo_forChina_chrData_bin[];
170 extern u8 _binary_logo_forChina_chrData_bin_end[];
171 extern u8 _binary_logo_forChina_scrData_bin[];
172 extern u8 _binary_logo_forChina_scrData_bin_end[];
173 extern u8 _binary_logo_forChina_palData_bin[];
174 extern u8 _binary_logo_forChina_palData_bin_end[];
175 /* *INDENT-OFF* */
176 static u8 *(ptr_table[]) =
177 {
178 _binary_notes_forChina_chrData_bin,
179 _binary_notes_forChina_scrData_bin,
180 _binary_digit_chrData_bin,
181 _binary_logo_forChina_chrData_bin,
182 _binary_logo_forChina_scrData_bin,
183 _binary_logo_forChina_palData_bin,
184 };
185 static u8 *(ptr_end_table[]) =
186 {
187 _binary_notes_forChina_chrData_bin_end,
188 _binary_notes_forChina_scrData_bin_end,
189 _binary_digit_chrData_bin_end,
190 _binary_logo_forChina_chrData_bin_end,
191 _binary_logo_forChina_scrData_bin_end,
192 _binary_logo_forChina_palData_bin_end,
193 };
194 /* *INDENT-ON* */
195 ptr = ptr_table[index];
196 if (p_size)
197 {
198 *p_size = (u32)(ptr_end_table[index] - ptr_table[index]);
199 }
200
201 #endif
202
203 return (u8 *)ptr;
204 }
205
206 /*---------------------------------------------------------------------------*
207 Name: WaitForNextFrame
208
209 Description: Processing when system is opened and closed, V-Blank wait, and sound update processing.
210
211 Arguments: None.
212
213 Returns: None.
214 *---------------------------------------------------------------------------*/
WaitForNextFrame(void)215 static void WaitForNextFrame(void)
216 {
217 /* Confirm that cover is closed */
218 if (PAD_DetectFold())
219 {
220 PM_GoSleepMode(PM_TRIGGER_COVER_OPEN | PM_TRIGGER_CARD, 0, 0);
221 }
222 SVC_WaitVBlankIntr();
223 }
224
225 /*---------------------------------------------------------------------------*
226 Name: VBlankIntr
227
228 Description: V-Blank interrupt vector in exclusive startup control screen.
229
230 Arguments: None.
231
232 Returns: None.
233 *---------------------------------------------------------------------------*/
VBlankIntr(void)234 static void VBlankIntr(void)
235 {
236 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
237 }
238
239 /*---------------------------------------------------------------------------*
240 Name: SetISBNString
241
242 Description: Applies the ISBN number (and other information) in a prescribed location in the screen data.
243
244 Arguments: isbn: String array relating to the ISBN number (and other information)
245 disp_isbn: If this is TRUE, display the ISBN number; if it is FALSE, hide the ISBN number
246
247 Returns: None.
248
249 Note: A single character is made up of two 8x16 characters.
250 The actual character sizes are as follows.
251 '-' : 5x10
252 '0'-'9' : 7x10
253 *---------------------------------------------------------------------------*/
SetISBNString(const char ** isbn,BOOL disp_isbn)254 static void SetISBNString(const char **isbn, BOOL disp_isbn)
255 {
256 s32 i, j;
257 const struct
258 {
259 u8 x, y; /* Leading display offset */
260 u8 length; /* Display character count */
261 }
262 pos[] =
263 {
264 {
265 80, 142, 17}
266 , /* ISBN */
267 {
268 125, 157, 12}
269 , /* Joint registration number */
270 {
271 106, 173, 4}
272 , /* New sound output tube (left) */
273 {
274 139, 173, 3}
275 , /* New sound output tube (right) */
276 }
277 ;
278 const int count = sizeof(pos) / sizeof(*pos); /* Total number of lines */
279 const int digit_num = 12; /* Number of characters for the digit display ("0123456789- ") */
280 u16 pos_x;
281 u16 pos_y;
282 u16 index;
283 u16 width;
284
285 GXOamAttr *dst = (GXOamAttr *)HW_DB_OAM;
286 for (i = disp_isbn ? 0 : 1; i < count; i++)
287 {
288 pos_x = pos[i].x;
289 pos_y = pos[i].y;
290
291 for (j = 0; j < pos[i].length; ++j)
292 {
293 if (isbn[i][j] == '-')
294 {
295 index = 10;
296 width = 5;
297 }
298 else if ((isbn[i][j] >= '0') && (isbn[i][j] <= '9'))
299 {
300 index = (u16)(isbn[i][j] - '0');
301 width = 7;
302 }
303 else
304 {
305 index = 11;
306 width = 7;
307 }
308
309 dst[0].attr01 = (u32)((pos_x << 16) | (pos_y << 0));
310 dst[0].attr2 = index;
311 dst[1].attr01 = (u32)((pos_x << 16) | (pos_y + 8 << 0));
312 dst[1].attr2 = (u16)(index + digit_num);
313
314 pos_x += width;
315 dst += 2;
316 }
317 }
318 }
319
320 /*---------------------------------------------------------------------------*
321 Name: OS_InitChina
322
323 Description: Initializes SDK's OS library.
324 Exclusively for applications for the China region.
325 Use this function instead of OS_Init function.
326
327 Arguments: isbn: String array relating to the ISBN number (and other information)
328 {
329 char ISBN[ 17 ] ,
330 char Joint registration code [ 12 ] ,
331 char New output sound pipe (left)[ 4 ] ,
332 char New output sound pipe (right) [ 4 ] ,
333 }
334
335 param: Behavior related to displaying ISBN numbers
336
337 Returns: None.
338 *---------------------------------------------------------------------------*/
OS_InitChina(const char ** isbn,OSChinaIsbn param)339 void OS_InitChina(const char **isbn, OSChinaIsbn param)
340 {
341 SDK_REFER_SYMBOL(checkString);
342
343 #ifdef SDK_ARM9
344 //---- System shared area check
345 SDK_ASSERT((u32)&(OS_GetSystemWork()->command_area) == HW_CMD_AREA);
346
347 #ifdef SDK_TWLLTD
348 if (OS_IsLimitedRomRunningOnTwl() != TRUE)
349 {
350 OS_ShowAttentionOfLimitedRomChina(); // Never return
351 }
352 #endif
353
354 #endif // SDK_ARM9
355
356 //---- Initialize SDK OS common
357 OSi_InitCommon();
358
359 //---- Check if possible to boot
360 CheckLanguageCode();
361
362 //---- Display logo and notes about health care
363 OS_ShowAttentionChina(isbn, param);
364 }
365
366 /*---------------------------------------------------------------------------*
367 Name: CheckLanguageCode
368
369 Description: Confirms whether to perform exclusive startup control based on language code.
370
371 Arguments: None.
372
373 Returns: None.
374 *---------------------------------------------------------------------------*/
CheckLanguageCode(void)375 static void CheckLanguageCode(void)
376 {
377 NVRAMConfig *src;
378
379 src = (NVRAMConfig *)(OS_GetSystemWork()->nvramUserInfo);
380 // Confirms whether it has been determined that language code should not be booted by ARM7
381 if ((src->ncd.version == 0xff) && (src->ncd.option.language == 7))
382 {
383 DispExclusiveMessage();
384 // Never return
385 }
386 }
387
388 /*---------------------------------------------------------------------------*
389 Name: DispExclusiveMessage
390
391 Description: Indicates that exclusive startup control was performed based on language code.
392
393 Arguments: None.
394
395 Returns: None.
396 *---------------------------------------------------------------------------*/
DispExclusiveMessage(void)397 static void DispExclusiveMessage(void)
398 {
399 // Stop display
400 reg_GX_DISPCNT = 0;
401 reg_GXS_DB_DISPCNT = 0;
402
403 // Initialize power control
404 if (!(reg_GX_POWCNT & REG_GX_POWCNT_LCD_MASK))
405 {
406 // When changing LCD enable from OFF to ON, wait 100 ms
407 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
408 }
409 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
410 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
411 // Initialization of master brightness
412 reg_GX_MASTER_BRIGHT = 0;
413 reg_GXS_DB_MASTER_BRIGHT = 0;
414
415 // Set main LCD
416 {
417 reg_GX_VRAMCNT_A =
418 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
419 reg_G2_BG0CNT =
420 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
421 (GX_BG_COLORMODE_16 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000 <<
422 REG_G2_BG0CNT_SCREENBASE_SHIFT)
423 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01 <<
424 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
425 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
426 reg_G2_BG0HOFS = (u16)(-(256 - OSi_ONLY_FORCHINA_DOT_WIDTH) / 2);
427 reg_G2_BG0VOFS = (u16)(-(192 - OSi_ONLY_FORCHINA_DOT_HEIGHT) / 2 + 2);
428 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
429 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
430 // Load character data into VRAM
431 {
432 MIUnpackBitsParam param = { OSi_ONLY_FORCHINA_CHAR_SIZE, 1, 4, 0, 0 };
433
434 SVC_UnpackBits(only_forChina_charData, (u32 *)(HW_BG_VRAM + 0x20), ¶m);
435 }
436 // Load screen data into VRAM
437 {
438 s32 i;
439 s32 j;
440 u16 code = 1;
441 u16 *dst = (u16 *)(HW_BG_VRAM + 0xf000);
442
443 for (i = 0; i < OSi_ONLY_FORCHINA_CHAR_HEIGHT; i++)
444 {
445 for (j = 0; j < OSi_ONLY_FORCHINA_CHAR_WIDTH; j++)
446 {
447 *dst++ = code++;
448 }
449 dst += (0x20 - OSi_ONLY_FORCHINA_CHAR_WIDTH);
450 }
451 }
452 }
453
454 // Set sub LCD
455 {
456 reg_GX_VRAMCNT_C =
457 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
458 reg_G2S_DB_BG0CNT =
459 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
460 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
461 <<
462 REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT)
463 | (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
464 <<
465 REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT)
466 | (0 << REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
467 reg_G2S_DB_BG0OFS = 0;
468 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
469 (GX_PLANEMASK_BG0 << REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
470 }
471
472 // V-Blank interrupt settings
473 (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
474 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
475 (void)OS_EnableIrq();
476 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
477
478 // Start display
479 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
480 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
481
482 {
483 u16 data = 0x001f;
484 u16 target = 0x0001 << 5;
485 s32 i;
486
487 // Cycle palette colors between red and yellow and loop indefinitely
488 while (TRUE)
489 {
490 for (i = 0; i < 31; i++)
491 {
492 // Confirm that cover is closed
493 if (TRUE == PAD_DetectFold())
494 {
495 // Turn off power
496 (void)PM_ForceToPowerOff();
497 }
498 OS_WaitVBlankIntr();
499 *((u16 *)(HW_BG_PLTT + 2)) = data;
500 data += target;
501 }
502 target = (u16)(~target + 1);
503 }
504 }
505 }
506
507 /*---------------------------------------------------------------------------*
508 Name: OS_ShowAttentionChina
509
510 Description: Displays logo for China and notice for prescribed time.
511
512 Arguments: isbn: String array relating to the ISBN number (and other information)
513 param: Behavior related to displaying ISBN numbers
514
515 Returns: None.
516 *---------------------------------------------------------------------------*/
OS_ShowAttentionChina(const char ** isbn,OSChinaIsbn param)517 SDK_WEAK_SYMBOL void OS_ShowAttentionChina(const char **isbn, OSChinaIsbn param)
518 {
519 /* Structure for saving register */
520 struct
521 {
522 u32 gx_dispcnt;
523 u32 gxs_dispcnt;
524 u16 gx_powcnt;
525 u16 gx_dispstat;
526 u16 gx_bright;
527 u16 gxs_bright;
528 u16 gx_bg0cnt;
529 u16 gxs_bg0cnt;
530 u32 gx_bg0ofs;
531 u32 gxs_bg0ofs;
532 u8 gx_vramcnt_a;
533 u8 gx_vramcnt_c;
534 u8 gx_vramcnt_d;
535 u8 reserved[1];
536
537 OSIrqFunction irqFunction;
538 OSIrqMask irqMask;
539 BOOL irq;
540 OSIntrMode interrupts;
541
542 }
543 shelter;
544
545 /* Pre-processing */
546 {
547 /* Save each register */
548 shelter.gx_dispstat = reg_GX_DISPSTAT;
549 shelter.gx_dispcnt = reg_GX_DISPCNT;
550 shelter.gxs_dispcnt = reg_GXS_DB_DISPCNT;
551 shelter.gx_bright = reg_GX_MASTER_BRIGHT;
552 shelter.gxs_bright = reg_GXS_DB_MASTER_BRIGHT;
553 shelter.gx_powcnt = reg_GX_POWCNT;
554 shelter.gx_vramcnt_a = reg_GX_VRAMCNT_A;
555 shelter.gx_vramcnt_c = reg_GX_VRAMCNT_C;
556 shelter.gx_vramcnt_d = reg_GX_VRAMCNT_D;
557 shelter.gx_bg0cnt = reg_G2_BG0CNT;
558 shelter.gxs_bg0cnt = reg_G2S_DB_BG0CNT;
559 shelter.gx_bg0ofs = reg_G2_BG0OFS;
560 shelter.gxs_bg0ofs = reg_G2S_DB_BG0OFS;
561
562 /* Stop display */
563 reg_GX_DISPCNT = 0;
564 reg_GXS_DB_DISPCNT = 0;
565
566 /* Initialize power control */
567 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
568 {
569 /* When changing LCD enable from OFF to ON, wait 100 ms */
570 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
571 }
572 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
573 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
574
575 /* Initialization of master brightness */
576 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) | 16);
577 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
578
579 /* Prepare display of logo screen */
580 {
581 reg_GX_VRAMCNT_A =
582 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
583 reg_G2_BG0CNT =
584 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
585 (GX_BG_COLORMODE_256 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
586 <<
587 REG_G2_BG0CNT_SCREENBASE_SHIFT)
588 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
589 <<
590 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
591 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
592 reg_G2_BG0OFS = 0;
593 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
594 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
595
596 /* Load character data into VRAM */
597 {
598 void *const src = LoadImage(IMAGE_LOGO_CHR, NULL);
599 MI_UncompressLZ16(src, (u32 *)HW_BG_VRAM);
600 }
601 /* Load screen data into VRAM */
602 {
603 u16 *src = (u16*)LoadImage(IMAGE_LOGO_SCR, NULL);
604 u16 *dst;
605 s32 i;
606 s32 j;
607
608 // Place 12x12 (96x96-pixel) screen data at the center
609 SVC_CpuClearFast(0, (u32 *)(HW_BG_VRAM + 0xf000), 32*24*2);
610 dst = (u16*)(HW_BG_VRAM + 0xf000 + ((6*32+10)*2));
611
612 for (i = 0; i < 12; i++, dst += 32)
613 {
614 for (j = 0; j < 12; j++, src++)
615 {
616 dst[j] = *src;
617 }
618 }
619 }
620 /* Load palette data into VRAM */
621 {
622 u32 size;
623 void *const src = LoadImage(IMAGE_LOGO_PAL, &size);
624 SVC_CpuCopyFast(src, (u32 *)(HW_BG_PLTT), size);
625 }
626 }
627
628 /* Prepare to display Notes screen */
629 {
630 reg_GX_VRAMCNT_C =
631 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
632 reg_GX_VRAMCNT_D =
633 (u8)((4 << REG_GX_VRAMCNT_D_MST_SHIFT) | (1 << REG_GX_VRAMCNT_D_E_SHIFT));
634 reg_G2S_DB_BG0CNT =
635 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
636 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) |
637 (GX_BG_SCRBASE_0xf000 << REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT) |
638 (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) |
639 (GX_BG_EXTPLTT_01 << REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT) | (0 <<
640 REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
641 reg_G2S_DB_BG0OFS = 0;
642 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
643 ((GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ) <<
644 REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
645
646 /* Load character data into VRAM */
647 {
648 u32 size;
649 void *src;
650 /* Background text */
651 src = LoadImage(IMAGE_NOTES_CHR, &size);
652 MI_UncompressLZ16(src, (u32 *)(HW_DB_BG_VRAM));
653 /* OBJ text */
654 src = LoadImage(IMAGE_NOTES_DIGIT, &size);
655 MI_UncompressLZ16(src, (u32 *)(HW_DB_OBJ_VRAM));
656 SVC_CpuClear(0xC0, (void *)HW_DB_OAM, HW_OAM_SIZE, 32);
657 }
658 /* Load screen data into VRAM */
659 {
660 u32 size;
661 void *const src = LoadImage(IMAGE_NOTES_SCR, &size);
662 SVC_CpuCopyFast(src, (u32 *)(HW_DB_BG_VRAM + 0xf000), size);
663 }
664
665 // Display settings for the ISBN string
666 SetISBNString(isbn, (BOOL)(param != OS_CHINA_ISBN_NO_DISP));
667
668 /* Edit palette */
669 *((u16 *)(HW_DB_BG_PLTT + 0)) = 0x7fff;
670 *((u16 *)(HW_DB_BG_PLTT + 2)) = 0x0000;
671 *((u16 *)(HW_DB_OBJ_PLTT + 0)) = 0x7fff;
672 *((u16 *)(HW_DB_OBJ_PLTT + 2)) = 0x0000;
673 }
674
675 /* Start display */
676 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
677 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
678
679 /* Interrupt settings */
680 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
681 shelter.irqFunction = OS_GetIrqFunction(OS_IE_V_BLANK);
682 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
683 shelter.irqMask = OS_EnableIrqMask(OS_IE_V_BLANK);
684 shelter.irq = OS_EnableIrq();
685 shelter.interrupts = OS_EnableInterrupts();
686
687 }
688
689 /* Main process */
690 {
691 s32 i;
692 u16 pad_old;
693 u16 pad;
694
695 /* Fade in */
696 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
697 {
698 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
699 16 - ((i + 1) * 16 / OSi_FORCHINA_FADE_SPAN));
700 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
701 WaitForNextFrame();
702 }
703
704 /* Skip based on button input */
705 pad_old = PAD_Read();
706 for (i = 0; i < OSi_FORCHINA_DISP_SPAN; i++)
707 {
708 pad = PAD_Read();
709 if ((param == OS_CHINA_ISBN_CHECK_ROM) && (~pad_old & pad))
710 {
711 /* If any button push trigger was detected, skip */
712 break;
713 }
714 pad_old = pad;
715 WaitForNextFrame();
716
717 // On ROMs used for censorship purposes, do not exit until a button is pressed
718 if(param == OS_CHINA_ISBN_CHECK_ROM) i = 0;
719 }
720
721 /* Fade out */
722 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
723 {
724 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
725 (i + 1) * 16 / OSi_FORCHINA_FADE_SPAN);
726 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
727 WaitForNextFrame();
728 }
729 }
730
731 /* Post-processing */
732 {
733 /* Stop display */
734 reg_GX_DISPCNT &= ~(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
735 reg_GXS_DB_DISPCNT &= ~REG_GXS_DB_DISPCNT_MODE_MASK;
736
737 /* Restore interrupt-related items */
738 (void)OS_RestoreInterrupts(shelter.interrupts);
739 (void)OS_RestoreIrq(shelter.irq);
740 (void)OS_SetIrqMask(shelter.irqMask);
741 OS_SetIrqFunction(OS_IE_V_BLANK, shelter.irqFunction);
742 reg_GX_DISPSTAT &= ~REG_GX_DISPSTAT_VBI_MASK;
743
744 /* Clear used VRAM (cannot restore initial values because the size is too big) */
745 SVC_CpuClearFast(0, (u32 *)HW_BG_VRAM, 0x10000);
746 SVC_CpuClearFast(0, (u32 *)HW_BG_PLTT, 0x200);
747 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_VRAM, 0x10000);
748 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_PLTT, 0x04);
749 SVC_CpuClearFast(0, (u32 *)HW_DB_OAM, HW_OAM_SIZE);
750
751 /* Restore each register */
752 reg_G2S_DB_BG0OFS = shelter.gxs_bg0ofs;
753 reg_G2_BG0OFS = shelter.gx_bg0ofs;
754 reg_G2S_DB_BG0CNT = shelter.gxs_bg0cnt;
755 reg_G2_BG0CNT = shelter.gx_bg0cnt;
756 reg_GX_VRAMCNT_D = shelter.gx_vramcnt_d;
757 reg_GX_VRAMCNT_C = shelter.gx_vramcnt_c;
758 reg_GX_VRAMCNT_A = shelter.gx_vramcnt_a;
759 reg_GX_POWCNT = shelter.gx_powcnt;
760 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
761 {
762 /* When changing LCD enable from ON to OFF, wait 100ms */
763 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
764 }
765 reg_GXS_DB_MASTER_BRIGHT = shelter.gxs_bright;
766 reg_GX_MASTER_BRIGHT = shelter.gx_bright;
767 reg_GXS_DB_DISPCNT = shelter.gxs_dispcnt;
768 reg_GX_DISPCNT = shelter.gx_dispcnt;
769 reg_GX_DISPSTAT = shelter.gx_dispstat;
770 }
771 }
772
773 /*---------------------------------------------------------------------------*
774 End of file
775 *---------------------------------------------------------------------------*/
776