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