xref: /netbsd-src/sys/arch/hpc/stand/hpcboot/menu/menu.cpp (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* -*-C++-*-	$NetBSD: menu.cpp,v 1.9 2004/03/28 15:32:35 uwe Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <hpcmenu.h>
40 #include <hpcboot.h>
41 #include <res/resource.h>
42 #include <menu/window.h>
43 #include <menu/tabwindow.h>
44 #include <menu/rootwindow.h>
45 #include <machine/bootinfo.h>
46 #include <framebuffer.h>
47 #include <console.h>
48 
49 #include <menu/menu.h>
50 
51 TabWindow *
52 TabWindowBase::boot(int id)
53 {
54 	TabWindow *w = NULL;
55 	HpcMenuInterface &menu = HPC_MENU;
56 
57 	switch(id) {
58 	default:
59 		break;
60 	case IDC_BASE_MAIN:
61 		menu._main = new MainTabWindow(*this, IDC_BASE_MAIN);
62 		w = menu._main;
63 		break;
64 	case IDC_BASE_OPTION:
65 		menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION);
66 		w = menu._option;
67 		break;
68 	case IDC_BASE_CONSOLE:
69 		menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE);
70 		w = menu._console;
71 		break;
72 	}
73 
74 	if (w)
75 		w->create(0);
76 
77 	return w;
78 }
79 
80 //
81 // Main window
82 //
83 void
84 MainTabWindow::_insert_item(HWND w, TCHAR *name, int id)
85 {
86 	int idx = SendDlgItemMessage(w, id, CB_ADDSTRING, 0,
87 	    reinterpret_cast <LPARAM>(name));
88 	if (idx != CB_ERR)
89 		SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETITEMDATA,
90 		    idx, _item_idx++);
91 }
92 
93 void
94 MainTabWindow::init(HWND w)
95 {
96 	HpcMenuInterface &menu = HPC_MENU;
97 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
98 
99 	_window = w;
100 	// insert myself to tab-control
101 	TabWindow::init(w);
102 
103 	// setup child.
104 	TCHAR *entry;
105 	int i;
106 	// kernel directory path
107 	for (i = 0; entry = menu.dir(i); i++)
108 		_insert_item(w, entry, IDC_MAIN_DIR);
109 	SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETCURSEL, menu.dir_default(),
110 	    0);
111 	// platform
112 	_sort_platids(w);
113 	// kernel file name.
114 	Edit_SetText(GetDlgItem(w, IDC_MAIN_KERNEL), pref.kernel_user ?
115 	    pref.kernel_user_file : TEXT("netbsd.gz"));
116 
117 	// root file system.
118 	int fs = pref.rootfs + IDC_MAIN_ROOT_;
119 	_set_check(fs, TRUE);
120 
121 	_edit_md_root = GetDlgItem(w, IDC_MAIN_ROOT_MD_OPS);
122 	Edit_SetText(_edit_md_root, pref.rootfs_file);
123 	EnableWindow(_edit_md_root, fs == IDC_MAIN_ROOT_MD ? TRUE : FALSE);
124 
125 	// layout checkbox and editbox.
126 	layout();
127 
128 	// set default kernel boot options.
129 	_set_check(IDC_MAIN_OPTION_A, pref.boot_ask_for_name);
130 	_set_check(IDC_MAIN_OPTION_D, pref.boot_debugger);
131 	_set_check(IDC_MAIN_OPTION_S, pref.boot_single_user);
132 	_set_check(IDC_MAIN_OPTION_V, pref.boot_verbose);
133 	_set_check(IDC_MAIN_OPTION_H, pref.boot_serial);
134 
135 	// serial console speed.
136 	TCHAR *speed_tab[] = { L"9600", L"19200", L"115200", 0 };
137 	int sel = 0;
138 	i = 0;
139 	for (TCHAR **speed = speed_tab; *speed; speed++, i++) {
140 		_insert_item(w, *speed, IDC_MAIN_OPTION_H_SPEED);
141 		if (_wtoi(*speed) == pref.serial_speed)
142 			sel = i;
143 	}
144 	_combobox_serial_speed = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED);
145 	SendDlgItemMessage(w, IDC_MAIN_OPTION_H_SPEED, CB_SETCURSEL, sel, 0);
146 	EnableWindow(_combobox_serial_speed, pref.boot_serial);
147 }
148 
149 int
150 MainTabWindow::_platcmp(const void *a, const void *b)
151 {
152 	const MainTabWindow::PlatMap *pa =
153 		reinterpret_cast <const MainTabWindow::PlatMap *>(a);
154 	const MainTabWindow::PlatMap *pb =
155 		reinterpret_cast <const MainTabWindow::PlatMap *>(b);
156 
157 	return wcscmp(pa->name, pb->name);
158 }
159 
160 void
161 MainTabWindow::_sort_platids(HWND w)
162 {
163 	HpcMenuInterface &menu = HPC_MENU;
164 	MainTabWindow::PlatMap *p;
165 	TCHAR *entry;
166 	int nids;
167 	int i;
168 
169 	for (nids = 0; menu.platform_get(nids); ++nids)
170 		continue;
171 
172 	_platmap = reinterpret_cast <MainTabWindow::PlatMap *>
173 		(malloc(nids * sizeof(MainTabWindow::PlatMap)));
174 
175 	if (_platmap == NULL) {
176 		// can't sort, present in the order of definition
177 		for (i = 0; entry = menu.platform_get(i); i++)
178 			_insert_item(w, entry, IDC_MAIN_PLATFORM);
179 		SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL,
180 				   menu.platform_default(), 0);
181 		return;
182 	}
183 
184 	for (i = 0, p = _platmap; i < nids; ++i, ++p) {
185 		p->id = i;
186 		p->name = menu.platform_get(i);
187 	}
188 
189 	qsort(_platmap, nids, sizeof(MainTabWindow::PlatMap),
190 	      MainTabWindow::_platcmp);
191 
192 	int defid = menu.platform_default();
193 	int defitem = 0;
194 	for (i = 0; i < nids; ++i) {
195 		if (_platmap[i].id == defid)
196 			defitem = i;
197 		_insert_item(w, _platmap[i].name, IDC_MAIN_PLATFORM);
198 	}
199 	SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, defitem, 0);
200 }
201 
202 int
203 MainTabWindow::_item_to_platid(int idx)
204 {
205 	if (_platmap == NULL)
206 		return idx;
207 	else
208 		return _platmap[idx].id;
209 }
210 
211 void
212 MainTabWindow::layout()
213 {
214 	// inquire display size.
215 	HDC hdc = GetDC(0);
216 	int width = GetDeviceCaps(hdc, HORZRES);
217 	int height = GetDeviceCaps(hdc, VERTRES);
218 	ReleaseDC(0, hdc);
219 
220 	// set origin
221 	int x, y;
222 	if (width <= 320) {
223 		x = 5, y = 125;
224 	} else if (height <= 240) {
225 		x = 250, y = 5;
226 	} else {
227 		x = 5, y = 125;
228 	}
229 
230 	HWND h;
231 	h = GetDlgItem(_window, IDC_MAIN_OPTION_V);
232 	SetWindowPos(h, 0, x, y, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
233 	h = GetDlgItem(_window, IDC_MAIN_OPTION_S);
234 	SetWindowPos(h, 0, x, y + 20, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
235 	h = GetDlgItem(_window, IDC_MAIN_OPTION_A);
236 	SetWindowPos(h, 0, x, y + 40, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
237 	h = GetDlgItem(_window, IDC_MAIN_OPTION_D);
238 	SetWindowPos(h, 0, x, y + 60, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
239 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H);
240 	SetWindowPos(h, 0, x, y + 80, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
241 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED);
242 	SetWindowPos(h, 0, x + 100, y + 80, 120, 10, SWP_NOSIZE | SWP_NOZORDER);
243 }
244 
245 void
246 MainTabWindow::get()
247 {
248 	HpcMenuInterface &menu = HPC_MENU;
249 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
250 
251 	HWND w = GetDlgItem(_window, IDC_MAIN_DIR);
252 	ComboBox_GetText(w, pref.dir_user_path, MAX_PATH);
253 	pref.dir_user = TRUE;
254 	w = GetDlgItem(_window, IDC_MAIN_KERNEL);
255 	Edit_GetText(w, pref.kernel_user_file, MAX_PATH);
256 	pref.kernel_user = TRUE;
257 
258 	int i = ComboBox_GetCurSel(GetDlgItem(_window, IDC_MAIN_PLATFORM));
259 	menu.platform_set(_item_to_platid(i));
260 
261 	if (_is_checked(IDC_MAIN_ROOT_WD))
262 		pref.rootfs = 0;
263 	else if (_is_checked(IDC_MAIN_ROOT_SD))
264 		pref.rootfs = 1;
265 	else if (_is_checked(IDC_MAIN_ROOT_MD))
266 		pref.rootfs = 2;
267 	else if (_is_checked(IDC_MAIN_ROOT_NFS))
268 		pref.rootfs = 3;
269 
270 	pref.boot_ask_for_name	= _is_checked(IDC_MAIN_OPTION_A);
271 	pref.boot_debugger	= _is_checked(IDC_MAIN_OPTION_D);
272 	pref.boot_verbose	= _is_checked(IDC_MAIN_OPTION_V);
273 	pref.boot_single_user	= _is_checked(IDC_MAIN_OPTION_S);
274 	pref.boot_serial	= _is_checked(IDC_MAIN_OPTION_H);
275 	Edit_GetText(_edit_md_root, pref.rootfs_file, MAX_PATH);
276 
277 	TCHAR tmpbuf[8];
278 	ComboBox_GetText(_combobox_serial_speed, tmpbuf, 8);
279 	pref.serial_speed = _wtoi(tmpbuf);
280 }
281 
282 void
283 MainTabWindow::command(int id, int msg)
284 {
285 	switch (id) {
286 	case IDC_MAIN_OPTION_H:
287 		EnableWindow(_combobox_serial_speed,
288 		    _is_checked(IDC_MAIN_OPTION_H));
289 		break;
290 	case IDC_MAIN_ROOT_WD:
291 		/* FALLTHROUGH */
292 	case IDC_MAIN_ROOT_SD:
293 		/* FALLTHROUGH */
294 	case IDC_MAIN_ROOT_MD:
295 		/* FALLTHROUGH */
296 	case IDC_MAIN_ROOT_NFS:
297 		EnableWindow(_edit_md_root, _is_checked(IDC_MAIN_ROOT_MD));
298 	}
299 }
300 
301 //
302 // Option window
303 //
304 void
305 OptionTabWindow::init(HWND w)
306 {
307 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
308 
309 	_window = w;
310 
311 	TabWindow::init(_window);
312 	_spin_edit = GetDlgItem(_window, IDC_OPT_AUTO_INPUT);
313 	_spin = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE |
314 	    UDS_SETBUDDYINT | UDS_ALIGNRIGHT, 80, 0, 50, 50, _window,
315 	    IDC_OPT_AUTO_UPDOWN, _app._instance, _spin_edit, 60, 1, 30);
316 	BOOL onoff = pref.auto_boot ? TRUE : FALSE;
317 	EnableWindow(_spin_edit, onoff);
318 	EnableWindow(_spin, onoff);
319 
320 	SET_CHECK(AUTO, pref.auto_boot);
321 	if (pref.auto_boot) {
322 		TCHAR tmp[32];
323 		wsprintf(tmp, TEXT("%d"), pref.auto_boot);
324 		Edit_SetText(_spin_edit, tmp);
325 	}
326 	SET_CHECK(VIDEO,	pref.reverse_video);
327 	SET_CHECK(PAUSE,	pref.pause_before_boot);
328 	SET_CHECK(DEBUG,	pref.load_debug_info);
329 	SET_CHECK(SAFETY,	pref.safety_message);
330 	Edit_SetText(GetDlgItem(w, IDC_OPT_EXTKOPT), pref.boot_extra);
331 }
332 
333 void
334 OptionTabWindow::command(int id, int msg)
335 {
336 	switch (id) {
337 	case IDC_OPT_AUTO:
338 		if (IS_CHECKED(AUTO)) {
339 			EnableWindow(_spin_edit, TRUE);
340 			EnableWindow(_spin, TRUE);
341 		} else {
342 			EnableWindow(_spin_edit, FALSE);
343 			EnableWindow(_spin, FALSE);
344 		}
345 		break;
346 	}
347 }
348 
349 void
350 OptionTabWindow::get()
351 {
352 	HWND w;
353 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
354 	if (IS_CHECKED(AUTO)) {
355 		TCHAR tmp[32];
356 		Edit_GetText(_spin_edit, tmp, 32);
357 		pref.auto_boot = _wtoi(tmp);
358 	} else
359 		pref.auto_boot = 0;
360 	pref.reverse_video	= IS_CHECKED(VIDEO);
361 	pref.pause_before_boot	= IS_CHECKED(PAUSE);
362 	pref.load_debug_info	= IS_CHECKED(DEBUG);
363 	pref.safety_message	= IS_CHECKED(SAFETY);
364 
365 	w = GetDlgItem(_window, IDC_OPT_EXTKOPT);
366 	Edit_GetText(w, pref.boot_extra, MAX_BOOT_STR);
367 }
368 #undef IS_CHECKED
369 #undef SET_CHECK
370 
371 
372 //
373 // Console window
374 //
375 void
376 ConsoleTabWindow::print(TCHAR *buf, BOOL force_display)
377 {
378 	int cr;
379 	TCHAR *p;
380 
381 	if (force_display)
382 		goto display;
383 
384 	if (_filesave) {
385 		if (_logfile == INVALID_HANDLE_VALUE && !_open_log_file()) {
386 			_filesave = FALSE;
387 			_set_check(IDC_CONS_FILESAVE, _filesave);
388 			EnableWindow(_filename_edit, _filesave);
389 			goto display;
390 		}
391 		DWORD cnt;
392 		char c;
393 		for (int i = 0; *buf != TEXT('\0'); buf++) {
394 			c = *buf & 0x7f;
395 			WriteFile(_logfile, &c, 1, &cnt, 0);
396 		}
397 		FlushFileBuffers(_logfile);
398 		return;
399 	}
400 
401  display:
402 	// count number of '\n'
403 	for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++)
404 		continue;
405 
406 	// total length of new buffer ('\n' -> "\r\n" + '\0')
407 	size_t sz = (wcslen(buf) + cr + 1) * sizeof(TCHAR);
408 
409 	p = reinterpret_cast <TCHAR *>(malloc(sz));
410 	if (p == NULL)
411 		return;
412 
413 	// convert newlines
414 	TCHAR *d = p;
415 	while (*buf != TEXT('\0')) {
416 		TCHAR c = *buf++;
417 		if (c == TEXT('\n'))
418 			*d++ = TEXT('\r');
419 		*d++ = c;
420 	}
421 	*d = TEXT('\0');
422 
423 	// append the text and scroll
424 	int end = Edit_GetTextLength(_edit);
425 	Edit_SetSel(_edit, end, end);
426 	Edit_ReplaceSel(_edit, p);
427 	Edit_ScrollCaret(_edit);
428 	UpdateWindow(_edit);
429 
430 	free(p);
431 }
432 
433 void
434 ConsoleTabWindow::init(HWND w)
435 {
436 	// at this time _window is NULL.
437 	// use argument of window procedure.
438 	TabWindow::init(w);
439 	_edit = GetDlgItem(w, IDC_CONS_EDIT);
440 	MoveWindow(_edit, 5, 60, _rect.right - _rect.left - 10,
441 	    _rect.bottom - _rect.top - 60, TRUE);
442 	Edit_FmtLines(_edit, TRUE);
443 
444 	// log file.
445 	_filename_edit = GetDlgItem(w, IDC_CONS_FILENAME);
446 	_filesave = FALSE;
447 	Edit_SetText(_filename_edit, L"bootlog.txt");
448 	EnableWindow(_filename_edit, _filesave);
449 }
450 
451 void
452 ConsoleTabWindow::command(int id, int msg)
453 {
454 	HpcMenuInterface &menu = HPC_MENU;
455 	struct HpcMenuInterface::cons_hook_args *hook = 0;
456 	int bit;
457 
458 	switch(id) {
459 	case IDC_CONS_FILESAVE:
460 		_filesave = _is_checked(IDC_CONS_FILESAVE);
461 		EnableWindow(_filename_edit, _filesave);
462 		break;
463 	case IDC_CONS_CHK0:
464 		/* FALLTHROUGH */
465 	case IDC_CONS_CHK1:
466 		/* FALLTHROUGH */
467 	case IDC_CONS_CHK2:
468 		/* FALLTHROUGH */
469 	case IDC_CONS_CHK3:
470 		/* FALLTHROUGH */
471 	case IDC_CONS_CHK4:
472 		/* FALLTHROUGH */
473 	case IDC_CONS_CHK5:
474 		/* FALLTHROUGH */
475 	case IDC_CONS_CHK6:
476 		/* FALLTHROUGH */
477 	case IDC_CONS_CHK7:
478 		bit = 1 << (id - IDC_CONS_CHK_);
479 		if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0))
480 			menu._cons_parameter |= bit;
481 		else
482 			menu._cons_parameter &= ~bit;
483 		break;
484 	case IDC_CONS_BTN0:
485 		/* FALLTHROUGH */
486 	case IDC_CONS_BTN1:
487 		/* FALLTHROUGH */
488 	case IDC_CONS_BTN2:
489 		/* FALLTHROUGH */
490 	case IDC_CONS_BTN3:
491 		hook = &menu._cons_hook[id - IDC_CONS_BTN_];
492 		if (hook->func)
493 			hook->func(hook->arg, menu._cons_parameter);
494 
495 		break;
496 	}
497 }
498 
499 BOOL
500 ConsoleTabWindow::_open_log_file()
501 {
502 	TCHAR path[MAX_PATH];
503 	TCHAR filename[MAX_PATH];
504 	TCHAR filepath[MAX_PATH];
505 
506 	if (!_find_pref_dir(path)) {
507 		print(L"couldn't find temporary directory.\n", TRUE);
508 		return FALSE;
509 	}
510 
511 	Edit_GetText(_filename_edit, filename, MAX_PATH);
512 	wsprintf(filepath, TEXT("\\%s\\%s"), path, filename);
513 	_logfile = CreateFile(filepath, GENERIC_WRITE, 0, 0,
514 	    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
515 	if (_logfile == INVALID_HANDLE_VALUE)
516 		return FALSE;
517 
518 	wsprintf(path, TEXT("log file is %s\n"), filepath);
519 	print(path, TRUE);
520 
521 	return TRUE;
522 }
523 
524 //
525 // Common utility
526 //
527 BOOL
528 _find_pref_dir(TCHAR *path)
529 {
530 	WIN32_FIND_DATA fd;
531 	HANDLE find;
532 
533 	lstrcpy(path, TEXT("\\*.*"));
534 	find = FindFirstFile(path, &fd);
535 
536 	if (find != INVALID_HANDLE_VALUE) {
537 		do {
538 			int attr = fd.dwFileAttributes;
539 			if ((attr & FILE_ATTRIBUTE_DIRECTORY) &&
540 			    (attr & FILE_ATTRIBUTE_TEMPORARY)) {
541 				wcscpy(path, fd.cFileName);
542 				FindClose(find);
543 				return TRUE;
544 			}
545 		} while (FindNextFile(find, &fd));
546 	}
547 	FindClose(find);
548 
549 	return FALSE;
550 }
551