2 Copyright © 1995-2012, 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';
213 else if (msg
->Code
>= 'a' && msg
->Code
<='j') {
214 BYTE pos
= msg
->Code
- 'a', i
= 0;
216 DOSBootBase
->db_BootNode
= NULL
;
218 Forbid(); /* .. access to ExpansionBase->MountList */
219 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
223 DOSBootBase
->db_BootNode
= bn
;
229 if (DOSBootBase
->db_BootNode
!= NULL
)
237 toggleMode(DOSBootBase
);
238 } else if (msg
->Class
== IDCMP_GADGETUP
)
244 DOSBootBase
->db_BootFlags
&= ~BF_NO_STARTUP_SEQUENCE
;
247 case BUTTON_BOOT_WNSS
:
248 DOSBootBase
->db_BootFlags
|= BF_NO_STARTUP_SEQUENCE
;
249 exit
= EXIT_BOOT_WNSS
;
252 DOSBootBase
->db_BootNode
= NULL
;
255 case BUTTON_CONTINUE
:
258 case BUTTON_BOOT_OPTIONS
:
261 case BUTTON_EXPBOARDDIAG
:
262 exit
= PAGE_EXPANSION
;
264 case BUTTON_DISPLAY_OPTIONS
:
269 ReplyMsg((struct Message
*)msg
);
274 bug("[BootMenu] msgLoop: Window lacks a userport!\n");
279 while ((msg
=(struct IntuiMessage
*)GetMsg(win
->UserPort
)))
280 ReplyMsg(&msg
->ExecMessage
);
285 static void initPageExpansion(LIBBASETYPEPTR DOSBootBase
)
287 struct Window
*win
= DOSBootBase
->bm_Window
;
288 struct ExpansionBase
*ExpansionBase
= DOSBootBase
->bm_ExpansionBase
;
289 struct ConfigDev
*cd
;
293 SetAPen(win
->RPort
, 1);
296 while ((cd
= FindConfigDev(cd
, -1, -1))) {
297 NewRawDoFmt("%2d: %08lx - %08lx (%08lx) %5d %3d %08lx", RAWFMTFUNC_STRING
, text
,
299 cd
->cd_BoardAddr
, cd
->cd_BoardAddr
+ cd
->cd_BoardSize
- 1, cd
->cd_BoardSize
,
300 cd
->cd_Rom
.er_Manufacturer
, cd
->cd_Rom
.er_Product
, cd
->cd_Rom
.er_SerialNumber
);
301 if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROIII
)
303 else if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROII
)
307 if (cd
->cd_Rom
.er_Type
& ERTF_DIAGVALID
)
308 strcat(text
, " ROM");
309 if (cd
->cd_Rom
.er_Type
& ERTF_MEMLIST
)
310 strcat(text
, " RAM");
311 Move(win
->RPort
, 20, y
);
312 Text(win
->RPort
, text
, strlen(text
));
317 static BOOL
bstreqcstr(BSTR bstr
, CONST_STRPTR cstr
)
323 blen
= AROS_BSTR_strlen(bstr
);
327 return (memcmp(AROS_BSTR_ADDR(bstr
),cstr
,clen
) == 0);
330 void selectBootDevice(LIBBASETYPEPTR DOSBootBase
)
332 struct BootNode
*bn
= NULL
;
334 if (DOSBootBase
->db_BootDevice
== NULL
&&
335 DOSBootBase
->db_BootNode
!= NULL
)
338 Forbid(); /* .. access to ExpansionBase->MountList */
340 if (DOSBootBase
->db_BootNode
== NULL
&& DOSBootBase
->db_BootDevice
== NULL
)
342 bn
= (APTR
)GetHead(&DOSBootBase
->bm_ExpansionBase
->MountList
);
347 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, i
)
349 struct DeviceNode
*dn
;
351 dn
= i
->bn_DeviceNode
;
352 if (dn
== NULL
|| dn
->dn_Name
== BNULL
)
355 if (bstreqcstr(dn
->dn_Name
, DOSBootBase
->db_BootDevice
))
365 DOSBootBase
->db_BootNode
= bn
;
366 DOSBootBase
->db_BootDevice
= NULL
;
369 /* This makes the selected boot device the actual
370 * boot device. It also updates the boot flags.
372 static void setBootDevice(LIBBASETYPEPTR DOSBootBase
)
376 bn
= DOSBootBase
->db_BootNode
;
380 Remove((struct Node
*)bn
);
381 bn
->bn_Node
.ln_Type
= NT_BOOTNODE
;
382 bn
->bn_Node
.ln_Pri
= 127;
383 /* We use AddHead() instead of Enqueue() here
384 * to *insure* that this gets to the front of
387 AddHead(&DOSBootBase
->bm_ExpansionBase
->MountList
, (struct Node
*)bn
);
390 DOSBootBase
->bm_ExpansionBase
->eb_BootFlags
= DOSBootBase
->db_BootFlags
;
393 static void initPageBoot(LIBBASETYPEPTR DOSBootBase
)
395 struct Window
*win
= DOSBootBase
->bm_Window
;
398 char text
[100], *textp
;
400 SetAPen(win
->RPort
, 1);
402 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
404 struct DeviceNode
*dn
= bn
->bn_DeviceNode
;
405 struct FileSysStartupMsg
*fssm
= BADDR(dn
->dn_Startup
);
406 struct DosEnvec
*de
= NULL
;
408 struct MsgPort
*port
;
412 BOOL devopen
, ismedia
;
414 if (y
>= DOSBootBase
->bottomY
- 20)
416 if (!fssm
|| !fssm
->fssm_Device
)
418 if (fssm
->fssm_Environ
> (BPTR
)0x64) {
419 de
= BADDR(fssm
->fssm_Environ
);
420 if (de
->de_TableSize
< 15)
424 NewRawDoFmt("%c%10s: %4d %s-%ld", RAWFMTFUNC_STRING
, text
,
425 (DOSBootBase
->db_BootNode
== bn
) ? '*' : IsBootableNode(bn
) ? '+' : ' ',
426 AROS_BSTR_ADDR(dn
->dn_Name
),
428 AROS_BSTR_ADDR(fssm
->fssm_Device
),
430 Move(win
->RPort
, 20, y
);
431 Text(win
->RPort
, text
, strlen(text
));
434 devopen
= ismedia
= FALSE
;
435 if ((port
= (struct MsgPort
*)CreateMsgPort())) {
436 if ((io
= (struct IOStdReq
*)CreateIORequest(port
, sizeof(struct IOStdReq
)))) {
437 if (!OpenDevice(AROS_BSTR_ADDR(fssm
->fssm_Device
), fssm
->fssm_Unit
, (struct IORequest
*)io
, fssm
->fssm_Flags
)) {
439 io
->io_Command
= TD_CHANGESTATE
;
441 DoIO((struct IORequest
*)io
);
442 if (!io
->io_Error
&& io
->io_Actual
== 0)
444 CloseDevice((struct IORequest
*)io
);
446 DeleteIORequest((struct IORequest
*)io
);
452 for (i
= 0; i
< 4; i
++) {
453 dostype
[i
] = (de
->de_DosType
>> ((3 - i
) * 8)) & 0xff;
456 else if (dostype
[i
] < 32)
461 size
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) * de
->de_Surfaces
* de
->de_BlocksPerTrack
;
462 /* try to prevent ULONG overflow */
463 if (de
->de_SizeBlock
<= 128)
466 size
*= de
->de_SizeBlock
/ 256;
468 NewRawDoFmt("%s [%08lx] %ldk", RAWFMTFUNC_STRING
, text
,
469 dostype
, de
->de_DosType
,
472 } else if (!devopen
) {
473 textp
= "[device open error]";
474 } else if (!ismedia
) {
475 textp
= "[no media]";
478 Move(win
->RPort
, 400, y
);
479 Text(win
->RPort
, textp
, strlen(textp
));
488 static void centertext(LIBBASETYPEPTR DOSBootBase
, BYTE pen
, WORD y
, const char *text
)
490 struct Window
*win
= DOSBootBase
->bm_Window
;
491 SetAPen(win
->RPort
, pen
);
492 Move(win
->RPort
, win
->Width
/ 2 - TextLength(win
->RPort
, text
, strlen(text
)) / 2, y
);
493 Text(win
->RPort
, text
, strlen(text
));
496 static void initPage(LIBBASETYPEPTR DOSBootBase
, WORD page
)
500 if (page
== PAGE_DISPLAY
)
501 text
= "Display Options";
502 else if (page
== PAGE_EXPANSION
)
503 text
= "Expansion Board Diagnostic";
504 else if (page
== PAGE_BOOT
)
505 text
= "Boot Options";
507 text
= "AROS Early Startup Control";
508 centertext(DOSBootBase
, 2, 10, text
);
510 if (page
== PAGE_BOOT
)
511 initPageBoot(DOSBootBase
);
512 else if (page
== PAGE_EXPANSION
)
513 initPageExpansion(DOSBootBase
);
515 if (page
== PAGE_MAIN
&& (GfxBase
->DisplayFlags
& (NTSC
| PAL
))) {
516 ULONG modeid
= GetVPModeID(&DOSBootBase
->bm_Screen
->ViewPort
);
517 if (modeid
!= INVALID_ID
&& (((modeid
& MONITOR_ID_MASK
) == NTSC_MONITOR_ID
) || ((modeid
& MONITOR_ID_MASK
) == PAL_MONITOR_ID
))) {
518 centertext(DOSBootBase
, 1, 30, "(press a key to toggle the display between PAL and NTSC)");
522 if (page
== PAGE_BOOT
)
523 centertext(DOSBootBase
, 1, 30, "Press A-J to select boot device");
526 static WORD
initWindow(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
, WORD page
)
528 struct Gadget
*first
= NULL
;
531 if ((first
= createGadgets(DOSBootBase
, page
)) != NULL
)
533 struct NewWindow nw
=
535 0, 0, /* Left, Top */
536 DOSBootBase
->bm_Screen
->Width
, /* Width, Height */
537 DOSBootBase
->bm_Screen
->Height
,
538 0, 1, /* DetailPen, BlockPen */
539 IDCMP_MOUSEBUTTONS
| IDCMP_MOUSEMOVE
| IDCMP_VANILLAKEY
| IDCMP_GADGETUP
| IDCMP_GADGETDOWN
, /* IDCMPFlags */
540 WFLG_SMART_REFRESH
| WFLG_BORDERLESS
| WFLG_ACTIVATE
, /* Flags */
541 first
, /* FirstGadget */
542 NULL
, /* CheckMark */
544 DOSBootBase
->bm_Screen
, /* Screen */
546 0, 0, /* MinWidth, MinHeight */
547 0, 0, /* MaxWidth, MaxHeight */
548 CUSTOMSCREEN
, /* Type */
551 D(bug("[BootMenu] initPage: Gadgets created @ %p\n", first
));
553 if ((DOSBootBase
->bm_Window
= OpenWindow(&nw
)) != NULL
)
555 D(bug("[BootMenu] initScreen: Window opened @ %p\n", DOSBootBase
->bm_Window
));
556 D(bug("[BootMenu] initScreen: Window RastPort @ %p\n", DOSBootBase
->bm_Window
->RPort
));
557 D(bug("[BootMenu] initScreen: Window UserPort @ %p\n", DOSBootBase
->bm_Window
->UserPort
));
558 initPage(DOSBootBase
, page
);
559 newpage
= msgLoop(DOSBootBase
, DOSBootBase
->bm_Window
);
561 CloseWindow(DOSBootBase
->bm_Window
);
563 freeGadgets(DOSBootBase
, page
);
568 static BOOL
initScreen(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
)
572 D(bug("[BootMenu] initScreen()\n"));
575 DOSBootBase
->bm_Screen
= OpenBootScreen(DOSBootBase
);
576 if (DOSBootBase
->bm_Screen
)
578 DOSBootBase
->bottomY
= DOSBootBase
->bm_Screen
->Height
- (DOSBootBase
->bm_Screen
->Height
> 256 ? 32 : 16);
579 D(bug("[BootMenu] initScreen: Screen opened @ %p\n", DOSBootBase
->bm_Screen
));
583 page
= initWindow(DOSBootBase
, bcfg
, page
);
584 } while (page
!= EXIT_BOOT
&& page
!= EXIT_BOOT_WNSS
);
585 CloseBootScreen(DOSBootBase
->bm_Screen
, DOSBootBase
);
590 /* From keyboard.device/keyboard_intern.h */
591 #define KB_MAXKEYS 256
592 #define KB_MATRIXSIZE (KB_MAXKEYS/(sizeof(UBYTE)*8))
593 #define ioStd(x) ((struct IOStdReq *)x)
595 static BOOL
buttonsPressed(LIBBASETYPEPTR DOSBootBase
)
597 BOOL success
= FALSE
;
598 struct MsgPort
*mp
= NULL
;
599 UBYTE matrix
[KB_MATRIXSIZE
];
603 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
604 * Let's check mouse buttons.
606 if (OpenResource("ciaa.resource"))
608 volatile UBYTE
*cia
= (UBYTE
*)0xbfe001;
609 volatile UWORD
*potinp
= (UWORD
*)0xdff016;
611 /* check left + right mouse button state */
612 if ((cia
[0] & 0x40) == 0 && (potinp
[0] & 0x0400) == 0)
617 if ((mp
= CreateMsgPort()) != NULL
)
619 struct IORequest
*io
= NULL
;
620 if ((io
= CreateIORequest(mp
, sizeof ( struct IOStdReq
))) != NULL
)
622 if (0 == OpenDevice("keyboard.device", 0, io
, 0))
624 D(bug("[BootMenu] buttonsPressed: Checking KBD_READMATRIX\n"));
625 ioStd(io
)->io_Command
= KBD_READMATRIX
;
626 ioStd(io
)->io_Data
= matrix
;
627 ioStd(io
)->io_Length
= sizeof(matrix
);
629 if (0 == io
->io_Error
)
633 bug("[BootMenu] buttonsPressed: Matrix : ");
634 for (i
= 0; i
< ioStd(io
)->io_Actual
; i
++)
636 bug("%02x ", matrix
[i
]);
640 if (matrix
[RAWKEY_SPACE
/8] & (1<<(RAWKEY_SPACE
%8)))
642 D(bug("[BootMenu] SPACEBAR pressed\n"));
655 int bootmenu_Init(LIBBASETYPEPTR LIBBASE
, BOOL WantBootMenu
)
657 BOOL bmi_RetVal
= FALSE
;
659 D(bug("[BootMenu] bootmenu_Init()\n"));
661 #ifdef INITHIDDS_KLUDGE
663 * PCI hardware display drivers still need external initialization.
664 * This urgently needs to be fixed. After fixing this kludge
665 * will not be needed any more.
667 InitBootConfig(&LIBBASE
->bm_BootConfig
);
668 if (!initHidds(LIBBASE
))
672 /* check keyboard if needed */
674 WantBootMenu
= buttonsPressed(LIBBASE
);
676 /* Bring up early startup menu if requested */
679 D(kprintf("[BootMenu] bootmenu_Init: Entering Boot Menu ...\n"));
680 bmi_RetVal
= initScreen(LIBBASE
, &LIBBASE
->bm_BootConfig
);
683 /* Make the user's selection the top boot device */
684 setBootDevice(LIBBASE
);