dosboot.resource: add small hint about boot device page
[AROS.git] / rom / dosboot / menu.c
blob39be2cd652214b0a899f3fbbcc1ef6e152212f67
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Main bootmenu code
6 Lang: english
7 */
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"
34 #include "menu.h"
36 #define PAGE_MAIN 1
37 #define PAGE_BOOT 2
38 #define PAGE_DISPLAY 3
39 #define PAGE_EXPANSION 4
40 #define EXIT_BOOT 5
41 #define EXIT_BOOT_WNSS 6
43 #if (AROS_FLAVOUR & AROS_FLAVOUR_STANDALONE)
44 #ifdef __ppc__
45 #define INITHIDDS_KLUDGE
46 #endif
47 #endif
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)
58 OOP_Class *gfxclass;
59 BOOL success = FALSE;
61 D(bug("[BootMenu] init_gfx('%s')\n", gfxclassname));
63 GfxBase = (void *)OpenLibrary("graphics.library", 41);
64 if (!GfxBase)
65 return FALSE;
67 gfxclass = OOP_FindClass(gfxclassname);
68 if (gfxclass)
70 if (!AddDisplayDriver(gfxclass, NULL, DDRV_BootMode, bootmode, TAG_DONE))
71 success = TRUE;
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))
87 return FALSE;
89 if (!init_gfx(bootcfg->gfxhidd, bootcfg->bootmode, DOSBootBase))
90 return FALSE;
93 D(bug("[BootMenu] initHidds: Hidds initialised\n"));
94 return TRUE;
97 #endif
99 static struct Gadget *createGadgetsBoot(LIBBASETYPEPTR DOSBootBase)
101 /* Create Option Gadgets */
102 DOSBootBase->bm_MainGadgets.bootopt = createButton(
103 180, 63, 280, 14,
104 NULL, "Boot Options...",
105 BUTTON_BOOT_OPTIONS, (struct DOSBootBase *)DOSBootBase);
106 DOSBootBase->bm_MainGadgets.displayopt = createButton(
107 180, 84, 280, 14,
108 DOSBootBase->bm_MainGadgets.bootopt->gadget, "Display Options...",
109 BUTTON_DISPLAY_OPTIONS, (struct DOSBootBase *)DOSBootBase);
110 DOSBootBase->bm_MainGadgets.expboarddiag = createButton(
111 180, 105, 280, 14,
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)
128 return NULL;
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,
136 NULL, "Use",
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)
144 return NULL;
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);
168 else
169 return createGadgetsUseCancel(DOSBootBase);
171 static void freeGadgets(LIBBASETYPEPTR DOSBootBase, WORD page)
173 if (page == PAGE_MAIN)
174 freeGadgetsBoot(DOSBootBase);
175 else
176 freeGadgetsUseCancel(DOSBootBase);
179 static void toggleMode(LIBBASETYPEPTR DOSBootBase)
181 #ifdef mc68000
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;
190 #endif
193 static UWORD msgLoop(LIBBASETYPEPTR DOSBootBase, struct Window *win)
195 WORD exit = -1;
196 struct IntuiMessage *msg;
197 struct Gadget *g;
199 D(bug("[BootMenu] msgLoop(DOSBootBase @ %p, Window @ %p)\n", DOSBootBase, win));
203 if (win->UserPort)
205 WaitPort(win->UserPort);
206 while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
208 if (msg->Class == IDCMP_VANILLAKEY) {
209 if (msg->Code == 27)
210 exit = PAGE_MAIN;
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;
215 struct BootNode *bn;
216 DOSBootBase->db_BootNode = NULL;
218 Forbid(); /* .. access to ExpansionBase->MountList */
219 ForeachNode(&DOSBootBase->bm_ExpansionBase->MountList, bn)
221 if (i++ == pos)
223 DOSBootBase->db_BootNode = bn;
224 break;
227 Permit();
229 if (DOSBootBase->db_BootNode != NULL)
231 /* Refresh itself */
232 exit = PAGE_BOOT;
233 break;
236 else
237 toggleMode(DOSBootBase);
238 } else if (msg->Class == IDCMP_GADGETUP)
240 g = msg->IAddress;
241 switch (g->GadgetID)
243 case BUTTON_BOOT:
244 DOSBootBase->db_BootFlags &= ~BF_NO_STARTUP_SEQUENCE;
245 exit = EXIT_BOOT;
246 break;
247 case BUTTON_BOOT_WNSS:
248 DOSBootBase->db_BootFlags |= BF_NO_STARTUP_SEQUENCE;
249 exit = EXIT_BOOT_WNSS;
250 break;
251 case BUTTON_CANCEL:
252 DOSBootBase->db_BootNode = NULL;
253 /* Fallthrough */
254 case BUTTON_USE:
255 case BUTTON_CONTINUE:
256 exit = PAGE_MAIN;
257 break;
258 case BUTTON_BOOT_OPTIONS:
259 exit = PAGE_BOOT;
260 break;
261 case BUTTON_EXPBOARDDIAG:
262 exit = PAGE_EXPANSION;
263 break;
264 case BUTTON_DISPLAY_OPTIONS:
265 exit = PAGE_DISPLAY;
266 break;
269 ReplyMsg((struct Message *)msg);
272 else
274 bug("[BootMenu] msgLoop: Window lacks a userport!\n");
275 Wait(0);
277 } while (exit < 0);
279 while ((msg=(struct IntuiMessage *)GetMsg(win->UserPort)))
280 ReplyMsg(&msg->ExecMessage);
282 return exit;
285 static void initPageExpansion(LIBBASETYPEPTR DOSBootBase)
287 struct Window *win = DOSBootBase->bm_Window;
288 struct ExpansionBase *ExpansionBase = DOSBootBase->bm_ExpansionBase;
289 struct ConfigDev *cd;
290 WORD y = 50, cnt;
291 char text[100];
293 SetAPen(win->RPort, 1);
294 cd = NULL;
295 cnt = 0;
296 while ((cd = FindConfigDev(cd, -1, -1))) {
297 NewRawDoFmt("%2d: %08lx - %08lx (%08lx) %5d %3d %08lx", RAWFMTFUNC_STRING, text,
298 ++cnt,
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)
302 strcat(text, " Z3");
303 else if ((cd->cd_Rom.er_Type & ERT_TYPEMASK) == ERT_ZORROII)
304 strcat(text, " Z2");
305 else
306 strcat(text, " ");
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));
313 y += 16;
317 static void initPageBoot(LIBBASETYPEPTR DOSBootBase)
319 struct Window *win = DOSBootBase->bm_Window;
320 struct BootNode *bn;
321 WORD y = 70;
322 char text[100], *textp;
324 SetAPen(win->RPort, 1);
326 ForeachNode(&DOSBootBase->bm_ExpansionBase->MountList, bn)
328 struct DeviceNode *dn = bn->bn_DeviceNode;
329 struct FileSysStartupMsg *fssm = BADDR(dn->dn_Startup);
330 struct DosEnvec *de = NULL;
331 struct IOStdReq *io;
332 struct MsgPort *port;
333 char dostype[5];
334 UBYTE i;
335 ULONG size;
336 BOOL devopen, ismedia;
338 if (y >= DOSBootBase->bottomY - 20)
339 break;
340 if (!fssm || !fssm->fssm_Device)
341 continue;
342 if (fssm->fssm_Environ > (BPTR)0x64) {
343 de = BADDR(fssm->fssm_Environ);
344 if (de->de_TableSize < 15)
345 de = NULL;
348 NewRawDoFmt("%c%10s: %4d %s-%ld", RAWFMTFUNC_STRING, text,
349 (DOSBootBase->db_BootNode == bn) ? '*' : IsBootableNode(bn) ? '+' : ' ',
350 AROS_BSTR_ADDR(dn->dn_Name),
351 bn->bn_Node.ln_Pri,
352 AROS_BSTR_ADDR(fssm->fssm_Device),
353 fssm->fssm_Unit);
354 Move(win->RPort, 20, y);
355 Text(win->RPort, text, strlen(text));
357 textp = NULL;
358 devopen = ismedia = FALSE;
359 if ((port = (struct MsgPort*)CreateMsgPort())) {
360 if ((io = (struct IOStdReq*)CreateIORequest(port, sizeof(struct IOStdReq)))) {
361 if (!OpenDevice(AROS_BSTR_ADDR(fssm->fssm_Device), fssm->fssm_Unit, (struct IORequest*)io, fssm->fssm_Flags)) {
362 devopen = TRUE;
363 io->io_Command = TD_CHANGESTATE;
364 io->io_Actual = 1;
365 DoIO((struct IORequest*)io);
366 if (!io->io_Error && io->io_Actual == 0)
367 ismedia = TRUE;
368 CloseDevice((struct IORequest*)io);
370 DeleteIORequest((struct IORequest*)io);
372 DeleteMsgPort(port);
375 if (de && ismedia) {
376 for (i = 0; i < 4; i++) {
377 dostype[i] = (de->de_DosType >> ((3 - i) * 8)) & 0xff;
378 if (dostype[i] < 9)
379 dostype[i] += '0';
380 else if (dostype[i] < 32)
381 dostype[i] = '.';
383 dostype[4] = 0;
385 size = (de->de_HighCyl - de->de_LowCyl + 1) * de->de_Surfaces * de->de_BlocksPerTrack;
386 /* try to prevent ULONG overflow */
387 if (de->de_SizeBlock <= 128)
388 size /= 2;
389 else
390 size *= de->de_SizeBlock / 256;
392 NewRawDoFmt("%s [%08lx] %ldk", RAWFMTFUNC_STRING, text,
393 dostype, de->de_DosType,
394 size);
395 textp = text;
396 } else if (!devopen) {
397 textp = "[device open error]";
398 } else if (!ismedia) {
399 textp = "[no media]";
401 if (textp) {
402 Move(win->RPort, 400, y);
403 Text(win->RPort, textp, strlen(textp));
406 y += 16;
412 static void centertext(LIBBASETYPEPTR DOSBootBase, BYTE pen, WORD y, const char *text)
414 struct Window *win = DOSBootBase->bm_Window;
415 SetAPen(win->RPort, pen);
416 Move(win->RPort, win->Width / 2 - TextLength(win->RPort, text, strlen(text)) / 2, y);
417 Text(win->RPort, text, strlen(text));
420 static void initPage(LIBBASETYPEPTR DOSBootBase, WORD page)
422 UBYTE *text;
424 if (page == PAGE_DISPLAY)
425 text = "Display Options";
426 else if (page == PAGE_EXPANSION)
427 text = "Expansion Board Diagnostic";
428 else if (page == PAGE_BOOT)
429 text = "Boot Options";
430 else
431 text = "AROS Early Startup Control";
432 centertext(DOSBootBase, 2, 10, text);
434 if (page == PAGE_BOOT)
435 initPageBoot(DOSBootBase);
436 else if (page == PAGE_EXPANSION)
437 initPageExpansion(DOSBootBase);
439 if (page == PAGE_MAIN && (GfxBase->DisplayFlags & (NTSC | PAL))) {
440 ULONG modeid = GetVPModeID(&DOSBootBase->bm_Screen->ViewPort);
441 if (modeid != INVALID_ID && (((modeid & MONITOR_ID_MASK) == NTSC_MONITOR_ID) || ((modeid & MONITOR_ID_MASK) == PAL_MONITOR_ID))) {
442 centertext(DOSBootBase, 1, 30, "(press a key to toggle the display between PAL and NTSC)");
446 if (page == PAGE_BOOT)
448 centertext(DOSBootBase, 1, 30, "Press A-J to select boot device");
449 centertext(DOSBootBase, 1, 45, "\"+\" => bootable, \"*\" => selected for boot");
453 static WORD initWindow(LIBBASETYPEPTR DOSBootBase, struct BootConfig *bcfg, WORD page)
455 struct Gadget *first = NULL;
456 WORD newpage = -1;
458 if ((first = createGadgets(DOSBootBase, page)) != NULL)
460 struct NewWindow nw =
462 0, 0, /* Left, Top */
463 DOSBootBase->bm_Screen->Width, /* Width, Height */
464 DOSBootBase->bm_Screen->Height,
465 0, 1, /* DetailPen, BlockPen */
466 IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE | IDCMP_VANILLAKEY | IDCMP_GADGETUP | IDCMP_GADGETDOWN, /* IDCMPFlags */
467 WFLG_SMART_REFRESH | WFLG_BORDERLESS | WFLG_ACTIVATE, /* Flags */
468 first, /* FirstGadget */
469 NULL, /* CheckMark */
470 NULL, /* Title */
471 DOSBootBase->bm_Screen, /* Screen */
472 NULL, /* BitMap */
473 0, 0, /* MinWidth, MinHeight */
474 0, 0, /* MaxWidth, MaxHeight */
475 CUSTOMSCREEN, /* Type */
478 D(bug("[BootMenu] initPage: Gadgets created @ %p\n", first));
480 if ((DOSBootBase->bm_Window = OpenWindow(&nw)) != NULL)
482 D(bug("[BootMenu] initScreen: Window opened @ %p\n", DOSBootBase->bm_Window));
483 D(bug("[BootMenu] initScreen: Window RastPort @ %p\n", DOSBootBase->bm_Window->RPort));
484 D(bug("[BootMenu] initScreen: Window UserPort @ %p\n", DOSBootBase->bm_Window->UserPort));
485 initPage(DOSBootBase, page);
486 newpage = msgLoop(DOSBootBase, DOSBootBase->bm_Window);
488 CloseWindow(DOSBootBase->bm_Window);
490 freeGadgets(DOSBootBase, page);
492 return newpage;
495 static BOOL initScreen(LIBBASETYPEPTR DOSBootBase, struct BootConfig *bcfg)
497 WORD page;
499 D(bug("[BootMenu] initScreen()\n"));
501 page = -1;
502 DOSBootBase->bm_Screen = OpenBootScreen(DOSBootBase);
503 if (DOSBootBase->bm_Screen)
505 DOSBootBase->bottomY = DOSBootBase->bm_Screen->Height - (DOSBootBase->bm_Screen->Height > 256 ? 32 : 16);
506 D(bug("[BootMenu] initScreen: Screen opened @ %p\n", DOSBootBase->bm_Screen));
508 page = PAGE_MAIN;
509 do {
510 page = initWindow(DOSBootBase, bcfg, page);
511 } while (page != EXIT_BOOT && page != EXIT_BOOT_WNSS);
512 CloseBootScreen(DOSBootBase->bm_Screen, DOSBootBase);
514 return page >= 0;
517 /* From keyboard.device/keyboard_intern.h */
518 #define KB_MAXKEYS 256
519 #define KB_MATRIXSIZE (KB_MAXKEYS/(sizeof(UBYTE)*8))
520 #define ioStd(x) ((struct IOStdReq *)x)
522 static BOOL buttonsPressed(LIBBASETYPEPTR DOSBootBase)
524 BOOL success = FALSE;
525 struct MsgPort *mp = NULL;
526 UBYTE matrix[KB_MATRIXSIZE];
528 #ifdef mc68000
530 * On m68k we may have ciaa.resource (if running on classic Amiga HW)
531 * Let's check mouse buttons.
533 if (OpenResource("ciaa.resource"))
535 volatile UBYTE *cia = (UBYTE*)0xbfe001;
536 volatile UWORD *potinp = (UWORD*)0xdff016;
538 /* check left + right mouse button state */
539 if ((cia[0] & 0x40) == 0 && (potinp[0] & 0x0400) == 0)
540 return TRUE;
542 #endif
544 if ((mp = CreateMsgPort()) != NULL)
546 struct IORequest *io = NULL;
547 if ((io = CreateIORequest(mp, sizeof ( struct IOStdReq))) != NULL)
549 if (0 == OpenDevice("keyboard.device", 0, io, 0))
551 D(bug("[BootMenu] buttonsPressed: Checking KBD_READMATRIX\n"));
552 ioStd(io)->io_Command = KBD_READMATRIX;
553 ioStd(io)->io_Data = matrix;
554 ioStd(io)->io_Length = sizeof(matrix);
555 DoIO(io);
556 if (0 == io->io_Error)
559 int i;
560 bug("[BootMenu] buttonsPressed: Matrix : ");
561 for (i = 0; i < ioStd(io)->io_Actual; i ++)
563 bug("%02x ", matrix[i]);
565 bug("\n");
567 if (matrix[RAWKEY_SPACE/8] & (1<<(RAWKEY_SPACE%8)))
569 D(bug("[BootMenu] SPACEBAR pressed\n"));
570 success = TRUE;
573 CloseDevice(io);
575 DeleteIORequest(io);
577 DeleteMsgPort(mp);
579 return success;
582 int bootmenu_Init(LIBBASETYPEPTR LIBBASE, BOOL WantBootMenu)
584 BOOL bmi_RetVal = FALSE;
586 D(bug("[BootMenu] bootmenu_Init()\n"));
588 #ifdef INITHIDDS_KLUDGE
590 * PCI hardware display drivers still need external initialization.
591 * This urgently needs to be fixed. After fixing this kludge
592 * will not be needed any more.
594 InitBootConfig(&LIBBASE->bm_BootConfig);
595 if (!initHidds(LIBBASE))
596 return FALSE;
597 #endif
599 /* check keyboard if needed */
600 if (!WantBootMenu)
601 WantBootMenu = buttonsPressed(LIBBASE);
603 /* Bring up early startup menu if requested */
604 if (WantBootMenu)
606 D(kprintf("[BootMenu] bootmenu_Init: Entering Boot Menu ...\n"));
607 bmi_RetVal = initScreen(LIBBASE, &LIBBASE->bm_BootConfig);
610 return bmi_RetVal;