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