1 /* -*-C++-*- $NetBSD: hpcmenu.cpp,v 1.3 2001/03/02 18:26:37 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 bit; 259 260 switch(id) { 261 case IDC_CONS_CHK0: 262 /* FALLTHROUGH */ 263 case IDC_CONS_CHK1: 264 /* FALLTHROUGH */ 265 case IDC_CONS_CHK2: 266 /* FALLTHROUGH */ 267 case IDC_CONS_CHK3: 268 /* FALLTHROUGH */ 269 case IDC_CONS_CHK4: 270 /* FALLTHROUGH */ 271 case IDC_CONS_CHK5: 272 /* FALLTHROUGH */ 273 case IDC_CONS_CHK6: 274 /* FALLTHROUGH */ 275 case IDC_CONS_CHK7: 276 bit = 1 << (id - IDC_CONS_CHK_); 277 if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0)) 278 menu._cons_parameter |= bit; 279 else 280 menu._cons_parameter &= ~bit; 281 break; 282 case IDC_CONS_BTN0: 283 /* FALLTHROUGH */ 284 case IDC_CONS_BTN1: 285 /* FALLTHROUGH */ 286 case IDC_CONS_BTN2: 287 /* FALLTHROUGH */ 288 case IDC_CONS_BTN3: 289 hook = &menu._cons_hook[id - IDC_CONS_BTN_]; 290 if (hook->func) 291 hook->func(hook->arg, menu._cons_parameter); 292 293 break; 294 } 295 } 296 297 void print(TCHAR *buf); 298 }; 299 300 void 301 ConsoleTabWindow::print(TCHAR *buf) 302 { 303 int cr; 304 TCHAR *p; 305 306 // count # of '\n' 307 for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++) 308 ; 309 // total length of new buffer('\n' -> "\r\n" + '\0') 310 int ln = wcslen(buf) + cr + 1; 311 312 // get old buffer. 313 int lo = Edit_GetTextLength(_edit); 314 size_t sz =(lo + ln) * sizeof(TCHAR); 315 316 p = reinterpret_cast <TCHAR *>(malloc(sz)); 317 if (p == NULL) 318 return; 319 320 memset(p, 0, sz); 321 Edit_GetText(_edit, p, lo + 1); 322 323 // put new buffer to end of old buffer. 324 TCHAR *d = p + lo; 325 while (*buf != TEXT('\0')) { 326 TCHAR c = *buf++; 327 if (c == TEXT('\n')) 328 *d++ = TEXT('\r'); 329 *d++ = c; 330 } 331 *d = TEXT('\0'); 332 333 // display total buffer. 334 Edit_SetText(_edit, p); 335 // Edit_Scroll(_edit, Edit_GetLineCount(_edit), 0); 336 UpdateWindow(_edit); 337 338 free(p); 339 } 340 341 TabWindow * 342 TabWindowBase::boot(int id) 343 { 344 TabWindow *w = NULL; 345 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 346 347 switch(id) { 348 default: 349 break; 350 case IDC_BASE_MAIN: 351 menu._main = new MainTabWindow(*this, IDC_BASE_MAIN); 352 w = menu._main; 353 break; 354 case IDC_BASE_OPTION: 355 menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION); 356 w = menu._option; 357 break; 358 case IDC_BASE_CONSOLE: 359 menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE); 360 w = menu._console; 361 break; 362 } 363 364 if (w) 365 w->create(0); 366 367 return w; 368 } 369 370 // 371 // External Interface 372 // 373 HpcMenuInterface *HpcMenuInterface::_instance = 0; 374 375 HpcMenuInterface & 376 HpcMenuInterface::Instance(void) 377 { 378 if (!_instance) 379 _instance = new HpcMenuInterface(); 380 return *_instance; 381 } 382 383 void 384 HpcMenuInterface::Destroy(void) 385 { 386 if (_instance) 387 delete _instance; 388 } 389 390 void 391 HpcMenuInterface::print(TCHAR *buf) 392 { 393 if (_console) 394 _console->print(buf); 395 } 396 397 void 398 HpcMenuInterface::get_options(void) 399 { 400 _main->get(); 401 _option->get(); 402 } 403 404 TCHAR * 405 HpcMenuInterface::dir(int i) 406 { 407 int res = IDS_DIR_RES(i); 408 if (!IDS_DIR_RES_VALID(res)) 409 return 0; 410 411 if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) { 412 return _pref.dir_user_path; 413 } 414 415 TCHAR *s = reinterpret_cast <TCHAR *> 416 (LoadString(_root->_app._instance, res, 0, 0)); 417 418 return s; 419 } 420 421 int 422 HpcMenuInterface::dir_default(void) 423 { 424 return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0; 425 } 426 427 BOOL 428 HpcMenuInterface::load(void) 429 { 430 TCHAR path[MAX_PATH]; 431 432 if (!_find_pref_dir(path)) 433 return FALSE; 434 435 TCHAR filename[MAX_PATH]; 436 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 437 HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, 438 FILE_ATTRIBUTE_NORMAL, 0); 439 if (file == INVALID_HANDLE_VALUE) 440 return FALSE; 441 442 DWORD cnt; 443 // read header. 444 if (!ReadFile(file, &_pref, 12, &cnt, 0)) 445 goto bad; 446 if (_pref._magic != HPCBOOT_MAGIC) 447 goto bad; 448 // read all. 449 SetFilePointer(file, 0, 0, FILE_BEGIN); 450 if (!ReadFile(file, &_pref, _pref._size, &cnt, 0)) 451 goto bad; 452 CloseHandle(file); 453 454 return TRUE; 455 bad: 456 CloseHandle(file); 457 return FALSE; 458 } 459 460 BOOL 461 HpcMenuInterface::save(void) 462 { 463 TCHAR path[MAX_PATH]; 464 465 if (_find_pref_dir(path)) { 466 TCHAR filename[MAX_PATH]; 467 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 468 HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, 469 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 470 0); 471 DWORD cnt; 472 WriteFile(file, &_pref, _pref._size, &cnt, 0); 473 CloseHandle(file); 474 return cnt == _pref._size; 475 } 476 477 return FALSE; 478 } 479 480 BOOL 481 HpcMenuInterface::_find_pref_dir(TCHAR *path) 482 { 483 WIN32_FIND_DATA fd; 484 HANDLE find; 485 486 lstrcpy(path, TEXT("\\*.*")); 487 find = FindFirstFile(path, &fd); 488 489 if (find != INVALID_HANDLE_VALUE) { 490 do { 491 int attr = fd.dwFileAttributes; 492 if ((attr & FILE_ATTRIBUTE_DIRECTORY) && 493 (attr & FILE_ATTRIBUTE_TEMPORARY)) { 494 wcscpy(path, fd.cFileName); 495 FindClose(find); 496 return TRUE; 497 } 498 } while (FindNextFile(find, &fd)); 499 } 500 FindClose(find); 501 return FALSE; 502 } 503 504 // arguments for kernel. 505 int 506 HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p) 507 { 508 int argc = 0; 509 kaddr_t *argv = reinterpret_cast <kaddr_t *>(v); 510 char *loc = reinterpret_cast <char *> 511 (v + sizeof(char **) * MAX_KERNEL_ARGS); 512 paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS; 513 size_t len; 514 TCHAR *w; 515 516 #define SETOPT(c) \ 517 __BEGIN_MACRO \ 518 argv[argc++] = ptokv(locp); \ 519 *loc++ =(c); \ 520 *loc++ = '\0'; \ 521 locp += 2; \ 522 __END_MACRO 523 // 1st arg is kernel name. 524 // DPRINTF_SETUP(); if you want to use debug print, enable this line. 525 526 w = _pref.kernel_user_file; 527 argv[argc++] = ptokv(locp); 528 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 529 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 530 loc[len] = '\0'; 531 loc += len + 1; 532 locp += len + 1; 533 534 if (_pref.boot_serial) // serial console 535 SETOPT('h'); 536 if (_pref.boot_verbose) // boot verbosely 537 SETOPT('v'); 538 if (_pref.boot_single_user) // boot to single user 539 SETOPT('s'); 540 if (_pref.boot_ask_for_name) // ask for file name to boot from 541 SETOPT('a'); 542 543 // boot from 544 switch(_pref.rootfs) { 545 case 0: // wd0 546 break; 547 case 1: // sd0 548 argv[argc++] = ptokv(locp); 549 strncpy(loc, "b=sd0", 6); 550 loc += 6; 551 locp += 6; 552 break; 553 case 2: // memory disk 554 w = _pref.rootfs_file; 555 argv[argc++] = ptokv(locp); 556 strncpy(loc, "m=", 2); 557 loc += 2; 558 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 559 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 560 loc[len] = '\0'; 561 loc += len + 1; 562 locp += 2 + len + 1; 563 break; 564 case 3: // nfs 565 argv[argc++] = ptokv(locp); 566 strncpy(loc, "b=nfs", 6); 567 loc += 6; 568 locp += 6; 569 break; 570 } 571 572 return argc; 573 } 574 575 // kernel bootinfo. 576 void 577 HpcMenuInterface::setup_bootinfo(struct bootinfo &bi) 578 { 579 FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo); 580 TIME_ZONE_INFORMATION tz; 581 GetTimeZoneInformation(&tz); 582 583 memset(&bi, 0, sizeof(struct bootinfo)); 584 bi.length = sizeof(struct bootinfo); 585 bi.reserved = 0; 586 bi.magic = BOOTINFO_MAGIC; 587 bi.fb_addr = fb.addr(); 588 bi.fb_type = fb.type(); 589 bi.fb_line_bytes = fb.linebytes(); 590 bi.fb_width = fb.width(); 591 bi.fb_height = fb.height(); 592 bi.platid_cpu = _pref.platid_hi; 593 bi.platid_machine = _pref.platid_lo; 594 bi.timezone = tz.Bias; 595 } 596 597 // Progress bar 598 void 599 HpcMenuInterface::progress(void) 600 { 601 SendMessage(_root->_progress_bar->_window, PBM_STEPIT, 0, 0); 602 } 603