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 LONG
centerx(LIBBASETYPEPTR DOSBootBase
, LONG width
)
101 return (DOSBootBase
->bm_Screen
->Width
- width
) / 2;
104 static LONG
rightto(LIBBASETYPEPTR DOSBootBase
, LONG width
, LONG right
)
106 return DOSBootBase
->bm_Screen
->Width
- width
- right
;
109 static struct Gadget
*createGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
111 LONG cx
= centerx((struct DOSBootBase
*)DOSBootBase
, 280);
113 /* Create Option Gadgets */
114 DOSBootBase
->bm_MainGadgets
.bootopt
= createButton(
116 NULL
, "Boot Options...",
117 BUTTON_BOOT_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
118 DOSBootBase
->bm_MainGadgets
.displayopt
= createButton(
120 DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
, "Display Options...",
121 BUTTON_DISPLAY_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
122 DOSBootBase
->bm_MainGadgets
.expboarddiag
= createButton(
124 DOSBootBase
->bm_MainGadgets
.displayopt
->gadget
, "Expansion Board Diagnostic...",
125 BUTTON_EXPBOARDDIAG
, (struct DOSBootBase
*)DOSBootBase
);
126 /* Create BOOT Gadgets */
127 DOSBootBase
->bm_MainGadgets
.boot
= createButton(
128 16, DOSBootBase
->bottomY
, 280, 14,
129 DOSBootBase
->bm_MainGadgets
.expboarddiag
->gadget
, "Boot",
130 BUTTON_BOOT
, (struct DOSBootBase
*)DOSBootBase
);
131 DOSBootBase
->bm_MainGadgets
.bootnss
= createButton(
132 rightto((struct DOSBootBase
*)DOSBootBase
, 280, 16), DOSBootBase
->bottomY
, 280, 14,
133 DOSBootBase
->bm_MainGadgets
.boot
->gadget
, "Boot With No Startup-Sequence",
134 BUTTON_BOOT_WNSS
, (struct DOSBootBase
*)DOSBootBase
);
135 if (!DOSBootBase
->bm_MainGadgets
.bootopt
||
136 !DOSBootBase
->bm_MainGadgets
.displayopt
||
137 !DOSBootBase
->bm_MainGadgets
.expboarddiag
||
138 !DOSBootBase
->bm_MainGadgets
.boot
||
139 !DOSBootBase
->bm_MainGadgets
.bootnss
)
141 return DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
;
144 static struct Gadget
*createGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
146 DOSBootBase
->bm_MainGadgets
.use
= createButton(
147 16, DOSBootBase
->bottomY
, 280, 14,
149 BUTTON_USE
, (struct DOSBootBase
*)DOSBootBase
);
150 DOSBootBase
->bm_MainGadgets
.cancel
= createButton(
151 rightto((struct DOSBootBase
*)DOSBootBase
, 280, 16), DOSBootBase
->bottomY
, 280, 14,
152 DOSBootBase
->bm_MainGadgets
.use
->gadget
, "Cancel",
153 BUTTON_CANCEL
, (struct DOSBootBase
*)DOSBootBase
);
154 if (!DOSBootBase
->bm_MainGadgets
.use
||
155 !DOSBootBase
->bm_MainGadgets
.cancel
)
157 return DOSBootBase
->bm_MainGadgets
.use
->gadget
;
161 static void freeGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
163 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.boot
, (struct DOSBootBase
*)DOSBootBase
);
164 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootnss
, (struct DOSBootBase
*)DOSBootBase
);
165 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootopt
, (struct DOSBootBase
*)DOSBootBase
);
166 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.displayopt
, (struct DOSBootBase
*)DOSBootBase
);
167 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.expboarddiag
, (struct DOSBootBase
*)DOSBootBase
);
170 static void freeGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
172 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.use
, (struct DOSBootBase
*)DOSBootBase
);
173 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.cancel
, (struct DOSBootBase
*)DOSBootBase
);
176 static struct Gadget
*createGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
178 if (page
== PAGE_MAIN
)
179 return createGadgetsBoot(DOSBootBase
);
181 return createGadgetsUseCancel(DOSBootBase
);
183 static void freeGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
185 if (page
== PAGE_MAIN
)
186 freeGadgetsBoot(DOSBootBase
);
188 freeGadgetsUseCancel(DOSBootBase
);
191 static void toggleMode(LIBBASETYPEPTR DOSBootBase
)
195 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
197 if (OpenResource("ciaa.resource")) {
198 volatile UWORD
*beamcon0
= (UWORD
*)0xdff1dc;
199 GfxBase
->DisplayFlags
^= PAL
| NTSC
;
200 *beamcon0
= (GfxBase
->DisplayFlags
& PAL
) ? 0x0020 : 0x0000;
205 static UWORD
msgLoop(LIBBASETYPEPTR DOSBootBase
, struct Window
*win
, WORD page
)
208 struct IntuiMessage
*msg
;
211 D(bug("[BootMenu] msgLoop(DOSBootBase @ %p, Window @ %p)\n", DOSBootBase
, win
));
217 WaitPort(win
->UserPort
);
218 while ((msg
= (struct IntuiMessage
*)GetMsg(win
->UserPort
)))
220 if (msg
->Class
== IDCMP_VANILLAKEY
) {
223 else if (msg
->Code
>= '1' && msg
->Code
<= '3')
224 exit
= PAGE_MAIN
+ msg
->Code
- '0';
225 else if (msg
->Code
>= 'a' && msg
->Code
<='j') {
226 BYTE pos
= msg
->Code
- 'a', i
= 0;
228 DOSBootBase
->bm_BootNode
= NULL
;
230 Forbid(); /* .. access to ExpansionBase->MountList */
231 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
235 DOSBootBase
->bm_BootNode
= bn
;
241 if (DOSBootBase
->bm_BootNode
!= NULL
)
249 toggleMode(DOSBootBase
);
250 } else if (msg
->Class
== IDCMP_GADGETUP
)
256 DOSBootBase
->db_BootFlags
&= ~BF_NO_STARTUP_SEQUENCE
;
259 case BUTTON_BOOT_WNSS
:
260 DOSBootBase
->db_BootFlags
|= BF_NO_STARTUP_SEQUENCE
;
261 exit
= EXIT_BOOT_WNSS
;
264 if (page
== PAGE_BOOT
)
265 DOSBootBase
->bm_BootNode
= NULL
;
269 /* Preserve selected value */
270 if (page
== PAGE_BOOT
)
271 if (DOSBootBase
->bm_BootNode
!= NULL
)
272 DOSBootBase
->db_BootNode
= DOSBootBase
->bm_BootNode
;
274 case BUTTON_CONTINUE
:
277 case BUTTON_BOOT_OPTIONS
:
280 case BUTTON_EXPBOARDDIAG
:
281 exit
= PAGE_EXPANSION
;
283 case BUTTON_DISPLAY_OPTIONS
:
288 ReplyMsg((struct Message
*)msg
);
293 bug("[BootMenu] msgLoop: Window lacks a userport!\n");
298 while ((msg
=(struct IntuiMessage
*)GetMsg(win
->UserPort
)))
299 ReplyMsg(&msg
->ExecMessage
);
304 static void initPageExpansion(LIBBASETYPEPTR DOSBootBase
)
306 struct Window
*win
= DOSBootBase
->bm_Window
;
307 struct ExpansionBase
*ExpansionBase
= DOSBootBase
->bm_ExpansionBase
;
308 struct ConfigDev
*cd
;
312 SetAPen(win
->RPort
, 1);
315 while ((cd
= FindConfigDev(cd
, -1, -1))) {
316 NewRawDoFmt("%2d: %08lx - %08lx (%08lx) %5d %3d %08lx", RAWFMTFUNC_STRING
, text
,
318 cd
->cd_BoardAddr
, cd
->cd_BoardAddr
+ cd
->cd_BoardSize
- 1, cd
->cd_BoardSize
,
319 cd
->cd_Rom
.er_Manufacturer
, cd
->cd_Rom
.er_Product
, cd
->cd_Rom
.er_SerialNumber
);
320 if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROIII
)
322 else if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROII
)
326 if (cd
->cd_Rom
.er_Type
& ERTF_DIAGVALID
)
327 strcat(text
, " ROM");
328 if (cd
->cd_Rom
.er_Type
& ERTF_MEMLIST
)
329 strcat(text
, " RAM");
330 Move(win
->RPort
, 20, y
);
331 Text(win
->RPort
, text
, strlen(text
));
336 static void initPageBoot(LIBBASETYPEPTR DOSBootBase
)
338 struct Window
*win
= DOSBootBase
->bm_Window
;
341 WORD xoff
= (win
->Width
- 640) / 2;
342 char text
[100], *textp
;
344 SetAPen(win
->RPort
, 1);
346 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
348 struct DeviceNode
*dn
= bn
->bn_DeviceNode
;
349 struct FileSysStartupMsg
*fssm
= BADDR(dn
->dn_Startup
);
350 struct DosEnvec
*de
= NULL
;
352 struct MsgPort
*port
;
356 BOOL devopen
, ismedia
;
358 if (y
>= DOSBootBase
->bottomY
- 20)
360 if (!fssm
|| !fssm
->fssm_Device
)
362 if (fssm
->fssm_Environ
> (BPTR
)0x64) {
363 de
= BADDR(fssm
->fssm_Environ
);
364 if (de
->de_TableSize
< 15)
368 NewRawDoFmt("%c%10s: %4d %s-%ld", RAWFMTFUNC_STRING
, text
,
369 (DOSBootBase
->bm_BootNode
== bn
) ? '*' : IsBootableNode(bn
) ? '+' : ' ',
370 AROS_BSTR_ADDR(dn
->dn_Name
),
372 AROS_BSTR_ADDR(fssm
->fssm_Device
),
374 Move(win
->RPort
, 20 + xoff
, y
);
375 Text(win
->RPort
, text
, strlen(text
));
378 devopen
= ismedia
= FALSE
;
379 if ((port
= (struct MsgPort
*)CreateMsgPort())) {
380 if ((io
= (struct IOStdReq
*)CreateIORequest(port
, sizeof(struct IOStdReq
)))) {
381 if (!OpenDevice(AROS_BSTR_ADDR(fssm
->fssm_Device
), fssm
->fssm_Unit
, (struct IORequest
*)io
, fssm
->fssm_Flags
)) {
383 io
->io_Command
= TD_CHANGESTATE
;
385 DoIO((struct IORequest
*)io
);
386 if (!io
->io_Error
&& io
->io_Actual
== 0)
388 CloseDevice((struct IORequest
*)io
);
390 DeleteIORequest((struct IORequest
*)io
);
396 STRPTR sunit
= "kMGT";
398 for (i
= 0; i
< 4; i
++) {
399 dostype
[i
] = (de
->de_DosType
>> ((3 - i
) * 8)) & 0xff;
402 else if (dostype
[i
] < 32)
407 size
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) * de
->de_Surfaces
* de
->de_BlocksPerTrack
;
408 /* try to prevent ULONG overflow */
409 if (de
->de_SizeBlock
<= 128)
412 size
*= de
->de_SizeBlock
/ 256;
413 while(size
> 1024 * 10) { /* Wrap on 10x unit to be more precise in displaying */
418 NewRawDoFmt("%s [%08lx] %ld%c", RAWFMTFUNC_STRING
, text
,
419 dostype
, de
->de_DosType
,
422 } else if (!devopen
) {
423 textp
= "[device open error]";
424 } else if (!ismedia
) {
425 textp
= "[no media]";
428 Move(win
->RPort
, 400 + xoff
, y
);
429 Text(win
->RPort
, textp
, strlen(textp
));
438 static void centertext(LIBBASETYPEPTR DOSBootBase
, BYTE pen
, WORD y
, const char *text
)
440 struct Window
*win
= DOSBootBase
->bm_Window
;
441 SetAPen(win
->RPort
, pen
);
442 Move(win
->RPort
, win
->Width
/ 2 - TextLength(win
->RPort
, text
, strlen(text
)) / 2, y
);
443 Text(win
->RPort
, text
, strlen(text
));
446 static void initPage(LIBBASETYPEPTR DOSBootBase
, WORD page
)
450 if (page
== PAGE_DISPLAY
)
451 text
= "Display Options";
452 else if (page
== PAGE_EXPANSION
)
453 text
= "Expansion Board Diagnostic";
454 else if (page
== PAGE_BOOT
)
455 text
= "Boot Options";
457 text
= "AROS Early Startup Control";
458 centertext(DOSBootBase
, 2, 10, text
);
460 if (page
== PAGE_BOOT
)
462 /* Set the default */
463 if (DOSBootBase
->bm_BootNode
== NULL
)
464 DOSBootBase
->bm_BootNode
= DOSBootBase
->db_BootNode
;
466 initPageBoot(DOSBootBase
);
467 centertext(DOSBootBase
, 1, 30, "Press A-J to select boot device");
468 centertext(DOSBootBase
, 1, 45, "\"+\" => bootable, \"*\" => selected for boot");
471 else if (page
== PAGE_EXPANSION
)
472 initPageExpansion(DOSBootBase
);
474 if (page
== PAGE_MAIN
&& (GfxBase
->DisplayFlags
& (NTSC
| PAL
))) {
475 ULONG modeid
= GetVPModeID(&DOSBootBase
->bm_Screen
->ViewPort
);
476 if (modeid
!= INVALID_ID
&& (((modeid
& MONITOR_ID_MASK
) == NTSC_MONITOR_ID
) || ((modeid
& MONITOR_ID_MASK
) == PAL_MONITOR_ID
))) {
477 centertext(DOSBootBase
, 1, 30, "(press a key to toggle the display between PAL and NTSC)");
483 static WORD
initWindow(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
, WORD page
)
485 struct Gadget
*first
= NULL
;
488 if ((first
= createGadgets(DOSBootBase
, page
)) != NULL
)
490 struct NewWindow nw
=
492 0, 0, /* Left, Top */
493 DOSBootBase
->bm_Screen
->Width
, /* Width, Height */
494 DOSBootBase
->bm_Screen
->Height
,
495 0, 1, /* DetailPen, BlockPen */
496 IDCMP_MOUSEBUTTONS
| IDCMP_MOUSEMOVE
| IDCMP_VANILLAKEY
| IDCMP_GADGETUP
| IDCMP_GADGETDOWN
, /* IDCMPFlags */
497 WFLG_SMART_REFRESH
| WFLG_BORDERLESS
| WFLG_ACTIVATE
, /* Flags */
498 first
, /* FirstGadget */
499 NULL
, /* CheckMark */
501 DOSBootBase
->bm_Screen
, /* Screen */
503 0, 0, /* MinWidth, MinHeight */
504 0, 0, /* MaxWidth, MaxHeight */
505 CUSTOMSCREEN
, /* Type */
508 D(bug("[BootMenu] initPage: Gadgets created @ %p\n", first
));
510 if ((DOSBootBase
->bm_Window
= OpenWindow(&nw
)) != NULL
)
512 D(bug("[BootMenu] initScreen: Window opened @ %p\n", DOSBootBase
->bm_Window
));
513 D(bug("[BootMenu] initScreen: Window RastPort @ %p\n", DOSBootBase
->bm_Window
->RPort
));
514 D(bug("[BootMenu] initScreen: Window UserPort @ %p\n", DOSBootBase
->bm_Window
->UserPort
));
515 initPage(DOSBootBase
, page
);
516 newpage
= msgLoop(DOSBootBase
, DOSBootBase
->bm_Window
, page
);
518 CloseWindow(DOSBootBase
->bm_Window
);
520 freeGadgets(DOSBootBase
, page
);
525 static BOOL
initScreen(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
)
529 D(bug("[BootMenu] initScreen()\n"));
532 DOSBootBase
->bm_Screen
= OpenBootScreen(DOSBootBase
);
533 if (DOSBootBase
->bm_Screen
)
535 DOSBootBase
->bottomY
= DOSBootBase
->bm_Screen
->Height
- (DOSBootBase
->bm_Screen
->Height
> 256 ? 32 : 16);
536 D(bug("[BootMenu] initScreen: Screen opened @ %p\n", DOSBootBase
->bm_Screen
));
540 page
= initWindow(DOSBootBase
, bcfg
, page
);
541 } while (page
!= EXIT_BOOT
&& page
!= EXIT_BOOT_WNSS
);
542 CloseBootScreen(DOSBootBase
->bm_Screen
, DOSBootBase
);
547 /* From keyboard.device/keyboard_intern.h */
548 #define KB_MAXKEYS 256
549 #define KB_MATRIXSIZE (KB_MAXKEYS/(sizeof(UBYTE)*8))
550 #define ioStd(x) ((struct IOStdReq *)x)
552 static BOOL
buttonsPressed(LIBBASETYPEPTR DOSBootBase
)
554 BOOL success
= FALSE
;
555 struct MsgPort
*mp
= NULL
;
556 UBYTE matrix
[KB_MATRIXSIZE
];
560 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
561 * Let's check mouse buttons.
563 if (OpenResource("ciaa.resource"))
565 volatile UBYTE
*cia
= (UBYTE
*)0xbfe001;
566 volatile UWORD
*potinp
= (UWORD
*)0xdff016;
568 /* check left + right mouse button state */
569 if ((cia
[0] & 0x40) == 0 && (potinp
[0] & 0x0400) == 0)
574 if ((mp
= CreateMsgPort()) != NULL
)
576 struct IORequest
*io
= NULL
;
577 if ((io
= CreateIORequest(mp
, sizeof ( struct IOStdReq
))) != NULL
)
579 if (0 == OpenDevice("keyboard.device", 0, io
, 0))
581 D(bug("[BootMenu] buttonsPressed: Checking KBD_READMATRIX\n"));
582 ioStd(io
)->io_Command
= KBD_READMATRIX
;
583 ioStd(io
)->io_Data
= matrix
;
584 ioStd(io
)->io_Length
= sizeof(matrix
);
586 if (0 == io
->io_Error
)
590 bug("[BootMenu] buttonsPressed: Matrix : ");
591 for (i
= 0; i
< ioStd(io
)->io_Actual
; i
++)
593 bug("%02x ", matrix
[i
]);
597 if (matrix
[RAWKEY_SPACE
/8] & (1<<(RAWKEY_SPACE
%8)))
599 D(bug("[BootMenu] SPACEBAR pressed\n"));
612 int bootmenu_Init(LIBBASETYPEPTR LIBBASE
, BOOL WantBootMenu
)
614 BOOL bmi_RetVal
= FALSE
;
616 D(bug("[BootMenu] bootmenu_Init()\n"));
618 #ifdef INITHIDDS_KLUDGE
620 * PCI hardware display drivers still need external initialization.
621 * This urgently needs to be fixed. After fixing this kludge
622 * will not be needed any more.
624 InitBootConfig(&LIBBASE
->bm_BootConfig
);
625 if (!initHidds(LIBBASE
))
629 /* check keyboard if needed */
631 WantBootMenu
= buttonsPressed(LIBBASE
);
633 /* Bring up early startup menu if requested */
636 D(kprintf("[BootMenu] bootmenu_Init: Entering Boot Menu ...\n"));
637 bmi_RetVal
= initScreen(LIBBASE
, &LIBBASE
->bm_BootConfig
);