2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Main bootmenu code
9 #include <aros/config.h>
10 #include <aros/debug.h>
12 #include <proto/bootloader.h>
13 #include <proto/exec.h>
14 #include <proto/graphics.h>
15 #include <proto/intuition.h>
16 #include <proto/expansion.h>
17 #include <proto/oop.h>
18 #include <devices/keyboard.h>
19 #include <devices/rawkeycodes.h>
20 #include <devices/timer.h>
21 #include <exec/memory.h>
22 #include <graphics/driver.h>
23 #include <libraries/expansionbase.h>
24 #include <libraries/configvars.h>
25 #include <dos/filehandler.h>
26 #include <devices/trackdisk.h>
27 #include <exec/rawfmt.h>
28 #include <aros/bootloader.h>
29 #include <aros/symbolsets.h>
31 #include LC_LIBDEFS_FILE
33 #include "dosboot_intern.h"
38 #define PAGE_DISPLAY 3
39 #define PAGE_EXPANSION 4
41 #define EXIT_BOOT_WNSS 6
43 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
45 #define INITHIDDS_KLUDGE
49 #ifdef INITHIDDS_KLUDGE
52 * This is an extremely obsolete kludge.
53 * It's still needed for ATI driver on PowerPC native.
56 static BOOL
init_gfx(STRPTR gfxclassname
, BOOL bootmode
, LIBBASETYPEPTR DOSBootBase
)
61 D(bug("[BootMenu] init_gfx('%s')\n", gfxclassname
));
63 GfxBase
= (void *)OpenLibrary("graphics.library", 41);
67 gfxclass
= OOP_FindClass(gfxclassname
);
70 if (!AddDisplayDriver(gfxclass
, NULL
, DDRV_BootMode
, bootmode
, TAG_DONE
))
74 CloseLibrary(&GfxBase
->LibNode
);
76 ReturnBool ("init_gfxhidd", success
);
79 static BOOL
initHidds(LIBBASETYPEPTR DOSBootBase
)
81 struct BootConfig
*bootcfg
= &DOSBootBase
->bm_BootConfig
;
83 D(bug("[BootMenu] initHidds()\n"));
85 if (bootcfg
->gfxhidd
) {
86 if (!OpenLibrary(bootcfg
->gfxlib
, 0))
89 if (!init_gfx(bootcfg
->gfxhidd
, bootcfg
->bootmode
, DOSBootBase
))
93 D(bug("[BootMenu] initHidds: Hidds initialised\n"));
99 static struct Gadget
*createGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
101 /* Create Option Gadgets */
102 DOSBootBase
->bm_MainGadgets
.bootopt
= createButton(
104 NULL
, "Boot Options...",
105 BUTTON_BOOT_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
106 DOSBootBase
->bm_MainGadgets
.displayopt
= createButton(
108 DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
, "Display Options...",
109 BUTTON_DISPLAY_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
110 DOSBootBase
->bm_MainGadgets
.expboarddiag
= createButton(
112 DOSBootBase
->bm_MainGadgets
.displayopt
->gadget
, "Expansion Board Diagnostic...",
113 BUTTON_EXPBOARDDIAG
, (struct DOSBootBase
*)DOSBootBase
);
114 /* Create BOOT Gadgets */
115 DOSBootBase
->bm_MainGadgets
.boot
= createButton(
116 16, DOSBootBase
->bottomY
, 280, 14,
117 DOSBootBase
->bm_MainGadgets
.expboarddiag
->gadget
, "Boot",
118 BUTTON_BOOT
, (struct DOSBootBase
*)DOSBootBase
);
119 DOSBootBase
->bm_MainGadgets
.bootnss
= createButton(
120 344, DOSBootBase
->bottomY
, 280, 14,
121 DOSBootBase
->bm_MainGadgets
.boot
->gadget
, "Boot With No Startup-Sequence",
122 BUTTON_BOOT_WNSS
, (struct DOSBootBase
*)DOSBootBase
);
123 if (!DOSBootBase
->bm_MainGadgets
.bootopt
||
124 !DOSBootBase
->bm_MainGadgets
.displayopt
||
125 !DOSBootBase
->bm_MainGadgets
.expboarddiag
||
126 !DOSBootBase
->bm_MainGadgets
.boot
||
127 !DOSBootBase
->bm_MainGadgets
.bootnss
)
129 return DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
;
132 static struct Gadget
*createGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
134 DOSBootBase
->bm_MainGadgets
.use
= createButton(
135 16, DOSBootBase
->bottomY
, 280, 14,
137 BUTTON_USE
, (struct DOSBootBase
*)DOSBootBase
);
138 DOSBootBase
->bm_MainGadgets
.cancel
= createButton(
139 344, DOSBootBase
->bottomY
, 280, 14,
140 DOSBootBase
->bm_MainGadgets
.use
->gadget
, "Cancel",
141 BUTTON_CANCEL
, (struct DOSBootBase
*)DOSBootBase
);
142 if (!DOSBootBase
->bm_MainGadgets
.use
||
143 !DOSBootBase
->bm_MainGadgets
.cancel
)
145 return DOSBootBase
->bm_MainGadgets
.use
->gadget
;
149 static void freeGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
151 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.boot
, (struct DOSBootBase
*)DOSBootBase
);
152 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootnss
, (struct DOSBootBase
*)DOSBootBase
);
153 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootopt
, (struct DOSBootBase
*)DOSBootBase
);
154 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.displayopt
, (struct DOSBootBase
*)DOSBootBase
);
155 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.expboarddiag
, (struct DOSBootBase
*)DOSBootBase
);
158 static void freeGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
160 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.use
, (struct DOSBootBase
*)DOSBootBase
);
161 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.cancel
, (struct DOSBootBase
*)DOSBootBase
);
164 static struct Gadget
*createGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
166 if (page
== PAGE_MAIN
)
167 return createGadgetsBoot(DOSBootBase
);
169 return createGadgetsUseCancel(DOSBootBase
);
171 static void freeGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
173 if (page
== PAGE_MAIN
)
174 freeGadgetsBoot(DOSBootBase
);
176 freeGadgetsUseCancel(DOSBootBase
);
179 static void toggleMode(LIBBASETYPEPTR DOSBootBase
)
183 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
185 if (OpenResource("ciaa.resource")) {
186 volatile UWORD
*beamcon0
= (UWORD
*)0xdff1dc;
187 GfxBase
->DisplayFlags
^= PAL
| NTSC
;
188 *beamcon0
= (GfxBase
->DisplayFlags
& PAL
) ? 0x0020 : 0x0000;
193 static UWORD
msgLoop(LIBBASETYPEPTR DOSBootBase
, struct Window
*win
)
196 struct IntuiMessage
*msg
;
199 D(bug("[BootMenu] msgLoop(DOSBootBase @ %p, Window @ %p)\n", DOSBootBase
, win
));
205 WaitPort(win
->UserPort
);
206 while ((msg
= (struct IntuiMessage
*)GetMsg(win
->UserPort
)))
208 if (msg
->Class
== IDCMP_VANILLAKEY
) {
211 else if (msg
->Code
>= '1' && msg
->Code
<= '3')
212 exit
= PAGE_MAIN
+ msg
->Code
- '0';
214 toggleMode(DOSBootBase
);
215 } else if (msg
->Class
== IDCMP_GADGETUP
)
221 DOSBootBase
->db_BootFlags
&= ~BF_NO_STARTUP_SEQUENCE
;
224 case BUTTON_BOOT_WNSS
:
225 DOSBootBase
->db_BootFlags
|= BF_NO_STARTUP_SEQUENCE
;
226 exit
= EXIT_BOOT_WNSS
;
230 case BUTTON_CONTINUE
:
233 case BUTTON_BOOT_OPTIONS
:
236 case BUTTON_EXPBOARDDIAG
:
237 exit
= PAGE_EXPANSION
;
239 case BUTTON_DISPLAY_OPTIONS
:
244 ReplyMsg((struct Message
*)msg
);
249 bug("[BootMenu] msgLoop: Window lacks a userport!\n");
253 while ((msg
=(struct IntuiMessage
*)GetMsg(win
->UserPort
)))
254 ReplyMsg(&msg
->ExecMessage
);
258 static void initPageExpansion(LIBBASETYPEPTR DOSBootBase
)
260 struct Window
*win
= DOSBootBase
->bm_Window
;
261 struct ExpansionBase
*ExpansionBase
= DOSBootBase
->bm_ExpansionBase
;
262 struct ConfigDev
*cd
;
266 SetAPen(win
->RPort
, 1);
269 while ((cd
= FindConfigDev(cd
, -1, -1))) {
270 NewRawDoFmt("%2d: %08lx - %08lx (%08lx) %5d %3d %08lx", RAWFMTFUNC_STRING
, text
,
272 cd
->cd_BoardAddr
, cd
->cd_BoardAddr
+ cd
->cd_BoardSize
- 1, cd
->cd_BoardSize
,
273 cd
->cd_Rom
.er_Manufacturer
, cd
->cd_Rom
.er_Product
, cd
->cd_Rom
.er_SerialNumber
);
274 if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROIII
)
276 else if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROII
)
280 if (cd
->cd_Rom
.er_Type
& ERTF_DIAGVALID
)
281 strcat(text
, " ROM");
282 if (cd
->cd_Rom
.er_Type
& ERTF_MEMLIST
)
283 strcat(text
, " RAM");
284 Move(win
->RPort
, 20, y
);
285 Text(win
->RPort
, text
, strlen(text
));
290 static BOOL
bstreqcstr(BSTR bstr
, CONST_STRPTR cstr
)
296 blen
= AROS_BSTR_strlen(bstr
);
300 return (memcmp(AROS_BSTR_ADDR(bstr
),cstr
,clen
) == 0);
303 void selectBootDevice(LIBBASETYPEPTR DOSBootBase
)
307 if (DOSBootBase
->db_BootDevice
== NULL
&&
308 DOSBootBase
->db_BootNode
!= NULL
)
311 Forbid(); /* .. access to ExpansionBase->MountList */
313 if (DOSBootBase
->db_BootNode
== NULL
&& DOSBootBase
->db_BootDevice
== NULL
)
315 bn
= (APTR
)GetHead(&DOSBootBase
->bm_ExpansionBase
->MountList
);
319 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
321 struct DeviceNode
*dn
;
323 dn
= bn
->bn_DeviceNode
;
324 if (dn
== NULL
|| dn
->dn_Name
== BNULL
)
327 if (bstreqcstr(dn
->dn_Name
, DOSBootBase
->db_BootDevice
))
334 DOSBootBase
->db_BootNode
= bn
;
335 DOSBootBase
->db_BootDevice
= NULL
;
338 /* This makes the selected boot device the actual
339 * boot device. It also updates the boot flags.
341 static void setBootDevice(LIBBASETYPEPTR DOSBootBase
)
345 bn
= DOSBootBase
->db_BootNode
;
349 Remove((struct Node
*)bn
);
350 bn
->bn_Node
.ln_Type
= NT_BOOTNODE
;
351 bn
->bn_Node
.ln_Pri
= 127;
352 /* We use AddHead() instead of Enqueue() here
353 * to *insure* that this gets to the front of
356 AddHead(&DOSBootBase
->bm_ExpansionBase
->MountList
, (struct Node
*)&bn
);
359 DOSBootBase
->bm_ExpansionBase
->eb_BootFlags
= DOSBootBase
->db_BootFlags
;
362 static void initPageBoot(LIBBASETYPEPTR DOSBootBase
)
364 struct Window
*win
= DOSBootBase
->bm_Window
;
367 char text
[100], *textp
;
369 SetAPen(win
->RPort
, 1);
371 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
373 struct DeviceNode
*dn
= bn
->bn_DeviceNode
;
374 struct FileSysStartupMsg
*fssm
= BADDR(dn
->dn_Startup
);
375 struct DosEnvec
*de
= NULL
;
377 struct MsgPort
*port
;
381 BOOL devopen
, ismedia
;
383 if (y
>= DOSBootBase
->bottomY
- 20)
385 if (!fssm
|| !fssm
->fssm_Device
)
387 if (fssm
->fssm_Environ
> (BPTR
)0x64) {
388 de
= BADDR(fssm
->fssm_Environ
);
389 if (de
->de_TableSize
< 15)
393 NewRawDoFmt("%c%10s: %4d %s-%ld", RAWFMTFUNC_STRING
, text
,
395 ((DOSBootBase
->db_BootNode
== bn
) ? '*' : '+')
397 AROS_BSTR_ADDR(dn
->dn_Name
),
399 AROS_BSTR_ADDR(fssm
->fssm_Device
),
401 Move(win
->RPort
, 20, y
);
402 Text(win
->RPort
, text
, strlen(text
));
405 devopen
= ismedia
= FALSE
;
406 if ((port
= (struct MsgPort
*)CreateMsgPort())) {
407 if ((io
= (struct IOStdReq
*)CreateIORequest(port
, sizeof(struct IOStdReq
)))) {
408 if (!OpenDevice(AROS_BSTR_ADDR(fssm
->fssm_Device
), fssm
->fssm_Unit
, (struct IORequest
*)io
, fssm
->fssm_Flags
)) {
410 io
->io_Command
= TD_CHANGESTATE
;
412 DoIO((struct IORequest
*)io
);
413 if (!io
->io_Error
&& io
->io_Actual
== 0)
415 CloseDevice((struct IORequest
*)io
);
417 DeleteIORequest((struct IORequest
*)io
);
423 for (i
= 0; i
< 4; i
++) {
424 dostype
[i
] = (de
->de_DosType
>> ((3 - i
) * 8)) & 0xff;
427 else if (dostype
[i
] < 32)
432 size
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) * de
->de_Surfaces
* de
->de_BlocksPerTrack
;
433 /* try to prevent ULONG overflow */
434 if (de
->de_SizeBlock
<= 128)
437 size
*= de
->de_SizeBlock
/ 256;
439 NewRawDoFmt("%s [%08lx] %ldk", RAWFMTFUNC_STRING
, text
,
440 dostype
, de
->de_DosType
,
443 } else if (!devopen
) {
444 textp
= "[device open error]";
445 } else if (!ismedia
) {
446 textp
= "[no media]";
449 Move(win
->RPort
, 400, y
);
450 Text(win
->RPort
, textp
, strlen(textp
));
459 static void centertext(LIBBASETYPEPTR DOSBootBase
, BYTE pen
, WORD y
, const char *text
)
461 struct Window
*win
= DOSBootBase
->bm_Window
;
462 SetAPen(win
->RPort
, pen
);
463 Move(win
->RPort
, win
->Width
/ 2 - TextLength(win
->RPort
, text
, strlen(text
)) / 2, y
);
464 Text(win
->RPort
, text
, strlen(text
));
467 static void initPage(LIBBASETYPEPTR DOSBootBase
, WORD page
)
471 if (page
== PAGE_DISPLAY
)
472 text
= "Display Options";
473 else if (page
== PAGE_EXPANSION
)
474 text
= "Expansion Board Diagnostic";
475 else if (page
== PAGE_BOOT
)
476 text
= "Boot Options";
478 text
= "AROS Early Startup Control";
479 centertext(DOSBootBase
, 2, 10, text
);
481 if (page
== PAGE_BOOT
)
482 initPageBoot(DOSBootBase
);
483 else if (page
== PAGE_EXPANSION
)
484 initPageExpansion(DOSBootBase
);
486 if (page
== PAGE_MAIN
&& (GfxBase
->DisplayFlags
& (NTSC
| PAL
))) {
487 ULONG modeid
= GetVPModeID(&DOSBootBase
->bm_Screen
->ViewPort
);
488 if (modeid
!= INVALID_ID
&& (((modeid
& MONITOR_ID_MASK
) == NTSC_MONITOR_ID
) || ((modeid
& MONITOR_ID_MASK
) == PAL_MONITOR_ID
))) {
489 centertext(DOSBootBase
, 1, 30, "(press a key to toggle the display between PAL and NTSC)");
494 static WORD
initWindow(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
, WORD page
)
496 struct Gadget
*first
= NULL
;
499 if ((first
= createGadgets(DOSBootBase
, page
)) != NULL
)
501 struct NewWindow nw
=
503 0, 0, /* Left, Top */
504 DOSBootBase
->bm_Screen
->Width
, /* Width, Height */
505 DOSBootBase
->bm_Screen
->Height
,
506 0, 1, /* DetailPen, BlockPen */
507 IDCMP_MOUSEBUTTONS
| IDCMP_MOUSEMOVE
| IDCMP_VANILLAKEY
| IDCMP_GADGETUP
| IDCMP_GADGETDOWN
, /* IDCMPFlags */
508 WFLG_SMART_REFRESH
| WFLG_BORDERLESS
| WFLG_ACTIVATE
, /* Flags */
509 first
, /* FirstGadget */
510 NULL
, /* CheckMark */
512 DOSBootBase
->bm_Screen
, /* Screen */
514 0, 0, /* MinWidth, MinHeight */
515 0, 0, /* MaxWidth, MaxHeight */
516 CUSTOMSCREEN
, /* Type */
519 D(bug("[BootMenu] initPage: Gadgets created @ %p\n", first
));
521 if ((DOSBootBase
->bm_Window
= OpenWindow(&nw
)) != NULL
)
523 D(bug("[BootMenu] initScreen: Window opened @ %p\n", DOSBootBase
->bm_Window
));
524 D(bug("[BootMenu] initScreen: Window RastPort @ %p\n", DOSBootBase
->bm_Window
->RPort
));
525 D(bug("[BootMenu] initScreen: Window UserPort @ %p\n", DOSBootBase
->bm_Window
->UserPort
));
526 initPage(DOSBootBase
, page
);
527 newpage
= msgLoop(DOSBootBase
, DOSBootBase
->bm_Window
);
529 CloseWindow(DOSBootBase
->bm_Window
);
531 freeGadgets(DOSBootBase
, page
);
536 static BOOL
initScreen(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
)
540 D(bug("[BootMenu] initScreen()\n"));
543 DOSBootBase
->bm_Screen
= OpenBootScreen(DOSBootBase
);
544 if (DOSBootBase
->bm_Screen
)
546 DOSBootBase
->bottomY
= DOSBootBase
->bm_Screen
->Height
- (DOSBootBase
->bm_Screen
->Height
> 256 ? 32 : 16);
547 D(bug("[BootMenu] initScreen: Screen opened @ %p\n", DOSBootBase
->bm_Screen
));
551 page
= initWindow(DOSBootBase
, bcfg
, page
);
552 } while (page
!= EXIT_BOOT
&& page
!= EXIT_BOOT_WNSS
);
553 CloseBootScreen(DOSBootBase
->bm_Screen
, DOSBootBase
);
558 /* From keyboard.device/keyboard_intern.h */
559 #define KB_MAXKEYS 256
560 #define KB_MATRIXSIZE (KB_MAXKEYS/(sizeof(UBYTE)*8))
561 #define ioStd(x) ((struct IOStdReq *)x)
563 static BOOL
buttonsPressed(LIBBASETYPEPTR DOSBootBase
)
565 BOOL success
= FALSE
;
566 struct MsgPort
*mp
= NULL
;
567 UBYTE matrix
[KB_MATRIXSIZE
];
571 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
572 * Let's check mouse buttons.
574 if (OpenResource("ciaa.resource"))
576 volatile UBYTE
*cia
= (UBYTE
*)0xbfe001;
577 volatile UWORD
*potinp
= (UWORD
*)0xdff016;
579 /* check left + right mouse button state */
580 if ((cia
[0] & 0x40) == 0 && (potinp
[0] & 0x0400) == 0)
585 if ((mp
= CreateMsgPort()) != NULL
)
587 struct IORequest
*io
= NULL
;
588 if ((io
= CreateIORequest(mp
, sizeof ( struct IOStdReq
))) != NULL
)
590 if (0 == OpenDevice("keyboard.device", 0, io
, 0))
592 D(bug("[BootMenu] buttonsPressed: Checking KBD_READMATRIX\n"));
593 ioStd(io
)->io_Command
= KBD_READMATRIX
;
594 ioStd(io
)->io_Data
= matrix
;
595 ioStd(io
)->io_Length
= sizeof(matrix
);
597 if (0 == io
->io_Error
)
601 bug("[BootMenu] buttonsPressed: Matrix : ");
602 for (i
= 0; i
< ioStd(io
)->io_Actual
; i
++)
604 bug("%02x ", matrix
[i
]);
608 if (matrix
[RAWKEY_SPACE
/8] & (1<<(RAWKEY_SPACE
%8)))
610 D(bug("[BootMenu] SPACEBAR pressed\n"));
623 int bootmenu_Init(LIBBASETYPEPTR LIBBASE
, BOOL WantBootMenu
)
625 BOOL bmi_RetVal
= FALSE
;
627 D(bug("[BootMenu] bootmenu_Init()\n"));
629 #ifdef INITHIDDS_KLUDGE
631 * PCI hardware display drivers still need external initialization.
632 * This urgently needs to be fixed. After fixing this kludge
633 * will not be needed any more.
635 InitBootConfig(&LIBBASE
->bm_BootConfig
);
636 if (!initHidds(LIBBASE
))
640 /* check keyboard if needed */
642 WantBootMenu
= buttonsPressed(LIBBASE
);
644 /* Bring up early startup menu if requested */
647 D(kprintf("[BootMenu] bootmenu_Init: Entering Boot Menu ...\n"));
648 bmi_RetVal
= initScreen(LIBBASE
, &LIBBASE
->bm_BootConfig
);
651 /* Make the user's select the top boot device */
652 setBootDevice(LIBBASE
);