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-08-20#$
14 $Rev: 10998 $
15 $Author: yada $
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, 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) to 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 equivalent to 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 #endif // SDK_ARM9
347
348 //---- Initialize SDK OS common
349 OSi_InitCommon();
350
351 //---- Check if possible to boot
352 // CheckLanguageCode(); Eliminated starting restrictions
353
354 //---- Display logo and notes about health care
355 OS_ShowAttentionChina(isbn, param);
356 }
357
358 /*---------------------------------------------------------------------------*
359 Name: CheckLanguageCode
360
361 Description: Confirms whether to perform exclusive startup control based on language code.
362
363 Arguments: None.
364
365 Returns: None.
366 *---------------------------------------------------------------------------*/
CheckLanguageCode(void)367 static void CheckLanguageCode(void)
368 {
369 NVRAMConfig *src;
370
371 src = (NVRAMConfig *)(OS_GetSystemWork()->nvramUserInfo);
372 // Confirms whether it has been determined that language code should not be booted by ARM7
373 if ((src->ncd.version == 0xff) && (src->ncd.option.language == 7))
374 {
375 DispExclusiveMessage();
376 // Never return
377 }
378 }
379
380 /*---------------------------------------------------------------------------*
381 Name: DispExclusiveMessage
382
383 Description: Indicates that exclusive startup control was performed based on language code.
384
385 Arguments: None.
386
387 Returns: None.
388 *---------------------------------------------------------------------------*/
DispExclusiveMessage(void)389 static void DispExclusiveMessage(void)
390 {
391 // Stop display
392 reg_GX_DISPCNT = 0;
393 reg_GXS_DB_DISPCNT = 0;
394
395 // Initialize power control
396 if (!(reg_GX_POWCNT & REG_GX_POWCNT_LCD_MASK))
397 {
398 // When changing LCD enable from OFF to ON, wait 100 ms
399 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
400 }
401 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
402 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
403 // Initialization of master brightness
404 reg_GX_MASTER_BRIGHT = 0;
405 reg_GXS_DB_MASTER_BRIGHT = 0;
406
407 // Set main LCD
408 {
409 reg_GX_VRAMCNT_A =
410 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
411 reg_G2_BG0CNT =
412 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
413 (GX_BG_COLORMODE_16 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000 <<
414 REG_G2_BG0CNT_SCREENBASE_SHIFT)
415 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01 <<
416 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
417 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
418 reg_G2_BG0HOFS = (u16)(-(256 - OSi_ONLY_FORCHINA_DOT_WIDTH) / 2);
419 reg_G2_BG0VOFS = (u16)(-(192 - OSi_ONLY_FORCHINA_DOT_HEIGHT) / 2 + 2);
420 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
421 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
422 // Load character data into VRAM
423 {
424 MIUnpackBitsParam param = { OSi_ONLY_FORCHINA_CHAR_SIZE, 1, 4, 0, 0 };
425
426 SVC_UnpackBits(only_forChina_charData, (u32 *)(HW_BG_VRAM + 0x20), ¶m);
427 }
428 // Load screen data into VRAM
429 {
430 s32 i;
431 s32 j;
432 u16 code = 1;
433 u16 *dst = (u16 *)(HW_BG_VRAM + 0xf000);
434
435 for (i = 0; i < OSi_ONLY_FORCHINA_CHAR_HEIGHT; i++)
436 {
437 for (j = 0; j < OSi_ONLY_FORCHINA_CHAR_WIDTH; j++)
438 {
439 *dst++ = code++;
440 }
441 dst += (0x20 - OSi_ONLY_FORCHINA_CHAR_WIDTH);
442 }
443 }
444 }
445
446 // Set sub LCD
447 {
448 reg_GX_VRAMCNT_C =
449 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
450 reg_G2S_DB_BG0CNT =
451 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
452 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
453 <<
454 REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT)
455 | (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
456 <<
457 REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT)
458 | (0 << REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
459 reg_G2S_DB_BG0OFS = 0;
460 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
461 (GX_PLANEMASK_BG0 << REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
462 }
463
464 // V-Blank interrupt settings
465 (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
466 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
467 (void)OS_EnableIrq();
468 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
469
470 // Start display
471 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
472 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
473
474 {
475 u16 data = 0x001f;
476 u16 target = 0x0001 << 5;
477 s32 i;
478
479 // Cycle palette colors between red and yellow and loop indefinitely
480 while (TRUE)
481 {
482 for (i = 0; i < 31; i++)
483 {
484 // Confirm that cover is closed
485 if (TRUE == PAD_DetectFold())
486 {
487 // Turn off power
488 (void)PM_ForceToPowerOff();
489 }
490 OS_WaitVBlankIntr();
491 *((u16 *)(HW_BG_PLTT + 2)) = data;
492 data += target;
493 }
494 target = (u16)(~target + 1);
495 }
496 }
497 }
498
499 /*---------------------------------------------------------------------------*
500 Name: OS_ShowAttentionChina
501
502 Description: Displays logo for China and notice for prescribed time.
503
504 Arguments: isbn: String array relating to the ISBN number (and other information)
505 param: Behavior related to displaying ISBN numbers
506
507 Returns: None.
508 *---------------------------------------------------------------------------*/
OS_ShowAttentionChina(const char ** isbn,OSChinaIsbn param)509 SDK_WEAK_SYMBOL void OS_ShowAttentionChina(const char **isbn, OSChinaIsbn param)
510 {
511 /* Structure for saving register */
512 struct
513 {
514 u32 gx_dispcnt;
515 u32 gxs_dispcnt;
516 u16 gx_powcnt;
517 u16 gx_dispstat;
518 u16 gx_bright;
519 u16 gxs_bright;
520 u16 gx_bg0cnt;
521 u16 gxs_bg0cnt;
522 u32 gx_bg0ofs;
523 u32 gxs_bg0ofs;
524 u8 gx_vramcnt_a;
525 u8 gx_vramcnt_c;
526 u8 gx_vramcnt_d;
527 u8 reserved[1];
528
529 OSIrqFunction irqFunction;
530 OSIrqMask irqMask;
531 BOOL irq;
532 OSIntrMode interrupts;
533
534 }
535 shelter;
536
537 /* Pre-processing */
538 {
539 /* Save each register */
540 shelter.gx_dispstat = reg_GX_DISPSTAT;
541 shelter.gx_dispcnt = reg_GX_DISPCNT;
542 shelter.gxs_dispcnt = reg_GXS_DB_DISPCNT;
543 shelter.gx_bright = reg_GX_MASTER_BRIGHT;
544 shelter.gxs_bright = reg_GXS_DB_MASTER_BRIGHT;
545 shelter.gx_powcnt = reg_GX_POWCNT;
546 shelter.gx_vramcnt_a = reg_GX_VRAMCNT_A;
547 shelter.gx_vramcnt_c = reg_GX_VRAMCNT_C;
548 shelter.gx_vramcnt_d = reg_GX_VRAMCNT_D;
549 shelter.gx_bg0cnt = reg_G2_BG0CNT;
550 shelter.gxs_bg0cnt = reg_G2S_DB_BG0CNT;
551 shelter.gx_bg0ofs = reg_G2_BG0OFS;
552 shelter.gxs_bg0ofs = reg_G2S_DB_BG0OFS;
553
554 /* Stop display */
555 reg_GX_DISPCNT = 0;
556 reg_GXS_DB_DISPCNT = 0;
557
558 /* Initialize power control */
559 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
560 {
561 /* When changing LCD enable from OFF to ON, wait 100 ms */
562 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
563 }
564 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
565 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
566
567 /* Initialization of master brightness */
568 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) | 16);
569 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
570
571 /* Prepare display of logo screen */
572 {
573 reg_GX_VRAMCNT_A =
574 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
575 reg_G2_BG0CNT =
576 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
577 (GX_BG_COLORMODE_256 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
578 <<
579 REG_G2_BG0CNT_SCREENBASE_SHIFT)
580 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
581 <<
582 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
583 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
584 reg_G2_BG0OFS = 0;
585 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
586 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
587
588 /* Load character data into VRAM */
589 {
590 void *const src = LoadImage(IMAGE_LOGO_CHR, NULL);
591 MI_UncompressLZ16(src, (u32 *)HW_BG_VRAM);
592 }
593 /* Load screen data into VRAM */
594 {
595 u16 *src = (u16*)LoadImage(IMAGE_LOGO_SCR, NULL);
596 u16 *dst;
597 s32 i;
598 s32 j;
599
600 // Place 12x12 (96x96-pixel) screen data at the center
601 SVC_CpuClearFast(0, (u32 *)(HW_BG_VRAM + 0xf000), 32*24*2);
602 dst = (u16*)(HW_BG_VRAM + 0xf000 + ((6*32+10)*2));
603
604 for (i = 0; i < 12; i++, dst += 32)
605 {
606 for (j = 0; j < 12; j++, src++)
607 {
608 dst[j] = *src;
609 }
610 }
611 }
612 /* Load palette data into VRAM */
613 {
614 u32 size;
615 void *const src = LoadImage(IMAGE_LOGO_PAL, &size);
616 SVC_CpuCopyFast(src, (u32 *)(HW_BG_PLTT), size);
617 }
618 }
619
620 /* Prepare to display Notes screen */
621 {
622 reg_GX_VRAMCNT_C =
623 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
624 reg_GX_VRAMCNT_D =
625 (u8)((4 << REG_GX_VRAMCNT_D_MST_SHIFT) | (1 << REG_GX_VRAMCNT_D_E_SHIFT));
626 reg_G2S_DB_BG0CNT =
627 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
628 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) |
629 (GX_BG_SCRBASE_0xf000 << REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT) |
630 (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) |
631 (GX_BG_EXTPLTT_01 << REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT) | (0 <<
632 REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
633 reg_G2S_DB_BG0OFS = 0;
634 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
635 ((GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ) <<
636 REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
637
638 /* Load character data into VRAM */
639 {
640 u32 size;
641 void *src;
642 /* Background text */
643 src = LoadImage(IMAGE_NOTES_CHR, &size);
644 MI_UncompressLZ16(src, (u32 *)(HW_DB_BG_VRAM));
645 /* OBJ text */
646 src = LoadImage(IMAGE_NOTES_DIGIT, &size);
647 MI_UncompressLZ16(src, (u32 *)(HW_DB_OBJ_VRAM));
648 SVC_CpuClear(0xC0, (void *)HW_DB_OAM, HW_OAM_SIZE, 32);
649 }
650 /* Load screen data into VRAM */
651 {
652 u32 size;
653 void *const src = LoadImage(IMAGE_NOTES_SCR, &size);
654 SVC_CpuCopyFast(src, (u32 *)(HW_DB_BG_VRAM + 0xf000), size);
655 }
656
657 // Display settings for the ISBN string
658 SetISBNString(isbn, (BOOL)(param != OS_CHINA_ISBN_NO_DISP));
659
660 /* Edit palette */
661 *((u16 *)(HW_DB_BG_PLTT + 0)) = 0x7fff;
662 *((u16 *)(HW_DB_BG_PLTT + 2)) = 0x0000;
663 *((u16 *)(HW_DB_OBJ_PLTT + 0)) = 0x7fff;
664 *((u16 *)(HW_DB_OBJ_PLTT + 2)) = 0x0000;
665 }
666
667 /* Start display */
668 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
669 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
670
671 /* Interrupt settings */
672 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
673 shelter.irqFunction = OS_GetIrqFunction(OS_IE_V_BLANK);
674 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
675 shelter.irqMask = OS_EnableIrqMask(OS_IE_V_BLANK);
676 shelter.irq = OS_EnableIrq();
677 shelter.interrupts = OS_EnableInterrupts();
678
679 }
680
681 /* Main process */
682 {
683 s32 i;
684 u16 pad_old;
685 u16 pad;
686
687 /* Fade in */
688 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
689 {
690 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
691 16 - ((i + 1) * 16 / OSi_FORCHINA_FADE_SPAN));
692 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
693 WaitForNextFrame();
694 }
695
696 /* Skip based on button input */
697 pad_old = PAD_Read();
698 for (i = 0; i < OSi_FORCHINA_DISP_SPAN; i++)
699 {
700 pad = PAD_Read();
701 if ((param == OS_CHINA_ISBN_CHECK_ROM) && (~pad_old & pad))
702 {
703 /* If any button push trigger was detected, skip */
704 break;
705 }
706 pad_old = pad;
707 WaitForNextFrame();
708
709 // On ROMs used for censorship purposes, do not exit until a button is pressed
710 if(param == OS_CHINA_ISBN_CHECK_ROM) i = 0;
711 }
712
713 /* Fade out */
714 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
715 {
716 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
717 (i + 1) * 16 / OSi_FORCHINA_FADE_SPAN);
718 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
719 WaitForNextFrame();
720 }
721 }
722
723 /* Post-processing */
724 {
725 /* Stop display */
726 reg_GX_DISPCNT &= ~(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
727 reg_GXS_DB_DISPCNT &= ~REG_GXS_DB_DISPCNT_MODE_MASK;
728
729 /* Restore interrupt-related items */
730 (void)OS_RestoreInterrupts(shelter.interrupts);
731 (void)OS_RestoreIrq(shelter.irq);
732 (void)OS_SetIrqMask(shelter.irqMask);
733 OS_SetIrqFunction(OS_IE_V_BLANK, shelter.irqFunction);
734 reg_GX_DISPSTAT &= ~REG_GX_DISPSTAT_VBI_MASK;
735
736 /* Clear used VRAM (cannot restore initial values because the size is too big) */
737 SVC_CpuClearFast(0, (u32 *)HW_BG_VRAM, 0x10000);
738 SVC_CpuClearFast(0, (u32 *)HW_BG_PLTT, 0x200);
739 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_VRAM, 0x10000);
740 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_PLTT, 0x04);
741 SVC_CpuClearFast(0, (u32 *)HW_DB_OAM, HW_OAM_SIZE);
742
743 /* Restore each register */
744 reg_G2S_DB_BG0OFS = shelter.gxs_bg0ofs;
745 reg_G2_BG0OFS = shelter.gx_bg0ofs;
746 reg_G2S_DB_BG0CNT = shelter.gxs_bg0cnt;
747 reg_G2_BG0CNT = shelter.gx_bg0cnt;
748 reg_GX_VRAMCNT_D = shelter.gx_vramcnt_d;
749 reg_GX_VRAMCNT_C = shelter.gx_vramcnt_c;
750 reg_GX_VRAMCNT_A = shelter.gx_vramcnt_a;
751 reg_GX_POWCNT = shelter.gx_powcnt;
752 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
753 {
754 /* When changing LCD enable from ON to OFF, wait 100 ms */
755 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
756 }
757 reg_GXS_DB_MASTER_BRIGHT = shelter.gxs_bright;
758 reg_GX_MASTER_BRIGHT = shelter.gx_bright;
759 reg_GXS_DB_DISPCNT = shelter.gxs_dispcnt;
760 reg_GX_DISPCNT = shelter.gx_dispcnt;
761 reg_GX_DISPSTAT = shelter.gx_dispstat;
762 }
763 }
764
765 /*---------------------------------------------------------------------------*
766 End of file
767 *---------------------------------------------------------------------------*/
768