1 /* -*-C++-*- $NetBSD: hpcmenu.cpp,v 1.2 2001/02/21 16:01:53 uch 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 // 50 // Main window 51 // 52 class MainTabWindow : public TabWindow 53 { 54 private: 55 HWND _edit_md_root; 56 57 int _item_idx; 58 void _insert_item(HWND w, TCHAR *name, int id) { 59 int idx = SendDlgItemMessage(w, id, CB_ADDSTRING, 0, 60 reinterpret_cast <LPARAM>(name)); 61 if (idx != CB_ERR) 62 SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETITEMDATA, 63 idx, _item_idx++); 64 } 65 66 public: 67 explicit MainTabWindow(TabWindowBase &base, int id) 68 : TabWindow(base, id, TEXT("WMain")) { 69 _item_idx = 0; 70 } 71 virtual ~MainTabWindow(void) { /* NO-OP */ } 72 virtual void init(HWND w) { 73 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 74 struct HpcMenuInterface::HpcMenuPreferences 75 *pref = &menu._pref; 76 _window = w; 77 // insert myself to tab-control 78 TabWindow::init(w); 79 80 // setup child. 81 TCHAR *entry; 82 int i; 83 // kernel directory path 84 for (i = 0; entry = menu.dir(i); i++) 85 _insert_item(w, entry, IDC_MAIN_DIR); 86 SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETCURSEL, 87 menu.dir_default(), 0); 88 // platform 89 for (i = 0; entry = menu.platform_get(i); i++) 90 _insert_item(w, entry, IDC_MAIN_PLATFORM); 91 SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, 92 menu.platform_default(), 0); 93 // kernel file name. 94 Edit_SetText(GetDlgItem(w, IDC_MAIN_KERNEL), 95 pref->kernel_user ? pref->kernel_user_file : 96 TEXT("netbsd.gz")); 97 98 // root file system. 99 int fs = pref->rootfs + IDC_MAIN_ROOT_; 100 _set_check(fs, TRUE); 101 102 _edit_md_root = GetDlgItem(w, IDC_MAIN_ROOT_MD_OPS); 103 Edit_SetText(_edit_md_root, pref->rootfs_file); 104 EnableWindow(_edit_md_root, fs == IDC_MAIN_ROOT_MD 105 ? TRUE : FALSE); 106 107 // kernel boot options. 108 _set_check(IDC_MAIN_OPTION_A, pref->boot_ask_for_name); 109 _set_check(IDC_MAIN_OPTION_S, pref->boot_single_user); 110 _set_check(IDC_MAIN_OPTION_V, pref->boot_verbose); 111 _set_check(IDC_MAIN_OPTION_H, pref->boot_serial); 112 } 113 114 void get(void) { 115 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 116 struct HpcMenuInterface::HpcMenuPreferences 117 *pref = &menu._pref; 118 119 HWND w = GetDlgItem(_window, IDC_MAIN_DIR); 120 ComboBox_GetText(w, pref->dir_user_path, MAX_PATH); 121 pref->dir_user = TRUE; 122 w = GetDlgItem(_window, IDC_MAIN_KERNEL); 123 Edit_GetText(w, pref->kernel_user_file, MAX_PATH); 124 pref->kernel_user = TRUE; 125 126 int i = ComboBox_GetCurSel(GetDlgItem(_window, 127 IDC_MAIN_PLATFORM)); 128 menu.platform_set(i); 129 130 if (_is_checked(IDC_MAIN_ROOT_WD)) 131 pref->rootfs = 0; 132 else if (_is_checked(IDC_MAIN_ROOT_SD)) 133 pref->rootfs = 1; 134 else if (_is_checked(IDC_MAIN_ROOT_MD)) 135 pref->rootfs = 2; 136 else if (_is_checked(IDC_MAIN_ROOT_NFS)) 137 pref->rootfs = 3; 138 139 pref->boot_ask_for_name = _is_checked(IDC_MAIN_OPTION_A); 140 pref->boot_verbose = _is_checked(IDC_MAIN_OPTION_V); 141 pref->boot_single_user = _is_checked(IDC_MAIN_OPTION_S); 142 pref->boot_serial = _is_checked(IDC_MAIN_OPTION_H); 143 Edit_GetText(_edit_md_root, pref->rootfs_file, MAX_PATH); 144 } 145 146 virtual void command(int id, int msg) { 147 EnableWindow(_edit_md_root, 148 _is_checked(IDC_MAIN_ROOT_MD) ? TRUE : FALSE); 149 } 150 }; 151 152 // 153 // Option window 154 // 155 class OptionTabWindow : public TabWindow 156 { 157 public: 158 HWND _spin_edit; 159 HWND _spin; 160 #define IS_CHECKED(x) _is_checked(IDC_OPT_##x) 161 #define SET_CHECK(x, b) _set_check(IDC_OPT_##x,(b)) 162 163 public: 164 explicit OptionTabWindow(TabWindowBase &base, int id) 165 : TabWindow(base, id, TEXT("WOption")) { 166 _spin_edit = NULL; 167 _spin = NULL; 168 } 169 virtual ~OptionTabWindow(void) { /* NO-OP */ } 170 virtual void init(HWND w) { 171 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 172 struct HpcMenuInterface::HpcMenuPreferences 173 *pref = &menu._pref; 174 _window = w; 175 176 TabWindow::init(_window); 177 _spin_edit = GetDlgItem(_window, IDC_OPT_AUTO_INPUT); 178 _spin = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | 179 UDS_SETBUDDYINT | UDS_ALIGNRIGHT, 180 80, 0, 50, 50, _window, 181 IDC_OPT_AUTO_UPDOWN, 182 _app._instance, _spin_edit, 183 60, 1, 30); 184 BOOL onoff = pref->auto_boot ? TRUE : FALSE; 185 EnableWindow(_spin_edit, onoff); 186 EnableWindow(_spin, onoff); 187 188 SET_CHECK(AUTO, pref->auto_boot); 189 if (pref->auto_boot) 190 { 191 TCHAR tmp[32]; 192 wsprintf(tmp, TEXT("%d"), pref->auto_boot); 193 Edit_SetText(_spin_edit, tmp); 194 } 195 SET_CHECK(VIDEO, pref->reverse_video); 196 SET_CHECK(PAUSE, pref->pause_before_boot); 197 SET_CHECK(DEBUG, pref->load_debug_info); 198 SET_CHECK(SAFETY, pref->safety_message); 199 } 200 201 virtual void command(int id, int msg) { 202 switch(id) { 203 case IDC_OPT_AUTO: 204 if (IS_CHECKED(AUTO)) { 205 EnableWindow(_spin_edit, TRUE); 206 EnableWindow(_spin, TRUE); 207 } else { 208 EnableWindow(_spin_edit, FALSE); 209 EnableWindow(_spin, FALSE); 210 } 211 break; 212 } 213 } 214 215 void get(void) { 216 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 217 struct HpcMenuInterface::HpcMenuPreferences 218 *pref = &menu._pref; 219 if (IS_CHECKED(AUTO)) { 220 TCHAR tmp[32]; 221 Edit_GetText(_spin_edit, tmp, 32); 222 pref->auto_boot = _wtoi(tmp); 223 } else 224 pref->auto_boot = 0; 225 pref->reverse_video = IS_CHECKED(VIDEO); 226 pref->pause_before_boot = IS_CHECKED(PAUSE); 227 pref->load_debug_info = IS_CHECKED(DEBUG); 228 pref->safety_message = IS_CHECKED(SAFETY); 229 } 230 }; 231 232 // 233 // Console window 234 // 235 class ConsoleTabWindow : public TabWindow 236 { 237 public: 238 HWND _edit; 239 240 public: 241 explicit ConsoleTabWindow(TabWindowBase &base, int id) 242 : TabWindow(base, id, TEXT("WConsole")) { 243 _edit = NULL; 244 } 245 virtual ~ConsoleTabWindow(void) { /* NO-OP */ } 246 virtual void init(HWND w) { 247 // at this time _window is NULL. 248 // use argument of window procedure. 249 TabWindow::init(w); 250 _edit = GetDlgItem(w, IDC_CONS_EDIT); 251 MoveWindow(_edit, 5, 20, _rect.right - _rect.left - 10, 252 _rect.bottom - _rect.top - 20, TRUE); 253 Edit_FmtLines(_edit, TRUE); 254 } 255 virtual void command(int id, int msg) { 256 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 257 struct HpcMenuInterface::cons_hook_args *hook = 0; 258 int arg = 0; 259 260 switch(id) { 261 case IDC_CONS_BTN0: 262 /* FALLTHROUGH */ 263 case IDC_CONS_BTN1: 264 /* FALLTHROUGH */ 265 case IDC_CONS_BTN2: 266 /* FALLTHROUGH */ 267 case IDC_CONS_BTN3: 268 for (int i = 0; i < IDC_CONS_CHK_END; i++) 269 if (SendDlgItemMessage(_window, 270 IDC_CONS_CHK_ + i, 271 BM_GETCHECK, 0, 0)) 272 arg |=(1 << i); 273 hook = &menu._cons_hook[id - IDC_CONS_BTN_]; 274 if (hook->func) 275 hook->func(hook->arg, arg); 276 break; 277 } 278 } 279 280 void print(TCHAR *buf); 281 }; 282 283 void 284 ConsoleTabWindow::print(TCHAR *buf) 285 { 286 int cr; 287 TCHAR *p; 288 289 // count # of '\n' 290 for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++) 291 ; 292 // total length of new buffer('\n' -> "\r\n" + '\0') 293 int ln = wcslen(buf) + cr + 1; 294 295 // get old buffer. 296 int lo = Edit_GetTextLength(_edit); 297 size_t sz =(lo + ln) * sizeof(TCHAR); 298 299 p = reinterpret_cast <TCHAR *>(malloc(sz)); 300 if (p == NULL) 301 return; 302 303 memset(p, 0, sz); 304 Edit_GetText(_edit, p, lo + 1); 305 306 // put new buffer to end of old buffer. 307 TCHAR *d = p + lo; 308 while (*buf != TEXT('\0')) { 309 TCHAR c = *buf++; 310 if (c == TEXT('\n')) 311 *d++ = TEXT('\r'); 312 *d++ = c; 313 } 314 *d = TEXT('\0'); 315 316 // display total buffer. 317 Edit_SetText(_edit, p); 318 // Edit_Scroll(_edit, Edit_GetLineCount(_edit), 0); 319 UpdateWindow(_edit); 320 321 free(p); 322 } 323 324 TabWindow * 325 TabWindowBase::boot(int id) 326 { 327 TabWindow *w = NULL; 328 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 329 330 switch(id) { 331 default: 332 break; 333 case IDC_BASE_MAIN: 334 menu._main = new MainTabWindow(*this, IDC_BASE_MAIN); 335 w = menu._main; 336 break; 337 case IDC_BASE_OPTION: 338 menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION); 339 w = menu._option; 340 break; 341 case IDC_BASE_CONSOLE: 342 menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE); 343 w = menu._console; 344 break; 345 } 346 347 if (w) 348 w->create(0); 349 350 return w; 351 } 352 353 // 354 // External Interface 355 // 356 HpcMenuInterface *HpcMenuInterface::_instance = 0; 357 358 HpcMenuInterface & 359 HpcMenuInterface::Instance(void) 360 { 361 if (!_instance) 362 _instance = new HpcMenuInterface(); 363 return *_instance; 364 } 365 366 void 367 HpcMenuInterface::Destroy(void) 368 { 369 if (_instance) 370 delete _instance; 371 } 372 373 void 374 HpcMenuInterface::print(TCHAR *buf) 375 { 376 if (_console) 377 _console->print(buf); 378 } 379 380 void 381 HpcMenuInterface::get_options(void) 382 { 383 _main->get(); 384 _option->get(); 385 } 386 387 TCHAR * 388 HpcMenuInterface::dir(int i) 389 { 390 int res = IDS_DIR_RES(i); 391 if (!IDS_DIR_RES_VALID(res)) 392 return 0; 393 394 if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) { 395 return _pref.dir_user_path; 396 } 397 398 TCHAR *s = reinterpret_cast <TCHAR *> 399 (LoadString(_root->_app._instance, res, 0, 0)); 400 401 return s; 402 } 403 404 int 405 HpcMenuInterface::dir_default(void) 406 { 407 return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0; 408 } 409 410 BOOL 411 HpcMenuInterface::load(void) 412 { 413 TCHAR path[MAX_PATH]; 414 415 if (!_find_pref_dir(path)) 416 return FALSE; 417 418 TCHAR filename[MAX_PATH]; 419 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 420 HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, 421 FILE_ATTRIBUTE_NORMAL, 0); 422 if (file == INVALID_HANDLE_VALUE) 423 return FALSE; 424 425 DWORD cnt; 426 // read header. 427 if (!ReadFile(file, &_pref, 12, &cnt, 0)) 428 goto bad; 429 if (_pref._magic != HPCBOOT_MAGIC) 430 goto bad; 431 // read all. 432 SetFilePointer(file, 0, 0, FILE_BEGIN); 433 if (!ReadFile(file, &_pref, _pref._size, &cnt, 0)) 434 goto bad; 435 CloseHandle(file); 436 437 return TRUE; 438 bad: 439 CloseHandle(file); 440 return FALSE; 441 } 442 443 BOOL 444 HpcMenuInterface::save(void) 445 { 446 TCHAR path[MAX_PATH]; 447 448 if (_find_pref_dir(path)) { 449 TCHAR filename[MAX_PATH]; 450 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 451 HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, 452 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 453 0); 454 DWORD cnt; 455 WriteFile(file, &_pref, _pref._size, &cnt, 0); 456 CloseHandle(file); 457 return cnt == _pref._size; 458 } 459 460 return FALSE; 461 } 462 463 BOOL 464 HpcMenuInterface::_find_pref_dir(TCHAR *path) 465 { 466 WIN32_FIND_DATA fd; 467 HANDLE find; 468 469 lstrcpy(path, TEXT("\\*.*")); 470 find = FindFirstFile(path, &fd); 471 472 if (find != INVALID_HANDLE_VALUE) { 473 do { 474 int attr = fd.dwFileAttributes; 475 if ((attr & FILE_ATTRIBUTE_DIRECTORY) && 476 (attr & FILE_ATTRIBUTE_TEMPORARY)) { 477 wcscpy(path, fd.cFileName); 478 FindClose(find); 479 return TRUE; 480 } 481 } while (FindNextFile(find, &fd)); 482 } 483 FindClose(find); 484 return FALSE; 485 } 486 487 // arguments for kernel. 488 int 489 HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p) 490 { 491 int argc = 0; 492 kaddr_t *argv = reinterpret_cast <kaddr_t *>(v); 493 char *loc = reinterpret_cast <char *> 494 (v + sizeof(char **) * MAX_KERNEL_ARGS); 495 paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS; 496 size_t len; 497 TCHAR *w; 498 499 #define SETOPT(c) \ 500 __BEGIN_MACRO \ 501 argv[argc++] = ptokv(locp); \ 502 *loc++ =(c); \ 503 *loc++ = '\0'; \ 504 locp += 2; \ 505 __END_MACRO 506 // 1st arg is kernel name. 507 // DPRINTF_SETUP(); if you want to use debug print, enable this line. 508 509 w = _pref.kernel_user_file; 510 argv[argc++] = ptokv(locp); 511 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 512 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 513 loc[len] = '\0'; 514 loc += len + 1; 515 locp += len + 1; 516 517 if (_pref.boot_serial) // serial console 518 SETOPT('h'); 519 if (_pref.boot_verbose) // boot verbosely 520 SETOPT('v'); 521 if (_pref.boot_single_user) // boot to single user 522 SETOPT('s'); 523 if (_pref.boot_ask_for_name) // ask for file name to boot from 524 SETOPT('a'); 525 526 // boot from 527 switch(_pref.rootfs) { 528 case 0: // wd0 529 break; 530 case 1: // sd0 531 argv[argc++] = ptokv(locp); 532 strncpy(loc, "b=sd0", 6); 533 loc += 6; 534 locp += 6; 535 break; 536 case 2: // memory disk 537 w = _pref.rootfs_file; 538 argv[argc++] = ptokv(locp); 539 strncpy(loc, "m=", 2); 540 loc += 2; 541 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 542 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 543 loc[len] = '\0'; 544 loc += len + 1; 545 locp += 2 + len + 1; 546 break; 547 case 3: // nfs 548 argv[argc++] = ptokv(locp); 549 strncpy(loc, "b=nfs", 6); 550 loc += 6; 551 locp += 6; 552 break; 553 } 554 555 return argc; 556 } 557 558 // kernel bootinfo. 559 void 560 HpcMenuInterface::setup_bootinfo(struct bootinfo &bi) 561 { 562 FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo); 563 TIME_ZONE_INFORMATION tz; 564 GetTimeZoneInformation(&tz); 565 566 memset(&bi, 0, sizeof(struct bootinfo)); 567 bi.length = sizeof(struct bootinfo); 568 bi.reserved = 0; 569 bi.magic = BOOTINFO_MAGIC; 570 bi.fb_addr = fb.addr(); 571 bi.fb_type = fb.type(); 572 bi.fb_line_bytes = fb.linebytes(); 573 bi.fb_width = fb.width(); 574 bi.fb_height = fb.height(); 575 bi.platid_cpu = _pref.platid_hi; 576 bi.platid_machine = _pref.platid_lo; 577 bi.timezone = tz.Bias; 578 } 579 580 // Progress bar 581 void 582 HpcMenuInterface::progress(void) 583 { 584 SendMessage(_root->_progress_bar->_window, PBM_STEPIT, 0, 0); 585 } 586