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)
46 static BOOL
init_gfx(STRPTR gfxclassname
, BOOL bootmode
, LIBBASETYPEPTR DOSBootBase
)
51 D(bug("[BootMenu] init_gfx('%s')\n", gfxclassname
));
53 GfxBase
= (void *)OpenLibrary("graphics.library", 41);
57 gfxhidd
= OOP_NewObject(NULL
, gfxclassname
, NULL
);
59 if (AddDisplayDriver(gfxhidd
, DDRV_BootMode
, bootmode
, TAG_DONE
))
60 OOP_DisposeObject(gfxhidd
);
65 CloseLibrary(&GfxBase
->LibNode
);
67 ReturnBool ("init_gfxhidd", success
);
70 static BOOL
initHidds(LIBBASETYPEPTR DOSBootBase
)
72 struct BootConfig
*bootcfg
= &DOSBootBase
->bm_BootConfig
;
74 D(bug("[BootMenu] initHidds()\n"));
76 if (bootcfg
->gfxhidd
) {
77 if (!OpenLibrary(bootcfg
->gfxlib
, 0))
80 if (!init_gfx(bootcfg
->gfxhidd
, bootcfg
->bootmode
, DOSBootBase
))
84 D(bug("[BootMenu] initHidds: Hidds initialised\n"));
91 static struct Gadget
*createGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
93 /* Create Option Gadgets */
94 DOSBootBase
->bm_MainGadgets
.bootopt
= createButton(
96 NULL
, "Boot Options...",
97 BUTTON_BOOT_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
98 DOSBootBase
->bm_MainGadgets
.displayopt
= createButton(
100 DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
, "Display Options...",
101 BUTTON_DISPLAY_OPTIONS
, (struct DOSBootBase
*)DOSBootBase
);
102 DOSBootBase
->bm_MainGadgets
.expboarddiag
= createButton(
104 DOSBootBase
->bm_MainGadgets
.displayopt
->gadget
, "Expansion Board Diagnostic...",
105 BUTTON_EXPBOARDDIAG
, (struct DOSBootBase
*)DOSBootBase
);
106 /* Create BOOT Gadgets */
107 DOSBootBase
->bm_MainGadgets
.boot
= createButton(
108 16, DOSBootBase
->bottomY
, 280, 14,
109 DOSBootBase
->bm_MainGadgets
.expboarddiag
->gadget
, "Boot",
110 BUTTON_BOOT
, (struct DOSBootBase
*)DOSBootBase
);
111 DOSBootBase
->bm_MainGadgets
.bootnss
= createButton(
112 344, DOSBootBase
->bottomY
, 280, 14,
113 DOSBootBase
->bm_MainGadgets
.boot
->gadget
, "Boot With No Startup-Sequence",
114 BUTTON_BOOT_WNSS
, (struct DOSBootBase
*)DOSBootBase
);
115 if (!DOSBootBase
->bm_MainGadgets
.bootopt
||
116 !DOSBootBase
->bm_MainGadgets
.displayopt
||
117 !DOSBootBase
->bm_MainGadgets
.expboarddiag
||
118 !DOSBootBase
->bm_MainGadgets
.boot
||
119 !DOSBootBase
->bm_MainGadgets
.bootnss
)
121 return DOSBootBase
->bm_MainGadgets
.bootopt
->gadget
;
124 static struct Gadget
*createGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
126 DOSBootBase
->bm_MainGadgets
.use
= createButton(
127 16, DOSBootBase
->bottomY
, 280, 14,
129 BUTTON_USE
, (struct DOSBootBase
*)DOSBootBase
);
130 DOSBootBase
->bm_MainGadgets
.cancel
= createButton(
131 344, DOSBootBase
->bottomY
, 280, 14,
132 DOSBootBase
->bm_MainGadgets
.use
->gadget
, "Cancel",
133 BUTTON_CANCEL
, (struct DOSBootBase
*)DOSBootBase
);
134 if (!DOSBootBase
->bm_MainGadgets
.use
||
135 !DOSBootBase
->bm_MainGadgets
.cancel
)
137 return DOSBootBase
->bm_MainGadgets
.use
->gadget
;
141 static void freeGadgetsBoot(LIBBASETYPEPTR DOSBootBase
)
143 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.boot
, (struct DOSBootBase
*)DOSBootBase
);
144 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootnss
, (struct DOSBootBase
*)DOSBootBase
);
145 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.bootopt
, (struct DOSBootBase
*)DOSBootBase
);
146 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.displayopt
, (struct DOSBootBase
*)DOSBootBase
);
147 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.expboarddiag
, (struct DOSBootBase
*)DOSBootBase
);
150 static void freeGadgetsUseCancel(LIBBASETYPEPTR DOSBootBase
)
152 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.use
, (struct DOSBootBase
*)DOSBootBase
);
153 freeButtonGadget(DOSBootBase
->bm_MainGadgets
.cancel
, (struct DOSBootBase
*)DOSBootBase
);
156 static struct Gadget
*createGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
158 if (page
== PAGE_MAIN
)
159 return createGadgetsBoot(DOSBootBase
);
161 return createGadgetsUseCancel(DOSBootBase
);
163 static void freeGadgets(LIBBASETYPEPTR DOSBootBase
, WORD page
)
165 if (page
== PAGE_MAIN
)
166 freeGadgetsBoot(DOSBootBase
);
168 freeGadgetsUseCancel(DOSBootBase
);
171 static void toggleMode(LIBBASETYPEPTR DOSBootBase
)
175 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
177 if (OpenResource("ciaa.resource")) {
178 volatile UWORD
*beamcon0
= (UWORD
*)0xdff1dc;
179 GfxBase
->DisplayFlags
^= PAL
| NTSC
;
180 *beamcon0
= (GfxBase
->DisplayFlags
& PAL
) ? 0x0020 : 0x0000;
185 static UWORD
msgLoop(LIBBASETYPEPTR DOSBootBase
, struct Window
*win
)
188 struct IntuiMessage
*msg
;
191 D(bug("[BootMenu] msgLoop(DOSBootBase @ %p, Window @ %p)\n", DOSBootBase
, win
));
197 WaitPort(win
->UserPort
);
198 while ((msg
= (struct IntuiMessage
*)GetMsg(win
->UserPort
)))
200 if (msg
->Class
== IDCMP_VANILLAKEY
) {
203 else if (msg
->Code
>= '1' && msg
->Code
<= '3')
204 exit
= PAGE_MAIN
+ msg
->Code
- '0';
206 toggleMode(DOSBootBase
);
207 } else if (msg
->Class
== IDCMP_GADGETUP
)
213 DOSBootBase
->db_BootFlags
&= ~BF_NO_STARTUP_SEQUENCE
;
216 case BUTTON_BOOT_WNSS
:
217 DOSBootBase
->db_BootFlags
|= BF_NO_STARTUP_SEQUENCE
;
218 exit
= EXIT_BOOT_WNSS
;
222 case BUTTON_CONTINUE
:
225 case BUTTON_BOOT_OPTIONS
:
228 case BUTTON_EXPBOARDDIAG
:
229 exit
= PAGE_EXPANSION
;
231 case BUTTON_DISPLAY_OPTIONS
:
236 ReplyMsg((struct Message
*)msg
);
241 bug("[BootMenu] msgLoop: Window lacks a userport!\n");
245 while ((msg
=(struct IntuiMessage
*)GetMsg(win
->UserPort
)))
246 ReplyMsg(&msg
->ExecMessage
);
250 static void initPageExpansion(LIBBASETYPEPTR DOSBootBase
)
252 struct Window
*win
= DOSBootBase
->bm_Window
;
253 struct ExpansionBase
*ExpansionBase
= DOSBootBase
->bm_ExpansionBase
;
254 struct ConfigDev
*cd
;
258 SetAPen(win
->RPort
, 1);
261 while ((cd
= FindConfigDev(cd
, -1, -1))) {
262 NewRawDoFmt("%2d: %08lx - %08lx (%08lx) %5d %3d %08lx", RAWFMTFUNC_STRING
, text
,
264 cd
->cd_BoardAddr
, cd
->cd_BoardAddr
+ cd
->cd_BoardSize
- 1, cd
->cd_BoardSize
,
265 cd
->cd_Rom
.er_Manufacturer
, cd
->cd_Rom
.er_Product
, cd
->cd_Rom
.er_SerialNumber
);
266 if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROIII
)
268 else if ((cd
->cd_Rom
.er_Type
& ERT_TYPEMASK
) == ERT_ZORROII
)
272 if (cd
->cd_Rom
.er_Type
& ERTF_DIAGVALID
)
273 strcat(text
, " ROM");
274 if (cd
->cd_Rom
.er_Type
& ERTF_MEMLIST
)
275 strcat(text
, " RAM");
276 Move(win
->RPort
, 20, y
);
277 Text(win
->RPort
, text
, strlen(text
));
282 static BOOL
bstreqcstr(BSTR bstr
, CONST_STRPTR cstr
)
288 blen
= AROS_BSTR_strlen(bstr
);
292 return (memcmp(AROS_BSTR_ADDR(bstr
),cstr
,clen
) == 0);
295 void selectBootDevice(LIBBASETYPEPTR DOSBootBase
)
299 if (DOSBootBase
->db_BootDevice
== NULL
&&
300 DOSBootBase
->db_BootNode
!= NULL
)
303 Forbid(); /* .. access to ExpansionBase->MountList */
305 if (DOSBootBase
->db_BootNode
== NULL
&& DOSBootBase
->db_BootDevice
== NULL
)
307 bn
= (APTR
)GetHead(&DOSBootBase
->bm_ExpansionBase
->MountList
);
311 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
313 struct DeviceNode
*dn
;
315 dn
= bn
->bn_DeviceNode
;
316 if (dn
== NULL
|| dn
->dn_Name
== BNULL
)
319 if (bstreqcstr(dn
->dn_Name
, DOSBootBase
->db_BootDevice
))
326 DOSBootBase
->db_BootNode
= bn
;
327 DOSBootBase
->db_BootDevice
= NULL
;
330 /* This makes the selected boot device the actual
331 * boot device. It also updates the boot flags.
333 static void setBootDevice(LIBBASETYPEPTR DOSBootBase
)
337 bn
= DOSBootBase
->db_BootNode
;
341 Remove((struct Node
*)bn
);
342 bn
->bn_Node
.ln_Type
= NT_BOOTNODE
;
343 bn
->bn_Node
.ln_Pri
= 127;
344 /* We use AddHead() instead of Enqueue() here
345 * to *insure* that this gets to the front of
348 AddHead(&DOSBootBase
->bm_ExpansionBase
->MountList
, (struct Node
*)&bn
);
351 DOSBootBase
->bm_ExpansionBase
->eb_BootFlags
= DOSBootBase
->db_BootFlags
;
354 static void initPageBoot(LIBBASETYPEPTR DOSBootBase
)
356 struct Window
*win
= DOSBootBase
->bm_Window
;
359 char text
[100], *textp
;
361 SetAPen(win
->RPort
, 1);
363 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, bn
)
365 struct DeviceNode
*dn
= bn
->bn_DeviceNode
;
366 struct FileSysStartupMsg
*fssm
= BADDR(dn
->dn_Startup
);
367 struct DosEnvec
*de
= NULL
;
369 struct MsgPort
*port
;
373 BOOL devopen
, ismedia
;
375 if (y
>= DOSBootBase
->bottomY
- 20)
377 if (!fssm
|| !fssm
->fssm_Device
)
379 if (fssm
->fssm_Environ
> (BPTR
)0x64) {
380 de
= BADDR(fssm
->fssm_Environ
);
381 if (de
->de_TableSize
< 15)
385 NewRawDoFmt("%c%10s: %4d %s-%ld", RAWFMTFUNC_STRING
, text
,
387 ((DOSBootBase
->db_BootNode
== bn
) ? '*' : '+')
389 AROS_BSTR_ADDR(dn
->dn_Name
),
391 AROS_BSTR_ADDR(fssm
->fssm_Device
),
393 Move(win
->RPort
, 20, y
);
394 Text(win
->RPort
, text
, strlen(text
));
397 devopen
= ismedia
= FALSE
;
398 if ((port
= (struct MsgPort
*)CreateMsgPort())) {
399 if ((io
= (struct IOStdReq
*)CreateIORequest(port
, sizeof(struct IOStdReq
)))) {
400 if (!OpenDevice(AROS_BSTR_ADDR(fssm
->fssm_Device
), fssm
->fssm_Unit
, (struct IORequest
*)io
, fssm
->fssm_Flags
)) {
402 io
->io_Command
= TD_CHANGESTATE
;
404 DoIO((struct IORequest
*)io
);
405 if (!io
->io_Error
&& io
->io_Actual
== 0)
407 CloseDevice((struct IORequest
*)io
);
409 DeleteIORequest((struct IORequest
*)io
);
415 for (i
= 0; i
< 4; i
++) {
416 dostype
[i
] = (de
->de_DosType
>> ((3 - i
) * 8)) & 0xff;
419 else if (dostype
[i
] < 32)
424 size
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) * de
->de_Surfaces
* de
->de_BlocksPerTrack
;
425 /* try to prevent ULONG overflow */
426 if (de
->de_SizeBlock
<= 128)
429 size
*= de
->de_SizeBlock
/ 256;
431 NewRawDoFmt("%s [%08lx] %ldk", RAWFMTFUNC_STRING
, text
,
432 dostype
, de
->de_DosType
,
435 } else if (!devopen
) {
436 textp
= "[device open error]";
437 } else if (!ismedia
) {
438 textp
= "[no media]";
441 Move(win
->RPort
, 400, y
);
442 Text(win
->RPort
, textp
, strlen(textp
));
451 static void centertext(LIBBASETYPEPTR DOSBootBase
, BYTE pen
, WORD y
, const char *text
)
453 struct Window
*win
= DOSBootBase
->bm_Window
;
454 SetAPen(win
->RPort
, pen
);
455 Move(win
->RPort
, win
->Width
/ 2 - TextLength(win
->RPort
, text
, strlen(text
)) / 2, y
);
456 Text(win
->RPort
, text
, strlen(text
));
459 static void initPage(LIBBASETYPEPTR DOSBootBase
, WORD page
)
463 if (page
== PAGE_DISPLAY
)
464 text
= "Display Options";
465 else if (page
== PAGE_EXPANSION
)
466 text
= "Expansion Board Diagnostic";
467 else if (page
== PAGE_BOOT
)
468 text
= "Boot Options";
470 text
= "AROS Early Startup Control";
471 centertext(DOSBootBase
, 2, 10, text
);
473 if (page
== PAGE_BOOT
)
474 initPageBoot(DOSBootBase
);
475 else if (page
== PAGE_EXPANSION
)
476 initPageExpansion(DOSBootBase
);
478 if (page
== PAGE_MAIN
&& (GfxBase
->DisplayFlags
& (NTSC
| PAL
))) {
479 ULONG modeid
= GetVPModeID(&DOSBootBase
->bm_Screen
->ViewPort
);
480 if (modeid
!= INVALID_ID
&& (((modeid
& MONITOR_ID_MASK
) == NTSC_MONITOR_ID
) || ((modeid
& MONITOR_ID_MASK
) == PAL_MONITOR_ID
))) {
481 centertext(DOSBootBase
, 1, 30, "(press a key to toggle the display between PAL and NTSC)");
486 static WORD
initWindow(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
, WORD page
)
488 struct Gadget
*first
= NULL
;
491 if ((first
= createGadgets(DOSBootBase
, page
)) != NULL
)
493 struct NewWindow nw
=
495 0, 0, /* Left, Top */
496 DOSBootBase
->bm_Screen
->Width
, /* Width, Height */
497 DOSBootBase
->bm_Screen
->Height
,
498 0, 1, /* DetailPen, BlockPen */
499 IDCMP_MOUSEBUTTONS
| IDCMP_MOUSEMOVE
| IDCMP_VANILLAKEY
| IDCMP_GADGETUP
| IDCMP_GADGETDOWN
, /* IDCMPFlags */
500 WFLG_SMART_REFRESH
| WFLG_BORDERLESS
| WFLG_ACTIVATE
, /* Flags */
501 first
, /* FirstGadget */
502 NULL
, /* CheckMark */
504 DOSBootBase
->bm_Screen
, /* Screen */
506 0, 0, /* MinWidth, MinHeight */
507 0, 0, /* MaxWidth, MaxHeight */
508 CUSTOMSCREEN
, /* Type */
511 D(bug("[BootMenu] initPage: Gadgets created @ %p\n", first
));
513 if ((DOSBootBase
->bm_Window
= OpenWindow(&nw
)) != NULL
)
515 D(bug("[BootMenu] initScreen: Window opened @ %p\n", DOSBootBase
->bm_Window
));
516 D(bug("[BootMenu] initScreen: Window RastPort @ %p\n", DOSBootBase
->bm_Window
->RPort
));
517 D(bug("[BootMenu] initScreen: Window UserPort @ %p\n", DOSBootBase
->bm_Window
->UserPort
));
518 initPage(DOSBootBase
, page
);
519 newpage
= msgLoop(DOSBootBase
, DOSBootBase
->bm_Window
);
521 CloseWindow(DOSBootBase
->bm_Window
);
523 freeGadgets(DOSBootBase
, page
);
528 static BOOL
initScreen(LIBBASETYPEPTR DOSBootBase
, struct BootConfig
*bcfg
)
532 D(bug("[BootMenu] initScreen()\n"));
535 DOSBootBase
->bm_Screen
= OpenBootScreen(DOSBootBase
);
536 if (DOSBootBase
->bm_Screen
)
538 DOSBootBase
->bottomY
= DOSBootBase
->bm_Screen
->Height
- (DOSBootBase
->bm_Screen
->Height
> 256 ? 32 : 16);
539 D(bug("[BootMenu] initScreen: Screen opened @ %p\n", DOSBootBase
->bm_Screen
));
543 page
= initWindow(DOSBootBase
, bcfg
, page
);
544 } while (page
!= EXIT_BOOT
&& page
!= EXIT_BOOT_WNSS
);
545 CloseBootScreen(DOSBootBase
->bm_Screen
, DOSBootBase
);
550 /* From keyboard.device/keyboard_intern.h */
551 #define KB_MAXKEYS 256
552 #define KB_MATRIXSIZE (KB_MAXKEYS/(sizeof(UBYTE)*8))
553 #define ioStd(x) ((struct IOStdReq *)x)
555 static BOOL
buttonsPressed(LIBBASETYPEPTR DOSBootBase
)
557 BOOL success
= FALSE
;
558 struct MsgPort
*mp
= NULL
;
559 UBYTE matrix
[KB_MATRIXSIZE
];
563 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
564 * Let's check mouse buttons.
566 if (OpenResource("ciaa.resource"))
568 volatile UBYTE
*cia
= (UBYTE
*)0xbfe001;
569 volatile UWORD
*potinp
= (UWORD
*)0xdff016;
571 /* check left + right mouse button state */
572 if ((cia
[0] & 0x40) == 0 && (potinp
[0] & 0x0400) == 0)
577 if ((mp
= CreateMsgPort()) != NULL
)
579 struct IORequest
*io
= NULL
;
580 if ((io
= CreateIORequest(mp
, sizeof ( struct IOStdReq
))) != NULL
)
582 if (0 == OpenDevice("keyboard.device", 0, io
, 0))
584 D(bug("[BootMenu] buttonsPressed: Checking KBD_READMATRIX\n"));
585 ioStd(io
)->io_Command
= KBD_READMATRIX
;
586 ioStd(io
)->io_Data
= matrix
;
587 ioStd(io
)->io_Length
= sizeof(matrix
);
589 if (0 == io
->io_Error
)
593 bug("[BootMenu] buttonsPressed: Matrix : ");
594 for (i
= 0; i
< ioStd(io
)->io_Actual
; i
++)
596 bug("%02x ", matrix
[i
]);
600 if (matrix
[RAWKEY_SPACE
/8] & (1<<(RAWKEY_SPACE
%8)))
602 D(bug("[BootMenu] SPACEBAR pressed\n"));
615 int bootmenu_Init(LIBBASETYPEPTR LIBBASE
, BOOL WantBootMenu
)
617 BOOL bmi_RetVal
= FALSE
;
619 D(bug("[BootMenu] bootmenu_Init()\n"));
621 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
624 * VGA and PCI hardware display drivers still need
625 * external initialization.
626 * This urgently needs to be fixed. After fixing this kludge
627 * will not be needed any more.
629 InitBootConfig(&LIBBASE
->bm_BootConfig
);
630 if (!initHidds(LIBBASE
))
635 /* check keyboard if needed */
637 WantBootMenu
= buttonsPressed(LIBBASE
);
639 /* Bring up early startup menu if requested */
642 D(kprintf("[BootMenu] bootmenu_Init: Entering Boot Menu ...\n"));
643 bmi_RetVal
= initScreen(LIBBASE
, &LIBBASE
->bm_BootConfig
);
646 /* Make the user's select the top boot device */
647 setBootDevice(LIBBASE
);