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-11-24#$
14 $Rev: 11189 $
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);
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: u32 pointer to 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 ending OS_ShowAttentionChina(),
111 each heap is deleted with OS_ClearAlloc() so
112 you don't need to explicitly free the memory returned here.
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
246 Returns: None.
247
248 Note: A single character is equivalent to two 8x16 characters.
249 The actual character sizes are as follows.
250 '-' : 5x10
251 '0'-'9' : 7x10
252 *---------------------------------------------------------------------------*/
SetISBNString(const char ** isbn)253 static void SetISBNString(const char **isbn)
254 {
255 s32 i, j;
256 const struct
257 {
258 u8 x, y; /* Leading display offset */
259 u8 length; /* Display character count */
260 }
261 pos[] =
262 {
263 {
264 80, 136, 17}
265 , /* ISBN */
266 {
267 125, 151, 12}
268 , /* Joint registration number */
269 {
270 106, 167, 4}
271 , /* (China-specific information displayed on left side) */
272 {
273 139, 167, 3}
274 , /* (China-specific information displayed on right side) */
275 }
276 ;
277 const int count = sizeof(pos) / sizeof(*pos); /* Total number of lines */
278 const int digit_num = 12; /* Number of characters for the digit display ("0123456789- ") */
279 u16 pos_x;
280 u16 pos_y;
281 u16 index;
282 u16 width;
283
284 GXOamAttr *dst = (GXOamAttr *)HW_DB_OAM;
285 for (i = 0; i < count; i++)
286 {
287 pos_x = pos[i].x;
288 pos_y = pos[i].y;
289
290 for (j = 0; j < pos[i].length; ++j)
291 {
292 if (isbn[i][j] == '-')
293 {
294 index = 10;
295 width = 5;
296 }
297 else if ((isbn[i][j] >= '0') && (isbn[i][j] <= '9'))
298 {
299 index = (u16)(isbn[i][j] - '0');
300 width = 7;
301 }
302 else
303 {
304 index = 11;
305 width = 7;
306 }
307
308 dst[0].attr01 = (u32)((pos_x << 16) | (pos_y << 0));
309 dst[0].attr2 = index;
310 dst[1].attr01 = (u32)((pos_x << 16) | (pos_y + 8 << 0));
311 dst[1].attr2 = (u16)(index + digit_num);
312
313 pos_x += width;
314 dst += 2;
315 }
316 }
317 }
318
319 /*---------------------------------------------------------------------------*
320 Name: OS_InitChina
321
322 Description: Initializes SDK's OS library.
323 Exclusively for applications for the China region.
324 Use this function instead of OS_Init function.
325
326 Arguments: isbn: String array relating to the ISBN number (and other information)
327 {
328 char ISBN[ 17 ] ,
329 char Joint registration code [ 12 ] ,
330 char (China-specific information displayed on left side) [ 4 ] ,
331 char (China-specific information displayed on right side) [ 3 ]
332 }
333
334 param: Behavior related to displaying ISBN numbers
335
336 Returns: None.
337 *---------------------------------------------------------------------------*/
OS_InitChina(const char ** isbn,OSChinaIsbn param)338 void OS_InitChina(const char **isbn, OSChinaIsbn param)
339 {
340 SDK_REFER_SYMBOL(checkString);
341
342 #ifdef SDK_ARM9
343 //---- System shared area check
344 SDK_ASSERT((u32)&(OS_GetSystemWork()->command_area) == HW_CMD_AREA);
345 #endif // SDK_ARM9
346
347 //---- Initialize SDK OS common
348 OSi_InitCommon();
349
350 //---- Check if possible to boot
351 // CheckLanguageCode(); Eliminated starting restrictions
352
353 //---- Display logo and notes about health care
354 OS_ShowAttentionChina(isbn, param);
355 }
356
357 /*---------------------------------------------------------------------------*
358 Name: CheckLanguageCode
359
360 Description: Confirms whether to perform exclusive startup control based on language code.
361
362 Arguments: None.
363
364 Returns: None.
365 *---------------------------------------------------------------------------*/
CheckLanguageCode(void)366 static void CheckLanguageCode(void)
367 {
368 NVRAMConfig *src;
369
370 src = (NVRAMConfig *)(OS_GetSystemWork()->nvramUserInfo);
371 // Confirms whether it has been determined that language code should not be booted by ARM7
372 if ((src->ncd.version == 0xff) && (src->ncd.option.language == 7))
373 {
374 DispExclusiveMessage();
375 // Never return
376 }
377 }
378
379 /*---------------------------------------------------------------------------*
380 Name: DispExclusiveMessage
381
382 Description: Indicates that exclusive startup control was performed based on language code.
383
384 Arguments: None.
385
386 Returns: None.
387 *---------------------------------------------------------------------------*/
DispExclusiveMessage(void)388 static void DispExclusiveMessage(void)
389 {
390 // Stop display
391 reg_GX_DISPCNT = 0;
392 reg_GXS_DB_DISPCNT = 0;
393
394 // Initialize power control
395 if (!(reg_GX_POWCNT & REG_GX_POWCNT_LCD_MASK))
396 {
397 // When changing LCD enable from OFF to ON, wait 100 ms
398 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
399 }
400 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
401 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
402 // Initialization of master brightness
403 reg_GX_MASTER_BRIGHT = 0;
404 reg_GXS_DB_MASTER_BRIGHT = 0;
405
406 // Set main LCD
407 {
408 reg_GX_VRAMCNT_A =
409 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
410 reg_G2_BG0CNT =
411 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
412 (GX_BG_COLORMODE_16 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000 <<
413 REG_G2_BG0CNT_SCREENBASE_SHIFT)
414 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01 <<
415 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
416 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
417 reg_G2_BG0HOFS = (u16)(-(256 - OSi_ONLY_FORCHINA_DOT_WIDTH) / 2);
418 reg_G2_BG0VOFS = (u16)(-(192 - OSi_ONLY_FORCHINA_DOT_HEIGHT) / 2 + 2);
419 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
420 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
421 // Load character data into VRAM
422 {
423 MIUnpackBitsParam param = { OSi_ONLY_FORCHINA_CHAR_SIZE, 1, 4, 0, 0 };
424
425 SVC_UnpackBits(only_forChina_charData, (u32 *)(HW_BG_VRAM + 0x20), ¶m);
426 }
427 // Load screen data into VRAM
428 {
429 s32 i;
430 s32 j;
431 u16 code = 1;
432 u16 *dst = (u16 *)(HW_BG_VRAM + 0xf000);
433
434 for (i = 0; i < OSi_ONLY_FORCHINA_CHAR_HEIGHT; i++)
435 {
436 for (j = 0; j < OSi_ONLY_FORCHINA_CHAR_WIDTH; j++)
437 {
438 *dst++ = code++;
439 }
440 dst += (0x20 - OSi_ONLY_FORCHINA_CHAR_WIDTH);
441 }
442 }
443 }
444
445 // Set sub LCD
446 {
447 reg_GX_VRAMCNT_C =
448 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
449 reg_G2S_DB_BG0CNT =
450 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
451 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
452 <<
453 REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT)
454 | (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
455 <<
456 REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT)
457 | (0 << REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
458 reg_G2S_DB_BG0OFS = 0;
459 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
460 (GX_PLANEMASK_BG0 << REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
461 }
462
463 // V-Blank interrupt settings
464 (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
465 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
466 (void)OS_EnableIrq();
467 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
468
469 // Start display
470 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
471 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
472
473 {
474 u16 data = 0x001f;
475 u16 target = 0x0001 << 5;
476 s32 i;
477
478 // Cycle palette colors between red and yellow and loop indefinitely
479 while (TRUE)
480 {
481 for (i = 0; i < 31; i++)
482 {
483 // Confirm that cover is closed
484 if (TRUE == PAD_DetectFold())
485 {
486 // Turn off power
487 (void)PM_ForceToPowerOff();
488 }
489 OS_WaitVBlankIntr();
490 *((u16 *)(HW_BG_PLTT + 2)) = data;
491 data += target;
492 }
493 target = (u16)(~target + 1);
494 }
495 }
496 }
497
498 /*---------------------------------------------------------------------------*
499 Name: OS_ShowAttentionChina
500
501 Description: Displays logo for China and notice for prescribed time.
502
503 Arguments: isbn: String array relating to the ISBN number (and other information)
504 param: Behavior related to displaying ISBN numbers
505
506 Returns: None.
507 *---------------------------------------------------------------------------*/
OS_ShowAttentionChina(const char ** isbn,OSChinaIsbn param)508 void OS_ShowAttentionChina(const char **isbn, OSChinaIsbn param)
509 {
510 /* Structure for saving register */
511 struct
512 {
513 u32 gx_dispcnt;
514 u32 gxs_dispcnt;
515 u16 gx_powcnt;
516 u16 gx_dispstat;
517 u16 gx_bright;
518 u16 gxs_bright;
519 u16 gx_bg0cnt;
520 u16 gxs_bg0cnt;
521 u32 gx_bg0ofs;
522 u32 gxs_bg0ofs;
523 u8 gx_vramcnt_a;
524 u8 gx_vramcnt_c;
525 u8 gx_vramcnt_d;
526 u8 reserved[1];
527
528 OSIrqFunction irqFunction;
529 OSIrqMask irqMask;
530 BOOL irq;
531 OSIntrMode interrupts;
532
533 }
534 shelter;
535
536 // Returns immediately if not displaying ISBN.
537 if ( param == OS_CHINA_ISBN_NO_DISP )
538 {
539 return;
540 }
541
542 /* Pre-processing */
543 {
544 /* Save each register */
545 shelter.gx_dispstat = reg_GX_DISPSTAT;
546 shelter.gx_dispcnt = reg_GX_DISPCNT;
547 shelter.gxs_dispcnt = reg_GXS_DB_DISPCNT;
548 shelter.gx_bright = reg_GX_MASTER_BRIGHT;
549 shelter.gxs_bright = reg_GXS_DB_MASTER_BRIGHT;
550 shelter.gx_powcnt = reg_GX_POWCNT;
551 shelter.gx_vramcnt_a = reg_GX_VRAMCNT_A;
552 shelter.gx_vramcnt_c = reg_GX_VRAMCNT_C;
553 shelter.gx_vramcnt_d = reg_GX_VRAMCNT_D;
554 shelter.gx_bg0cnt = reg_G2_BG0CNT;
555 shelter.gxs_bg0cnt = reg_G2S_DB_BG0CNT;
556 shelter.gx_bg0ofs = reg_G2_BG0OFS;
557 shelter.gxs_bg0ofs = reg_G2S_DB_BG0OFS;
558
559 /* Stop display */
560 reg_GX_DISPCNT = 0;
561 reg_GXS_DB_DISPCNT = 0;
562
563 /* Initialize power control */
564 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
565 {
566 /* When changing LCD enable from OFF to ON, wait 100 ms */
567 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
568 }
569 reg_GX_POWCNT = (u16)(REG_GX_POWCNT_DSEL_MASK | REG_GX_POWCNT_E2DG_MASK |
570 REG_GX_POWCNT_E2DGB_MASK | REG_GX_POWCNT_LCD_MASK);
571
572 /* Initialization of master brightness */
573 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) | 16);
574 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
575
576 /* Prepare display of logo screen */
577 {
578 reg_GX_VRAMCNT_A =
579 (u8)((1 << REG_GX_VRAMCNT_A_MST_SHIFT) | (1 << REG_GX_VRAMCNT_A_E_SHIFT));
580 reg_G2_BG0CNT =
581 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2_BG0CNT_SCREENSIZE_SHIFT) |
582 (GX_BG_COLORMODE_256 << REG_G2_BG0CNT_COLORMODE_SHIFT) | (GX_BG_SCRBASE_0xf000
583 <<
584 REG_G2_BG0CNT_SCREENBASE_SHIFT)
585 | (GX_BG_CHARBASE_0x00000 << REG_G2_BG0CNT_CHARBASE_SHIFT) | (GX_BG_EXTPLTT_01
586 <<
587 REG_G2_BG0CNT_BGPLTTSLOT_SHIFT)
588 | (0 << REG_G2_BG0CNT_PRIORITY_SHIFT));
589 reg_G2_BG0OFS = 0;
590 reg_GX_DISPCNT |= ((GX_BGMODE_0 << REG_GX_DISPCNT_BGMODE_SHIFT) |
591 (GX_PLANEMASK_BG0 << REG_GX_DISPCNT_DISPLAY_SHIFT));
592
593 /* Load character data into VRAM */
594 {
595 void *const src = LoadImage(IMAGE_LOGO_CHR, NULL);
596 MI_UncompressLZ16(src, (u32 *)HW_BG_VRAM);
597 }
598 /* Load screen data into VRAM */
599 {
600 u16 *src = (u16*)LoadImage(IMAGE_LOGO_SCR, NULL);
601 u16 *dst;
602 s32 i;
603 s32 j;
604
605 // Place 12x12 (96x96-pixel) screen data at the center
606 SVC_CpuClearFast(0, (u32 *)(HW_BG_VRAM + 0xf000), 32*24*2);
607 dst = (u16*)(HW_BG_VRAM + 0xf000 + ((6*32+10)*2));
608
609 for (i = 0; i < 12; i++, dst += 32)
610 {
611 for (j = 0; j < 12; j++, src++)
612 {
613 dst[j] = *src;
614 }
615 }
616 }
617 /* Load palette data into VRAM */
618 {
619 u32 size;
620 void *const src = LoadImage(IMAGE_LOGO_PAL, &size);
621 SVC_CpuCopyFast(src, (u32 *)(HW_BG_PLTT), size);
622 }
623 }
624
625 /* Prepare to display Notes screen */
626 {
627 reg_GX_VRAMCNT_C =
628 (u8)((4 << REG_GX_VRAMCNT_C_MST_SHIFT) | (1 << REG_GX_VRAMCNT_C_E_SHIFT));
629 reg_GX_VRAMCNT_D =
630 (u8)((4 << REG_GX_VRAMCNT_D_MST_SHIFT) | (1 << REG_GX_VRAMCNT_D_E_SHIFT));
631 reg_G2S_DB_BG0CNT =
632 (u16)((GX_BG_SCRSIZE_TEXT_256x256 << REG_G2S_DB_BG0CNT_SCREENSIZE_SHIFT) |
633 (GX_BG_COLORMODE_16 << REG_G2S_DB_BG0CNT_COLORMODE_SHIFT) |
634 (GX_BG_SCRBASE_0xf000 << REG_G2S_DB_BG0CNT_SCREENBASE_SHIFT) |
635 (GX_BG_CHARBASE_0x00000 << REG_G2S_DB_BG0CNT_CHARBASE_SHIFT) |
636 (GX_BG_EXTPLTT_01 << REG_G2S_DB_BG0CNT_BGPLTTSLOT_SHIFT) | (0 <<
637 REG_G2S_DB_BG0CNT_PRIORITY_SHIFT));
638 reg_G2S_DB_BG0OFS = 0;
639 reg_GXS_DB_DISPCNT |= ((GX_BGMODE_0 << REG_GXS_DB_DISPCNT_BGMODE_SHIFT) |
640 ((GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ) <<
641 REG_GXS_DB_DISPCNT_DISPLAY_SHIFT));
642
643 /* Load character data into VRAM */
644 {
645 u32 size;
646 void *src;
647 /* Background text */
648 src = LoadImage(IMAGE_NOTES_CHR, &size);
649 MI_UncompressLZ16(src, (u32 *)(HW_DB_BG_VRAM));
650 /* OBJ text */
651 src = LoadImage(IMAGE_NOTES_DIGIT, &size);
652 MI_UncompressLZ16(src, (u32 *)(HW_DB_OBJ_VRAM));
653 SVC_CpuClear(0xC0, (void *)HW_DB_OAM, HW_OAM_SIZE, 32);
654 }
655 /* Load screen data into VRAM */
656 {
657 u32 size;
658 void *const src = LoadImage(IMAGE_NOTES_SCR, &size);
659 SVC_CpuCopyFast(src, (u32 *)(HW_DB_BG_VRAM + 0xf000), size);
660 }
661
662 // Display settings for the ISBN string
663 SetISBNString(isbn);
664
665 /* Edit palette */
666 *((u16 *)(HW_DB_BG_PLTT + 0)) = 0x7fff;
667 *((u16 *)(HW_DB_BG_PLTT + 2)) = 0x0000;
668 *((u16 *)(HW_DB_OBJ_PLTT + 0)) = 0x7fff;
669 *((u16 *)(HW_DB_OBJ_PLTT + 2)) = 0x0000;
670 }
671
672 /* Start display */
673 reg_GX_DISPCNT |= (u32)(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
674 reg_GXS_DB_DISPCNT |= (u32)(REG_GXS_DB_DISPCNT_MODE_MASK);
675
676 /* Interrupt settings */
677 reg_GX_DISPSTAT |= REG_GX_DISPSTAT_VBI_MASK;
678 shelter.irqFunction = OS_GetIrqFunction(OS_IE_V_BLANK);
679 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
680 shelter.irqMask = OS_EnableIrqMask(OS_IE_V_BLANK);
681 shelter.irq = OS_EnableIrq();
682 shelter.interrupts = OS_EnableInterrupts();
683
684 }
685
686 /* Main process */
687 {
688 s32 i;
689 u16 pad_old;
690 u16 pad;
691
692 /* Fade in */
693 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
694 {
695 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
696 16 - ((i + 1) * 16 / OSi_FORCHINA_FADE_SPAN));
697 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
698 WaitForNextFrame();
699 }
700
701 /* Skip based on button input */
702 pad_old = PAD_Read();
703 for (i = 0; i < OSi_FORCHINA_DISP_SPAN; i++)
704 {
705 pad = PAD_Read();
706 if ((param == OS_CHINA_ISBN_CHECK_ROM) && (~pad_old & pad))
707 {
708 /* If any button presses were detected, skip */
709 break;
710 }
711 pad_old = pad;
712 WaitForNextFrame();
713
714 // On ROMs used for censorship purposes, do not exit until a button is pressed
715 if(param == OS_CHINA_ISBN_CHECK_ROM) i = 0;
716 }
717
718 /* Fade out */
719 for (i = 0; i < OSi_FORCHINA_FADE_SPAN; i++)
720 {
721 reg_GX_MASTER_BRIGHT = (u16)((1 << REG_GX_MASTER_BRIGHT_E_MOD_SHIFT) |
722 (i + 1) * 16 / OSi_FORCHINA_FADE_SPAN);
723 reg_GXS_DB_MASTER_BRIGHT = reg_GX_MASTER_BRIGHT;
724 WaitForNextFrame();
725 }
726 }
727
728 /* Post-processing */
729 {
730 /* Stop display */
731 reg_GX_DISPCNT &= ~(GX_DISPMODE_GRAPHICS << REG_GX_DISPCNT_MODE_SHIFT);
732 reg_GXS_DB_DISPCNT &= ~REG_GXS_DB_DISPCNT_MODE_MASK;
733
734 /* Restore interrupt-related items */
735 (void)OS_RestoreInterrupts(shelter.interrupts);
736 (void)OS_RestoreIrq(shelter.irq);
737 (void)OS_SetIrqMask(shelter.irqMask);
738 OS_SetIrqFunction(OS_IE_V_BLANK, shelter.irqFunction);
739 reg_GX_DISPSTAT &= ~REG_GX_DISPSTAT_VBI_MASK;
740
741 /* Clear used VRAM (cannot restore initial values because the size is too big) */
742 SVC_CpuClearFast(0, (u32 *)HW_BG_VRAM, 0x10000);
743 SVC_CpuClearFast(0, (u32 *)HW_BG_PLTT, 0x200);
744 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_VRAM, 0x10000);
745 SVC_CpuClearFast(0, (u32 *)HW_DB_BG_PLTT, 0x04);
746 SVC_CpuClearFast(0, (u32 *)HW_DB_OAM, HW_OAM_SIZE);
747
748 /* Restore each register */
749 reg_G2S_DB_BG0OFS = shelter.gxs_bg0ofs;
750 reg_G2_BG0OFS = shelter.gx_bg0ofs;
751 reg_G2S_DB_BG0CNT = shelter.gxs_bg0cnt;
752 reg_G2_BG0CNT = shelter.gx_bg0cnt;
753 reg_GX_VRAMCNT_D = shelter.gx_vramcnt_d;
754 reg_GX_VRAMCNT_C = shelter.gx_vramcnt_c;
755 reg_GX_VRAMCNT_A = shelter.gx_vramcnt_a;
756 reg_GX_POWCNT = shelter.gx_powcnt;
757 if (!(shelter.gx_powcnt & REG_GX_POWCNT_LCD_MASK))
758 {
759 /* When changing LCD enable from ON to OFF, wait 100 ms */
760 SVC_WaitByLoop(HW_CPU_CLOCK_ARM9 / 40);
761 }
762 reg_GXS_DB_MASTER_BRIGHT = shelter.gxs_bright;
763 reg_GX_MASTER_BRIGHT = shelter.gx_bright;
764 reg_GXS_DB_DISPCNT = shelter.gxs_dispcnt;
765 reg_GX_DISPCNT = shelter.gx_dispcnt;
766 reg_GX_DISPSTAT = shelter.gx_dispstat;
767 }
768 }
769
770 /*---------------------------------------------------------------------------*
771 End of file
772 *---------------------------------------------------------------------------*/
773