diff --git a/src/86box.cfg b/src/86box.cfg new file mode 100644 index 000000000..ad83f0d35 Binary files /dev/null and b/src/86box.cfg differ diff --git a/src/CPU/codegen_x86-64.c b/src/CPU/codegen_x86-64.c index 7673a08e4..e591adc95 100644 --- a/src/CPU/codegen_x86-64.c +++ b/src/CPU/codegen_x86-64.c @@ -1,16 +1,14 @@ #ifdef __amd64__ #include -#include "ibm.h" +#include "../ibm.h" +#include "../mem.h" #include "cpu.h" #include "x86.h" #include "x86_flags.h" #include "x86_ops.h" #include "x87.h" -#include "mem.h" - #include "386_common.h" - #include "codegen.h" #include "codegen_ops.h" #include "codegen_ops_x86-64.h" diff --git a/src/Makefile.mingw b/src/Makefile.mingw index d2cbc03e3..39caf693b 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -29,7 +29,7 @@ STUFF = EXTRAS = # Do we want a debugging build? -DEBUG = n +DEBUG = y OPTIM = n X64 = n @@ -200,7 +200,7 @@ LIBS = -mwindows -lcomctl32 -lwinmm -lopenal.dll -lopenal -lddraw \ # Build rules. %.o: %.c @echo $< - @$(CC) $(CFLAGS) -c $< + $(CC) $(CFLAGS) -c $< %.o: %.cc @echo $< diff --git a/src/WIN/86Box.manifest b/src/WIN/86Box.manifest new file mode 100644 index 000000000..be8c16756 --- /dev/null +++ b/src/WIN/86Box.manifest @@ -0,0 +1,22 @@ + + + +Emulator for X86-based systems. + + + + + + diff --git a/src/WIN/86Box.rc b/src/WIN/86Box.rc new file mode 100644 index 000000000..fb5d56296 --- /dev/null +++ b/src/WIN/86Box.rc @@ -0,0 +1,941 @@ +#include + +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +STATUSBARMENU MENU DISCARDABLE +BEGIN + POPUP "FDD 1" + BEGIN + MENUITEM "&Change...", IDM_DISC_1 + MENUITEM "Change FDD 1 (&Write-protected)...", IDM_DISC_1_WP + MENUITEM "&Eject FDD 1", IDM_EJECT_1 + END + POPUP "FDD 2" + BEGIN + MENUITEM "&Change...", IDM_DISC_2 + MENUITEM "Change FDD 2 (&Write-protected)...", IDM_DISC_2_WP + MENUITEM "&Eject FDD 2", IDM_EJECT_2 + END + POPUP "FDD 3" + BEGIN + MENUITEM "&Change...", IDM_DISC_3 + MENUITEM "Change FDD 3 (&Write-protected)...", IDM_DISC_3_WP + MENUITEM "&Eject FDD 3", IDM_EJECT_3 + END + POPUP "FDD 4" + BEGIN + MENUITEM "&Change...", IDM_DISC_4 + MENUITEM "Change FDD 4 (&Write-protected)...", IDM_DISC_4_WP + MENUITEM "&Eject FDD 4", IDM_EJECT_4 + END + POPUP "CD-ROM 1" + BEGIN + MENUITEM "&Mute", IDM_CDROM_1_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_1_EMPTY + MENUITEM "&Reload previous disc", IDM_CDROM_1_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image...", IDM_CDROM_1_IMAGE + END + POPUP "CD-ROM 2" + BEGIN + MENUITEM "&Mute", IDM_CDROM_2_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_2_EMPTY + MENUITEM "&Reload previous disc", IDM_CDROM_2_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image...", IDM_CDROM_2_IMAGE + END + POPUP "CD-ROM 3" + BEGIN + MENUITEM "&Mute", IDM_CDROM_3_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_3_EMPTY + MENUITEM "&Reload previous disc", IDM_CDROM_3_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image...", IDM_CDROM_3_IMAGE + END + POPUP "CD-ROM 4" + BEGIN + MENUITEM "&Mute", IDM_CDROM_4_MUTE + MENUITEM SEPARATOR + MENUITEM "E&mpty", IDM_CDROM_4_EMPTY + MENUITEM "&Reload previous disc", IDM_CDROM_4_RELOAD + MENUITEM SEPARATOR + MENUITEM "&Image...", IDM_CDROM_4_IMAGE + END +END + +MAINMENU MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Hard Reset", IDM_FILE_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_FILE_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_FILE_EXIT + END + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM SEPARATOR + MENUITEM "&Load configuration...", IDM_CONFIG_LOAD + MENUITEM "&Save configuration...", IDM_CONFIG_SAVE + MENUITEM SEPARATOR + POPUP "&Video" + BEGIN + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "Direct&3D 9", IDM_VID_D3D + MENUITEM SEPARATOR + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + MENUITEM SEPARATOR + MENUITEM "&Fullscreen", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels", IDM_VID_FS_SQ + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + MENUITEM SEPARATOR + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + MENUITEM "E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + MENUITEM SEPARATOR + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_VID_SCREENSHOT + END + MENUITEM "S&tatus", IDM_STATUS +#ifdef ENABLE_LOG_TOGGLES +#if defined ENABLE_BUSLOGIC_LOG || defined ENABLE_CDROM_LOG || defined ENABLE_D86F_LOG || defined ENABLE_FDC_LOG || defined ENABLE_IDE_LOG || defined ENABLE_NE2000_LOG + MENUITEM SEPARATOR +#endif +#ifdef ENABLE_BUSLOGIC_LOG + MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC +#endif +#ifdef ENABLE_CDROM_LOG + MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM +#endif +#ifdef ENABLE_D86F_LOG + MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F +#endif +#ifdef ENABLE_FDC_LOG + MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC +#endif +#ifdef ENABLE_IDE_LOG + MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE +#endif +#ifdef ENABLE_NE2000_LOG + MENUITEM "Enable NE2000 logs\tCtrl+F9", IDM_LOG_NE2000 +#endif +#endif +#ifdef ENABLE_LOG_BREAKPOINT + MENUITEM SEPARATOR + MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT +#ifdef ENABLE_VRAM_DUMP + MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM +#endif +#else +#ifdef ENABLE_VRAM_DUMP + MENUITEM SEPARATOR + MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM +#endif +#endif + END + POPUP "&Help" + BEGIN + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +MAINACCEL ACCELERATORS MOVEABLE PURE +BEGIN +#ifdef ENABLE_VRAM_DUMP + VK_F1, IDM_DUMP_VRAM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_LOG_TOGGLES +#ifdef ENABLE_BUSLOGIC_LOG + VK_F4, IDM_LOG_BUSLOGIC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_CDROM_LOG + VK_F5, IDM_LOG_CDROM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_D86F_LOG + VK_F6, IDM_LOG_D86F, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_FDC_LOG + VK_F7, IDM_LOG_FDC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_IDE_LOG + VK_F8, IDM_LOG_IDE, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_NE2000_LOG + VK_F9, IDM_LOG_NE2000, CONTROL, VIRTKEY +#endif +#endif +#ifdef ENABLE_LOG_BREAKPOINT + VK_F10, IDM_LOG_BREAKPOINT, CONTROL, VIRTKEY +#endif + VK_F11, IDM_VID_SCREENSHOT, VIRTKEY, CONTROL + VK_F12, IDM_FILE_RESET_CAD, VIRTKEY, CONTROL +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +CONFIGUREDLG_MAIN DIALOG DISCARDABLE 0, 0, 366, 241 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "86Box Settings" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,246,220,50,14 + PUSHBUTTON "Cancel",IDCANCEL,307,220,50,14 + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | + LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,7,90,197 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,211,363,1 + LTEXT "Language:",2047,7,222,41,10 + COMBOBOX IDC_COMBO_LANG,48,221,108,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +END + +CONFIGUREDLG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 111 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Hard Disk" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,55,89,50,14 + PUSHBUTTON "Cancel",IDCANCEL,112,89,50,14 + EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 + PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 + EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 + EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 + EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 + EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 + COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Sectors:",IDC_STATIC,154,35,27,10 + LTEXT "Heads:",1793,81,35,29,8 + LTEXT "Cylinders:",1794,7,35,32,12 + LTEXT "Size (MB):",1795,7,54,33,8 + LTEXT "Type:",1797,86,54,24,8 + LTEXT "File name:",-1,7,7,204,9 + COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",1798,7,72,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",1799,99,72,34,8 + COMBOBOX IDC_COMBO_HD_ID,133,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",1800,117,72,15,8 + COMBOBOX IDC_COMBO_HD_LUN,185,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",1801,168,72,15,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",1802,99,72,34,8 +END + +STATUSDLG DIALOG DISCARDABLE 0, 0, 186, 386 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDC_STEXT_DEVICE,16,16,180,1000 + LTEXT "1",IDC_STEXT1,16,186,180,1000 +END + +ABOUTDLG DIALOG DISCARDABLE 0, 0, 209, 114 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About 86Box" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,94,71,12 + ICON 100,IDC_ABOUT_ICON,7,7,20,20 + LTEXT "86Box v1.20 - A fork of PCem\n\nAuthors: Sarah Walker, Tohka, waltje, SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", + IDC_ABOUT_ICON,54,7,146,73 + CONTROL "",IDC_ABOUT_ICON,"Static",SS_BLACKFRAME | SS_SUNKEN,0, + 86,208,1 +END + +CONFIGUREDLG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 112 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_MACHINE,71,7,138,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Machine:",1794,7,8,60,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,7,46,12 + COMBOBOX IDC_COMBO_CPU_TYPE,71,25,45,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU type:",1796,7,26,59,10 + COMBOBOX IDC_COMBO_WS,71,44,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Wait states:",1798,7,45,60,10 + COMBOBOX IDC_COMBO_CPU,145,25,115,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU:",1797,124,26,18,10 + CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 + CONTROL "Enable FPU",IDC_CHECK_FPU,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,147,80,113,10 + EDITTEXT IDC_MEMTEXT,70,63,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,63, + 12,12 + LTEXT "MB",IDC_TEXT_MB,123,64,10,10 + LTEXT "Memory:",1802,7,64,30,10 + CONTROL "Enable time sync",IDC_CHECK_SYNC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,95,102,10 +END + +CONFIGUREDLG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 63 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_VIDEO,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Video:",1795,7,8,55,10 + COMBOBOX IDC_COMBO_VIDEO_SPEED,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Video speed:",1800,7,26,58,10 + CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_VOODOO,214,44,46,12 + PUSHBUTTON "Configure",IDC_CONFIGUREVID,214,7,46,12 +END + +CONFIGUREDLG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Mouse :",IDC_STATIC,7,8,57,10 + COMBOBOX IDC_COMBO_MOUSE,71,7,189,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP + LTEXT "Joystick :",1793,7,26,58,10 + COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 + PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 + DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 + PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 +END + +CONFIGUREDLG_SOUND DIALOG DISCARDABLE 97, 0, 267, 78 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBOSND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Sound card:",1800,7,8,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURESND,214,7,46,12 + COMBOBOX IDC_COMBO_MIDI,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI Out Device:",1801,7,26,59,10 + CONTROL "CMS / Game Blaster",IDC_CHECKCMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,87,43,80,10 + CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,43,80,10 + CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,174,43,80,10 + CONTROL "Use Nuked OPL",IDC_CHECKNUKEDOPL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,61,80,10 +END + +CONFIGUREDLG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Network type:",1800,7,8,59,10 + COMBOBOX IDC_COMBONETTYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "PCap device:",1801,7,26,59,10 + COMBOBOX IDC_COMBOPCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "Network adapter:",1802,7,44,59,10 + COMBOBOX IDC_COMBONET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURENET,214,43,46,12 +END + +CONFIGUREDLG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 115 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "SCSI Controller:",1804,7,8,59,10 + COMBOBOX IDC_COMBO_SCSI,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,214,7,46,12 + + LTEXT "HD Controller:",1799,7,26,61,10 + COMBOBOX IDC_COMBO_HDC,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "Tertiary IDE:",1802,7,44,61,10 + COMBOBOX IDC_COMBO_IDE_TER,71,43,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "Quaternary IDE:",1803,7,62,61,10 + COMBOBOX IDC_COMBO_IDE_QUA,71,61,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + CONTROL "Serial port 1",IDC_CHECKSERIAL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 + CONTROL "Serial port 2",IDC_CHECKSERIAL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,80,94,10 + + CONTROL "Parallel port",IDC_CHECKPARALLEL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,98,94,10 + CONTROL "ISABugger device",IDC_CHECKBUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,98,94,10 +END + +CONFIGUREDLG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,18,253,92 + LTEXT "Hard disks:",-1,7,7,34,8 + PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 + PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 + PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 + COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",1798,7,118,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",1799,131,118,38,8 + COMBOBOX IDC_COMBO_HD_ID,170,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",1800,131,118,38,8 + COMBOBOX IDC_COMBO_HD_LUN,239,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",1801,200,118,38,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",1802,131,118,38,8 +END + +CONFIGUREDLG_REMOVABLE_DEVICES DIALOG DISCARDABLE 97, 0, 267, 202 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP, + 7,18,253,60 + LTEXT "Floppy drives:",-1,7,7,43,8 + CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,116,253,60 + LTEXT "CD-ROM drives:",-1,7,106,50,8 + COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",1803,7,86,24,8 + COMBOBOX IDC_COMBO_CD_BUS,33,183,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",1798,7,184,24,8 + COMBOBOX IDC_COMBO_CD_ID,170,183,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",1800,131,184,38,8 + COMBOBOX IDC_COMBO_CD_LUN,239,183,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",1801,200,184,38,8 + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,183,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",1802,131,184,38,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// 24 +// + +1 24 MOVEABLE PURE "86Box.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +#ifdef RELEASE_BUILD +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ +100 ICON DISCARDABLE "ICONS/86Box-RB.ico" +#else +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ +100 ICON DISCARDABLE "ICONS/86Box.ico" +#endif +128 ICON DISCARDABLE "ICONS/floppy_525_1dd.ico" +129 ICON DISCARDABLE "ICONS/floppy_525_1dd_active.ico" +130 ICON DISCARDABLE "ICONS/floppy_525_2dd.ico" +131 ICON DISCARDABLE "ICONS/floppy_525_2dd_active.ico" +132 ICON DISCARDABLE "ICONS/floppy_525_2qd.ico" +133 ICON DISCARDABLE "ICONS/floppy_525_2qd_active.ico" +134 ICON DISCARDABLE "ICONS/floppy_525_2hd.ico" +135 ICON DISCARDABLE "ICONS/floppy_525_2hd_active.ico" +144 ICON DISCARDABLE "ICONS/floppy_35_1dd.ico" +145 ICON DISCARDABLE "ICONS/floppy_35_1dd_active.ico" +146 ICON DISCARDABLE "ICONS/floppy_35_2dd.ico" +147 ICON DISCARDABLE "ICONS/floppy_35_2dd_active.ico" +150 ICON DISCARDABLE "ICONS/floppy_35_2hd.ico" +151 ICON DISCARDABLE "ICONS/floppy_35_2hd_active.ico" +152 ICON DISCARDABLE "ICONS/floppy_35_2ed.ico" +153 ICON DISCARDABLE "ICONS/floppy_35_2ed_active.ico" +160 ICON DISCARDABLE "ICONS/cdrom_atapi.ico" +161 ICON DISCARDABLE "ICONS/cdrom_atapi_active.ico" +162 ICON DISCARDABLE "ICONS/cdrom_atapi_dma.ico" +163 ICON DISCARDABLE "ICONS/cdrom_atapi_dma_active.ico" +164 ICON DISCARDABLE "ICONS/cdrom_scsi.ico" +165 ICON DISCARDABLE "ICONS/cdrom_scsi_active.ico" +176 ICON DISCARDABLE "ICONS/hard_disk_mfm.ico" +177 ICON DISCARDABLE "ICONS/hard_disk_mfm_active.ico" +178 ICON DISCARDABLE "ICONS/hard_disk.ico" +179 ICON DISCARDABLE "ICONS/hard_disk_active.ico" +180 ICON DISCARDABLE "ICONS/hard_disk_ide.ico" +181 ICON DISCARDABLE "ICONS/hard_disk_ide_active.ico" +182 ICON DISCARDABLE "ICONS/hard_disk_scsi.ico" +183 ICON DISCARDABLE "ICONS/hard_disk_scsi_active.ico" +256 ICON DISCARDABLE "ICONS/machine.ico" +257 ICON DISCARDABLE "ICONS/video.ico" +258 ICON DISCARDABLE "ICONS/input_devices.ico" +259 ICON DISCARDABLE "ICONS/sound.ico" +260 ICON DISCARDABLE "ICONS/network.ico" +261 ICON DISCARDABLE "ICONS/other_peripherals.ico" +262 ICON DISCARDABLE "ICONS/hard_disk.ico" +263 ICON DISCARDABLE "ICONS/removable_devices.ico" +384 ICON DISCARDABLE "ICONS/floppy_525_1dd_empty.ico" +385 ICON DISCARDABLE "ICONS/floppy_525_1dd_empty_active.ico" +386 ICON DISCARDABLE "ICONS/floppy_525_2dd_empty.ico" +387 ICON DISCARDABLE "ICONS/floppy_525_2dd_empty_active.ico" +388 ICON DISCARDABLE "ICONS/floppy_525_2qd_empty.ico" +389 ICON DISCARDABLE "ICONS/floppy_525_2qd_empty_active.ico" +390 ICON DISCARDABLE "ICONS/floppy_525_2hd_empty.ico" +391 ICON DISCARDABLE "ICONS/floppy_525_2hd_empty_active.ico" +400 ICON DISCARDABLE "ICONS/floppy_35_1dd_empty.ico" +401 ICON DISCARDABLE "ICONS/floppy_35_1dd_empty_active.ico" +402 ICON DISCARDABLE "ICONS/floppy_35_2dd_empty.ico" +403 ICON DISCARDABLE "ICONS/floppy_35_2dd_empty_active.ico" +406 ICON DISCARDABLE "ICONS/floppy_35_2hd_empty.ico" +407 ICON DISCARDABLE "ICONS/floppy_35_2hd_empty_active.ico" +408 ICON DISCARDABLE "ICONS/floppy_35_2ed_empty.ico" +409 ICON DISCARDABLE "ICONS/floppy_35_2ed_empty_active.ico" +416 ICON DISCARDABLE "ICONS/cdrom_atapi_empty.ico" +417 ICON DISCARDABLE "ICONS/cdrom_atapi_empty_active.ico" +418 ICON DISCARDABLE "ICONS/cdrom_atapi_dma_empty.ico" +419 ICON DISCARDABLE "ICONS/cdrom_atapi_dma_empty_active.ico" +420 ICON DISCARDABLE "ICONS/cdrom_scsi_empty.ico" +421 ICON DISCARDABLE "ICONS/cdrom_scsi_empty_active.ico" +512 ICON DISCARDABLE "ICONS/floppy_disabled.ico" +514 ICON DISCARDABLE "ICONS/cdrom_disabled.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resources.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + CONFIGUREDLG_MAIN, DIALOG + BEGIN + RIGHTMARGIN, 365 + END + + ABOUTDLG, DIALOG + BEGIN + RIGHTMARGIN, 208 + END + + CONFIGUREDLG_MACHINE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 105 + END + + CONFIGUREDLG_VIDEO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + CONFIGUREDLG_INPUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + CONFIGUREDLG_SOUND, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 71 + END + + CONFIGUREDLG_NETWORK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + CONFIGUREDLG_PERIPHERALS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + END + + CONFIGUREDLG_HARD_DISKS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 137 + END + + CONFIGUREDLG_REMOVABLE_DEVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 195 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_STRING2049 "86Box Error" + IDS_STRING2050 "86Box Fatal Error" + IDS_STRING2051 "This will reset 86Box.\nAre you sure you want to save the settings?" + IDS_STRING2052 "DirectDraw Screenshot Error" + IDS_STRING2053 "Invalid number of sectors (valid values are between 1 and 63)" + IDS_STRING2054 "Invalid number of heads (valid values are between 1 and 16)" + IDS_STRING2055 "Invalid number of cylinders (valid values are between 1 and 266305)" + IDS_STRING2056 "Please enter a valid file name" + IDS_STRING2057 "Unable to open the file for write" + IDS_STRING2058 "Attempting to create a HDI image larger than 4 GB" + IDS_STRING2059 "Remember to partition and format the new drive" + IDS_STRING2060 "Unable to open the file for read" + IDS_STRING2061 "HDI or HDX image with a sector size that is not 512 are not supported" + IDS_STRING2062 "86Box was unable to find any ROMs.\nAt least one ROM set is required to use 86Box." + IDS_STRING2063 "Configured ROM set not available.\nDefaulting to an available ROM set." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_STRING2064 "Configured video BIOS not available.\nDefaulting to an available video BIOS." + IDS_STRING2065 "Machine" + IDS_STRING2066 "Video" + IDS_STRING2067 "Input devices" + IDS_STRING2068 "Sound" + IDS_STRING2069 "Network" + IDS_STRING2070 "Other peripherals" + IDS_STRING2071 "Hard disks" + IDS_STRING2072 "Removable devices" + IDS_STRING2073 "%i"" floppy drive: %s" + IDS_STRING2074 "Disabled CD-ROM drive" + IDS_STRING2075 "%s CD-ROM drive: %s" + IDS_STRING2076 "Host CD/DVD Drive (%c:)" + IDS_STRING2077 "Click to capture mouse" + IDS_STRING2078 "Press F12-F8 to release mouse" + IDS_STRING2079 "Press F12-F8 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + 2080 "Drive" + 2081 "Location" + 2082 "Bus" + 2083 "File" + 2084 "C" + 2085 "H" + 2086 "S" + 2087 "MB" + 2088 "%i" + 2089 "Enabled" + 2090 "Mute" + 2091 "Type" + 2092 "Bus" + 2093 "DMA" + 2094 "KB" + 2095 "MFM, RLL, or ESDI CD-ROM drives never existed" +END + +STRINGTABLE DISCARDABLE +BEGIN + 2096 "Slave" + 2097 "SCSI (ID %s, LUN %s)" + 2098 "Adapter Type" + 2099 "Base Address" + 2100 "IRQ" + 2101 "8-bit DMA" + 2102 "16-bit DMA" + 2103 "BIOS" + 2104 "Network Type" + 2105 "Surround Module" + 2106 "MPU-401 Base Address" + 2107 "No PCap devices found" + 2108 "On-board RAM" + 2109 "Memory Size" + 2110 "Display Type" + 2111 "RGB" +END + +STRINGTABLE DISCARDABLE +BEGIN + 2112 "Composite" + 2113 "Composite Type" + 2114 "Old" + 2115 "New" + 2116 "RGB Type" + 2117 "Color" + 2118 "Monochrome (Green)" + 2119 "Monochrome (Amber)" + 2120 "Monochrome (Gray)" + 2121 "Color (no brown)" + 2122 "Monochrome (Default)" + 2123 "Snow Emulation" + 2124 "Bilinear Filtering" + 2125 "Dithering" + 2126 "Framebuffer Memory Size" + 2127 "Texture Memory Size" +END + +STRINGTABLE DISCARDABLE +BEGIN + 2128 "Screen Filter" + 2129 "Render Threads" + 2130 "Recompiler" + 2131 "System Default" + 2132 "%i Wait state(s)" + 2133 "8-bit" + 2134 "Slow 16-bit" + 2135 "Fast 16-bit" + 2136 "Slow VLB/PCI" + 2137 "Mid VLB/PCI" + 2138 "Fast VLB/PCI" + 2139 "Microsoft 2-button mouse (serial)" + 2140 "Mouse Systems mouse (serial)" + 2141 "2-button mouse (PS/2)" + 2142 "Microsoft Intellimouse (PS/2)" + 2143 "Bus mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + 2144 "Standard 2-button joystick(s)" + 2145 "Standard 4-button joystick" + 2146 "Standard 6-button joystick" + 2147 "Standard 8-button joystick" + 2148 "CH Flightstick Pro" + 2149 "Microsoft SideWinder Pad" + 2150 "Thrustmaster Flight Control System" + 2151 "Disabled" + 2152 "None" + 2153 "AT Fixed Disk Adapter" + 2154 "Internal IDE" + 2155 "IRQ %i" + 2156 "MFM (%01i:%01i)" + 2157 "IDE (PIO+DMA) (%01i:%01i)" + 2158 "SCSI (%02i:%02i)" + 2159 "Invalid number of cylinders (valid values are between 1 and 1023)" + 2160 "%" PRIu64 + 2161 "Genius Bus mouse" + 2162 "Amstrad mouse" + 2163 "Attempting to create a spuriously large hard disk image" + 2164 "Invalid number of sectors (valid values are between 1 and 99)" + 2165 "MFM" + 2166 "IDE (PIO-only)" + 2167 "IDE (PIO and DMA)" + 2168 "SCSI" + 2169 "%01i:%01i" + 2170 "Custom..." + 2171 "%" PRIu64 " MB (CHS: %" PRIu64 ", %" PRIu64 ", %" PRIu64 ")" + 2172 "Hard disk images (*.HDI;*.HDX;*.IMA;*.IMG)\0*.HDI;*.HDX;*.IMA;*.IMG\0All files (*.*)\0*.*\0" + 2173 "All floppy images (*.0??;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF)\0*.0??;*.12;*.144;*.360;*.720;*.86F;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMD;*.IMG;*.TD0;*.VFD;*.XDF\0Advanced sector-based images (*.IMD;*.TD0)\0*.IMD;*.TD0\0Basic sector-based images (*.0??;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF)\0*.0??;*.12;*.144;*.360;*.720;*.BIN;*.CQ;*.CQM;*.DSK;*.FDI;*.FDF;*.FLP;*.HDM;*.IMA;*.IMG;*.VFD;*.XDF\0Flux images (*.FDI)\0*.FDI\0Surface-based images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" + 2174 "Configuration files (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0" + 2175 "CD-ROM image (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + 2176 "Use CTRL + ALT + PAGE DOWN to return to windowed mode" + 2177 "Olivetti M24 mouse" + 2178 "This image exists and will be overwritten.\nAre you sure you want to use it?" + 2179 "Floppy %i (%s): %ws" + 2180 "CD-ROM %i: %ws" + 2181 "MFM hard disk" + 2182 "IDE hard disk (PIO-only)" + 2183 "IDE hard disk (PIO and DMA)" + 2184 "SCSI hard disk" + 2185 "(empty)" + 2186 "(host drive %c:)" + 2187 "Custom (large)..." + 2188 "Type" + 2189 "ATAPI (PIO-only)" + 2190 "ATAPI (PIO and DMA)" + 2191 "ATAPI (PIO-only) (%01i:%01i)" + 2192 "ATAPI (PIO and DMA) (%01i:%01i)" + 2193 "Use CTRL + ALT + PAGE DOWN to return to windowed mode" + 2194 "Unable to create bitmap file: %s" + 2195 "IDE (PIO-only) (%01i:%01i)" + 2196 "Add New Hard Disk" + 2197 "Add Existing Hard Disk" + 2198 "Removable disk %i: %s" + 2199 "USB is not yet supported" + 2200 "Invalid PCap device" + 2201 "English (United States)" +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,20,0,0 + PRODUCTVERSION 1,20,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "86Box - an emulator for X86-based systems\0" + VALUE "FileVersion", "1.20\0" + VALUE "InternalName", "pc_new\0" + VALUE "LegalCopyright", "Copyright © SoftHistory, Sarah Walker, 2007-2017, Released under the GNU GPL v2\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "86Box.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "86Box Emulator\0" + VALUE "ProductVersion", "1.20\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/WIN/pcap_if.rc b/src/WIN/pcap_if.rc new file mode 100644 index 000000000..57d78e657 --- /dev/null +++ b/src/WIN/pcap_if.rc @@ -0,0 +1,52 @@ +#ifdef _WIN32 +#include +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + + +#ifdef RELEASE_BUILD +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ +100 ICON DISCARDABLE "ICONS/86Box-RB.ico" +#else +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ +100 ICON DISCARDABLE "ICONS/86Box.ico" +#endif + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,2,0 + PRODUCTVERSION 1,0,2,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "PCap_IF - test tool for WinPcap\0" + VALUE "FileVersion", "1.0.2\0" + VALUE "InternalName", "pcap_if\0" + VALUE "LegalCopyright", "Copyright 2017 Fred N. van Kempen\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "pcap_if.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "WinPcap Test Tool\0" + VALUE "ProductVersion", "1.0.2\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/WIN/plat_dinput.h b/src/WIN/plat_dinput.h new file mode 100644 index 000000000..b5d7eca06 --- /dev/null +++ b/src/WIN/plat_dinput.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern LPDIRECTINPUT lpdi; diff --git a/src/WIN/plat_dir.h b/src/WIN/plat_dir.h new file mode 100644 index 000000000..6eb372aa0 --- /dev/null +++ b/src/WIN/plat_dir.h @@ -0,0 +1,76 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the platform OpenDir module. + * + * Version: @(#)plat_dir.h 1.0.1 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef PLAT_DIR_H +# define PLAT_DIR_H + + +#ifdef _MAX_FNAME +# define MAXNAMLEN _MAX_FNAME +#else +# define MAXNAMLEN 15 +#endif +# define MAXDIRLEN 127 + + +struct direct { + long d_ino; + unsigned short d_reclen; + unsigned short d_off; +#ifdef UNICODE + wchar_t d_name[MAXNAMLEN + 1]; +#else + char d_name[MAXNAMLEN + 1]; +#endif +}; +#define d_namlen d_reclen + + +typedef struct { + short flags; /* internal flags */ + short offset; /* offset of entry into dir */ + long handle; /* open handle to Win32 system */ + short sts; /* last known status code */ + char *dta; /* internal work data */ +#ifdef UNICODE + wchar_t dir[MAXDIRLEN+1]; /* open dir */ +#else + char dir[MAXDIRLEN+1]; /* open dir */ +#endif + struct direct dent; /* actual directory entry */ +} DIR; + + +/* Directory routine flags. */ +#define DIR_F_LOWER 0x0001 /* force to lowercase */ +#define DIR_F_SANE 0x0002 /* force this to sane path */ +#define DIR_F_ISROOT 0x0010 /* this is the root directory */ + + +/* Function prototypes. */ +#ifdef UNICODE +extern DIR *opendirw(const wchar_t *); +#else +extern DIR *opendir(const char *); +#endif +extern struct direct *readdir(DIR *); +extern long telldir(DIR *); +extern void seekdir(DIR *, long); +extern int closedir(DIR *); + +#define rewinddir(dirp) seekdir(dirp, 0L) + + +#endif /*PLAT_DIR_H*/ diff --git a/src/WIN/plat_joystick.h b/src/WIN/plat_joystick.h new file mode 100644 index 000000000..aecb3537c --- /dev/null +++ b/src/WIN/plat_joystick.h @@ -0,0 +1,69 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + void joystick_init(); + void joystick_close(); + void joystick_poll(); + + typedef struct plat_joystick_t + { + char name[64]; + + int a[8]; + int b[32]; + int p[4]; + + struct + { + char name[32]; + int id; + } axis[8]; + + struct + { + char name[32]; + int id; + } button[32]; + + struct + { + char name[32]; + int id; + } pov[4]; + + int nr_axes; + int nr_buttons; + int nr_povs; + } plat_joystick_t; + + #define MAX_PLAT_JOYSTICKS 8 + + extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; + extern int joysticks_present; + + #define POV_X 0x80000000 + #define POV_Y 0x40000000 + + typedef struct joystick_t + { + int axis[8]; + int button[32]; + int pov[4]; + + int plat_joystick_nr; + int axis_mapping[8]; + int button_mapping[32]; + int pov_mapping[4][2]; + } joystick_t; + + #define MAX_JOYSTICKS 4 + extern joystick_t joystick_state[MAX_JOYSTICKS]; + + #define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/WIN/plat_keyboard.h b/src/WIN/plat_keyboard.h new file mode 100644 index 000000000..f062c5951 --- /dev/null +++ b/src/WIN/plat_keyboard.h @@ -0,0 +1,22 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + void keyboard_init(); + void keyboard_close(); + void keyboard_poll_host(); + extern int recv_key[272]; + extern int rawinputkey[272]; + +#ifndef __unix + #define KEY_LCONTROL 0x1d + #define KEY_RCONTROL (0x1d | 0x80) + #define KEY_END (0x4f | 0x80) +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/src/WIN/plat_midi.h b/src/WIN/plat_midi.h new file mode 100644 index 000000000..87ed57306 --- /dev/null +++ b/src/WIN/plat_midi.h @@ -0,0 +1,10 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +void midi_init(); +void midi_close(); +void midi_write(uint8_t val); +int midi_get_num_devs(); +void midi_get_dev_name(int num, char *s); + +extern int midi_id; diff --git a/src/WIN/plat_mouse.h b/src/WIN/plat_mouse.h new file mode 100644 index 000000000..ff248f301 --- /dev/null +++ b/src/WIN/plat_mouse.h @@ -0,0 +1,16 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + + void mouse_init(); + void mouse_close(); + extern int mouse_buttons; + void mouse_poll_host(); + void mouse_get_mickeys(int *x, int *y, int *z); + extern int mousecapture; +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/plat_serial.h b/src/WIN/plat_serial.h new file mode 100644 index 000000000..cf87192c0 --- /dev/null +++ b/src/WIN/plat_serial.h @@ -0,0 +1,49 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the Bottom Half of the SERIAL card. + * + * Version: @(#)plat_serial.h 1.0.3 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef PLAT_SERIAL_H +# define PLAT_SERIAL_H + + +typedef struct { + char name[79]; /* name of open port */ + void (*rd_done)(void *, int); + void *rd_arg; +#ifdef BHTTY_C + HANDLE handle; + OVERLAPPED rov, /* READ and WRITE events */ + wov; + int tmo; /* current timeout value */ + DCB dcb, /* terminal settings */ + odcb; +#endif +} BHTTY; + + +extern BHTTY *bhtty_open(char *__port, int __tmo); +extern void bhtty_close(BHTTY *); +extern int bhtty_flush(BHTTY *); +extern void bhtty_raw(BHTTY *, void *__arg); +extern int bhtty_speed(BHTTY *, long __speed); +extern int bhtty_params(BHTTY *, char __dbit, char __par, char __sbit); +extern int bhtty_sstate(BHTTY *, void *__arg); +extern int bhtty_gstate(BHTTY *, void *__arg); +extern int bhtty_crtscts(BHTTY *, char __yesno); + +extern int bhtty_write(BHTTY *, unsigned char); +extern int bhtty_read(BHTTY *, unsigned char *, int); + + +#endif /*PLAT_SERIAL_H*/ diff --git a/src/WIN/resource.h b/src/WIN/resource.h new file mode 100644 index 000000000..5364bf674 --- /dev/null +++ b/src/WIN/resource.h @@ -0,0 +1,432 @@ +/* Copyright holders: Tenshi + see COPYING for more details +*/ +/* {{NO_DEPENDENCIES}} + Microsoft Developer Studio generated include file. + Used by 86Box.rc +*/ +#define IDHDCONFIG 3 +#define IDCDCONFIG 4 +#define CONFIGUREDLG_MACHINE 101 +#define CONFIGUREDLG_VIDEO 102 +#define CONFIGUREDLG_INPUT 103 +#define CONFIGUREDLG_SOUND 104 +#define CONFIGUREDLG_NETWORK 105 +#define CONFIGUREDLG_PERIPHERALS 106 +#define CONFIGUREDLG_HARD_DISKS 107 +#define CONFIGUREDLG_REMOVABLE_DEVICES 108 +#define ABOUTDLG 109 +#define CONFIGUREDLG_HARD_DISKS_ADD 110 +#define CONFIGUREDLG_MAIN 117 +#define IDC_SETTINGSCATLIST 1004 +#define IDC_LIST_HARD_DISKS 1005 +#define IDC_COMBO_MACHINE 1006 +#define IDC_COMBO_CPU_TYPE 1007 +#define IDC_COMBO_CPU 1008 +#define IDC_COMBO_WS 1009 +#define IDC_CHECK_DYNAREC 1010 +#define IDC_CHECK_FPU 1011 +#define IDC_COMBO_SCSI 1012 +#define IDC_CONFIGURE_SCSI 1013 +#define IDC_COMBO_VIDEO 1014 +#define IDC_COMBO_VIDEO_SPEED 1015 +#define IDC_CHECK_VOODOO 1016 +#define IDC_CHECKCMS 1016 +#define IDC_CONFIGURE_VOODOO 1017 +#define IDC_CHECKNUKEDOPL 1018 +#define IDC_COMBO_JOYSTICK 1018 +#define IDC_CHECK_SYNC 1019 +#define IDC_LIST_FLOPPY_DRIVES 1020 +#define IDC_LIST_CDROM_DRIVES 1021 +#define IDC_CONFIGURE_MACHINE 1022 +#define IDC_COMBO_LANG 1023 +#define IDC_BUTTON_FDD_ADD 1024 +#define IDC_BUTTON_FDD_EDIT 1025 +#define IDC_BUTTON_FDD_REMOVE 1026 +#define IDC_BUTTON_CDROM_ADD 1027 +#define IDC_BUTTON_HDD_ADD_NEW 1027 +#define IDC_BUTTON_CDROM_EDIT 1028 +#define IDC_BUTTON_HDD_ADD 1028 +#define IDC_BUTTON_CDROM_REMOVE 1029 +#define IDC_BUTTON_HDD_REMOVE 1029 +#define IDC_HDIMAGE_NEW 1035 +#define IDC_HD_BUS 1036 +#define IDC_HDIMAGE_EXISTING 1037 +#define IDC_COMBO_HD_BUS 1038 +#define IDC_EDIT_HD_FILE_NAME 1039 +#define IDC_EDIT_HD_CYL 1040 +#define IDC_EDIT_HD_HPC 1041 +#define IDC_EDIT_HD_SPT 1042 +#define IDC_EDIT_HD_SIZE 1043 +#define IDC_COMBO_HD_TYPE 1044 +#define IDC_COMBO_HD_LOCATION 1045 +#define IDC_CHECKGUS 1046 +#define IDC_COMBO_HD_CHANNEL 1047 +#define IDC_COMBO_HD_CHANNEL_IDE 1048 +#define IDC_COMBO_HD_ID 1050 +#define IDC_COMBO_HD_LUN 1051 +#define IDC_CHECKBUGGER 1052 +#define IDC_CHECKSERIAL1 1053 +#define IDC_CHECKPARALLEL 1054 +#define IDC_CHECKSERIAL2 1055 +#define IDC_COMBO_HDC 1068 +#define IDC_COMBO_MOUSE 1069 +#define IDC_COMBO_IDE_TER 1069 +#define IDC_COMBO_IDE_QUA 1070 +#define IDC_COMBO_FD_TYPE 1071 +#define IDC_COMBO_CD_BUS 1072 +#define IDC_COMBO_CD_CHANNEL_IDE 1073 +#define IDC_COMBO_CD_ID 1074 +#define IDC_COMBO_CD_LUN 1075 +#define IDC_COMBO_MIDI 1076 +#define IDC_CHECK_CDROM_1_AUDIO_ENABLED 1584 +#define IDC_CHECK_CDROM_2_AUDIO_ENABLED 1585 +#define IDC_CHECK_CDROM_3_AUDIO_ENABLED 1586 +#define IDC_CHECK_CDROM_4_AUDIO_ENABLED 1587 +#define IDS_STRING2049 2049 +#define IDS_STRING2050 2050 +#define IDS_STRING2051 2051 +#define IDS_STRING2052 2052 +#define IDS_STRING2053 2053 +#define IDS_STRING2054 2054 +#define IDS_STRING2055 2055 +#define IDS_STRING2056 2056 +#define IDS_STRING2057 2057 +#define IDS_STRING2058 2058 +#define IDS_STRING2059 2059 +#define IDS_STRING2060 2060 +#define IDS_STRING2061 2061 +#define IDS_STRING2062 2062 +#define IDS_STRING2063 2063 +#define IDS_STRING2064 2064 +#define IDS_STRING2065 2065 +#define IDS_STRING2066 2066 +#define IDS_STRING2067 2067 +#define IDS_STRING2068 2068 +#define IDS_STRING2069 2069 +#define IDS_STRING2070 2070 +#define IDS_STRING2071 2071 +#define IDS_STRING2072 2072 +#define IDS_STRING2073 2073 +#define IDS_STRING2074 2074 +#define IDS_STRING2075 2075 +#define IDS_STRING2076 2076 +#define IDS_STRING2077 2077 +#define IDS_STRING2078 2078 +#define IDS_STRING2079 2079 +#define IDM_ABOUT 40001 +#define IDC_ABOUT_ICON 65535 + +#define IDM_DISC_1 40000 +#define IDM_DISC_2 40001 +#define IDM_DISC_3 40002 +#define IDM_DISC_4 40003 +#define IDM_DISC_1_WP 40004 +#define IDM_DISC_2_WP 40005 +#define IDM_DISC_3_WP 40006 +#define IDM_DISC_4_WP 40007 +#define IDM_EJECT_1 40008 +#define IDM_EJECT_2 40009 +#define IDM_EJECT_3 40010 +#define IDM_EJECT_4 40011 + +#define IDM_FILE_RESET 40015 +#define IDM_FILE_HRESET 40016 +#define IDM_FILE_EXIT 40017 +#define IDM_FILE_RESET_CAD 40018 +#define IDM_HDCONF 40019 +#define IDM_CONFIG 40020 +#define IDM_CONFIG_LOAD 40021 +#define IDM_CONFIG_SAVE 40022 +#define IDM_USE_NUKEDOPL 40023 +#define IDM_STATUS 40030 +#define IDM_VID_RESIZE 40050 +#define IDM_VID_REMEMBER 40051 +#define IDM_VID_DDRAW 40060 +#define IDM_VID_D3D 40061 +#define IDM_VID_SCALE_1X 40064 +#define IDM_VID_SCALE_2X 40065 +#define IDM_VID_SCALE_3X 40066 +#define IDM_VID_SCALE_4X 40067 +#define IDM_VID_FULLSCREEN 40070 +#define IDM_VID_FS_FULL 40071 +#define IDM_VID_FS_43 40072 +#define IDM_VID_FS_SQ 40073 +#define IDM_VID_FS_INT 40074 +#define IDM_VID_FORCE43 40075 +#define IDM_VID_OVERSCAN 40076 +#define IDM_VID_FLASH 40077 +#define IDM_VID_SCREENSHOT 40078 +#define IDM_VID_INVERT 40079 + +#define IDM_CDROM_1_MUTE 40128 +#define IDM_CDROM_1_IMAGE 40144 +#define IDM_CDROM_1_RELOAD 40160 +#define IDM_CDROM_1_EMPTY 40176 +#define IDM_CDROM_1_REAL 40192 +#define IDM_CDROM_2_MUTE 40129 +#define IDM_CDROM_2_IMAGE 40145 +#define IDM_CDROM_2_RELOAD 40161 +#define IDM_CDROM_2_EMPTY 40177 +#define IDM_CDROM_2_REAL 40193 +#define IDM_CDROM_3_MUTE 40130 +#define IDM_CDROM_3_IMAGE 40146 +#define IDM_CDROM_3_RELOAD 40162 +#define IDM_CDROM_3_EMPTY 40178 +#define IDM_CDROM_3_REAL 40194 +#define IDM_CDROM_4_MUTE 40131 +#define IDM_CDROM_4_IMAGE 40147 +#define IDM_CDROM_4_RELOAD 40163 +#define IDM_CDROM_4_EMPTY 40179 +#define IDM_CDROM_4_REAL 40195 + +#define IDM_IDE_TER_ENABLED 44000 +#define IDM_IDE_TER_IRQ9 44009 +#define IDM_IDE_TER_IRQ10 44010 +#define IDM_IDE_TER_IRQ11 44011 +#define IDM_IDE_TER_IRQ12 44012 +#define IDM_IDE_TER_IRQ14 44014 +#define IDM_IDE_TER_IRQ15 44015 +#define IDM_IDE_QUA_ENABLED 44020 +#define IDM_IDE_QUA_IRQ9 44029 +#define IDM_IDE_QUA_IRQ10 44030 +#define IDM_IDE_QUA_IRQ11 44031 +#define IDM_IDE_QUA_IRQ12 44032 +#define IDM_IDE_QUA_IRQ14 44033 +#define IDM_IDE_QUA_IRQ15 44035 + +#ifdef ENABLE_LOG_TOGGLES +# ifdef ENABLE_BUSLOGIC_LOG +# define IDM_LOG_BUSLOGIC 51200 +# endif +# ifdef ENABLE_CDROM_LOG +# define IDM_LOG_CDROM 51201 +# endif +# ifdef ENABLE_D86F_LOG +# define IDM_LOG_D86F 51202 +# endif +# ifdef ENABLE_FDC_LOG +# define IDM_LOG_FDC 51203 +# endif +# ifdef ENABLE_IDE_LOG +# define IDM_LOG_IDE 51204 +# endif +# ifdef ENABLE_NE2000_LOG +# define IDM_LOG_NE2000 51205 +# endif +#endif +#ifdef ENABLE_LOG_BREAKPOINT +# define IDM_LOG_BREAKPOINT 51206 +#endif +#ifdef ENABLE_VRAM_DUMP +# define IDM_DUMP_VRAM 51207 +#endif + +#define IDC_COMBO1 1000 +#define IDC_COMBOVID 1001 +#define IDC_COMBO3 1002 +#define IDC_COMBO4 1003 +#define IDC_COMBO5 1004 +#define IDC_COMBO386 1005 +#define IDC_COMBO486 1006 +#define IDC_COMBOSND 1007 +#define IDC_COMBONETTYPE 1008 +#define IDC_COMBOPCAP 1009 +#define IDC_COMBONET 1010 +#define IDC_COMBOCPUM 1060 +#define IDC_COMBOSPD 1061 +#define IDC_COMBODR1 1062 +#define IDC_COMBODR2 1063 +#define IDC_COMBODR3 1064 +#define IDC_COMBODR4 1065 +#define IDC_COMBOJOY 1066 +#define IDC_COMBOWS 1067 +#define IDC_COMBOMOUSE 1068 +#define IDC_COMBOHDD 1069 +#define IDC_CHECK1 1010 +#define IDC_CHECK2 1011 +#define IDC_CHECK3 1012 +#define IDC_CHECKSSI 1014 +#define IDC_CHECKVOODOO 1015 +#define IDC_CHECKDYNAREC 1016 +#define IDC_CHECKBUSLOGIC 1017 +#define IDC_CHECKSYNC 1024 +#define IDC_CHECKXTIDE 1025 +#define IDC_CHECKFPU 1026 +#define IDC_EDIT1 1030 +#define IDC_EDIT2 1031 +#define IDC_EDIT3 1032 +#define IDC_EDIT4 1033 +#define IDC_EDIT5 1034 +#define IDC_EDIT6 1035 +#define IDC_COMBOHDT 1036 + +#define IDC_EJECTC 1040 +#define IDC_EDITC 1050 +#define IDC_CFILE 1060 +#define IDC_CNEW 1070 +#define IDC_EDIT_C_SPT 1200 +#define IDC_EDIT_C_HPC 1210 +#define IDC_EDIT_C_CYL 1220 +#define IDC_EDIT_C_FN 1230 +#define IDC_TEXT_C_SIZE 1240 + +#define IDC_EJECTD 1041 +#define IDC_EDITD 1051 +#define IDC_DFILE 1061 +#define IDC_DNEW 1071 +#define IDC_EDIT_D_SPT 1201 +#define IDC_EDIT_D_HPC 1211 +#define IDC_EDIT_D_CYL 1221 +#define IDC_EDIT_D_FN 1231 +#define IDC_TEXT_D_SIZE 1241 + +#define IDC_EJECTE 1042 +#define IDC_EDITE 1052 +#define IDC_EFILE 1062 +#define IDC_ENEW 1072 +#define IDC_EDIT_E_SPT 1202 +#define IDC_EDIT_E_HPC 1212 +#define IDC_EDIT_E_CYL 1222 +#define IDC_EDIT_E_FN 1232 +#define IDC_TEXT_E_SIZE 1242 + +#define IDC_EJECTF 1043 +#define IDC_EDITF 1053 +#define IDC_FFILE 1063 +#define IDC_FNEW 1073 +#define IDC_EDIT_F_SPT 1203 +#define IDC_EDIT_F_HPC 1213 +#define IDC_EDIT_F_CYL 1223 +#define IDC_EDIT_F_FN 1233 +#define IDC_TEXT_F_SIZE 1243 + +#define IDC_EJECTG 1044 +#define IDC_EDITG 1054 +#define IDC_GFILE 1064 +#define IDC_GNEW 1074 +#define IDC_EDIT_G_SPT 1204 +#define IDC_EDIT_G_HPC 1214 +#define IDC_EDIT_G_CYL 1224 +#define IDC_EDIT_G_FN 1234 +#define IDC_TEXT_G_SIZE 1244 + +#define IDC_EJECTH 1045 +#define IDC_EDITH 1055 +#define IDC_HFILE 1065 +#define IDC_HNEW 1075 +#define IDC_EDIT_H_SPT 1205 +#define IDC_EDIT_H_HPC 1215 +#define IDC_EDIT_H_CYL 1225 +#define IDC_EDIT_H_FN 1235 +#define IDC_TEXT_H_SIZE 1245 + +#define IDC_EJECTI 1046 +#define IDC_EDITI 1056 +#define IDC_IFILE 1066 +#define IDC_INEW 1076 +#define IDC_EDIT_I_SPT 1206 +#define IDC_EDIT_I_HPC 1216 +#define IDC_EDIT_I_CYL 1226 +#define IDC_EDIT_I_FN 1236 +#define IDC_TEXT_I_SIZE 1246 + +#define IDC_EJECTJ 1047 +#define IDC_EDITJ 1057 +#define IDC_JFILE 1067 +#define IDC_JNEW 1077 +#define IDC_EDIT_J_SPT 1207 +#define IDC_EDIT_J_HPC 1217 +#define IDC_EDIT_J_CYL 1227 +#define IDC_EDIT_J_FN 1237 +#define IDC_TEXT_J_SIZE 1247 + +#define IDC_HDTYPE 1280 + +#define IDC_RENDER 1281 +#define IDC_STATUS 1282 + +#define IDC_MEMSPIN 1100 +#define IDC_MEMTEXT 1101 +#define IDC_STEXT1 1102 +#define IDC_STEXT2 1103 +#define IDC_STEXT3 1104 +#define IDC_STEXT4 1105 +#define IDC_STEXT5 1106 +#define IDC_STEXT6 1107 +#define IDC_STEXT7 1108 +#define IDC_STEXT8 1109 +#define IDC_STEXT_DEVICE 1110 +#define IDC_TEXT_MB 1111 +#define IDC_TEXT1 1115 +#define IDC_TEXT2 1116 + +#define IDC_CONFIGUREVID 1200 +#define IDC_CONFIGURESND 1201 +#define IDC_CONFIGUREVOODOO 1202 +#define IDC_CONFIGUREMOD 1203 +#define IDC_CONFIGURENETTYPE 1204 +#define IDC_CONFIGUREBUSLOGIC 1205 +#define IDC_CONFIGUREPCAP 1206 +#define IDC_CONFIGURENET 1207 +#define IDC_JOY1 1210 +#define IDC_JOY2 1211 +#define IDC_JOY3 1212 +#define IDC_JOY4 1213 + +#define IDC_CONFIG_BASE 1200 + +#define WM_RESETD3D WM_USER +#define WM_LEAVEFULLSCREEN WM_USER + 1 + +#define C_BASE 6 +#define D_BASE 44 +#define E_BASE 82 +#define F_BASE 120 +#define G_BASE 158 +#define H_BASE 196 +#define I_BASE 234 +#define J_BASE 272 +#define CMD_BASE 314 +#define DLG_HEIGHT 346 + +#define IDC_CHECK_CDROM_1_ENABLED 1536 +#define IDC_COMBO_CDROM_1_BUS 1544 +#define IDC_COMBO_CDROM_1_CHANNEL 1552 +#define IDC_CHECK_CDROM_1_DMA_ENABLED 1560 +#define IDC_COMBO_CDROM_1_SCSI_ID 1568 +#define IDC_COMBO_CDROM_1_SCSI_LUN 1576 + +#define IDC_CHECK_CDROM_2_ENABLED 1537 +#define IDC_COMBO_CDROM_2_BUS 1545 +#define IDC_COMBO_CDROM_2_CHANNEL 1553 +#define IDC_CHECK_CDROM_2_DMA_ENABLED 1561 +#define IDC_COMBO_CDROM_2_SCSI_ID 1569 +#define IDC_COMBO_CDROM_2_SCSI_LUN 1577 + +#define IDC_CHECK_CDROM_3_ENABLED 1538 +#define IDC_COMBO_CDROM_3_BUS 1546 +#define IDC_COMBO_CDROM_3_CHANNEL 1554 +#define IDC_CHECK_CDROM_3_DMA_ENABLED 1562 +#define IDC_COMBO_CDROM_3_SCSI_ID 1570 +#define IDC_COMBO_CDROM_3_SCSI_LUN 1578 + +#define IDC_CHECK_CDROM_4_ENABLED 1539 +#define IDC_COMBO_CDROM_4_BUS 1547 +#define IDC_COMBO_CDROM_4_CHANNEL 1555 +#define IDC_CHECK_CDROM_4_DMA_ENABLED 1563 +#define IDC_COMBO_CDROM_4_SCSI_ID 1571 +#define IDC_COMBO_CDROM_4_SCSI_LUN 1579 + +#define IDC_STATIC 1792 + +/* Next default values for new objects */ +#ifdef APSTUDIO_INVOKED +# ifndef APSTUDIO_READONLY_SYMBOLS +# define _APS_NO_MFC 1 +# define _APS_NEXT_RESOURCE_VALUE 111 +# define _APS_NEXT_COMMAND_VALUE 40002 +# define _APS_NEXT_CONTROL_VALUE 1055 +# define _APS_NEXT_SYMED_VALUE 101 +# endif +#endif diff --git a/src/WIN/win.c b/src/WIN/win.c new file mode 100644 index 000000000..a56660e20 --- /dev/null +++ b/src/WIN/win.c @@ -0,0 +1,2427 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#define UNICODE +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disc.h" +#include "../fdd.h" +#include "../hdd.h" +#include "../ibm.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../nvr.h" +#include "../thread.h" +#include "../config.h" +#include "../model.h" +#include "../ide.h" +#include "../cdrom.h" +#include "../cdrom_null.h" +#include "../cdrom_ioctl.h" +#include "../cdrom_image.h" +#include "../video/video.h" +#include "../video/vid_ega.h" +#include "../mouse.h" +#include "../sound/sound.h" +#include "../sound/snd_dbopl.h" +#include "plat_keyboard.h" +#include "plat_mouse.h" +#include "plat_midi.h" + +#include "win.h" +#include "win_ddraw.h" +#include "win_ddraw-fs.h" +#include "win_d3d.h" +#include "win_d3d-fs.h" +#include "win_language.h" +#include "resource.h" + + +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +static int save_window_pos = 0; +uint64_t timer_freq; + +int rawinputkey[272]; + +static RAWINPUTDEVICE device; +static uint16_t scancode_map[65536]; + +static struct +{ + int (*init)(HWND h); + void (*close)(); + void (*resize)(int x, int y); +} vid_apis[2][2] = +{ + { + ddraw_init, ddraw_close, NULL, + d3d_init, d3d_close, d3d_resize + }, + { + ddraw_fs_init, ddraw_fs_close, NULL, + d3d_fs_init, d3d_fs_close, NULL + }, +}; + +#define TIMER_1SEC 1 + +int winsizex=640,winsizey=480; +int efwinsizey=480; +int gfx_present[GFX_MAX]; + +HANDLE ghMutex; + +HANDLE mainthreadh; + +int infocus=1; + +int drawits=0; + +int romspresent[ROM_MAX]; +int quited=0; + +RECT oldclip; +int mousecapture=0; + +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +LONG OriginalStatusBarProcedure; + +HWND ghwnd; + +HINSTANCE hinstance; + +HMENU menu; + +extern int updatestatus; + +int pause=0; + +static int win_doresize = 0; + +static int leave_fullscreen_flag = 0; + +static int unscaled_size_x = 0; +static int unscaled_size_y = 0; + +int scale = 0; + +HWND hwndRender, hwndStatus; + +void updatewindowsize(int x, int y) +{ + int owsx = winsizex; + int owsy = winsizey; + + int temp_overscan_x = overscan_x; + int temp_overscan_y = overscan_y; + + if (vid_resize) return; + + if (x < 160) x = 160; + if (y < 100) y = 100; + + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + if (suppress_overscan) + { + temp_overscan_x = temp_overscan_y = 0; + } + + unscaled_size_x=x; efwinsizey=y; + + if (force_43) + { + /* Account for possible overscan. */ + if (temp_overscan_y == 16) + { + /* CGA */ + unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; + } + else if (temp_overscan_y < 16) + { + /* MDA/Hercules */ + unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); + } + else + { + if (enable_overscan) + { + /* EGA/(S)VGA with overscan */ + unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; + } + else + { + /* EGA/(S)VGA without overscan */ + unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); + } + } + } + else + { + unscaled_size_y = efwinsizey; + } + + switch(scale) + { + case 0: + winsizex = unscaled_size_x >> 1; + winsizey = unscaled_size_y >> 1; + break; + case 1: + winsizex = unscaled_size_x; + winsizey = unscaled_size_y; + break; + case 2: + winsizex = (unscaled_size_x * 3) >> 1; + winsizey = (unscaled_size_y * 3) >> 1; + break; + case 3: + winsizex = unscaled_size_x << 1; + winsizey = unscaled_size_y << 1; + break; + } + + if ((owsx != winsizex) || (owsy != winsizey)) + { + win_doresize = 1; + } + else + { + win_doresize = 0; + } +} + +void uws_natural() +{ + updatewindowsize(unscaled_size_x, efwinsizey); +} + +void releasemouse() +{ + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture = 0; + } +} + +void startblit() +{ + WaitForSingleObject(ghMutex, INFINITE); +} + +void endblit() +{ + ReleaseMutex(ghMutex); +} + +void leave_fullscreen() +{ + leave_fullscreen_flag = 1; +} + +uint64_t main_time; + +uint64_t start_time; +uint64_t end_time; + +void mainthread(LPVOID param) +{ + int frames = 0; + DWORD old_time, new_time; + + RECT r; + int sb_borders[3]; + + drawits=0; + old_time = GetTickCount(); + while (!quited) + { + if (updatestatus) + { + updatestatus = 0; + if (status_is_open) + SendMessage(status_hwnd, WM_USER, 0, 0); + } + new_time = GetTickCount(); + drawits += new_time - old_time; + old_time = new_time; + if (drawits > 0 && !pause) + { + start_time = timer_read(); + drawits-=10; if (drawits>50) drawits=0; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + end_time = timer_read(); + main_time += end_time - start_time; + } + else + Sleep(1); + + if (!video_fullscreen && win_doresize && (winsizex > 0) && (winsizey > 0)) + { + video_wait_for_blit(); + SendMessage(hwndStatus, SB_GETBORDERS, 0, (LPARAM) sb_borders); + GetWindowRect(ghwnd, &r); + MoveWindow(hwndRender, 0, 0, + winsizex, + winsizey, + TRUE); + GetWindowRect(hwndRender, &r); + MoveWindow(hwndStatus, 0, r.bottom + GetSystemMetrics(SM_CYEDGE), + winsizex, + 17, + TRUE); + GetWindowRect(ghwnd, &r); + + MoveWindow(ghwnd, r.left, r.top, + winsizex + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + winsizey + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, + TRUE); + + win_doresize = 0; + } + + if (leave_fullscreen_flag) + { + leave_fullscreen_flag = 0; + SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); + } + if (video_fullscreen && infocus) + { + SetCursorPos(9999, 9999); + } + } +} + +void *thread_create(void (*thread_rout)(void *param), void *param) +{ + return (void *)_beginthread(thread_rout, 0, param); +} + +void thread_kill(void *handle) +{ + TerminateThread(handle, 0); +} + +void thread_sleep(int t) +{ + Sleep(t); +} + +typedef struct win_event_t +{ + HANDLE handle; +} win_event_t; + +event_t *thread_create_event() +{ + win_event_t *event = malloc(sizeof(win_event_t)); + + event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + SetEvent(event->handle); +} + +void thread_reset_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + ResetEvent(event->handle); +} + +int thread_wait_event(event_t *_event, int timeout) +{ + win_event_t *event = (win_event_t *)_event; + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(event->handle, timeout)) + return 1; + return 0; +} + +void thread_destroy_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + CloseHandle(event->handle); + + free(event); +} + +HMENU smenu; + +static void initmenu(void) +{ + int i, c; + HMENU m; + WCHAR s[64]; + + for (i = 0; i < CDROM_NUM; i++) + { + m=GetSubMenu(smenu, i + 4); /*CD-ROM*/ + + /* Loop through each Windows drive letter and test to see if + it's a CDROM */ + for (c='A';c<='Z';c++) + { + _swprintf(s,L"%c:\\",c); + if (GetDriveType(s)==DRIVE_CDROM) + { + _swprintf(s, win_language_get_string_from_id(2076), c); + AppendMenu(m,MF_STRING,IDM_CDROM_1_REAL+(c << 2)+i,s); + } + } + } +} + +void get_executable_name(WCHAR *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + +void set_window_title(WCHAR *s) +{ + if (video_fullscreen) + return; + SetWindowText(ghwnd, s); +} + +uint64_t timer_read() +{ + LARGE_INTEGER qpc_time; + QueryPerformanceCounter(&qpc_time); + return qpc_time.QuadPart; +} + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +UINT16 convert_scan_code(UINT16 scan_code) +{ + switch (scan_code) + { + case 0xE001: + return 0xF001; + case 0xE002: + return 0xF002; + case 0xE0AA: + return 0xF003; + case 0xE005: + return 0xF005; + case 0xE006: + return 0xF006; + case 0xE007: + return 0xF007; + case 0xE071: + return 0xF008; + case 0xE072: + return 0xF009; + case 0xE07F: + return 0xF00A; + case 0xE0E1: + return 0xF00B; + case 0xE0EE: + return 0xF00C; + case 0xE0F1: + return 0xF00D; + case 0xE0FE: + return 0xF00E; + case 0xE0EF: + return 0xF00F; + + default: + return scan_code; + } +} + +void get_registry_key_map() +{ + WCHAR *keyName = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + WCHAR *valueName = L"Scancode Map"; + unsigned char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + + /* First, prepare the default scan code map list which is 1:1. + Remappings will be inserted directly into it. + 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, + since each array element is a scan code and provides for E0, etc. ones too. */ + for (j = 0; j < 65536; j++) + scancode_map[j] = convert_scan_code(j); + + bufSize = 32768; + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) + { + if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) + { + UINT32 *bufEx2 = (UINT32 *) buf; + int scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) + { + UINT16 *bufEx = (UINT16 *) (buf + 12); + for (j = 0; j < scMapCount*2; j += 2) + { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + int scancode_unmapped = bufEx[j + 1]; + int scancode_mapped = bufEx[j]; + + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Fixes scan code map logging. */ + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + +static wchar_t **argv; +static int argc; +static wchar_t *argbuf; + +static void process_command_line() +{ + WCHAR *cmdline; + int argc_max; + int i, q; + + cmdline = GetCommandLine(); + i = wcslen(cmdline) + 1; + argbuf = malloc(i * 2); + memcpy(argbuf, cmdline, i * 2); + + argc = 0; + argc_max = 64; + argv = malloc(sizeof(wchar_t *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + + i = 0; + + /* parse commandline into argc/argv format */ + while (argbuf[i]) + { + while (argbuf[i] == L' ') + i++; + + if (argbuf[i]) + { + if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) + { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } + else + q = 0; + + argv[argc++] = &argbuf[i]; + + if (argc >= argc_max) + { + argc_max += 64; + argv = realloc(argv, sizeof(wchar_t *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + } + + while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != L' '))) + i++; + + if (argbuf[i]) + { + argbuf[i] = 0; + i++; + } + } + } + + argv[argc] = NULL; +} + +int valid_models[2] = { 0, 1 }; +int valid_bases[6] = { 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 }; +int valid_irqs[6] = { 9, 10, 11, 12, 14, 15 }; +int valid_dma_channels[3] = { 5, 6, 7 }; +int valid_ide_channels[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; +int valid_scsi_ids[15] = { 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; +int valid_scsi_luns[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + +int find_in_array(int *array, int val, int len, int menu_base) +{ + int i = 0; + int temp = 0; + for (i = 0; i < len; i++) + { + CheckMenuItem(menu, menu_base + array[i], MF_UNCHECKED); + if (array[i] == val) + { + temp = 1; + } + } + return temp; +} + +HANDLE hinstAcc; + +HICON LoadIconEx(PCTSTR pszIconName) +{ + return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 16, 16, LR_SHARED); +} + +HICON LoadIconBig(PCTSTR pszIconName) +{ + return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 64, 64, 0); +} + +int fdd_type_to_icon(int type) +{ + switch(type) + { + default: + case 0: + return 512; + case 1: + return 128; + case 2: + return 130; + case 3: + return 132; + case 4: + case 5: + case 6: + return 134; + case 7: + return 144; + case 8: + return 146; + case 9: + case 10: + case 11: + case 12: + return 150; + case 13: + return 152; + } +} + +int sb_parts = 10; + +int sb_part_meanings[12]; +int sb_part_icons[12]; + +int sb_icon_width = 24; + +int count_hard_disks(int bus) +{ + int i = 0; + + int c = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if (hdc[i].bus == bus) + { + c++; + } + } + + return c; +} + +HICON hIcon[512]; + +int iStatusWidths[] = { 18, 36, 54, 72, 90, 108, 126, 144, 168, 192, 210, -1 }; + +#define SBI_FLAG_ACTIVE 1 +#define SBI_FLAG_EMPTY 256 + +int sb_icon_flags[512]; + +/* This is for the disk activity indicator. */ +void update_status_bar_icon(int tag, int active) +{ + int i = 0; + int found = -1; + int temp_flags = 0; + + if ((tag & 0xf0) >= 0x30) + { + return; + } + + temp_flags |= active; + + for (i = 0; i < 12; i++) + { + if (sb_part_meanings[i] == tag) + { + found = i; + break; + } + } + + if (found != -1) + { + if (temp_flags != (sb_icon_flags[found] & 1)) + { + sb_icon_flags[found] &= ~1; + sb_icon_flags[found] |= active; + + sb_part_icons[found] &= ~257; + sb_part_icons[found] |= sb_icon_flags[found]; + + SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); + } + } +} + +/* This is for the drive state indicator. */ +void update_status_bar_icon_state(int tag, int state) +{ + int i = 0; + int found = -1; + + if ((tag & 0xf0) >= 0x20) + { + return; + } + + for (i = 0; i < 12; i++) + { + if (sb_part_meanings[i] == tag) + { + found = i; + break; + } + } + + if (found != -1) + { + sb_icon_flags[found] &= ~256; + sb_icon_flags[found] |= state ? 256 : 0; + + sb_part_icons[found] &= ~257; + sb_part_icons[found] |= sb_icon_flags[found]; + + SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); + } +} + +WCHAR sbTips[24][512]; + +void create_floppy_tip(int part) +{ + WCHAR *szText; + WCHAR wtext[512]; + + int drive = sb_part_meanings[part] & 0xf; + + mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), strlen(fdd_getname(fdd_get_type(drive))) + 1); + if (wcslen(discfns[drive]) == 0) + { + _swprintf(sbTips[part], win_language_get_string_from_id(2179), drive + 1, wtext, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(sbTips[part], win_language_get_string_from_id(2179), drive + 1, wtext, discfns[drive]); + } +} + +void create_cdrom_tip(int part) +{ + WCHAR *szText; + char ansi_text[3][512]; + WCHAR wtext[512]; + + int drive = sb_part_meanings[part] & 0xf; + + if (cdrom_drives[drive].host_drive == 200) + { + if (wcslen(cdrom_image[drive].image_path) == 0) + { + _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, cdrom_image[drive].image_path); + } + } + else if (cdrom_drives[drive].host_drive < 0x41) + { + _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); + } + else + { + _swprintf(wtext, win_language_get_string_from_id(2186), cdrom_drives[drive].host_drive & ~0x20); + _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, wtext); + } +} + +void create_hd_tip(int part) +{ + WCHAR *szText; + + int bus = sb_part_meanings[part] & 0xf; + szText = (WCHAR *) win_language_get_string_from_id(2181 + bus); + memcpy(sbTips[part], szText, (wcslen(szText) << 1) + 2); +} + +void update_tip(int meaning) +{ + int i = 0; + int part = -1; + + for (i = 0; i < sb_parts; i++) + { + if (sb_part_meanings[i] == meaning) + { + part = i; + } + } + + if (part != -1) + { + switch(meaning & 0x30) + { + case 0x00: + create_floppy_tip(part); + break; + case 0x10: + create_cdrom_tip(part); + break; + case 0x20: + create_hd_tip(part); + break; + default: + break; + } + + SendMessage(hwndStatus, SB_SETTIPTEXT, part, (LPARAM) sbTips[part]); + } +} + +static int get_floppy_state(int id) +{ + return (wcslen(discfns[id]) == 0) ? 1 : 0; +} + +static int get_cd_state(int id) +{ + if (cdrom_drives[id].host_drive < 0x41) + { + return 1; + } + else + { + if (cdrom_drives[id].host_drive == 0x200) + { + return (wcslen(cdrom_image[id].image_path) == 0) ? 1 : 0; + } + else + { + return 0; + } + } +} + +void status_settextw(wchar_t *wstr) +{ + int i = 0; + int part = -1; + + for (i = 0; i < sb_parts; i++) + { + if (sb_part_meanings[i] == 0x30) + { + part = i; + } + } + + if (part != -1) + { + SendMessage(hwndStatus, SB_SETTEXT, part | SBT_NOBORDERS, (LPARAM) wstr); + } +} + +static wchar_t cwstr[512]; + +void status_settext(char *str) +{ + memset(cwstr, 0, 1024); + mbstowcs(cwstr, str, strlen(str) + 1); + status_settextw(cwstr); +} + +void update_status_bar_panes(HWND hwnds) +{ + int i, j, id; + int edge = 0; + + int c_rll = 0; + int c_mfm = 0; + int c_ide_pio = 0; + int c_ide_dma = 0; + int c_scsi = 0; + + c_mfm = count_hard_disks(1); + c_ide_pio = count_hard_disks(2); + c_ide_dma = count_hard_disks(3); + c_scsi = count_hard_disks(4); + + for (i = 0; i < sb_parts; i++) + { + SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); + } + + sb_parts = 0; + memset(iStatusWidths, 0, 48); + memset(sb_part_meanings, 0, 48); + for (i = 0; i < 4; i++) + { + if (fdd_get_type(i) != 0) + { + /* pclog("update_status_bar_panes(): Found floppy drive %c:, type %i\n", 65 + i, fdd_get_type(i)); */ + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x00 | i; + sb_parts++; + } + } + for (i = 0; i < 4; i++) + { + if (cdrom_drives[i].bus_type != 0) + { + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x10 | i; + sb_parts++; + } + } + if (c_mfm && !(models[model].flags & MODEL_HAS_IDE) && !!memcmp(hdd_controller_name, "none", 4) && !!memcmp(hdd_controller_name, "xtide", 5)) + { + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x20; + sb_parts++; + } + if (c_ide_pio && ((models[model].flags & MODEL_HAS_IDE) || !memcmp(hdd_controller_name, "xtide", 5))) + { + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x21; + sb_parts++; + } + if (c_ide_dma && ((models[model].flags & MODEL_HAS_IDE) || !memcmp(hdd_controller_name, "xtide", 5))) + { + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x22; + sb_parts++; + } + if (c_scsi) + { + edge += sb_icon_width; + iStatusWidths[sb_parts] = edge; + sb_part_meanings[sb_parts] = 0x23; + sb_parts++; + } + if (sb_parts) + { + iStatusWidths[sb_parts - 1] += (24 - sb_icon_width); + } + iStatusWidths[sb_parts] = -1; + sb_part_meanings[sb_parts] = 0x30; + sb_parts++; + + SendMessage(hwnds, SB_SETPARTS, (WPARAM) sb_parts, (LPARAM) iStatusWidths); + + for (i = 0; i < sb_parts; i++) + { + switch (sb_part_meanings[i] & 0x30) + { + case 0x00: + /* Floppy */ + sb_icon_flags[i] = (wcslen(discfns[sb_part_meanings[i] & 0xf]) == 0) ? 256 : 0; + sb_part_icons[i] = fdd_type_to_icon(fdd_get_type(sb_part_meanings[i] & 0xf)) | sb_icon_flags[i]; + create_floppy_tip(i); + break; + case 0x10: + /* CD-ROM */ + id = sb_part_meanings[i] & 0xf; + if (cdrom_drives[id].host_drive < 0x41) + { + sb_icon_flags[i] = 256; + } + else + { + if (cdrom_drives[id].host_drive == 0x200) + { + sb_icon_flags[i] = (wcslen(cdrom_image[id].image_path) == 0) ? 256 : 0; + } + else + { + sb_icon_flags[i] = 0; + } + } + if (cdrom_drives[id].bus_type == 4) + { + j = 164; + } + else if (cdrom_drives[id].bus_type == 3) + { + j = 162; + } + else + { + j = 160; + } + sb_part_icons[i] = j | sb_icon_flags[i]; + create_cdrom_tip(i); + break; + case 0x20: + /* Hard disk */ + sb_part_icons[i] = 176 + ((sb_part_meanings[i] & 0xf) << 1); + create_hd_tip(i); + break; + case 0x30: + /* Status text */ + SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) L"Welcome to Unicode 86Box! :p"); + sb_part_icons[i] = -1; + break; + } + if (sb_part_icons[i] != -1) + { + SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) ""); + SendMessage(hwnds, SB_SETICON, i, (LPARAM) hIcon[sb_part_icons[i]]); + SendMessage(hwnds, SB_SETTIPTEXT, i, (LPARAM) sbTips[i]); + /* pclog("Status bar part found: %02X (%i)\n", sb_part_meanings[i], sb_part_icons[i]); */ + } + else + { + SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); + } + } +} + +HWND EmulatorStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinst) +{ + HWND hwndStatus; + int i; + RECT rectDialog; + int dw, dh; + + for (i = 128; i < 136; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 144; i < 148; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 150; i < 154; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 160; i < 166; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 176; i < 184; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 384; i < 392; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 400; i < 404; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 406; i < 410; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + for (i = 416; i < 422; i++) + { + hIcon[i] = LoadIconEx((PCTSTR) i); + } + + GetWindowRect(hwndParent, &rectDialog); + dw = rectDialog.right - rectDialog.left; + dh = rectDialog.bottom - rectDialog.top; + + InitCommonControls(); + + hwndStatus = CreateWindowEx( + 0, + STATUSCLASSNAME, + (PCTSTR) NULL, + SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE | SBT_TOOLTIPS, + 0, dh - 17, dw, 17, + hwndParent, + (HMENU) idStatus, + hinst, + NULL); + + GetWindowRect(hwndStatus, &rectDialog); + + SetWindowPos( + hwndStatus, + HWND_TOPMOST, + rectDialog.left, + rectDialog.top, + rectDialog.right - rectDialog.left, + rectDialog.bottom - rectDialog.top, + SWP_SHOWWINDOW); + + SendMessage(hwndStatus, SB_SETMINHEIGHT, (WPARAM) 17, (LPARAM) 0); + + update_status_bar_panes(hwndStatus); + + return hwndStatus; +} + +void win_menu_update() +{ +#if 0 + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + + smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); + initmenu(); + + SetMenu(ghwnd, menu); + + win_title_update = 1; +#endif +} + +int recv_key[272]; + +int WINAPI WinMain (HINSTANCE hThisInstance, + HINSTANCE hPrevInstance, + LPSTR lpszArgument, + int nFunsterStil) + +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + int c, d, e, bRet; + WCHAR emulator_title[200]; + LARGE_INTEGER qpc_freq; + HACCEL haccel; /* Handle to accelerator table */ + + memset(recv_key, 0, sizeof(recv_key)); + + process_command_line(); + + win_language_load_common_strings(); + + hinstance=hThisInstance; + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon(hinstance, (LPCTSTR) 100); + wincl.hIconSm = LoadIcon(hinstance, (LPCTSTR) 100); + wincl.hCursor = NULL; + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx(&wincl)) + return 0; + + wincl.lpszClassName = szSubClassName; + wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ + + if (!RegisterClassEx(&wincl)) + return 0; + + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + + _swprintf(emulator_title, L"86Box v%s", emulator_version_w); + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + emulator_title, /* Title Text */ + (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX)/* | DS_3DLOOK*/, /* default window */ + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where the window ends up on the screen */ + 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ + 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + menu, /* Menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow (hwnd, nFunsterStil); + + /* Load the accelerator table */ + haccel = LoadAccelerators(hinstAcc, L"MainAccel"); + if (haccel == NULL) + fatal("haccel is null\n"); + + memset(rawinputkey, 0, sizeof(rawinputkey)); + device.usUsagePage = 0x01; + device.usUsage = 0x06; + device.dwFlags = RIDEV_NOHOTKEYS; + device.hwndTarget = hwnd; + + if (RegisterRawInputDevices(&device, 1, sizeof(device))) + pclog("Raw input registered!\n"); + else + pclog("Raw input registration failed!\n"); + + get_registry_key_map(); + + ghwnd=hwnd; + + initpc(argc, argv); + + hwndRender = CreateWindow(L"STATIC", NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 0, 0, 1, 1, ghwnd, NULL, hinstance, NULL); + + hwndStatus = EmulatorStatusBar(hwnd, IDC_STATUS, hThisInstance); + + OriginalStatusBarProcedure = GetWindowLong(hwndStatus, GWL_WNDPROC); + SetWindowLong(hwndStatus, GWL_WNDPROC, (LONG) &StatusBarProcedure); + + smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); + initmenu(); + + if (vid_apis[0][vid_api].init(hwndRender) == 0) + { + if (vid_apis[0][vid_api ^ 1].init(hwndRender) == 0) + { + fatal("Both DirectDraw and Direct3D renderers failed to initialize\n"); + } + else + { + vid_api ^= 1; + } + } + + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX); + + /* Note by Kiririn: I've redone this since the CD-ROM can be disabled but still have something inside it. */ + for (e = 0; e < CDROM_NUM; e++) + { + if (!cdrom_drives[e].sound_on) + { + CheckMenuItem(smenu, IDM_CDROM_1_MUTE + e, MF_CHECKED); + } + + if (cdrom_drives[e].host_drive == 200) + { + CheckMenuItem(smenu, IDM_CDROM_1_IMAGE + e, MF_CHECKED); + } + else if (cdrom_drives[e].host_drive >= 65) + { + CheckMenuItem(smenu, IDM_CDROM_1_REAL + e + (cdrom_drives[e].host_drive << 2), MF_CHECKED); + } + else + { + CheckMenuItem(smenu, IDM_CDROM_1_EMPTY + e, MF_CHECKED); + } + } + +#ifdef ENABLE_LOG_TOGGLES +#ifdef ENABLE_BUSLOGIC_LOG + CheckMenuItem(menu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#ifdef ENABLE_CDROM_LOG + CheckMenuItem(menu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#ifdef ENABLE_D86F_LOG + CheckMenuItem(menu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#ifdef ENABLE_FDC_LOG + CheckMenuItem(menu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#ifdef ENABLE_IDE_LOG + CheckMenuItem(menu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#ifdef ENABLE_NE2000_LOG + CheckMenuItem(menu, IDM_LOG_NE2000, ne2000_do_log ? MF_CHECKED : MF_UNCHECKED); +#endif +#endif + + CheckMenuItem(menu, IDM_VID_FORCE43, force_43 ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_OVERSCAN, enable_overscan ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_INVERT, invert_display ? MF_CHECKED : MF_UNCHECKED); + + if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menu, IDM_VID_SCALE_1X + scale, MF_CHECKED); + + d=romset; + for (c=0;c= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + loadbios(); + resetpchard(); + + timeBeginPeriod(1); + + atexit(releasemouse); + + ghMutex = CreateMutex(NULL, FALSE, NULL); + mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); + SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); + + + updatewindowsize(640, 480); + + QueryPerformanceFrequency(&qpc_freq); + timer_freq = qpc_freq.QuadPart; + + if (start_in_fullscreen) + { + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(hwndRender); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + } + if (window_remember) + { + MoveWindow(hwnd, window_x, window_y, + window_w, + window_h, + TRUE); + } + else + { + MoveWindow(hwndRender, 0, 0, + winsizex, + winsizey, + TRUE); + MoveWindow(hwndStatus, 0, winsizey + 6, + winsizex, + 17, + TRUE); + } + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (!quited) + { + while (((bRet = GetMessage(&messages,NULL,0,0)) != 0) && !quited) + { + if (bRet == -1) + { + fatal("bRet is -1\n"); + } + + if (messages.message==WM_QUIT) quited=1; + if (!TranslateAccelerator(hwnd, haccel, &messages)) + { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + + if (recv_key[0x58] && recv_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + + if ((recv_key[0x1D] || recv_key[0x9D]) && + (recv_key[0x38] || recv_key[0xB8]) && + (recv_key[0x51] || recv_key[0xD1]) && + video_fullscreen) + { + leave_fullscreen(); + } + } + + quited=1; + } + + startblit(); + Sleep(200); + TerminateThread(mainthreadh,0); + savenvr(); + saveconfig(); + closepc(); + + vid_apis[video_fullscreen][vid_api].close(); + + timeEndPeriod(1); + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + } + + UnregisterClass(szSubClassName, hinstance); + UnregisterClass(szClassName, hinstance); + + return messages.wParam; +} + +HHOOK hKeyboardHook; +int hook_enabled = 0; + +LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + BOOL bControlKeyDown; + KBDLLHOOKSTRUCT* p; + + if (nCode < 0 || nCode != HC_ACTION) + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); + + p = (KBDLLHOOKSTRUCT*)lParam; + + if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ + if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1; /* disable windows keys */ + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-escape */ + bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1); /* checks ctrl key pressed */ + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; /* disable ctrl-escape */ + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} + +void cdrom_close(uint8_t id) +{ + switch (cdrom_drives[id].host_drive) + { + case 0: + null_close(id); + break; + default: + ioctl_close(id); + break; + case 200: + image_close(id); + break; + } +} + +int ide_ter_set_irq(HMENU hmenu, int irq, int id) +{ + if (ide_irq[2] == irq) + { + return 0; + } + if (msgbox_reset_yn(ghwnd) != IDYES) + { + return 0; + } + pause = 1; + Sleep(100); + ide_irq[2] = irq; + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ9, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ10, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ11, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ12, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ14, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_TER_IRQ15, MF_UNCHECKED); + CheckMenuItem(hmenu, id, MF_CHECKED); + saveconfig(); + resetpchard(); + pause = 0; + return 1; +} + +int ide_qua_set_irq(HMENU hmenu, int irq, int id) +{ + if (ide_irq[3] == irq) + { + return 0; + } + if (msgbox_reset_yn(ghwnd) != IDYES) + { + return 0; + } + pause = 1; + Sleep(100); + ide_irq[3] = irq; + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ9, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ10, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ11, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ12, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ14, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ15, MF_UNCHECKED); + CheckMenuItem(hmenu, id, MF_CHECKED); + saveconfig(); + resetpchard(); + pause = 0; + return 1; +} + +void video_toggle_option(HMENU hmenu, int *val, int id) +{ + *val ^= 1; + CheckMenuItem(hmenu, id, *val ? MF_CHECKED : MF_UNCHECKED); + saveconfig(); +} + +void win_cdrom_eject(uint8_t id) +{ + HMENU hmenu; + hmenu = GetSubMenu(smenu, id + 4); + if (cdrom_drives[id].host_drive == 0) + { + /* Switch from empty to empty. Do nothing. */ + return; + } + cdrom_drives[id].handler->exit(id); + cdrom_close(id); + cdrom_null_open(id, 0); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + id, MF_UNCHECKED); + if ((cdrom_drives[id].host_drive >= 65) && (cdrom_drives[id].host_drive <= 90)) + { + CheckMenuItem(hmenu, IDM_CDROM_1_REAL + id + (cdrom_drive << 2), MF_UNCHECKED); + } + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + cdrom_drives[id].host_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_CHECKED); + update_status_bar_icon_state(0x10 | id, get_cd_state(id)); + update_tip(0x10 | id); + saveconfig(); +} + +void win_cdrom_reload(uint8_t id) +{ + HMENU hmenu; + hmenu = GetSubMenu(smenu, id + 4); + int new_cdrom_drive; + if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) + { + /* Switch from empty to empty. Do nothing. */ + return; + } + cdrom_close(id); + if (cdrom_drives[id].prev_host_drive == 200) + { + image_open(id, cdrom_image[id].image_path); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_UNCHECKED); + cdrom_drives[id].host_drive = 200; + CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + id, MF_CHECKED); + } + else + { + new_cdrom_drive = cdrom_drives[id].prev_host_drive; + ioctl_open(id, new_cdrom_drive); + if (cdrom_drives[id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(id); + } + CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_UNCHECKED); + cdrom_drive = new_cdrom_drive; + CheckMenuItem(hmenu, IDM_CDROM_1_REAL + id + (cdrom_drives[id].host_drive << 2), MF_CHECKED); + } + update_status_bar_icon_state(0x10 | id, get_cd_state(id)); + update_tip(0x10 | id); + saveconfig(); +} + +static BOOL CALLBACK about_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + + switch (message) + { + case WM_INITDIALOG: + pause = 1; + h = GetDlgItem(hdlg, IDC_ABOUT_ICON); + SendMessage(h, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) LoadIconBig((PCTSTR) 100)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + default: + break; + } + break; + } + + return FALSE; +} + +void about_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR) ABOUTDLG, hwnd, about_dlgproc); +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + RECT rect; + uint32_t ri_size = 0; + int edgex, edgey; + int sb_borders[3]; + + switch (message) + { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + hook_enabled = 1; + break; + + case WM_COMMAND: + hmenu=GetMenu(hwnd); + switch (LOWORD(wParam)) + { + case IDM_FILE_HRESET: + pause=1; + Sleep(100); + savenvr(); + saveconfig(); + resetpchard(); + pause=0; + break; + case IDM_FILE_RESET_CAD: + pause=1; + Sleep(100); + savenvr(); + saveconfig(); + resetpc_cad(); + pause=0; + break; + case IDM_FILE_EXIT: + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + case IDM_CONFIG: + win_settings_open(hwnd); + break; + case IDM_ABOUT: + about_open(hwnd); + break; + case IDM_STATUS: + status_open(hwnd); + break; + + case IDM_VID_RESIZE: + vid_resize=!vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX); + GetWindowRect(hwnd,&rect); + SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + GetWindowRect(hwndStatus,&rect); + SetWindowPos(hwndStatus, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + if (vid_resize) + { + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); + scale = 1; + } + EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + win_doresize = 1; + saveconfig(); + break; + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember) + { + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + saveconfig(); + break; + + case IDM_VID_DDRAW: case IDM_VID_D3D: + startblit(); + video_wait_for_blit(); + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); + vid_apis[0][vid_api].close(); + vid_api = LOWORD(wParam) - IDM_VID_DDRAW; + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + vid_apis[0][vid_api].init(hwndRender); + endblit(); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_FULLSCREEN: + + if(video_fullscreen!=1){ + + if (video_fullscreen_first) + { + video_fullscreen_first = 0; + msgbox_info(ghwnd, 2193); + } + startblit(); + video_wait_for_blit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + } + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_SQ: + case IDM_VID_FS_INT: + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + saveconfig(); + break; + + case IDM_VID_SCALE_1X: + case IDM_VID_SCALE_2X: + case IDM_VID_SCALE_3X: + case IDM_VID_SCALE_4X: + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + scale = LOWORD(wParam) - IDM_VID_SCALE_1X; + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_CHECKED); + saveconfig(); + break; + + case IDM_VID_FORCE43: + video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); + break; + + case IDM_VID_INVERT: + video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); + break; + + case IDM_VID_OVERSCAN: + video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); + update_overscan = 1; + break; + + case IDM_VID_FLASH: + video_toggle_option(hmenu, &enable_flash, IDM_VID_FLASH); + break; + + case IDM_VID_SCREENSHOT: + take_screenshot(); + break; + +#ifdef ENABLE_LOG_TOGGLES +#ifdef ENABLE_BUSLOGIC_LOG + case IDM_LOG_BUSLOGIC: + buslogic_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_CDROM_LOG + case IDM_LOG_CDROM: + cdrom_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_D86F_LOG + case IDM_LOG_D86F: + d86f_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_FDC_LOG + case IDM_LOG_FDC: + fdc_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_IDE_LOG + case IDM_LOG_IDE: + ide_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif + +#ifdef ENABLE_NE2000_LOG + case IDM_LOG_NE2000: + ne2000_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_NE2000, ne2000_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +#endif +#endif + +#ifdef ENABLE_LOG_BREAKPOINT + case IDM_LOG_BREAKPOINT: + pclog("---- LOG BREAKPOINT ----\n"); + break; +#endif + +#ifdef ENABLE_VRAM_DUMP + case IDM_DUMP_VRAM: + svga_dump_vram(); + break; +#endif + + case IDM_CONFIG_LOAD: + pause = 1; + if (!file_dlg_st(hwnd, 2174, "", 0)) + { + if (msgbox_reset_yn(ghwnd) == IDYES) + { + config_save(config_file_default); + loadconfig(wopenfilestring); + pclog_w(L"NVR path: %s\n", nvr_path); + mem_resize(); + loadbios(); + resetpchard(); + } + } + pause = 0; + break; + + case IDM_CONFIG_SAVE: + pause = 1; + if (!file_dlg_st(hwnd, 2174, "", 1)) + config_save(wopenfilestring); + pause = 0; + break; + } + return 0; + + case WM_INPUT: + { + UINT size; + RAWINPUT *raw; + + if (!infocus) + break; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + + if (raw == NULL) + { + return 0; + } + + /* Here we read the raw input data for the keyboard */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + if(ri_size != size) + { + return 0; + } + + /* If the input is keyboard, we process it */ + if (raw->header.dwType == RIM_TYPEKEYBOARD) + { + const RAWKEYBOARD rawKB = raw->data.keyboard; + USHORT scancode = rawKB.MakeCode; + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) + { + if (rawKB.Flags & RI_KEY_E0) + scancode |= (0xE0 << 8); + + /* Remap it according to the list from the Registry */ + scancode = scancode_map[scancode]; + + if ((scancode >> 8) == 0xF0) + scancode |= 0x100; /* Extended key code in disambiguated format */ + else if ((scancode >> 8) == 0xE0) + scancode |= 0x80; /* Normal extended key code */ + + /* If it's not 0 (therefore not 0xE1, 0xE2, etc), + then pass it on to the rawinputkey array */ + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + else + { + if (rawKB.MakeCode == 0x1D) + scancode = 0xFF; + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + } + free(raw); + + } + break; + + case WM_SETFOCUS: + infocus=1; + if (!hook_enabled) + { + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + hook_enabled = 1; + } + break; + + case WM_KILLFOCUS: + infocus=0; + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + memset(rawinputkey, 0, sizeof(rawinputkey)); + if (video_fullscreen) + leave_fullscreen_flag = 1; + if (hook_enabled) + { + UnhookWindowsHookEx(hKeyboardHook); + hook_enabled = 0; + } + break; + + case WM_LBUTTONUP: + if (!mousecapture && !video_fullscreen) + { + RECT pcclip; + + GetClipCursor(&oldclip); + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + mousecapture = 1; + while (1) + { + if (ShowCursor(FALSE) < 0) break; + } + } + break; + + case WM_MBUTTONUP: + if (!(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) + releasemouse(); + break; + + case WM_ENTERMENULOOP: + break; + + case WM_SIZE: + winsizex = (lParam & 0xFFFF); + winsizey = (lParam >> 16) - (17 + 6); + + MoveWindow(hwndRender, 0, 0, + winsizex, + winsizey, + TRUE); + + if (vid_apis[video_fullscreen][vid_api].resize) + { + startblit(); + video_wait_for_blit(); + vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); + endblit(); + } + + MoveWindow(hwndStatus, 0, winsizey + 6, + winsizex, + 17, + TRUE); + + if (mousecapture) + { + RECT pcclip; + + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + } + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_MOVE: + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) + onesec(); + break; + + case WM_RESETD3D: + startblit(); + if (video_fullscreen) + d3d_fs_reset(); + else + d3d_reset(); + endblit(); + break; + + case WM_LEAVEFULLSCREEN: + startblit(); + mouse_close(); + vid_apis[1][vid_api].close(); + video_fullscreen = 0; + vid_apis[0][vid_api].init(ghwnd); + mouse_init(); + endblit(); + device_force_redraw(); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + return 0; + + case WM_DESTROY: + UnhookWindowsHookEx( hKeyboardHook ); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + + case WM_SYSCOMMAND: + /* Disable ALT key *ALWAYS*, I don't think there's any use for reaching the menu that way. */ + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) + return 0; /*disable ALT key for menu*/ + + default: + return DefWindowProc (hwnd, message, wParam, lParam); + } + return 0; +} + +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} + +VOID APIENTRY HandlePopupMenu(HWND hwnd, POINT pt, int id) +{ + HMENU pmenu; + int menu_id = -1; + if (id >= (sb_parts - 1)) + { + return; + } + pt.x = id * sb_icon_width; /* Justify to the left. */ + pt.y = 0; /* Justify to the top. */ + ClientToScreen(hwnd, (LPPOINT) &pt); + if ((sb_part_meanings[id] & 0x30) == 0x00) + { + menu_id = sb_part_meanings[id] & 0xf; + } + else if ((sb_part_meanings[id] & 0x30) == 0x10) + { + menu_id = (sb_part_meanings[id] & 0xf) + 4; + } + if (menu_id != -1) + { + pmenu = GetSubMenu(smenu, menu_id); + TrackPopupMenu(pmenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, hwndStatus, NULL); + } +} + +LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + RECT rc; + POINT pt; + + WCHAR temp_image_path[1024]; + int new_cdrom_drive; + int cdrom_id = 0; + int menu_sub_param = 0; + int menu_super_param = 0; + int ret = 0; + + HMENU hmenu; + + switch (message) + { + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDM_DISC_1: + case IDM_DISC_1_WP: + ret = file_dlg_w_st(hwnd, 2173, discfns[0], 0); + if (!ret) + { + disc_close(0); + ui_writeprot[0] = (LOWORD(wParam) == IDM_DISC_1_WP) ? 1 : 0; + disc_load(0, wopenfilestring); + update_status_bar_icon_state(0x00, 0); + update_tip(0x00); + saveconfig(); + } + break; + case IDM_DISC_2: + case IDM_DISC_2_WP: + ret = file_dlg_w_st(hwnd, 2173, discfns[1], 0); + if (!ret) + { + disc_close(1); + ui_writeprot[1] = (LOWORD(wParam) == IDM_DISC_2_WP) ? 1 : 0; + disc_load(1, wopenfilestring); + update_status_bar_icon_state(0x01, 0); + update_tip(0x01); + saveconfig(); + } + break; + case IDM_DISC_3: + case IDM_DISC_3_WP: + ret = file_dlg_w_st(hwnd, 2173, discfns[2], 0); + if (!ret) + { + disc_close(2); + ui_writeprot[2] = (LOWORD(wParam) == IDM_DISC_3_WP) ? 1 : 0; + disc_load(2, wopenfilestring); + update_status_bar_icon_state(0x02, 0); + update_tip(0x02); + saveconfig(); + } + break; + case IDM_DISC_4: + case IDM_DISC_4_WP: + ret = file_dlg_w_st(hwnd, 2173, discfns[3], 0); + if (!ret) + { + disc_close(3); + ui_writeprot[3] = (LOWORD(wParam) == IDM_DISC_4_WP) ? 1 : 0; + disc_load(3, wopenfilestring); + update_status_bar_icon_state(0x03, 0); + update_tip(0x03); + saveconfig(); + } + break; + case IDM_EJECT_1: + disc_close(0); + update_status_bar_icon_state(0x00, 1); + update_tip(0x00); + saveconfig(); + break; + case IDM_EJECT_2: + disc_close(1); + update_status_bar_icon_state(0x01, 1); + update_tip(0x01); + saveconfig(); + break; + case IDM_EJECT_3: + disc_close(2); + update_status_bar_icon_state(0x02, 1); + update_tip(0x02); + saveconfig(); + break; + case IDM_EJECT_4: + disc_close(3); + update_status_bar_icon_state(0x03, 1); + update_tip(0x03); + saveconfig(); + break; + + case IDM_CDROM_1_MUTE: + case IDM_CDROM_2_MUTE: + case IDM_CDROM_3_MUTE: + case IDM_CDROM_4_MUTE: + cdrom_id = LOWORD(wParam) & 3; + hmenu = GetSubMenu(smenu, cdrom_id + 4); + Sleep(100); + cdrom_drives[cdrom_id].sound_on ^= 1; + CheckMenuItem(hmenu, IDM_CDROM_1_MUTE + (cdrom_id * 1000), cdrom_drives[cdrom_id].sound_on ? MF_UNCHECKED : MF_CHECKED); + saveconfig(); + sound_cd_thread_reset(); + break; + + case IDM_CDROM_1_EMPTY: + case IDM_CDROM_2_EMPTY: + case IDM_CDROM_3_EMPTY: + case IDM_CDROM_4_EMPTY: + cdrom_id = LOWORD(wParam) & 3; + hmenu = GetSubMenu(smenu, cdrom_id + 4); + win_cdrom_eject(cdrom_id); + break; + + case IDM_CDROM_1_RELOAD: + case IDM_CDROM_2_RELOAD: + case IDM_CDROM_3_RELOAD: + case IDM_CDROM_4_RELOAD: + cdrom_id = LOWORD(wParam) & 3; + hmenu = GetSubMenu(smenu, cdrom_id + 4); + win_cdrom_reload(cdrom_id); + break; + + case IDM_CDROM_1_IMAGE: + case IDM_CDROM_2_IMAGE: + case IDM_CDROM_3_IMAGE: + case IDM_CDROM_4_IMAGE: + cdrom_id = LOWORD(wParam) & 3; + hmenu = GetSubMenu(smenu, cdrom_id + 4); + if (!file_dlg_w_st(hwnd, 2175, cdrom_image[cdrom_id].image_path, 0)) + { + cdrom_drives[cdrom_id].prev_host_drive = cdrom_drives[cdrom_id].host_drive; + wcscpy(temp_image_path, wopenfilestring); + if ((wcscmp(cdrom_image[cdrom_id].image_path, temp_image_path) == 0) && (cdrom_drives[cdrom_id].host_drive == 200)) + { + /* Switching from image to the same image. Do nothing. */ + break; + } + cdrom_drives[cdrom_id].handler->exit(cdrom_id); + cdrom_close(cdrom_id); + image_open(cdrom_id, temp_image_path); + if (cdrom_drives[cdrom_id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom_id); + } + CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + cdrom_id, MF_UNCHECKED); + if ((cdrom_drives[cdrom_id].host_drive != 0) && (cdrom_drives[cdrom_id].host_drive != 200)) + { + CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_UNCHECKED); + } + cdrom_drives[cdrom_id].host_drive = 200; + CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + cdrom_id, MF_CHECKED); + update_tip(0x10 | cdrom_id); + saveconfig(); + } + break; + + default: + cdrom_id = LOWORD(wParam) & 3; + hmenu = GetSubMenu(smenu, cdrom_id + 4); + menu_sub_param = ((LOWORD(wParam) - IDM_CDROM_1_REAL) - cdrom_id) >> 2; + /* pclog("[%04X] Guest drive %c [%i]: -> Host drive %c [%i]:\n", LOWORD(wParam), 0x4b + cdrom_id, cdrom_id, menu_sub_param, menu_sub_param); */ + if (((LOWORD(wParam) & ~3) >= (IDM_CDROM_1_REAL + ('A' << 2))) && ((LOWORD(wParam) & ~3) <= (IDM_CDROM_1_REAL + ('Z' << 2)))) + { + new_cdrom_drive = menu_sub_param; + if (cdrom_drives[cdrom_id].host_drive == new_cdrom_drive) + { + /* Switching to the same drive. Do nothing. */ + break; + } + cdrom_drives[cdrom_id].prev_host_drive = cdrom_drives[cdrom_id].host_drive; + cdrom_drives[cdrom_id].handler->exit(cdrom_id); + cdrom_close(cdrom_id); + ioctl_open(cdrom_id, new_cdrom_drive); + if (cdrom_drives[cdrom_id].bus_type) + { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom_id); + } + CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + cdrom_id, MF_UNCHECKED); + if ((cdrom_drives[cdrom_id].host_drive != 0) && (cdrom_drives[cdrom_id].host_drive != 200)) + { + CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_UNCHECKED); + } + CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + cdrom_id, MF_UNCHECKED); + cdrom_drives[cdrom_id].host_drive = new_cdrom_drive; + CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_CHECKED); + update_tip(0x10 | cdrom_id); + saveconfig(); + } + break; + } + return 0; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if (PtInRect((LPRECT) &rc, pt)) + { + HandlePopupMenu(hwnd, pt, (pt.x / sb_icon_width)); + } + break; + + default: + return CallWindowProc((WNDPROC) OriginalStatusBarProcedure, hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/src/WIN/win.h b/src/WIN/win.h new file mode 100644 index 000000000..0e09db88f --- /dev/null +++ b/src/WIN/win.h @@ -0,0 +1,51 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern HINSTANCE hinstance; +extern HWND ghwnd; +extern int mousecapture; + +#ifdef __cplusplus +extern "C" { +#endif + +#define szClassName L"86BoxMainWnd" +#define szSubClassName L"86BoxSubWnd" +#define szStatusBarClassName L"86BoxStatusBar" + +void leave_fullscreen(); + +#ifdef __cplusplus +} +#endif + + +void status_open(HWND hwnd); +extern HWND status_hwnd; +extern int status_is_open; + +void deviceconfig_open(HWND hwnd, struct device_t *device); +void joystickconfig_open(HWND hwnd, int joy_nr, int type); + +extern char openfilestring[260]; +extern WCHAR wopenfilestring[260]; + +int getfile(HWND hwnd, char *f, char *fn); +int getsfile(HWND hwnd, char *f, char *fn); + +void get_executable_name(WCHAR *s, int size); +void set_window_title(WCHAR *s); + +void startblit(); +void endblit(); + +extern int pause; + +void win_settings_open(HWND hwnd); +void win_menu_update(); + +void update_status_bar_panes(HWND hwnds); + +int fdd_type_to_icon(int type); + +extern HWND hwndStatus; diff --git a/src/WIN/win_cgapal.h b/src/WIN/win_cgapal.h new file mode 100644 index 000000000..d6ac7ffd8 --- /dev/null +++ b/src/WIN/win_cgapal.h @@ -0,0 +1,13 @@ +extern PALETTE cgapal; +extern PALETTE cgapal_mono[6]; + +extern uint32_t pal_lookup[256]; + +#ifdef __cplusplus +extern "C" { +#endif +void cgapal_rebuild(); +void destroy_bitmap(BITMAP *b); +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_crashdump.c b/src/WIN/win_crashdump.c new file mode 100644 index 000000000..3fee061b3 --- /dev/null +++ b/src/WIN/win_crashdump.c @@ -0,0 +1,185 @@ +/* Copyright holders: Riley + see COPYING for more details + + win_crashdump.c : Windows exception handler to make a crash dump just before a crash happens. +*/ +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include +#include +#include "../86box.h" +#include "win_crashdump.h" + +PVOID hExceptionHandler; +char* ExceptionHandlerBuffer; +#define ExceptionHandlerBufferSize (10240) + + +LONG CALLBACK MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) { + // Win32-specific functions will be used wherever possible, just in case the C stdlib-equivalents try to allocate memory. + // (The Win32-specific functions are generally just wrappers over NT system calls anyway.) + + if ((ExceptionInfo->ExceptionRecord->ExceptionCode >> 28) != 0xC) { + // The exception code is not a fatal exception (highest 4 bits of ntstatus = 0xC) + // Not going to crash, let's not make a crash dump + return EXCEPTION_CONTINUE_SEARCH; + } + + // So, the program is about to crash. Oh no what do? + // Let's create a crash dump file as a debugging-aid. + + // First, get the path to 86Box.exe. + char* CurrentBufferPointer; + GetModuleFileName(NULL,ExceptionHandlerBuffer,ExceptionHandlerBufferSize); + if (GetLastError() != ERROR_SUCCESS) { + // Could not get the full path of 86Box.exe. Just create the file in the current directory. + CurrentBufferPointer = ExceptionHandlerBuffer; + } else { + // Walk through the string backwards looking for the last backslash, so as to remove the "86Box.exe" filename from the string. + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + for (; CurrentBufferPointer > ExceptionHandlerBuffer; CurrentBufferPointer--) { + if (CurrentBufferPointer[0] == '\\') { + // Found the backslash, null terminate the string after it. + CurrentBufferPointer[1] = 0; + break; + } + } + + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + } + + // What would a good filename be? It should contain the current date and time so as to be (hopefully!) unique. + SYSTEMTIME SystemTime; + GetSystemTime(&SystemTime); + sprintf(CurrentBufferPointer, + "86box-%d%02d%02d-%02d-%02d-%02d-%03d.dmp", + SystemTime.wYear, + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond, + SystemTime.wMilliseconds); + + DWORD Error; + + // Now the filename is in the buffer, the file can be created. + HANDLE hDumpFile = CreateFile( + ExceptionHandlerBuffer, // The filename of the file to open. + GENERIC_WRITE, // The permissions to request. + 0, // Make sure other processes can't touch the crash dump at all while it's open. + NULL, // Leave the security descriptor undefined, it doesn't matter. + OPEN_ALWAYS, // Opens the file if it exists, creates a new file if it doesn't. + FILE_ATTRIBUTE_NORMAL, // File attributes / etc don't matter. + NULL); // A template file is not being used. + + // Check to make sure the file was actually created. + if (hDumpFile == INVALID_HANDLE_VALUE) { + // CreateFile() failed, so just do nothing more. + return EXCEPTION_CONTINUE_SEARCH; + } + + // Now the file is open, let's write the data we were passed out in a human-readable format. + + // Let's get the name of the module where the exception occured. + HMODULE hMods[1024]; + MODULEINFO modInfo; + HMODULE ipModule = 0; + DWORD cbNeeded; + // Try to get a list of all loaded modules. + if (EnumProcessModules(GetCurrentProcess(), hMods, sizeof(hMods), &cbNeeded)) { + // The list was obtained, walk through each of the modules. + for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { + // For each module, get the module information (base address, size, entry point) + GetModuleInformation(GetCurrentProcess(), hMods[i], &modInfo, sizeof(MODULEINFO)); + // If the exception address is located in the range of where this module is loaded... + if ( + (ExceptionInfo->ExceptionRecord->ExceptionAddress >= modInfo.lpBaseOfDll) && + (ExceptionInfo->ExceptionRecord->ExceptionAddress < (modInfo.lpBaseOfDll + modInfo.SizeOfImage)) + ) { + // ...this is the module we're looking for! + ipModule = hMods[i]; + break; + } + } + } + + // Start to put the crash-dump string into the buffer. + + sprintf(ExceptionHandlerBuffer, + "86Box version %s crashed on %d-%02d-%02d %02d:%02d:%02d.%03d\r\n\r\n" + "" + "Exception details:\r\n" + "Exception NTSTATUS code: 0x%08x\r\n" + "Occured at address: 0x%p", + emulator_version, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, + + ExceptionInfo->ExceptionRecord->ExceptionCode, + ExceptionInfo->ExceptionRecord->ExceptionAddress); + + + // If we found the module that the exception occured in, get the full path to the module the exception occured at and include it. + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + if (ipModule != 0) { + sprintf(CurrentBufferPointer," ["); + GetModuleFileName(ipModule,&CurrentBufferPointer[2],ExceptionHandlerBufferSize - strlen(ExceptionHandlerBuffer)); + if (GetLastError() == ERROR_SUCCESS) { + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(CurrentBufferPointer,"]"); + CurrentBufferPointer += 1; + } + } + + // Continue to create the crash-dump string. + sprintf(CurrentBufferPointer, + "\r\n" + "Number of parameters: %d\r\n" + "Exception parameters: ", + ExceptionInfo->ExceptionRecord->NumberParameters); + + // Add the exception parameters to the crash-dump string. + for (int i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++) { + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(CurrentBufferPointer,"0x%p ",ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); + } + + CurrentBufferPointer = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer) - 1]; + + PCONTEXT Registers = ExceptionInfo->ContextRecord; + + #if defined(__i386__) && !defined(__x86_64) + // This binary is being compiled for x86, include a register dump. + sprintf(CurrentBufferPointer, + "\r\n" + "Register dump:\r\n" + "eax=0x%08x ebx=0x%08x ecx=0x%08x edx=0x%08x ebp=0x%08x esp=0x%08x esi=0x%08x edi=0x%08x eip=0x%08x\r\n" + "\r\n", + Registers->Eax, Registers->Ebx, Registers->Ecx, Registers->Edx, Registers->Ebp, Registers->Esp, Registers->Esi, Registers->Edi, Registers->Eip); + #else + // Register dump is supported by no other architectures right now. MinGW headers seem to lack the x64 CONTEXT structure definition. + sprintf(CurrentBufferPointer,"\r\n"); + #endif + + // The crash-dump string has been created, write it to disk. + WriteFile(hDumpFile, + ExceptionHandlerBuffer, + strlen(ExceptionHandlerBuffer), + NULL, + NULL); + + // Finally, close the file. + CloseHandle(hDumpFile); + + // And return, therefore causing the crash, but only after the crash dump has been created. + + return EXCEPTION_CONTINUE_SEARCH; +} + +void InitCrashDump() { + // An exception handler should not allocate memory, so allocate 10kb for it to use if it gets called, an amount which should be more than enough. + ExceptionHandlerBuffer = malloc(ExceptionHandlerBufferSize); + // Register the exception handler. Zero first argument means this exception handler gets called last, therefore, crash dump is only made, when a crash is going to happen. + hExceptionHandler = AddVectoredExceptionHandler(0,MakeCrashDump); +} diff --git a/src/WIN/win_crashdump.h b/src/WIN/win_crashdump.h new file mode 100644 index 000000000..8048cd7af --- /dev/null +++ b/src/WIN/win_crashdump.h @@ -0,0 +1,7 @@ +/* Copyright holders: Riley + see COPYING for more details + + win-crashdump.c : Windows crash dump exception handler header file. +*/ + +void InitCrashDump(); \ No newline at end of file diff --git a/src/WIN/win_d3d-fs.cc b/src/WIN/win_d3d-fs.cc new file mode 100644 index 000000000..4e6a367cb --- /dev/null +++ b/src/WIN/win_d3d-fs.cc @@ -0,0 +1,587 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "../86box.h" +#include "../video/video.h" +#include "win.h" +#include "win_d3d-fs.h" +#include "win_cgapal.h" +#include "resource.h" + + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(void); + +static void d3d_fs_init_objects(void); +static void d3d_fs_close_objects(void); +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +extern "C" void video_blit_complete(void); + + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; +static HWND d3d_device_window; + +static int d3d_fs_w, d3d_fs_h; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +PALETTE cgapal = +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +PALETTE cgapal_mono[6] = +{ + { // 0 - green, 4-color-optimized contrast + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05},{0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a},{0x03,0x39,0x0d},{0x03,0x3c,0x0e}, + {0x00,0x07,0x01},{0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08},{0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17}, + }, + { // 1 - green, 16-color-optimized contrast + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05},{0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08},{0x02,0x2e,0x0b},{0x02,0x31,0x0b}, + {0x01,0x22,0x08},{0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c},{0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17}, + }, + { // 2 - amber, 4-color-optimized contrast + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00},{0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00},{0x3f,0x26,0x01},{0x3f,0x2b,0x06}, + {0x0b,0x02,0x00},{0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00},{0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d}, + }, + { // 3 - amber, 16-color-optimized contrast + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00},{0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00},{0x38,0x1c,0x00},{0x3b,0x1e,0x00}, + {0x2c,0x13,0x00},{0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00},{0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d}, + }, + { // 4 - grey, 4-color-optimized contrast + {0x00,0x00,0x00},{0x0b,0x0c,0x0a},{0x12,0x14,0x10},{0x15,0x17,0x13},{0x21,0x24,0x1e},{0x23,0x26,0x21},{0x30,0x31,0x2e},{0x34,0x35,0x33}, + {0x07,0x08,0x07},{0x0e,0x0f,0x0d},{0x19,0x1b,0x16},{0x1c,0x1f,0x1a},{0x28,0x2b,0x26},{0x2b,0x2d,0x2a},{0x37,0x38,0x37},{0x3d,0x3d,0x3c}, + }, + { // 5 - grey, 16-color-optimized contrast + {0x00,0x00,0x00},{0x0b,0x0c,0x0a},{0x0f,0x11,0x0e},{0x12,0x14,0x10},{0x1b,0x1d,0x18},{0x1c,0x1f,0x1a},{0x25,0x28,0x23},{0x28,0x2b,0x26}, + {0x1c,0x1e,0x19},{0x20,0x23,0x1d},{0x27,0x2a,0x25},{0x29,0x2c,0x27},{0x31,0x32,0x30},{0x33,0x34,0x32},{0x3a,0x3b,0x3a},{0x3d,0x3d,0x3c}, + }, +}; + +uint32_t pal_lookup[256]; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +void cgapal_rebuild(void) +{ + int c; + for (c = 0; c < 256; c++) + { + pal_lookup[c] = makecol(video_6to8[cgapal[c].r], video_6to8[cgapal[c].g], video_6to8[cgapal[c].b]); + } + if ((cga_palette > 1) && (cga_palette < 8)) + { + for (c = 0; c < 16; c++) + { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c + 48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], video_6to8[cgapal_mono[cga_palette - 1][c].g], video_6to8[cgapal_mono[cga_palette - 1][c].b]); + } + } + if (cga_palette == 8) + { + pal_lookup[0x16] = makecol(video_6to8[42], video_6to8[42], video_6to8[0]); + } +} + +int d3d_fs_init(HWND h) +{ + HRESULT hr; + WCHAR emulator_title[200]; + + d3d_fs_w = GetSystemMetrics(SM_CXSCREEN); + d3d_fs_h = GetSystemMetrics(SM_CYSCREEN); + + cgapal_rebuild(); + + d3d_hwnd = h; + + _swprintf(emulator_title, L"86Box v%s", emulator_version_w); + d3d_device_window = CreateWindowEx ( + 0, + szSubClassName, + emulator_title, + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL + ); + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + if (d3d == NULL) + { + return 0; + } + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + if (FAILED(hr)) + { + return 0; + } + + d3d_fs_init_objects(); + + video_blit_memtoscreen_func = d3d_fs_blit_memtoscreen; + video_blit_memtoscreen_8_func = d3d_fs_blit_memtoscreen_8; + + return 1; +} + +static void d3d_fs_close_objects(void) +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +static void d3d_fs_init_objects(void) +{ + D3DLOCKED_RECT dr; + RECT r; + + d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + // r.top = r.left = 0; + r.bottom = 2047; + r.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + /* for (y = 0; y < 2048; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2048 * 4); + } */ + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +/*void d3d_resize(int x, int y) +{ + HRESULT hr; + + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +}*/ + +void d3d_fs_reset(void) +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_fs_close(void) +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } + DestroyWindow(d3d_device_window); +} + +static void d3d_fs_size(RECT window_rect, double *l, double *t, double *r, double *b, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + *l = -0.5; + *t = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + break; + case FULLSCR_SCALE_43: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_SQ: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + *l = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; + break; + } +} + +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + int yy; + double l, t, r, b; + + if ((y1 == y2) || (d3dTexture == NULL)) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if (hr == D3D_OK && !(y1 == 0 && y2 == 0)) + { + RECT lock_rect; + + lock_rect.top = y1; + lock_rect.left = 0; + lock_rect.bottom = y2; + lock_rect.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy((uint32_t *) &(((uint8_t *) dr.pBits)[(yy - y1) * dr.Pitch]), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + video_blit_complete(); + d3dTexture->UnlockRect(0); + } + else + video_blit_complete(); + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + uint32_t *p; + int xx, yy; + double l, t, r, b; + + if (!h || (d3dTexture == NULL)) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if (hr == D3D_OK) + { + RECT lock_rect; + + lock_rect.top = 0; + lock_rect.left = 0; + lock_rect.bottom = 2047; + lock_rect.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + p = (uint32_t *) &(((uint8_t *) dr.pBits)[yy * dr.Pitch]); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + video_blit_complete(); + + d3dTexture->UnlockRect(0); + } + else + video_blit_complete(); + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +void d3d_fs_take_screenshot(wchar_t *fn) +{ + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/WIN/win_d3d-fs.h b/src/WIN/win_d3d-fs.h new file mode 100644 index 000000000..41ca32e21 --- /dev/null +++ b/src/WIN/win_d3d-fs.h @@ -0,0 +1,13 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + int d3d_fs_init(HWND h); + void d3d_fs_close(); + void d3d_fs_reset(); + void d3d_fs_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_d3d.cc b/src/WIN/win_d3d.cc new file mode 100644 index 000000000..258bcd4f8 --- /dev/null +++ b/src/WIN/win_d3d.cc @@ -0,0 +1,398 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "win.h" +#include "win_d3d.h" +#include "../video/video.h" +#include "win_cgapal.h" +#include "resource.h" + + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(void); +extern "C" void video_blit_complete(void); + + +void d3d_init_objects(void); +void d3d_close_objects(void); +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +void d3d_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +int d3d_init(HWND h) +{ + HRESULT hr; + + cgapal_rebuild(); + + d3d_hwnd = h; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + if (d3d == NULL) + { + return 0; + } + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = h; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + if (FAILED(hr)) + { + return 0; + } + + d3d_init_objects(); + + video_blit_memtoscreen_func = d3d_blit_memtoscreen; + video_blit_memtoscreen_8_func = d3d_blit_memtoscreen_8; + + return 1; +} + +void d3d_close_objects(void) +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +void d3d_init_objects(void) +{ + D3DLOCKED_RECT dr; + RECT r; + + d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + // r.top = r.left = 0; + r.bottom = r.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + /* for (y = 0; y < 2048; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2048 * 4); + } */ + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +void d3d_resize(int x, int y) +{ + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +} + +void d3d_reset(void) +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_hwnd; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_close(void) +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } +} + +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + int yy; + + if ((w <= 0) || (w > 2048) || (h <= 0) || (h > 2048) || (y1 == y2) || (y1 < 0) || (y1 > 2048) || (y2 < 0) || (y2 > 2048) || (d3dTexture == NULL)) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + r.top = y1; + r.left = 0; + r.bottom = y2; + r.right = 2047; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy((uint32_t *) &(((uint8_t *) dr.pBits)[(yy - y1) * dr.Pitch]), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + video_blit_complete(); + d3dTexture->UnlockRect(0); + } + else + video_blit_complete(); + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_blit_memtoscreen_8(int x, int y, int w, int h) +{ + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p; + int yy, xx; + HRESULT hr = D3D_OK; + + if ((w <= 0) || (w > 2048) || (h <= 0) || (h > 2048) || (d3dTexture == NULL)) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + r.top = 0; + r.left = 0; + r.bottom = h; + r.right = 2047; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + p = (uint32_t *) &((((uint8_t *) dr.pBits)[yy * dr.Pitch])); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + video_blit_complete(); + + d3dTexture->UnlockRect(0); + } + else + video_blit_complete(); + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_take_screenshot(wchar_t *fn) +{ + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/WIN/win_d3d.h b/src/WIN/win_d3d.h new file mode 100644 index 000000000..7210d454b --- /dev/null +++ b/src/WIN/win_d3d.h @@ -0,0 +1,13 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + int d3d_init(HWND h); + void d3d_close(); + void d3d_reset(); + void d3d_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_ddraw-fs.cc b/src/WIN/win_ddraw-fs.cc new file mode 100644 index 000000000..42fd984ed --- /dev/null +++ b/src/WIN/win_ddraw-fs.cc @@ -0,0 +1,338 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "../video/video.h" +#include "win_ddraw-fs.h" +#include "win_ddraw-screenshot.h" +#include "win_cgapal.h" + + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(void); + +extern "C" int ddraw_fs_init(HWND h); +extern "C" void ddraw_fs_close(void); + +extern "C" void video_blit_complete(void); + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW7 lpdd7 = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; +static int ddraw_w, ddraw_h; + +int ddraw_fs_init(HWND h) +{ + ddraw_w = GetSystemMetrics(SM_CXSCREEN); + ddraw_h = GetSystemMetrics(SM_CYSCREEN); + + cgapal_rebuild(); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + return 0; + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (LPVOID *)&lpdd7))) + return 0; + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_fs_close); + + if (FAILED(lpdd7->SetCooperativeLevel(h, DDSCL_SETFOCUSWINDOW | + DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT))) + return 0; + + if (FAILED(lpdd7->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) + return 0; + + // memset(&ddsd, 0, sizeof(ddsd)); + // ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 1; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_pri, NULL))) + return 0; + + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) + return 0; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + return 0; + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen_func = ddraw_fs_blit_memtoscreen; + video_blit_memtoscreen_8_func = ddraw_fs_blit_memtoscreen_8; + + return 1; +} + +void ddraw_fs_close(void) +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd7) + { + lpdd7->Release(); + lpdd7 = NULL; + } +} + +static void ddraw_fs_size(RECT window_rect, RECT *r_dest, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + r_dest->left = 0; + r_dest->top = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + break; + case FULLSCR_SCALE_43: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 1; + } + break; + case FULLSCR_SCALE_SQ: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 1; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 1; + break; + } +} + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int yy; + HRESULT hr; + DDBLTFX ddbltfx; + + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) + { + video_blit_complete(); + return; + } + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0) memcpy((unsigned char*)ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + video_blit_complete(); + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + } +} + +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int xx, yy; + HRESULT hr; + DDBLTFX ddbltfx; + + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) + { + video_blit_complete(); + return; + } + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + uint32_t *p = (uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + } + video_blit_complete(); + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); +} + +void ddraw_fs_take_screenshot(wchar_t *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/WIN/win_ddraw-fs.h b/src/WIN/win_ddraw-fs.h new file mode 100644 index 000000000..048c9c160 --- /dev/null +++ b/src/WIN/win_ddraw-fs.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + int ddraw_fs_init(HWND h); + void ddraw_fs_close(); +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_ddraw-screenshot.cc b/src/WIN/win_ddraw-screenshot.cc new file mode 100644 index 000000000..bb3cb6660 --- /dev/null +++ b/src/WIN/win_ddraw-screenshot.cc @@ -0,0 +1,178 @@ +/* Copyright holders: Tenshi + see COPYING for more details +*/ +#include +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "../video/video.h" +#include "win.h" +#include "win_ddraw-screenshot.h" +#include "win_language.h" + + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(void); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(void); + +HBITMAP hbitmap; + +int xs, ys, ys2; + +void CopySurface(IDirectDrawSurface7 *pDDSurface) +{ + HDC hdc, hmemdc; + + HBITMAP hprevbitmap; + + DDSURFACEDESC2 ddsd2; + + pDDSurface->GetDC(&hdc); + + hmemdc = CreateCompatibleDC(hdc); + + ZeroMemory(&ddsd2 ,sizeof( ddsd2 )); // better to clear before using + + ddsd2.dwSize = sizeof( ddsd2 ); //initialize with size + + pDDSurface->GetSurfaceDesc(&ddsd2); + + hbitmap = CreateCompatibleBitmap( hdc ,xs ,ys); + + hprevbitmap = (HBITMAP) SelectObject( hmemdc, hbitmap ); + + BitBlt(hmemdc,0 ,0 ,xs ,ys ,hdc ,0 ,0,SRCCOPY); + + SelectObject(hmemdc,hprevbitmap); // restore the old bitmap + + DeleteDC(hmemdc); + + pDDSurface->ReleaseDC(hdc); + + return ; +} + +void DoubleLines(uint8_t *dst, uint8_t *src) +{ + int i = 0; + for (i = 0; i < ys; i++) + { + memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4); + memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4); + } +} + +static WCHAR szMessage[2048]; + +void SaveBitmap(wchar_t *szFilename,HBITMAP hBitmap) +{ + HDC hdc=NULL; + FILE* fp=NULL; + LPVOID pBuf=NULL; + LPVOID pBuf2=NULL; + BITMAPINFO bmpInfo; + BITMAPFILEHEADER bmpFileHeader; + + do{ + + hdc=GetDC(NULL); + + ZeroMemory(&bmpInfo,sizeof(BITMAPINFO)); + + bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS); + + if(bmpInfo.bmiHeader.biSizeImage<=0) + bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL) + { + // pclog("ERROR: Unable to Allocate Bitmap Memory"); + break; + } + + if (ys2 <= 250) + { + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2); + } + + bmpInfo.bmiHeader.biCompression=BI_RGB; + + GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS); + + if((fp = _wfopen(szFilename,L"wb"))==NULL) + { + _swprintf(szMessage, win_language_get_string_from_id(2194), szFilename); + msgbox_error_wstr(ghwnd, szMessage); + break; + } + + bmpFileHeader.bfReserved1=0; + + bmpFileHeader.bfReserved2=0; + + if (pBuf2) + { + bmpInfo.bmiHeader.biSizeImage <<= 1; + bmpInfo.bmiHeader.biHeight <<= 1; + } + + bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage; + + bmpFileHeader.bfType=0x4D42; + + bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + + fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); + + fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); + + if (pBuf2) + { + DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); + fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + else + { + fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + + }while(false); + + if(hdc) ReleaseDC(NULL,hdc); + + if(pBuf2) free(pBuf2); + + if(pBuf) free(pBuf); + + if(fp) fclose(fp); +} + +void ddraw_common_take_screenshot(wchar_t *fn, IDirectDrawSurface7 *pDDSurface) +{ + xs = xsize; + ys = ys2 = ysize; + /* For EGA/(S)VGA, the size is NOT adjusted for overscan. */ + if ((overscan_y > 16) && enable_overscan) + { + xs += overscan_x; + ys += overscan_y; + } + /* For CGA, the width is adjusted for overscan, but the height is not. */ + if (overscan_y == 16) + { + if (ys2 <= 250) + ys += (overscan_y >> 1); + else + ys += overscan_y; + } + CopySurface(pDDSurface); + SaveBitmap(fn, hbitmap); +} diff --git a/src/WIN/win_ddraw-screenshot.h b/src/WIN/win_ddraw-screenshot.h new file mode 100644 index 000000000..4739174a1 --- /dev/null +++ b/src/WIN/win_ddraw-screenshot.h @@ -0,0 +1,4 @@ +/* Copyright holders: Tenshi + see COPYING for more details +*/ +void ddraw_common_take_screenshot(wchar_t *fn, IDirectDrawSurface7 *pDDSurface); diff --git a/src/WIN/win_ddraw.cc b/src/WIN/win_ddraw.cc new file mode 100644 index 000000000..af329eb29 --- /dev/null +++ b/src/WIN/win_ddraw.cc @@ -0,0 +1,318 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "../video/video.h" +#include "win_ddraw.h" +#include "win_ddraw-screenshot.h" +#include "win_cgapal.h" + + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(void); + +extern "C" int ddraw_init(HWND h); +extern "C" void ddraw_close(void); + +extern "C" void video_blit_complete(void); + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW7 lpdd7 = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE7 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; + +int ddraw_init(HWND h) +{ + cgapal_rebuild(); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + return 0; + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (LPVOID *)&lpdd7))) + return 0; + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd7->SetCooperativeLevel(h, DDSCL_NORMAL))) + return 0; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_pri, NULL))) + return 0; + + // memset(&ddsd, 0, sizeof(ddsd)); + // ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back, NULL))) + return 0; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd7->CreateSurface(&ddsd, &lpdds_back2, NULL))) + return 0; + + if (FAILED(lpdd7->CreateClipper(0, &lpdd_clipper, NULL))) + return 0; + if (FAILED(lpdd_clipper->SetHWnd(0, h))) + return 0; + if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) + return 0; + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen_func = ddraw_blit_memtoscreen; + video_blit_memtoscreen_8_func = ddraw_blit_memtoscreen_8; + + return 1; +} + +void ddraw_close(void) +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd7) + { + lpdd7->Release(); + lpdd7 = NULL; + } +} + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; +// pclog("Blit memtoscreen %i,%i %i %i %i,%i\n", x, y, y1, y2, w, h); + + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) + { + video_blit_complete(); + return; + } + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + memcpy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + video_blit_complete(); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; +#ifdef LEGACY_READ_FLASH + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = &(((uint32_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + } +#endif + } + lpdds_back2->Unlock(NULL); + +// pclog("Blit from %i,%i %i,%i to %i,%i %i,%i\n", r_src.left, r_src.top, r_src.right, r_src.bottom, r_dest.left, r_dest.top, r_dest.right, r_dest.bottom); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + + if (lpdds_back == NULL) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) + { + video_blit_complete(); + return; + } + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + p = (uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + } + p = &(((uint32_t *) ddsd.lpSurface)[4 * ddsd.lPitch]); + lpdds_back->Unlock(NULL); + video_blit_complete(); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + lpdds_back2->Unlock(NULL); + } + } + + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +void ddraw_take_screenshot(wchar_t *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/WIN/win_ddraw.h b/src/WIN/win_ddraw.h new file mode 100644 index 000000000..a4044899d --- /dev/null +++ b/src/WIN/win_ddraw.h @@ -0,0 +1,12 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + int ddraw_init(HWND h); + void ddraw_close(); +#ifdef __cplusplus +} +#endif + diff --git a/src/WIN/win_deviceconfig.c b/src/WIN/win_deviceconfig.c new file mode 100644 index 000000000..457a38f75 --- /dev/null +++ b/src/WIN/win_deviceconfig.c @@ -0,0 +1,317 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "resource.h" +#include "win.h" + +static device_t *config_device; + +static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int val_int; + int num; + char s[80]; + + switch (message) + { + case WM_INITDIALOG: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + SendMessage(h, BM_SETCHECK, val_int, 0); + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)selection->description); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + } + config++; + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + int changed = 0; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) + changed = 1; + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + } + config++; + } + + if (!changed) + { + EndDialog(hdlg, 0); + return TRUE; + } + + if (MessageBox(NULL, "This will reset 86Box!\nOkay to continue?", "86Box", MB_OKCANCEL) != IDOK) + { + EndDialog(hdlg, 0); + return TRUE; + } + + id = IDC_CONFIG_BASE; + config = config_device->config; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + config_set_int(config_device->name, config->name, SendMessage(h, BM_GETCHECK, 0, 0)); + + id++; + break; + + case CONFIG_SELECTION: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_int(config_device->name, config->name, selection->value); + + id += 2; + break; + } + config++; + } + + saveconfig(); + + resetpchard(); + + EndDialog(hdlg, 0); + return TRUE; + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void deviceconfig_open(HWND hwnd, device_t *device) +{ + device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 80; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + y += 20; + break; + + case CONFIG_SELECTION: + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + y += 20; + break; + } + + if (((unsigned long)data) & 2) + data++; + + config++; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; /* no creation data */ + + dlg->cy = y + 20; + + config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + + free(data_block); +} diff --git a/src/WIN/win_joystick.cc b/src/WIN/win_joystick.cc new file mode 100644 index 000000000..63d970eaa --- /dev/null +++ b/src/WIN/win_joystick.cc @@ -0,0 +1,281 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +extern "C" { +#include "../device.h" +#include "../gameport.h" +} +#include "plat_joystick.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void joystick_init(); +extern "C" void joystick_close(); +extern "C" void poll_joystick(); + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_joystick[2] = {NULL, NULL}; + +int joysticks_present = 0; +static GUID joystick_guids[MAX_JOYSTICKS]; + +static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, LPVOID data) +{ + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + pclog("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); + + joystick_guids[joysticks_present++] = lpddi->guidInstance; + + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK DIEnumDeviceObjectsCallback( + LPCDIDEVICEOBJECTINSTANCE lpddoi, + LPVOID pvRef) +{ + plat_joystick_t *state = (plat_joystick_t *)pvRef; + + if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || + lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis || + lpddoi->guidType == GUID_Slider) + { + strncpy(state->axis[state->nr_axes].name, lpddoi->tszName, sizeof(state->axis[state->nr_axes].name)); + pclog("Axis %i : %s %x %x\n", state->nr_axes, state->axis[state->nr_axes].name, lpddoi->dwOfs, lpddoi->dwType); + if (lpddoi->guidType == GUID_XAxis) + state->axis[state->nr_axes].id = 0; + else if (lpddoi->guidType == GUID_YAxis) + state->axis[state->nr_axes].id = 1; + else if (lpddoi->guidType == GUID_ZAxis) + state->axis[state->nr_axes].id = 2; + else if (lpddoi->guidType == GUID_RxAxis) + state->axis[state->nr_axes].id = 3; + else if (lpddoi->guidType == GUID_RyAxis) + state->axis[state->nr_axes].id = 4; + else if (lpddoi->guidType == GUID_RzAxis) + state->axis[state->nr_axes].id = 5; + state->nr_axes++; + } + else if (lpddoi->guidType == GUID_Button) + { + strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + pclog("Button %i : %s %x %x\n", state->nr_buttons, state->button[state->nr_buttons].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_buttons++; + } + else if (lpddoi->guidType == GUID_POV) + { + strncpy(state->pov[state->nr_povs].name, lpddoi->tszName, sizeof(state->pov[state->nr_povs].name)); + pclog("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_povs++; + } + + return DIENUM_CONTINUE; +} + +void joystick_init() +{ + int c; + + if (joystick_type == 7) return; + + atexit(joystick_close); + + joysticks_present = 0; + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("joystick_init : DirectInputCreate failed\n"); + + if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) + fatal("joystick_init : EnumDevices failed\n"); + + pclog("joystick_init: joysticks_present=%i\n", joysticks_present); + + for (c = 0; c < joysticks_present; c++) + { + LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; + DIPROPRANGE joy_axis_range; + DIDEVICEINSTANCE device_instance; + DIDEVCAPS devcaps; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) + fatal("joystick_init : CreateDevice failed\n"); + if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) + fatal("joystick_init : CreateDevice failed\n"); + lpdi_joystick_temp->Release(); + + memset(&device_instance, 0, sizeof(device_instance)); + device_instance.dwSize = sizeof(device_instance); + if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) + fatal("joystick_init : GetDeviceInfo failed\n"); + pclog("Joystick %i :\n", c); + pclog(" tszInstanceName = %s\n", device_instance.tszInstanceName); + pclog(" tszProductName = %s\n", device_instance.tszProductName); + strncpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 64); + + memset(&devcaps, 0, sizeof(devcaps)); + devcaps.dwSize = sizeof(devcaps); + if (FAILED(lpdi_joystick[c]->GetCapabilities(&devcaps))) + fatal("joystick_init : GetCapabilities failed\n"); + pclog(" Axes = %i\n", devcaps.dwAxes); + pclog(" Buttons = %i\n", devcaps.dwButtons); + pclog(" POVs = %i\n", devcaps.dwPOVs); + + lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); + + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(ghwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + fatal("joystick_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) + fatal("joystick_init : SetDataFormat failed\n"); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + joy_axis_range.diph.dwObj = DIJOFS_X; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Y; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Z; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RX; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RY; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RZ; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + if (FAILED(lpdi_joystick[c]->Acquire())) + fatal("joystick_init : Acquire failed\n"); + } +} + +void joystick_close() +{ + if (lpdi_joystick[1]) + { + lpdi_joystick[1]->Release(); + lpdi_joystick[1] = NULL; + } + if (lpdi_joystick[0]) + { + lpdi_joystick[0]->Release(); + lpdi_joystick[0] = NULL; + } +} + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return sin((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (mapping & POV_Y) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; +} + +void joystick_poll() +{ + int c, d; + + for (c = 0; c < joysticks_present; c++) + { + DIJOYSTATE joystate; + int b; + + if (FAILED(lpdi_joystick[c]->Poll())) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + } + if (FAILED(lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate))) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); + } + + plat_joystick_state[c].a[0] = joystate.lX; + plat_joystick_state[c].a[1] = joystate.lY; + plat_joystick_state[c].a[2] = joystate.lZ; + plat_joystick_state[c].a[3] = joystate.lRx; + plat_joystick_state[c].a[4] = joystate.lRy; + plat_joystick_state[c].a[5] = joystate.lRz; + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; +// pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +} + diff --git a/src/WIN/win_joystickconfig.c b/src/WIN/win_joystickconfig.c new file mode 100644 index 000000000..8962366d6 --- /dev/null +++ b/src/WIN/win_joystickconfig.c @@ -0,0 +1,541 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "../ibm.h" +#include "../config.h" +#include "../device.h" +#include "../gameport.h" +#include "plat_joystick.h" +#include "resource.h" +#include "win.h" + +static int joystick_nr; +static int joystick_config_type; +#define AXIS_STRINGS_MAX 3 +static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"}; + +static void rebuild_axis_button_selections(HWND hdlg) +{ + int id = IDC_CONFIG_BASE + 2; + HWND h; + int joystick; + int c, d; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + if (c < AXIS_STRINGS_MAX) + { + if (!stricmp(axis_strings[c], plat_joystick_state[joystick-1].axis[d].name)) + sel = d; + } + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].button[d].name); + SendMessage(h, CB_SETCURSEL, c, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_pov_count(joystick_config_type)*2; c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + +} + +static int get_axis(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes; + + if (axis_sel < nr_axes) + return axis_sel; + + axis_sel -= nr_axes; + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); +} + +static int get_pov(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; + + if (axis_sel < nr_povs) + { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + + return axis_sel - nr_povs; +} + +static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c; + int id; + int joystick; + int nr_axes; + int nr_povs; + int mapping; + + switch (message) + { + case WM_INITDIALOG: + { + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + id = IDC_CONFIG_BASE + 2; + joystick = joystick_state[joystick_nr].plat_joystick_nr; + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + + for (c = 0; c < joysticks_present; c++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name); + + SendMessage(h, CB_SETCURSEL, joystick, 0); + + rebuild_axis_button_selections(hdlg); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + nr_axes = plat_joystick_state[joystick-1].nr_axes; + nr_povs = plat_joystick_state[joystick-1].nr_povs; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + + h = GetDlgItem(hdlg, id); + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0); + id += 2; + } + for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][0]; + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + h = GetDlgItem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][1]; + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + } + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIG_BASE: + if (HIWORD(wParam) == CBN_SELCHANGE) + rebuild_axis_button_selections(hdlg); + break; + + case IDOK: + { + id = IDC_CONFIG_BASE + 2; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].button_mapping[c] = SendMessage(h, CB_GETCURSEL, 0, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id); + id += 2; + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id); + id += 2; + } + } + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void joystickconfig_open(HWND hwnd, int joy_nr, int type) +{ + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + int c; + + joystick_nr = joy_nr; + joystick_config_type = type; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + y += 20; + + + for (c = 0; c < joystick_get_axis_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_button_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_pov_count(type)*2; c++) + { + char s[80]; + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + if (c & 1) + sprintf(s, "%s (Y axis)", joystick_get_pov_name(type, c/2)); + else + sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2)); + data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; /* no creation data */ + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; /* no creation data */ + + dlg->cy = y + 20; + + DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); + + free(data_block); +} diff --git a/src/WIN/win_language.c b/src/WIN/win_language.c new file mode 100644 index 000000000..e87964d37 --- /dev/null +++ b/src/WIN/win_language.c @@ -0,0 +1,197 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include + +#include "../ibm.h" +#include "../device.h" +#include "../ide.h" +#include "resource.h" +#include "win.h" +#include "win_language.h" + +LCID dwLanguage; + +uint32_t dwLangID, dwSubLangID; + +#define STRINGS_NUM 154 + +WCHAR lpResourceString[STRINGS_NUM][512]; + +char openfilestring[260]; +WCHAR wopenfilestring[260]; + +void win_language_set() +{ + SetThreadLocale(dwLanguage); +} + +void win_language_load_common_strings() +{ + int i = 0; + + for (i = 0; i < STRINGS_NUM; i++) + { + LoadString(hinstance, 2048 + i, lpResourceString[i], 512); + } +} + +LPTSTR win_language_get_settings_category(int i) +{ + return lpResourceString[17 + i]; +} + +void win_language_update() +{ + win_language_set(); + win_menu_update(); + win_language_load_common_strings(); +} + +void win_language_check() +{ + LCID dwLanguageNew = MAKELCID(dwLangID, dwSubLangID); + if (dwLanguageNew != dwLanguage) + { + dwLanguage = dwLanguageNew; + win_language_update(); + } +} + +LPTSTR win_language_get_string_from_id(int i) +{ + return lpResourceString[i - 2048]; +} + +LPTSTR win_language_get_string_from_string(char *str) +{ + return lpResourceString[atoi(str) - 2048]; +} + +int msgbox_reset(HWND hwndParent) +{ + return MessageBox(hwndParent, lpResourceString[3], lpResourceString[0], MB_YESNOCANCEL | MB_ICONQUESTION); +} + +int msgbox_reset_yn(HWND hwndParent) +{ + return MessageBox(hwndParent, lpResourceString[3], lpResourceString[0], MB_YESNO | MB_ICONQUESTION); +} + +int msgbox_question(HWND hwndParent, int i) +{ + return MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[0], MB_YESNO | MB_ICONQUESTION); +} + +void msgbox_info(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[0], MB_OK | MB_ICONINFORMATION); +} + +void msgbox_info_wstr(HWND hwndParent, WCHAR *wstr) +{ + MessageBox(hwndParent, wstr, lpResourceString[0], MB_OK | MB_ICONINFORMATION); +} + +void msgbox_error(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[1], MB_OK | MB_ICONWARNING); +} + +void msgbox_error_wstr(HWND hwndParent, WCHAR *wstr) +{ + MessageBox(hwndParent, wstr, lpResourceString[1], MB_OK | MB_ICONWARNING); +} + +void msgbox_critical(HWND hwndParent, int i) +{ + MessageBox(hwndParent, win_language_get_string_from_id(i), lpResourceString[2], MB_OK | MB_ICONERROR); +} + +void msgbox_fatal(HWND hwndParent, char *string) +{ + LPTSTR lptsTemp; + lptsTemp = (LPTSTR) malloc(512); + + mbstowcs(lptsTemp, string, strlen(string) + 1); + + MessageBox(hwndParent, lptsTemp, lpResourceString[2], MB_OK | MB_ICONERROR); + + free(lptsTemp); +} + +int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +{ + OPENFILENAME ofn; /* common dialog box structure */ + BOOL r; + DWORD err; + + /* Initialize OPENFILENAME */ + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = wopenfilestring; + /* + Set lpstrFile[0] to '\0' so that GetOpenFileName does not + use the contents of szFile to initialize itself. + */ + memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); + ofn.nMaxFile = 259; + ofn.lpstrFilter = f; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST; + if (!save) + { + ofn.Flags |= OFN_FILEMUSTEXIST; + } + + /* Display the Open dialog box. */ + + if (save) + { + pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetSaveFileName(&ofn); + } + else + { + pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetOpenFileName(&ofn); + } + if (r) + { + wcstombs(openfilestring, wopenfilestring, 520); + pclog("File dialog return true\n"); + return 0; + } + pclog("File dialog return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) +{ + WCHAR ufn[512]; + mbstowcs(ufn, fn, strlen(fn) + 1); + return file_dlg_w(hwnd, f, ufn, save); +} + +int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save) +{ + return file_dlg_w(hwnd, win_language_get_string_from_id(i), fn, save); +} + +int file_dlg_st(HWND hwnd, int i, char *fn, int save) +{ + return file_dlg(hwnd, win_language_get_string_from_id(i), fn, save); +} diff --git a/src/WIN/win_language.h b/src/WIN/win_language.h new file mode 100644 index 000000000..5c4237249 --- /dev/null +++ b/src/WIN/win_language.h @@ -0,0 +1,33 @@ +#ifdef __cplusplus +extern "C" { +#endif + +LCID dwLanguage; + +int msgbox_reset(HWND hwndParent); +int msgbox_reset_yn(HWND hwndParent); +int msgbox_question(HWND hwndParent, int i); +void msgbox_info(HWND hwndParent, int i); +void msgbox_info_wstr(HWND hwndParent, WCHAR *wstr); +void msgbox_error(HWND hwndParent, int i); +void msgbox_error_wstr(HWND hwndParent, WCHAR *wstr); +void msgbox_fatal(HWND hwndParent, char *string); +void msgbox_critical(HWND hwndParent, int i); + +int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); +int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); +int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); +int file_dlg_st(HWND hwnd, int i, char *fn, int save); + +void win_language_load_common_strings(); +LPTSTR win_language_get_settings_category(int i); + +void win_language_update(); +void win_language_check(); + +LPTSTR win_language_get_string_from_id(int i); +LPTSTR win_language_get_string_from_string(char *str); + +#ifdef __cplusplus +} +#endif diff --git a/src/WIN/win_midi.c b/src/WIN/win_midi.c new file mode 100644 index 000000000..2fdf58bec --- /dev/null +++ b/src/WIN/win_midi.c @@ -0,0 +1,279 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include "../ibm.h" +#include "../config.h" +#include "plat_midi.h" + +int midi_id; +static HMIDIOUT midi_out_device = NULL; + +HANDLE m_event; + +void midi_close(); + +static uint8_t midi_rt_buf[1024]; +static uint8_t midi_cmd_buf[1024]; +static int midi_cmd_pos = 0; +static int midi_cmd_len = 0; +static uint8_t midi_status = 0; +static unsigned int midi_sysex_start = 0; +static unsigned int midi_sysex_delay = 0; + +uint8_t MIDI_evt_len[256] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x10 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x40 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x70 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x80 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x90 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xa0 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0 + + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xc0 + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xd0 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xe0 + + 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 +}; + +void midi_init() +{ + MMRESULT hr = MMSYSERR_NOERROR; + + memset(midi_rt_buf, 0, 1024); + memset(midi_cmd_buf, 0, 1024); + + midi_cmd_pos = midi_cmd_len = 0; + midi_status = 0; + + midi_sysex_start = midi_sysex_delay = 0; + + midi_id = config_get_int(NULL, "midi", 0); + + m_event = CreateEvent(NULL, TRUE, TRUE, NULL); + + hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + midi_id = 0; + hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + } + + midiOutReset(midi_out_device); +} + +void midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + midi_out_device = NULL; + CloseHandle(m_event); + } +} + +int midi_get_num_devs() +{ + return midiOutGetNumDevs(); +} +void midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + +static int midi_pos, midi_len; +static uint32_t midi_command; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; +static int midi_insysex; +static char midi_sysex_data[1024+2]; + +static void midi_send_sysex() +{ + MIDIHDR hdr; + + hdr.lpData = midi_sysex_data; + hdr.dwBufferLength = midi_pos; + hdr.dwFlags = 0; + + midiOutPrepareHeader(midi_out_device, &hdr, sizeof(MIDIHDR)); + midiOutLongMsg(midi_out_device, &hdr, sizeof(MIDIHDR)); + + midi_insysex = 0; +} + +void PlayMsg(uint8_t *msg) +{ + midiOutShortMsg(midi_out_device, *(uint32_t *) msg); +} + +MIDIHDR m_hdr; + +void PlaySysex(uint8_t *sysex, unsigned int len) +{ + MMRESULT result; + + if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) + { + pclog("Can't send MIDI message\n"); + return; + } + + midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + m_hdr.lpData = (char *) sysex; + m_hdr.dwBufferLength = len; + m_hdr.dwBytesRecorded = len; + m_hdr.dwUser = 0; + + result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + if (result != MMSYSERR_NOERROR) return; + ResetEvent(m_event); + result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); + if (result != MMSYSERR_NOERROR) + { + SetEvent(m_event); + return; + } +} + +#define SYSEX_SIZE 1024 +#define RAWBUF 1024 + +void midi_write(uint8_t val) +{ + uint32_t passed_ticks; + + if (midi_sysex_start) + { + passed_ticks = GetTickCount() - midi_sysex_start; + if (passed_ticks < midi_sysex_delay) + { + Sleep(midi_sysex_delay - passed_ticks); + } + } + + /* Test for a realtime MIDI message */ + if (val >= 0xf8) + { + midi_rt_buf[0] = val; + PlayMsg(midi_rt_buf); + return; + } + + /* Test for a active sysex transfer */ + + if (midi_status == 0xf0) + { + if (!(val & 0x80)) + { + if (midi_pos < (SYSEX_SIZE-1)) midi_sysex_data[midi_pos++] = val; + return; + } + else + { + midi_sysex_data[midi_pos++] = 0xf7; + + if ((midi_sysex_start) && (midi_pos >= 4) && (midi_pos <= 9) && (midi_sysex_data[1] == 0x411) && (midi_sysex_data[3] == 0x16)) + { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } + else + { + PlaySysex(midi_sysex_data, midi_pos); + if (midi_sysex_start) + { + if (midi_sysex_data[5] == 0x7f) + { + midi_sysex_delay = 290; /* All parameters reset */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x04)) + { + midi_sysex_delay = 145; /* Viking Child */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x01)) + { + midi_sysex_delay = 30; /* Dark Sun 1 */ + } + else + midi_sysex_delay = (unsigned int) (((float) (midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + + midi_sysex_start = GetTickCount(); + } + } + } + } + + + if (val & 0x80) + { + midi_status = val; + midi_cmd_pos = 0; + midi_cmd_len = MIDI_evt_len[val]; + if (midi_status == 0xf0) + { + midi_sysex_data[0] = 0xf0; + midi_pos = 1; + } + } + + if (midi_cmd_len) + { + midi_cmd_buf[midi_cmd_pos++] = val; + if (midi_cmd_pos >= midi_cmd_len) + { + PlayMsg(midi_cmd_buf); + midi_cmd_pos = 1; + } + } +} + +void midi_reset() +{ + uint8_t buf[64], used; + + /* Flush buffers */ + midiOutReset(midi_out_device); + + /* GM1 reset */ + buf[0] = 0xf0; + buf[1] = 0x7e; + buf[2] = 0x7f; + buf[3] = 0x09; + buf[4] = 0x01; + buf[5] = 0xf7; + PlaySysex((uint8_t *) buf, 6); + + /* GS1 reset */ + buf[0] = 0xf0; + buf[1] = 0x41; + buf[2] = 0x10; + buf[3] = 0x42; + buf[4] = 0x12; + buf[5] = 0x40; + buf[6] = 0x00; + buf[7] = 0x7f; + buf[8] = 0x00; + buf[9] = 0x41; + buf[10] = 0xf7; + PlaySysex((uint8_t *) buf, 11); +} diff --git a/src/WIN/win_mouse.cc b/src/WIN/win_mouse.cc new file mode 100644 index 000000000..f64b714a0 --- /dev/null +++ b/src/WIN/win_mouse.cc @@ -0,0 +1,75 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include "plat_mouse.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void mouse_init(); +extern "C" void mouse_close(); +extern "C" void mouse_poll_host(); +extern "C" void mouse_get_mickeys(int *x, int *y, int *z); + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; +static DIMOUSESTATE mousestate; +static int mouse_x = 0, mouse_y = 0, mouse_z = 0; +int mouse_buttons = 0; + +void mouse_init() +{ + atexit(mouse_close); + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("mouse_init : DirectInputCreate failed\n"); + if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) + fatal("mouse_init : CreateDevice failed\n"); + if (FAILED(lpdi_mouse->SetCooperativeLevel(ghwnd, DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) + fatal("mouse_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) + fatal("mouse_init : SetDataFormat failed\n"); +} + +void mouse_close() +{ + if (lpdi_mouse) + { + lpdi_mouse->Release(); + lpdi_mouse = NULL; + } +} + +void mouse_poll_host() +{ + if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) + { + lpdi_mouse->Acquire(); + lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); + } + mouse_buttons = 0; + if (mousestate.rgbButtons[0] & 0x80) + mouse_buttons |= 1; + if (mousestate.rgbButtons[1] & 0x80) + mouse_buttons |= 2; + if (mousestate.rgbButtons[2] & 0x80) + mouse_buttons |= 4; + mouse_x += mousestate.lX; + mouse_y += mousestate.lY; + mouse_z += mousestate.lZ/120; + if (!mousecapture && !video_fullscreen) + mouse_x = mouse_y = mouse_buttons = 0; +} + +void mouse_get_mickeys(int *x, int *y, int *z) +{ + *x = mouse_x; + *y = mouse_y; + *z = mouse_z; + mouse_x = mouse_y = mouse_z = 0; +} diff --git a/src/WIN/win_opendir.c b/src/WIN/win_opendir.c new file mode 100644 index 000000000..00347a365 --- /dev/null +++ b/src/WIN/win_opendir.c @@ -0,0 +1,213 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation POSIX OpenDir(3) and friends for Win32 API. + * + * Based on old original code @(#)dir_win32.c 1.2.0 2007/04/19 + * + * Version: @(#)win_opendir.c 1.0.1 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 1998-2007 MicroWalt Corporation + * Copyright 2017 Fred N. van Kempen + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "plat_dir.h" + + +#ifdef UNICODE +# define SUFFIX L"\\*" +# define FINDATA struct _wfinddata_t +# define FINDFIRST _wfindfirst +# define FINDNEXT _wfindnext +#else +# define SUFFIX "\\*" +# define FINDATA struct _finddata_t +# define FINDFIRST _findfirst +# define FINDNEXT _findnext +#endif + + +/* Open a directory. */ +DIR * +#ifdef UNICODE +opendirw(const wchar_t *name) +#else +opendir(const char *name) +#endif +{ + DIR *p; + + /* Create a new control structure. */ + p = (DIR *) malloc(sizeof(DIR)); + if (p == NULL) + return(NULL); + memset(p, 0x00, sizeof(DIR)); + p->flags = (DIR_F_LOWER | DIR_F_SANE); + p->offset = 0; + p->sts = 0; + + /* Create a work area. */ + p->dta = (char *)malloc(sizeof(FINDATA)); + if (p->dta == NULL) { + free(p); + return(NULL); + } + memset(p->dta, 0x00, sizeof(struct _finddata_t)); + + /* Add search filespec. */ +#ifdef UNICODE + wcscpy(p->dir, name); + wcscat(p->dir, SUFFIX); +#else + strcpy(p->dir, name); + strcat(p->dir, SUFFIX); +#endif + + /* Special case: flag if we are in the root directory. */ +#ifdef UNICODE + if (wcslen(p->dir) == 3) +#else + if (strlen(p->dir) == 3) +#endif + p->flags |= DIR_F_ISROOT; + + /* Start the searching by doing a FindFirst. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + free(p->dta); + free(p); + return(NULL); + } + + /* All OK. */ + return(p); +} + + +/* Close an open directory. */ +int +closedir(DIR *p) +{ + if (p == NULL) + return(0); + + _findclose(p->handle); + + if (p->dta != NULL) + free(p->dta); + free(p); + + return(0); +} + + +/* + * Read the next entry from a directory. + * Note that the DOS (FAT), Windows (FAT, FAT32) and Windows NTFS + * file systems do not have a root directory containing the UNIX- + * standard "." and ".." entries. Many applications do assume + * this anyway, so we simply fake these entries. + */ +struct direct * +readdir(DIR *p) +{ + FINDATA *ffp; + + if (p == NULL || p->sts == 1) + return(NULL); + + /* Format structure with current data. */ + ffp = (FINDATA *)p->dta; + p->dent.d_ino = 1L; + p->dent.d_off = p->offset++; + switch(p->offset) { + case 1: /* . */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L".", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ".", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 1; + break; + + case 2: /* .. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L"..", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, "..", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 2; + break; + + default: /* regular entry. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#endif + p->dent.d_reclen = (char) wcslen(p->dent.d_name); + } + + /* Read next entry. */ + p->sts = 0; + + /* Fake the "." and ".." entries here.. */ + if ((p->flags & DIR_F_ISROOT) && (p->offset <= 2)) + return(&(p->dent)); + + /* Get the next entry if we did not fake the above. */ + if (FINDNEXT(p->handle, ffp) < 0) + p->sts = 1; + + return(&(p->dent)); +} + + +/* Report current position within the directory. */ +long +telldir(DIR *p) +{ + return(p->offset); +} + + +void +seekdir(DIR *p, long newpos) +{ + short pos; + + /* First off, rewind to start of directory. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + p->sts = 1; + return; + } + p->offset = 0; + p->sts = 0; + + /* If we are rewinding, that's all... */ + if (newpos == 0L) return; + + /* Nope.. read entries until we hit the right spot. */ + pos = (short) newpos; + while (p->offset != pos) { + p->offset++; + if (FINDNEXT(p->handle, (FINDATA *)p->dta) < 0) { + p->sts = 1; + return; + } + } +} diff --git a/src/WIN/win_serial.c b/src/WIN/win_serial.c new file mode 100644 index 000000000..cfe8f0b43 --- /dev/null +++ b/src/WIN/win_serial.c @@ -0,0 +1,606 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of host serial port services for Win32. + * + * This code is based on a universal serial port driver for + * Windows and UNIX systems, with support for FTDI and Prolific + * USB ports. Support for these has been removed. + * + * Version: @(#)win_serial.c 1.0.2 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#define BHTTY_C +#include "plat_serial.h" + + +extern void pclog(char *__fmt, ...); + + +/* Set the state of a port. */ +int +bhtty_sstate(BHTTY *pp, void *arg) +{ + int i = 0; + + /* Make sure we can do this. */ + if (pp == NULL || arg == NULL) { + pclog("invalid argument\n"); + return(-1); + } + + if (SetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: set state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Fetch the state of a port. */ +int +bhtty_gstate(BHTTY *pp, void *arg) +{ + int i = 0; + + /* Make sure we can do this. */ + if (pp == NULL || arg == NULL) { + pclog("BHTTY: invalid argument\n"); + return(-1); + } + + if (GetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: get state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Enable or disable RTS/CTS mode (hardware handshaking.) */ +int +bhtty_crtscts(BHTTY *pp, char yesno) +{ + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid handle\n"); + return(-1); + } + + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + switch(yesno) { + case 0: /* disable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + case 1: /* enable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, yesno); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Set the port parameters. */ +int +bhtty_params(BHTTY *pp, char dbit, char par, char sbit) +{ + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid handle\n"); + return(-1); + } + + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* Set the desired word length. */ + switch((int)dbit) { + case -1: /* no change */ + break; + + case 5: /* FTDI doesnt like these */ + case 6: + case 9: + break; + + case 7: + case 8: + pp->dcb.ByteSize = dbit; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, dbit); + return(-1); + } + + /* Set the type of parity encoding. */ + switch((int)par) { + case -1: /* no change */ + case ' ': + break; + + case 0: + case 'N': + pp->dcb.fParity = FALSE; + pp->dcb.Parity = NOPARITY; + break; + + case 1: + case 'O': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = ODDPARITY; + break; + + case 2: + case 'E': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = EVENPARITY; + break; + + case 3: + case 'M': + case 4: + case 'S': + break; + + default: + pclog("%s: invalid parameter '%c'!\n", pp->name, par); + return(-1); + } + + /* Set the number of stop bits. */ + switch((int)sbit) { + case -1: /* no change */ + break; + + case 1: + pp->dcb.StopBits = ONESTOPBIT; + break; + + case 2: + pp->dcb.StopBits = TWOSTOPBITS; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, sbit); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Put a port in transparent ("raw") state. */ +void +bhtty_raw(BHTTY *pp, void *arg) +{ + DCB *dcb = (DCB *)arg; + + /* Make sure we can do this. */ + if (pp == NULL || arg == NULL) { + pclog("invalid parameter\n"); + return; + } + + /* Enable BINARY transparent mode. */ + dcb->fBinary = 1; + dcb->fErrorChar = 0; /* disable Error Replacement */ + dcb->fNull = 0; /* disable NUL stripping */ + + /* Disable the DTR and RTS lines. */ + dcb->fDtrControl = DTR_CONTROL_DISABLE; /* DTR line */ + dcb->fRtsControl = RTS_CONTROL_DISABLE; /* RTS line */ + + /* Disable DSR/DCD handshaking. */ + dcb->fOutxDsrFlow = 0; /* DSR handshaking */ + dcb->fDsrSensitivity = 0; /* DSR Sensitivity */ + + /* Disable RTS/CTS handshaking. */ + dcb->fOutxCtsFlow = 0; /* CTS handshaking */ + + /* Disable XON/XOFF handshaking. */ + dcb->fTXContinueOnXoff = 0; /* continue TX after Xoff */ + dcb->fOutX = 0; /* enable output X-ON/X-OFF */ + dcb->fInX = 0; /* enable input X-ON/X-OFF */ + dcb->XonChar = 0x11; /* ASCII XON */ + dcb->XoffChar = 0x13; /* ASCII XOFF */ + dcb->XonLim = 100; + dcb->XoffLim = 100; + + dcb->fParity = FALSE; + dcb->Parity = NOPARITY; + dcb->StopBits = ONESTOPBIT; + dcb->BaudRate = CBR_1200; +} + + +/* Set the port speed. */ +int +bhtty_speed(BHTTY *pp, long speed) +{ + int i; + + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid handle\n"); + return(-1); + } + + /* Get the current mode and speed. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* + * Set speed. + * + * This is not entirely correct, we should use a table + * with DCB_xxx speed values here, but we removed that + * and just hardcode the speed value into DCB. --FvK + */ + pp->dcb.BaudRate = speed; + + /* Set new speed. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Clean up and flush. */ +int +bhtty_flush(BHTTY *pp) +{ + DWORD dwErrs; + COMSTAT cs; + int i = 0; + + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid handle\n"); + return(-1); + } + + /* First, clear any errors. */ + (void)ClearCommError(pp->handle, &dwErrs, &cs); + + /* Now flush all buffers. */ + if (PurgeComm(pp->handle, + (PURGE_RXABORT | PURGE_TXABORT | \ + PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) { + pclog("%s: flush: %d\n", pp->name, GetLastError()); + return(-1); + } + + /* Re-clear any errors. */ + if (ClearCommError(pp->handle, &dwErrs, &cs) == FALSE) { + pclog("%s: clear errors: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Close an open serial port. */ +void +bhtty_close(BHTTY *pp) +{ + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("BHTTY: invalid handle\n"); + return; + } + + if (pp->handle != INVALID_HANDLE_VALUE) { + /* Restore the previous port state, if any. */ + (void)bhtty_sstate(pp, &pp->odcb); + + /* Close the port. */ + CloseHandle(pp->handle); + pp->handle = INVALID_HANDLE_VALUE; + } + + /* Release the control block. */ + free(pp); +} + + +/* Open a host serial port for I/O. */ +BHTTY * +bhtty_open(char *port, int tmo) +{ + char buff[64]; + COMMTIMEOUTS to; +#if 0 + COMMCONFIG conf; + DWORD d; +#endif + BHTTY *pp; + int i = 0; + + /* Make sure we can do this. */ + if (port == NULL) { + pclog("invalid argument!\n"); + return(NULL); + } + + /* First things first... create a control block. */ + if ((pp = (BHTTY *)malloc(sizeof(BHTTY))) == NULL) { + pclog("%s: out of memory!\n", port); + return(NULL); + } + memset(pp, 0x00, sizeof(BHTTY)); + strncpy(pp->name, port, sizeof(pp->name)-1); + + /* Try a regular Win32 serial port. */ + sprintf(buff, "\\\\.\\%s", pp->name); + pp->handle = CreateFile(buff, + (GENERIC_READ|GENERIC_WRITE), + 0, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + 0); + if (pp->handle == INVALID_HANDLE_VALUE) { + pclog("%s: open port: %d\n", pp->name, GetLastError()); + free(pp); + return(NULL); + } + +#if 0 + /* Set up buffer size of the port. */ + if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set buffers: %d\n", pp->name, GetLastError()); +// CloseHandle(pp->handle); +// free(pp); +// return(NULL); + } + + /* Grab default config for the driver and set it. */ + d = sizeof(COMMCONFIG); + memset(&conf, 0x00, d); + conf.dwSize = d; + if (GetDefaultCommConfig(pp->name, &conf, &d) == TRUE) { + /* Change config here... */ + + /* Set new configuration. */ + if (SetCommConfig(pp->handle, &conf, d) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set configuration: %d\n", pp->name, GetLastError()); +// CloseHandle(pp->handle); +// free(pp); +// return(NULL); + } + } +#endif + + /* + * We now have an open port. To allow for clean exit + * of the application, we first retrieve the port's + * current settings, and save these for later. + */ + if (bhtty_gstate(pp, &pp->odcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + memcpy(&pp->dcb, &pp->odcb, sizeof(DCB)); + + /* Force the port to BINARY mode. */ + bhtty_raw(pp, &pp->dcb); + + /* Set new state of this port. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + /* Just to make sure.. disable RTS/CTS mode. */ + (void)bhtty_crtscts(pp, 0); + + /* Set new timeout values. */ + if (GetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while getting current TO\n", + pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + if (tmo < 0) { + /* No timeout, immediate return. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = 0; + to.ReadTotalTimeoutConstant = 0; + } else if (tmo == 0) { + /* No timeout, wait for data. */ + memset(&to, 0x00, sizeof(to)); + } else { + /* Timeout specified. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = MAXDWORD; + to.ReadTotalTimeoutConstant = tmo; + } + if (SetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while setting TO\n", + pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + + /* Clear all errors and flush all buffers. */ + if (bhtty_flush(pp) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + return(pp); +} + + +/* A pending WRITE has finished, handle it. */ +static VOID CALLBACK +bhtty_write_comp(DWORD err, DWORD num, OVERLAPPED *priv) +{ + BHTTY *pp = (BHTTY *)priv->hEvent; + +//pclog("%s: write complete, status %d, num %d\n", pp->name, err, num); +#if 0 + if ( + if (GetOverlappedResult(p->handle, + &p->rov, &mst, TRUE) == FALSE) { + r = GetLastError(); + if (r != ERROR_OPERATION_ABORTED) + /* OK, we're being shut down. */ + sprintf(serial_errmsg, + "%s: I/O read error!", p->name); + return(-1); + } +#endif +} + + +/* Try to write data to an open port. */ +int +bhtty_write(BHTTY *pp, unsigned char val) +{ + DWORD n; + + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid parameter\n"); + return(-1); + } +//pclog("BHwrite(%08lx, %02x, '%c')\n", pp->handle, val, val); + + /* Save the control pointer for later use. */ + pp->wov.hEvent = (HANDLE)pp; + + if (WriteFileEx(pp->handle, + &val, 1, + &pp->wov, + bhtty_write_comp) == FALSE) { + n = GetLastError(); + pclog("%s: I/O error %d in write!\n", pp->name, n); + return(-1); + } + + /* Its pending, so handled in the completion routine. */ + SleepEx(1, TRUE); + + return(0); +} + + +/* + * A pending READ has finished, handle it. + */ +static VOID CALLBACK +bhtty_read_comp(DWORD err, DWORD num, OVERLAPPED *priv) +{ + BHTTY *pp = (BHTTY *)priv->hEvent; + DWORD r; +//pclog("%s: read complete, status %d, num %d\n", pp->name, err, num); + + if (GetOverlappedResult(pp->handle, &pp->rov, &r, TRUE) == FALSE) { + r = GetLastError(); + if (r != ERROR_OPERATION_ABORTED) + /* OK, we're being shut down. */ + pclog("%s: I/O read error!", pp->name); + return; + } +//pclog("%s: read done, num=%d (%d)\n", pp->name, num, r); + + /* Do a callback to let them know. */ + if (pp->rd_done != NULL) + pp->rd_done(pp->rd_arg, num); +} + + +/* + * Try to read data from an open port. + * + * For now, we will use one byte per call. Eventually, + * we should go back to loading a buffer full of data, + * just to speed things up a bit. --FvK + * + * Also, not that we do not wait here. We just POST a + * read operation, and the completion routine will do + * the clean-up and notify the caller. + */ +int +bhtty_read(BHTTY *pp, unsigned char *bufp, int max) +{ + DWORD r; + + /* Just one byte. */ + max = 1; + + /* Make sure we can do this. */ + if (pp == NULL) { + pclog("invalid parameter\n"); + return(-1); + } + + /* Save the control pointer for later use. */ + pp->rov.hEvent = (HANDLE)pp; +//pclog("%s: read(%08lx, %d)\n", pp->name, pp->handle, max); + + /* Post a READ on the device. */ + if (ReadFileEx(pp->handle, + bufp, (DWORD)max, + &pp->rov, + bhtty_read_comp) == FALSE) { + r = GetLastError(); + if (r != ERROR_IO_PENDING) { + /* OK, we're being shut down. */ + if (r != ERROR_INVALID_HANDLE) + pclog("%s: I/O read error!\n", pp->name); + return(-1); + } + } + + /* Make ourself alertable. */ + SleepEx(1, TRUE); + + /* OK, it's pending, so we are good for now. */ + return(0); +} diff --git a/src/WIN/win_settings.c b/src/WIN/win_settings.c new file mode 100644 index 000000000..6916bca28 --- /dev/null +++ b/src/WIN/win_settings.c @@ -0,0 +1,3694 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include +#include "../ibm.h" +#include "../mem.h" +#include "../cpu/cpu.h" +#include "../nvr.h" +#include "../model.h" +#include "../device.h" +#include "../cdrom.h" +#include "../disc.h" +#include "../fdd.h" +#include "../hdd.h" +#include "../ide.h" +#include "../scsi.h" +#include "../scsi_buslogic.h" +#include "../network.h" +#include "../sound/sound.h" +#include "../sound/snd_dbopl.h" +#include "../video/video.h" +#include "../video/vid_voodoo.h" +#include "../gameport.h" +#include "../mouse.h" +#include "plat_midi.h" +#include "win.h" +#include "win_language.h" +#include "resource.h" + + +#define WM_SAVESETTINGS 0x8888 /* 86Box-specific message, used to tell the child dialog to save the currently specified settings. */ + + +/* Machine category */ +int temp_model, temp_cpu_m, temp_cpu, temp_wait_states, temp_mem_size, temp_dynarec, temp_fpu, temp_sync; + +/* Video category */ +int temp_gfxcard, temp_video_speed, temp_voodoo; + +/* Input devices category */ +int temp_mouse, temp_joystick; + +/* Sound category */ +int temp_sound_card, temp_midi_id, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl3_type; + +/* Network category */ +int temp_net_type, temp_net_card; +char temp_pcap_dev[520]; + +/* Peripherals category */ +int temp_scsi_card, hdc_ignore, temp_ide_ter, temp_ide_ter_irq, temp_ide_qua, temp_ide_qua_irq; +int temp_serial[2], temp_lpt, temp_bugger; + +char temp_hdc_name[16]; + +/* Hard disks category */ +hard_disk_t temp_hdc[HDC_NUM]; +wchar_t temp_hdd_fn[HDC_NUM][512]; + +/* Removable devices category */ +int temp_fdd_types[FDD_NUM]; +cdrom_drive_t temp_cdrom_drives[CDROM_NUM]; + +static HWND hwndParentDialog, hwndChildDialog; + +int hdd_controller_current; + +int displayed_category = 0; + +extern int is486; +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; +static int settings_mouse_to_list[20], settings_list_to_mouse[20]; +static int settings_scsi_to_list[20], settings_list_to_scsi[20]; +static int settings_network_to_list[20], settings_list_to_network[20]; +static char *hdd_names[16]; + + +/* This does the initial read of global variables into the temporary ones. */ +static void win_settings_init(void) +{ + int i = 0; + + /* Machine category */ + temp_model = model; + temp_cpu_m = cpu_manufacturer; + temp_cpu = cpu; + temp_mem_size = mem_size; + temp_dynarec = cpu_use_dynarec; + temp_fpu = enable_external_fpu; + temp_sync = enable_sync; + + /* Video category */ + temp_gfxcard = gfxcard; + temp_video_speed = video_speed; + temp_voodoo = voodoo_enabled; + + /* Input devices category */ + temp_mouse = mouse_type; + temp_joystick = joystick_type; + + /* Sound category */ + temp_sound_card = sound_card_current; + temp_midi_id = midi_id; + temp_SSI2001 = SSI2001; + temp_GAMEBLASTER = GAMEBLASTER; + temp_GUS = GUS; + temp_opl3_type = opl3_type; + + /* Network category */ + temp_net_type = network_type; + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_pcap); + temp_net_card = network_card; + + /* Peripherals category */ + temp_scsi_card = scsi_card_current; + strncpy(temp_hdc_name, hdd_controller_name, sizeof(temp_hdc_name) - 1); + temp_ide_ter = ide_enable[2]; + temp_ide_ter_irq = ide_irq[2]; + temp_ide_qua = ide_enable[3]; + temp_ide_qua_irq = ide_irq[3]; + temp_serial[0] = serial_enabled[0]; + temp_serial[1] = serial_enabled[1]; + temp_lpt = lpt_enabled; + temp_bugger = bugger_enabled; + + /* Hard disks category */ + memcpy(temp_hdc, hdc, HDC_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDC_NUM; i++) + { + memcpy(temp_hdd_fn[i], hdd_fn[i], 1024); + } + + /* Removable devices category */ + for (i = 0; i < FDD_NUM; i++) + { + temp_fdd_types[i] = fdd_get_type(i); + } + memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); +} + + +/* This returns 1 if any variable has changed, 0 if not. */ +static int win_settings_changed(void) +{ + int i = 0; + int j = 0; + + /* Machine category */ + i = i || (model != temp_model); + i = i || (cpu_manufacturer != temp_cpu_m); + i = i || (cpu != temp_cpu); + i = i || (mem_size != temp_mem_size); + i = i || (temp_dynarec != cpu_use_dynarec); + i = i || (temp_fpu != enable_external_fpu); + i = i || (temp_sync != enable_sync); + + /* Video category */ + i = i || (gfxcard != temp_gfxcard); + i = i || (video_speed != temp_video_speed); + i = i || (voodoo_enabled != temp_voodoo); + + /* Input devices category */ + i = i || (mouse_type != temp_mouse); + i = i || (joystick_type != temp_joystick); + + /* Sound category */ + i = i || (sound_card_current != temp_sound_card); + i = i || (midi_id != temp_midi_id); + i = i || (SSI2001 != temp_SSI2001); + i = i || (GAMEBLASTER != temp_GAMEBLASTER); + i = i || (GUS != temp_GUS); + i = i || (opl3_type != temp_opl3_type); + + /* Network category */ + i = i || (network_type != temp_net_type); + i = i || strcmp(temp_pcap_dev, network_pcap); + i = i || (network_card != temp_net_card); + + /* Peripherals category */ + i = i || (scsi_card_current != temp_scsi_card); + i = i || strncmp(temp_hdc_name, hdd_controller_name, sizeof(temp_hdc_name) - 1); + i = i || (temp_ide_ter != ide_enable[2]); + i = i || (temp_ide_ter_irq != ide_irq[2]); + i = i || (temp_ide_qua != ide_enable[3]); + i = i || (temp_ide_qua_irq != ide_irq[3]); + i = i || (temp_serial[0] != serial_enabled[0]); + i = i || (temp_serial[1] != serial_enabled[1]); + i = i || (temp_lpt != lpt_enabled); + i = i || (temp_bugger != bugger_enabled); + + /* Hard disks category */ + i = i || memcmp(hdc, temp_hdc, HDC_NUM * sizeof(hard_disk_t)); + for (j = 0; j < HDC_NUM; j++) + { + i = i || memcmp(hdd_fn[j], temp_hdd_fn[j], 1024); + } + + /* Removable devices category */ + for (j = 0; j < FDD_NUM; j++) + { + i = i || (temp_fdd_types[j] != fdd_get_type(j)); + } + i = i || memcmp(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + + return i; +} + + +static int settings_msgbox_reset(void) +{ + int i = 0; + int changed = 0; + + changed = win_settings_changed(); + + if (changed) + { + i = msgbox_reset(hwndParentDialog); + + if (i == IDNO) + { + return 1; + } + else if (i == IDCANCEL) + { + return 0; + } + else + { + return 2; + } + } + else +{ + return 1; + } +} + + +/* This saves the settings back to the global variables. */ +static void win_settings_save(void) +{ + int i = 0; + + /* Machine category */ + model = temp_model; + romset = model_getromset(); + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + mem_size = temp_mem_size; + cpu_use_dynarec = temp_dynarec; + enable_external_fpu = temp_fpu; + enable_sync = temp_sync; + + /* Video category */ + gfxcard = temp_gfxcard; + video_speed = temp_video_speed; + voodoo_enabled = temp_voodoo; + + /* Input devices category */ + mouse_type = temp_mouse; + joystick_type = temp_joystick; + + /* Sound category */ + sound_card_current = temp_sound_card; + midi_id = temp_midi_id; + SSI2001 = temp_SSI2001; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + opl3_type = temp_opl3_type; + + /* Network category */ + network_type = temp_net_type; + memset(network_pcap, '\0', sizeof(network_pcap)); + strcpy(network_pcap, temp_pcap_dev); + network_card = temp_net_card; + + /* Peripherals category */ + scsi_card_current = temp_scsi_card; + strncpy(hdd_controller_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); + ide_enable[2] = temp_ide_ter; + ide_irq[2] = temp_ide_ter_irq; + ide_enable[3] = temp_ide_qua; + ide_irq[3] = temp_ide_qua_irq; + serial_enabled[0] = temp_serial[0]; + serial_enabled[1] = temp_serial[1]; + lpt_enabled = temp_lpt; + bugger_enabled = temp_bugger; + + /* Hard disks category */ + memcpy(hdc, temp_hdc, HDC_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDC_NUM; i++) + { + memcpy(hdd_fn[i], temp_hdd_fn[i], 1024); + } + + /* Removable devices category */ + for (i = 0; i < FDD_NUM; i++) + { + fdd_set_type(i, temp_fdd_types[i]); + } + memcpy(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + + mem_resize(); + loadbios(); + + resetpchard(); + + cpu_set(); + + cpu_update_waitstates(); + + saveconfig(); + + speedchanged(); + + if (joystick_type != 7) gameport_update_joystick_type(); + + update_status_bar_panes(hwndStatus); +} + + +static void win_settings_machine_recalc_cpu(HWND hdlg) +{ + HWND h; + int temp_romset = 0; + int cpu_flags; + int cpu_type; + + temp_romset = model_getromset_ex(temp_model); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + cpu_type = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + cpu_flags = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) + { + fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); + } + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + { + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC)) + { + temp_dynarec = 0; + } + if (cpu_flags & CPU_REQUIRES_DYNAREC) + { + temp_dynarec = 1; + } + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } + + h = GetDlgItem(hdlg, IDC_CHECK_FPU); + cpu_type = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + { + EnableWindow(h, TRUE); + } + else if (cpu_type < CPU_286) + { + temp_fpu = 0; + EnableWindow(h, FALSE); + } + else + { + temp_fpu = 1; + EnableWindow(h, FALSE); + } + SendMessage(h, BM_SETCHECK, temp_fpu, 0); +} + + +static void win_settings_machine_recalc_cpu_m(HWND hdlg) +{ + HWND h; + int c = 0; + int temp_romset = 0; + LPTSTR lptsTemp; + char *stransi; + + temp_romset = model_getromset_ex(temp_model); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + stransi = models[romstomodel[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + win_settings_machine_recalc_cpu(hdlg); + + free(lptsTemp); +} + + +static void win_settings_machine_recalc_model(HWND hdlg) +{ + HWND h; + int c = 0; + int temp_romset = 0; + LPTSTR lptsTemp; + char *stransi; + UDACCEL accel; + + temp_romset = model_getromset_ex(temp_model); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); + if (model_getdevice(temp_model)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[romstomodel[temp_romset]].cpu[c].cpus != NULL && c < 4) + { + stransi = models[romstomodel[temp_romset]].cpu[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) + { + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } + + win_settings_machine_recalc_cpu_m(hdlg); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (models[romstomodel[temp_romset]].min_ram << 16) | models[romstomodel[temp_romset]].max_ram); + accel.nSec = 0; + accel.nInc = models[romstomodel[temp_romset]].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + if (!(models[romstomodel[temp_romset]].flags & MODEL_AT)) + { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) win_language_get_string_from_id(2094)); + } + else + { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) win_language_get_string_from_id(2087)); + } + + free(lptsTemp); +} + + +static BOOL CALLBACK win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + char *stransi; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + for (c = 0; c < ROM_MAX; c++) + { + romstolist[c] = 0; + } + c = d = 0; + while (models[c].id != -1) + { + if (romspresent[models[c].id]) + { + stransi = models[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, modeltolist[temp_model], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2131)); + + for (c = 0; c < 8; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2132), c); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + SendMessage(h, CB_SETCURSEL, cpu_waitstates, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + SendMessage(h, BM_SETCHECK, temp_sync, 0); + + win_settings_machine_recalc_model(hdlg); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_MACHINE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + win_settings_machine_recalc_model(hdlg); + } + break; + case IDC_COMBO_CPU_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + temp_cpu = 0; + win_settings_machine_recalc_cpu_m(hdlg); + } + break; + case IDC_COMBO_CPU: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + win_settings_machine_recalc_cpu(hdlg); + } + break; + case IDC_CONFIGURE_MACHINE: + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)model_getdevice(temp_model)); + break; + } + + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + temp_sync = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FPU); + temp_fpu = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + temp_wait_states = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + sscanf(stransi, "%i", &temp_mem_size); + temp_mem_size &= ~(models[temp_model].ram_granularity - 1); + if (temp_mem_size < models[temp_model].min_ram) + { + temp_mem_size = models[temp_model].min_ram; + } + else if (temp_mem_size > models[temp_model].max_ram) + { + temp_mem_size = models[temp_model].max_ram; + } + if (models[temp_model].flags & MODEL_AT) + { + temp_mem_size *= 1024; + } + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + + return FALSE; +} + + +static void recalc_vid_list(HWND hdlg) +{ + HWND h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_SETCURSEL, 0, 0); + + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)] && + ((models[temp_model].flags & MODEL_PCI) || !(video_card_getdevice(c)->flags & DEVICE_PCI))) + { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (video_new_to_old(c) == gfxcard) + { + + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; + } + + c++; + } + if (!found_card) + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, models[temp_model].fixed_gfxcard ? FALSE : TRUE); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + EnableWindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VOODOO); + EnableWindow(h, ((models[model].flags & MODEL_PCI) && temp_voodoo) ? TRUE : FALSE); +} + + +static BOOL CALLBACK win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + char *stransi; + char *s; + int gfx = 0; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + recalc_vid_list(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO_SPEED); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2133)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2134)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2135)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2136)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2137)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2138)); + SendMessage(h, CB_SETCURSEL, temp_video_speed, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); + SendMessage(h, BM_SETCHECK, temp_voodoo, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + gfx = video_card_getid(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(gfx)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_VIDEO: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + gfx = video_card_getid(stransi); + temp_gfxcard = video_new_to_old(gfx); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(gfx)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + free(stransi); + free(lptsTemp); + break; + + case IDC_CHECK_VOODOO: + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VOODOO); + EnableWindow(h, temp_voodoo ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_VOODOO: + deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_CONFIGUREVID: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(stransi))); + + free(stransi); + free(lptsTemp); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, (wcslen(lptsTemp) * 2) + 2); + temp_gfxcard = video_new_to_old(video_card_getid(stransi)); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO_SPEED); + temp_video_speed = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + return FALSE; +} + + +static int mouse_valid(int type, int model) +{ + type &= MOUSE_TYPE_MASK; + + if ((type == MOUSE_TYPE_PS2) && + !(models[model].flags & MODEL_PS2)) return(0); + + if ((type == MOUSE_TYPE_AMSTRAD) && + !(models[model].flags & MODEL_AMSTRAD)) return(0); + + if ((type == MOUSE_TYPE_OLIM24) && + !(models[model].flags & MODEL_OLIM24)) return(0); + + return(1); +} + + +static BOOL CALLBACK win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + int type; + int str_id = 0; + + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + c = d = 0; + for (c = 0; c < mouse_get_ndev(); c++) + { + type = mouse_get_type(c); + + settings_mouse_to_list[c] = d; + + if (mouse_valid(type, temp_model)) + { + switch(c) + { + case 0: /* MS Serial */ + default: + str_id = 2139; + break; + case 1: /* PS2 2b */ + str_id = 2141; + break; + case 2: /* PS2 intelli 3b */ + str_id = 2142; + break; + case 3: /* MS/logi bus 2b */ + str_id = 2143; + break; + case 4: /* Amstrad */ + str_id = 2162; + break; + case 5: /* Olivetti M24 */ + str_id = 2177; + break; + case 6: /* MouseSystems */ + str_id = 2140; + break; + case 7: /* Genius Bus */ + str_id = 2161; + break; + } + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(str_id)); + + settings_list_to_mouse[d] = c; + d++; + } + } + + SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[temp_mouse], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + c = 0; + while (joystick_get_name(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2144 + c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_joystick, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_JOYSTICK: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + } + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 0, temp_joystick); + break; + + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 1, temp_joystick); + break; + + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 2, temp_joystick); + break; + + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 3, temp_joystick); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void recalc_hdd_list(HWND hdlg, int model, int use_selected_hdd) +{ + HWND h; + + char *s; + int valid = 0; + char old_name[16]; + int c, d; + + LPTSTR lptsTemp; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + + if (models[model].flags & MODEL_HAS_IDE) + { + hdc_ignore = 1; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2154)); + EnableWindow(h, FALSE); + SendMessage(h, CB_SETCURSEL, 0, 0); + } + else + { + hdc_ignore = 0; + + valid = 0; + + if (use_selected_hdd) + { + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (c != -1 && hdd_names[c]) + { + strncpy(old_name, hdd_names[c], sizeof(old_name) - 1); + } + else + { + strcpy(old_name, "none"); + } + } + else + { + strncpy(old_name, temp_hdc_name, sizeof(old_name) - 1); + } + + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) + { + s = hdd_controller_get_name(c); + if (s[0] == 0) + { + break; + } + if ((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model].flags & MODEL_AT)) + { + c++; + continue; + } + if ((hdd_controller_get_flags(c) & DEVICE_PS2) && !(models[model].flags & MODEL_PS2_HDD)) + { + c++; + continue; + } + if ((hdd_controller_get_flags(c) & DEVICE_MCA) && !(models[model].flags & MODEL_MCA)) + { + c++; + continue; + } + if (!hdd_controller_available(c)) + { + c++; + continue; + } + if (c < 2) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152 + c)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + hdd_names[d] = hdd_controller_get_internal_name(c); + if (!strcmp(old_name, hdd_names[d])) + { + SendMessage(h, CB_SETCURSEL, d, 0); + valid = 1; + } + c++; + d++; + } + + if (!valid) + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + EnableWindow(h, TRUE); + } + + free(lptsTemp); +} + + +int valid_ide_irqs[11] = { 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 }; + + +int find_irq_in_array(int irq, int def) +{ + int i = 0; + + for (i = 0; i < 11; i++) + { + if (valid_ide_irqs[i] == irq) + { + return i + 1; + } + } + + return 7 + def; +} + + +static char midi_dev_name_buf[512]; + +static BOOL CALLBACK win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + device_t *sound_dev; + int num = 0; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBOSND); + c = d = 0; + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + { + break; + } + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) + { + sound_dev = sound_card_getdevice(c); + + if (!sound_dev || (sound_dev->flags & DEVICE_MCA) == (models[temp_model].flags & MODEL_MCA)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_sound[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[temp_sound_card], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(temp_sound_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + num = midi_get_num_devs(); + for (c = 0; c < num; c++) + { + memset(midi_dev_name_buf, 0, 512); + midi_get_dev_name(c, midi_dev_name_buf); + mbstowcs(lptsTemp, midi_dev_name_buf, strlen(midi_dev_name_buf) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + if (c == temp_midi_id) + SendMessage(h, CB_SETCURSEL, c, 0); + } + + h=GetDlgItem(hdlg, IDC_CHECKCMS); + SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECKGUS); + SendMessage(h, BM_SETCHECK, temp_GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSSI); + SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECKNUKEDOPL); + SendMessage(h, BM_SETCHECK, temp_opl3_type, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIGURESND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); + break; + + case IDC_COMBOSND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(temp_sound_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKCMS); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKGUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKNUKEDOPL); + temp_opl3_type = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static BOOL CALLBACK win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + device_t *scsi_dev; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + /*SCSI config*/ + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + c = d = 0; + while (1) + { + char *s = scsi_card_getname(c); + + if (!s[0]) + { + break; + } + + settings_scsi_to_list[c] = d; + + if (scsi_card_available(c)) + { + scsi_dev = scsi_card_getdevice(c); + + if (!scsi_dev || (scsi_dev->flags & DEVICE_MCA) == (models[temp_model].flags & MODEL_MCA)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_scsi[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_scsi_to_list[temp_scsi_card], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + recalc_hdd_list(hdlg, temp_model, 0); + + h=GetDlgItem(hdlg, IDC_COMBO_IDE_TER); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2151)); + + for (c = 0; c < 11; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2155), valid_ide_irqs[c]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (temp_ide_ter) + { + SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_ter_irq, 0), 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + h=GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2151)); + + for (c = 0; c < 11; c++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2155), valid_ide_irqs[c]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (temp_ide_qua) + { + SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_qua_irq, 1), 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + + h=GetDlgItem(hdlg, IDC_CHECKSERIAL1); + SendMessage(h, BM_SETCHECK, temp_serial[0], 0); + + h=GetDlgItem(hdlg, IDC_CHECKSERIAL2); + SendMessage(h, BM_SETCHECK, temp_serial[1], 0); + + h=GetDlgItem(hdlg, IDC_CHECKPARALLEL); + SendMessage(h, BM_SETCHECK, temp_lpt, 0); + + h=GetDlgItem(hdlg, IDC_CHECKBUGGER); + SendMessage(h, BM_SETCHECK, temp_bugger, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIGURE_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); + break; + + case IDC_COMBO_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + break; + } + return FALSE; + + case WM_SAVESETTINGS: + if (hdc_ignore == 0) + { + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + { + strncpy(temp_hdc_name, hdd_names[c], sizeof(temp_hdc_name) - 1); + } + else + { + strcpy(temp_hdc_name, "none"); + } + } + else + { + strcpy(temp_hdc_name, "none"); + } + + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_IDE_TER); + temp_ide_ter = SendMessage(h, CB_GETCURSEL, 0, 0); + if (temp_ide_ter > 1) + { + temp_ide_ter_irq = valid_ide_irqs[temp_ide_ter - 1]; + temp_ide_ter = 1; + } + + h = GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); + temp_ide_qua = SendMessage(h, CB_GETCURSEL, 0, 0); + if (temp_ide_qua > 1) + { + temp_ide_qua_irq = valid_ide_irqs[temp_ide_qua - 1]; + temp_ide_qua = 1; + } + + h = GetDlgItem(hdlg, IDC_CHECKSERIAL1); + temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSERIAL2); + temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKPARALLEL); + temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKBUGGER); + temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +int net_ignore_message = 0; + +static void network_recalc_combos(HWND hdlg) +{ + HWND h; + + net_ignore_message = 1; + + h = GetDlgItem(hdlg, IDC_COMBOPCAP); + if (temp_net_type == NET_TYPE_PCAP) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBONET); + if (temp_net_type == NET_TYPE_SLIRP) + { + EnableWindow(h, TRUE); + } + else if ((temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_CONFIGURENET); + if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_SLIRP)) + { + EnableWindow(h, TRUE); + } + else if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + net_ignore_message = 0; +} + +static BOOL CALLBACK win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c = 0; + int d = 0; + LPTSTR lptsTemp; + device_t *scsi_dev; + + switch (message) + { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBONETTYPE); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"PCap"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"SLiRP"); + SendMessage(h, CB_SETCURSEL, temp_net_type, 0); + + h = GetDlgItem(hdlg, IDC_COMBOPCAP); + if (temp_net_type == NET_TYPE_PCAP) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_COMBOPCAP); + for (c = 0; c < network_ndev; c++) + { + mbstowcs(lptsTemp, network_devs[c].description, strlen(network_devs[c].description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + SendMessage(h, CB_SETCURSEL, network_dev_to_id(temp_pcap_dev), 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBONET); + c = d = 0; + while (1) + { + char *s = network_card_getname(c); + + if (s[0] == '\0') + { + break; + } + + settings_network_to_list[c] = d; + + if (network_card_available(c)) + { + if (c == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2152)); + } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_network[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_network_to_list[temp_net_card], 0); + + network_recalc_combos(hdlg); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBONETTYPE: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBONETTYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBOPCAP: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBOPCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBONET: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + network_recalc_combos(hdlg); + break; + + case IDC_CONFIGURENET: + if (net_ignore_message) + { + return FALSE; + } + + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBONETTYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBOPCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + default: + return FALSE; + } + + return FALSE; +} + +static BOOL win_settings_hard_disks_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 8; i += 2) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) (176 + i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +int next_free_id = 0; + +wchar_t ifn[HDC_NUM][512]; + +static void normalize_hd_list() +{ + hard_disk_t ihdc[HDC_NUM]; + int i, j; + + j = 0; + memset(ihdc, 0, HDC_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDC_NUM; i++) + { + memset(ifn[i], 0, 1024); + } + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus > 0) + { + memcpy(&(ihdc[j]), &(temp_hdc[i]), sizeof(hard_disk_t)); + memcpy(ifn[j], temp_hdd_fn[i], 1024); + j++; + } + } + + memcpy(temp_hdc, ihdc, HDC_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDC_NUM; i++) + { + memcpy(temp_hdd_fn[i], ifn[i], 1024); + } +} + +int hdc_id_to_listview_index[HDC_NUM]; +int hd_listview_items; + +hard_disk_t new_hdc; +int hdlv_current_sel; + +static int get_selected_hard_disk(HWND hdlg) +{ + int hard_disk = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 6; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + hard_disk = i; + } + } + + return hard_disk; +} + +static void add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + for (i = 0; i < 4; i++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2165 + i)); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + for (i = 0; i < 16; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + +static void recalc_location_controls(HWND hdlg, int is_add_dlg) +{ + int i = 0; + HWND h; + + int bus = 0; + + for (i = 1799; i < 1803; i++) + { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + if ((hd_listview_items > 0) || is_add_dlg) + { + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + bus = SendMessage(h, CB_GETCURSEL, 0, 0); + + switch(bus) + { + case 0: /* MFM/RLL */ + h = GetDlgItem(hdlg, 1799); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.mfm_channel : temp_hdc[hdlv_current_sel].mfm_channel, 0); + break; + case 1: /* IDE (PIO-only) */ + case 2: /* IDE (PIO and DMA) */ + h = GetDlgItem(hdlg, 1802); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.ide_channel : temp_hdc[hdlv_current_sel].ide_channel, 0); + break; + case 3: /* SCSI */ + h = GetDlgItem(hdlg, 1800); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, 1801); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.scsi_id : temp_hdc[hdlv_current_sel].scsi_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdc.scsi_lun : temp_hdc[hdlv_current_sel].scsi_lun, 0); + break; + } + } + + if ((hd_listview_items == 0) && !is_add_dlg) + { + h = GetDlgItem(hdlg, 1798); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); + } + else + { + h = GetDlgItem(hdlg, 1798); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } +} + +static void recalc_next_free_id(HWND hdlg) +{ + HWND h; + int i; + + int c_mfm = 0; + int c_ide_pio = 0; + int c_ide_dma = 0; + int c_scsi = 0; + int enable_add = 0; + + next_free_id = -1; + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus == 1) + { + c_mfm++; + } + else if (temp_hdc[i].bus == 2) + { + c_ide_pio++; + } + else if (temp_hdc[i].bus == 3) + { + c_ide_dma++; + } + else if (temp_hdc[i].bus == 4) + { + c_scsi++; + } + } + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus == 0) + { + next_free_id = i; + break; + } + } + + /* pclog("Next free ID: %i\n", next_free_id); */ + + enable_add = enable_add || (next_free_id >= 0); + /* pclog("Enable add: %i\n", enable_add); */ + enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_ide_pio < IDE_NUM) || (c_ide_dma < IDE_NUM) || (c_scsi < SCSI_NUM)); + /* pclog("Enable add: %i\n", enable_add); */ + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD_NEW); + + if (enable_add) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD); + + if (enable_add) + { + EnableWindow(h, TRUE); + } + else + { + EnableWindow(h, FALSE); + } + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); + + if ((c_mfm == 0) && (c_ide_pio == 0) && (c_ide_dma == 0) && (c_scsi == 0)) + { + EnableWindow(h, FALSE); + } + else + { + EnableWindow(h, TRUE); + } +} + +static void win_settings_hard_disks_update_item(HWND hwndList, int i, int column) +{ + LVITEM lvI; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = column; + lvI.iItem = i; + + if (column == 0) + { + switch(temp_hdc[i].bus) + { + case 1: + wsprintf(szText, win_language_get_string_from_id(2156), temp_hdc[i].mfm_channel >> 1, temp_hdc[i].mfm_channel & 1); + break; + case 2: + wsprintf(szText, win_language_get_string_from_id(2195), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case 3: + wsprintf(szText, win_language_get_string_from_id(2157), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case 4: + wsprintf(szText, win_language_get_string_from_id(2158), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iImage = temp_hdc[i].bus - 1; + } + else if (column == 1) + { + lvI.pszText = temp_hdd_fn[i]; + lvI.iImage = 0; + } + else if (column == 2) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].tracks); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 3) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].hpc); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 4) + { + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].spt); + lvI.pszText = szText; + lvI.iImage = 0; + } + else if (column == 5) + { + wsprintf(szText, win_language_get_string_from_id(2088), (temp_hdc[i].tracks * temp_hdc[i].hpc * temp_hdc[i].spt) >> 11); + lvI.pszText = szText; + lvI.iImage = 0; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static BOOL win_settings_hard_disks_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + int j = 0; + WCHAR szText[256]; + + hd_listview_items = 0; + hdlv_current_sel = -1; + + ListView_DeleteAllItems(hwndList); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < HDC_NUM; i++) + { + if (temp_hdc[i].bus > 0) + { + hdc_id_to_listview_index[i] = j; + lvI.iSubItem = 0; + switch(temp_hdc[i].bus) + { + case 1: + wsprintf(szText, win_language_get_string_from_id(2156), temp_hdc[i].mfm_channel >> 1, temp_hdc[i].mfm_channel & 1); + break; + case 2: + wsprintf(szText, win_language_get_string_from_id(2195), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case 3: + wsprintf(szText, win_language_get_string_from_id(2157), temp_hdc[i].ide_channel >> 1, temp_hdc[i].ide_channel & 1); + break; + case 4: + wsprintf(szText, win_language_get_string_from_id(2158), temp_hdc[i].scsi_id, temp_hdc[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = temp_hdc[i].bus - 1; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 1; + lvI.pszText = temp_hdd_fn[i]; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 2; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].tracks); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 3; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].hpc); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 4; + wsprintf(szText, win_language_get_string_from_id(2088), temp_hdc[i].spt); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + lvI.iSubItem = 5; + wsprintf(szText, win_language_get_string_from_id(2088), (temp_hdc[i].tracks * temp_hdc[i].hpc * temp_hdc[i].spt) >> 11); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return FALSE; + } + + j++; + } + else + { + hdc_id_to_listview_index[i] = -1; + } + } + + hd_listview_items = j; + + return TRUE; +} + +/* Icon, Bus, File, C, H, S, Size */ +#define C_COLUMNS_HARD_DISKS 6 + +static BOOL win_settings_hard_disks_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + int iCol; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) + { + lvc.iSubItem = iCol; + lvc.pszText = win_language_get_string_from_id(2082 + iCol); + + switch(iCol) + { + + case 0: /* Bus */ + lvc.cx = 135; + lvc.fmt = LVCFMT_LEFT; + break; + case 2: /* Cylinders */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + case 3: /* Heads */ + case 4: /* Sectors */ + lvc.cx = 25; + lvc.fmt = LVCFMT_RIGHT; + break; + case 1: /* File */ + lvc.cx = 150; + lvc.fmt = LVCFMT_LEFT; + break; + case 5: /* Size (MB) 8 */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + } + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + { + return FALSE; + } + } + + return TRUE; +} + +static void get_edit_box_contents(HWND hdlg, int id, uint64_t *val) +{ + HWND h; + WCHAR szText[256]; + char stransi[256]; + + h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) szText); + wcstombs(stransi, szText, (wcslen(szText) * 2) + 2); + sscanf(stransi, "%" PRIu64, val); +} + +static void get_combo_box_selection(HWND hdlg, int id, uint64_t *val) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + *val = SendMessage(h, CB_GETCURSEL, 0, 0); +} + +static void set_edit_box_contents(HWND hdlg, int id, uint64_t val) +{ + HWND h; + WCHAR szText[256]; + + h = GetDlgItem(hdlg, id); + wsprintf(szText, win_language_get_string_from_id(2160), val); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); +} + +int hard_disk_added = 0; +int max_spt = 63; + +int no_update = 0; + +int existing = 0; +uint64_t selection = 127; + +uint64_t spt, hpc, tracks, size; +wchar_t hd_file_name[512]; + +static int hdconf_initialize_hdt_combo(HWND hdlg) +{ + HWND h; + int i = 0; + uint64_t temp_size = 0; + uint64_t size_mb = 0; + WCHAR szText[256]; + + selection = 127; + + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) + { + temp_size = hdt[i][0] * hdt[i][1] * hdt[i][2]; + size_mb = temp_size >> 11; + wsprintf(szText, win_language_get_string_from_id(2171), size_mb, hdt[i][0], hdt[i][1], hdt[i][2]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if ((tracks == hdt[i][0]) && (hpc == hdt[i][1]) && (spt == hdt[i][2])) + { + selection = i; + } + } + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2170)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2187)); + SendMessage(h, CB_SETCURSEL, selection, 0); + return selection; +} + +static void recalc_selection(HWND hdlg) +{ + HWND h; + int i = 0; + + selection = 127; + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) + { + if ((tracks == hdt[i][0]) && (hpc == hdt[i][1]) && (spt == hdt[i][2])) + { + selection = i; + } + } + if ((selection == 127) && (hpc == 16) && (spt == 63)) + { + selection = 128; + } + SendMessage(h, CB_SETCURSEL, selection, 0); +} + +static BOOL CALLBACK win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int64_t i = 0; + int bus; + uint64_t temp; + WCHAR szText[256]; + FILE *f; + uint32_t sector_size = 512; + uint32_t zero = 0; + uint32_t base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + char buf[512]; + + switch (message) + { + case WM_INITDIALOG: + memset(hd_file_name, 0, 512); + + SetWindowText(hdlg, win_language_get_string_from_id(existing ? 2197 : 2196)); + + no_update = 1; + spt = existing ? 0 : 17; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + hpc = existing ? 0 : 15; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + tracks = existing ? 0 : 1023; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + hdconf_initialize_hdt_combo(hdlg); + if (existing) + { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + } + add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, 1, 0); + recalc_location_controls(hdlg, 1); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + no_update = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + if (wcslen(hd_file_name) == 0) + { + msgbox_error(hwndParentDialog, 2056); + return TRUE; + } + + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(temp_hdc[next_free_id].spt)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(temp_hdc[next_free_id].hpc)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &(temp_hdc[next_free_id].tracks)); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + temp_hdc[next_free_id].bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + temp_hdc[next_free_id].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + temp_hdc[next_free_id].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + temp_hdc[next_free_id].scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + temp_hdc[next_free_id].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + memset(temp_hdd_fn[next_free_id], 0, 1024); + memcpy(temp_hdd_fn[next_free_id], hd_file_name, (wcslen(hd_file_name) << 1) + 2); + + sector_size = 512; + + if (!existing && (wcslen(hd_file_name) > 0)) + { + f = _wfopen(hd_file_name, L"wb"); + + if (image_is_hdi(hd_file_name)) + { + if (size >= 0x100000000ll) + { + fclose(f); + msgbox_error(hwndParentDialog, 2058); + return TRUE; + } + + fwrite(&zero, 1, 4, f); /* 00000000: Zero/unknown */ + fwrite(&zero, 1, 4, f); /* 00000004: Zero/unknown */ + fwrite(&base, 1, 4, f); /* 00000008: Offset at which data starts */ + fwrite(&size, 1, 4, f); /* 0000000C: Full size of the data (32-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + + for (i = 0; i < 0x3f8; i++) + { + fwrite(&zero, 1, 4, f); + } + } + else if (image_is_hdx(hd_file_name, 0)) + { + if (size > 0xffffffffffffffffll) + { + fclose(f); + msgbox_error(hwndParentDialog, 2163); + return TRUE; + } + + fwrite(&signature, 1, 8, f); /* 00000000: Signature */ + fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ + fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ + } + + memset(buf, 0, 512); + size >>= 9; + for (i = 0; i < size; i++) + { + fwrite(buf, 512, 1, f); + } + + fclose(f); + msgbox_info(hwndParentDialog, 2059); + } + + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + hard_disk_added = 0; + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, win_language_get_string_from_id(2172), L"", !existing)) + { + if (!existing) + { + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) + { + fclose(f); + if (msgbox_question(ghwnd, 2178) != IDYES) + { + return FALSE; + } + } + } + + f = _wfopen(wopenfilestring, existing ? L"rb" : L"wb"); + if (f == NULL) + { + msgbox_error(hwndParentDialog, existing ? 2060 : 2057); + return TRUE; + } + if (existing) + { + if (image_is_hdi(wopenfilestring) || image_is_hdx(wopenfilestring, 1)) + { + fseeko64(f, 0x10, SEEK_SET); + fread(§or_size, 1, 4, f); + if (sector_size != 512) + { + msgbox_error(hwndParentDialog, 2061); + fclose(f); + return TRUE; + } + spt = hpc = tracks = 0; + fread(&spt, 1, 4, f); + fread(&hpc, 1, 4, f); + fread(&tracks, 1, 4, f); + } + else + { + fseeko64(f, 0, SEEK_END); + size = ftello64(f); + fclose(f); + if (((size % 17) == 0) && (size <= 133693440)) + { + spt = 17; + if (size <= 26738688) + { + hpc = 4; + } + else if (size <= 53477376) + { + hpc = 6; + } + else if (size <= 71303168) + { + hpc = 8; + } + else + { + hpc = 15; + } + } + else + { + spt = 63; + hpc = 16; + } + + tracks = ((size >> 9) / hpc) / spt; + } + + no_update = 1; + + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, TRUE); + + no_update = 0; + } + else + { + fclose(f); + } + } + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memcpy(hd_file_name, wopenfilestring, (wcslen(wopenfilestring) << 1) + 2); + + return TRUE; + + case IDC_EDIT_HD_CYL: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); + if (temp != tracks) + { + tracks = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + no_update = 0; + break; + + case IDC_EDIT_HD_HPC: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); + if (temp != hpc) + { + hpc = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + no_update = 0; + break; + + case IDC_EDIT_HD_SPT: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); + if (temp != spt) + { + spt = temp; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + } + no_update = 0; + break; + + case IDC_EDIT_HD_SIZE: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, &temp); + if (temp != (size >> 20)) + { + size = temp << 20; + tracks = ((size >> 9) / hpc) / spt; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + recalc_selection(hdlg); + } + no_update = 0; + break; + + case IDC_COMBO_HD_TYPE: + if (no_update) + { + return FALSE; + } + + no_update = 1; + get_combo_box_selection(hdlg, IDC_COMBO_HD_TYPE, &temp); + if ((temp != selection) && (temp != 127) && (temp != 128)) + { + selection = temp; + tracks = hdt[selection][0]; + hpc = hdt[selection][1]; + spt = hdt[selection][2]; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + } + else if ((temp != selection) && (temp == 127)) + { + selection = temp; + } + else if ((temp != selection) && (temp == 128)) + { + selection = temp; + hpc = 16; + spt = 63; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + } + no_update = 0; + break; + + case IDC_COMBO_HD_BUS: + if (no_update) + { + return FALSE; + } + + no_update = 1; + recalc_location_controls(hdlg, 1); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + bus = SendMessage(h, CB_GETCURSEL, 0, 0); + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &spt); + max_spt = (bus == 2) ? 99 : 63; + if (spt > max_spt) + { + spt = max_spt; + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, 17); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + recalc_selection(hdlg); + } + no_update = 0; + break; + } + + return FALSE; + } + + return FALSE; +} + +void hard_disk_add_open(HWND hwnd, int is_existing) +{ + BOOL ret; + + existing = !!is_existing; + hard_disk_added = 0; + ret = DialogBox(hinstance, (LPCWSTR) CONFIGUREDLG_HARD_DISKS_ADD, hwnd, win_settings_hard_disks_add_proc); +} + +int ignore_change = 0; + +static BOOL CALLBACK win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0; + + switch (message) + { + case WM_INITDIALOG: + ignore_change = 1; + + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. + This will cause an emulator reset prompt on the first opening of this category with a messy hard disk list + (which can only happen by manually editing the configuration file). */ + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_init_columns(h); + win_settings_hard_disks_image_list_init(h); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + add_locations(hdlg); + if (hd_listview_items > 0) + { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[0].bus - 1, 0); + } + else + { + hdlv_current_sel = -1; + } + recalc_location_controls(hdlg, 0); + + ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if ((hd_listview_items == 0) || ignore_change) + { + return FALSE; + } + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_HARD_DISKS)) + { + old_sel = hdlv_current_sel; + hdlv_current_sel = get_selected_hard_disk(hdlg); + if (hdlv_current_sel == old_sel) + { + return FALSE; + } + else if (hdlv_current_sel == -1) + { + ignore_change = 1; + hdlv_current_sel = old_sel; + ListView_SetItemState(h, hdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + ignore_change = 0; + return FALSE; + } + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[hdlv_current_sel].bus - 1, 0); + recalc_location_controls(hdlg, 0); + ignore_change = 0; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_HD_BUS: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + recalc_location_controls(hdlg, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + temp_hdc[hdlv_current_sel].bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + temp_hdc[hdlv_current_sel].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL_IDE: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + temp_hdc[hdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_ID: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + temp_hdc[hdlv_current_sel].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_LUN: + if (ignore_change) + { + return FALSE; + } + + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + temp_hdc[hdlv_current_sel].scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_BUTTON_HDD_ADD: + hard_disk_add_open(hdlg, 1); + if (hard_disk_added) + { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_ADD_NEW: + hard_disk_add_open(hdlg, 0); + if (hard_disk_added) + { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_REMOVE: + memcpy(temp_hdd_fn[hdlv_current_sel], L"", 4); + temp_hdc[hdlv_current_sel].bus = 0; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + if (hd_listview_items > 0) + { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdc[0].bus - 1, 0); + } + else + { + hdlv_current_sel = -1; + } + recalc_location_controls(hdlg, 0); + ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + +int fdlv_current_sel; +int cdlv_current_sel; + +static int combo_id_to_string_id(int combo_id) +{ + switch (combo_id) + { + case 0: /* Disabled */ + default: + return 2151; + break; + case 2: /* Atapi (PIO-only) */ + return 2189; + break; + case 3: /* Atapi (PIA and DMA) */ + return 2190; + break; + case 4: /* SCSI */ + return 2168; + break; + } +} + +static int combo_id_to_format_string_id(int combo_id) +{ + switch (combo_id) + { + case 0: /* Disabled */ + default: + return 2151; + break; + case 2: /* Atapi (PIO-only) */ + return 2191; + break; + case 3: /* Atapi (PIA and DMA) */ + return 2192; + break; + case 4: /* SCSI */ + return 2158; + break; + } +} + +static BOOL win_settings_floppy_drives_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 14; i++) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) fdd_type_to_icon(i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + int j = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 514); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 160); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 162); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + hiconItem = LoadIcon(hinstance, (LPCWSTR) 164); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_floppy_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) + { + if (temp_fdd_types[i] > 0) + { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } + else + { + lvI.pszText = win_language_get_string_from_id(2151); + } + lvI.iItem = i; + lvI.iImage = temp_fdd_types[i]; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + char s[256]; + WCHAR szText[256]; + int bid = 0; + int fsid = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) + { + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) + { + case 0: + default: + lvI.pszText = win_language_get_string_from_id(fsid); + break; + case 2: + case 3: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + break; + case 4: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + break; + } + + lvI.iItem = i; + + if (temp_cdrom_drives[i].bus_type) + { + lvI.iImage = temp_cdrom_drives[i].bus_type - 1; + } + else + { + lvI.iImage = 0; + } + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + +static BOOL win_settings_floppy_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = win_language_get_string_from_id(2188); + + lvc.cx = 392; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + { + return FALSE; + } + + return TRUE; +} + +static BOOL win_settings_cdrom_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = win_language_get_string_from_id(2082); + + lvc.cx = 392; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + { + return FALSE; + } + + return TRUE; +} + +static int get_selected_floppy_drive(HWND hdlg) +{ + int floppy_drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 6; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + floppy_drive = i; + } + } + + return floppy_drive; +} + +static int get_selected_cdrom_drive(HWND hdlg) +{ + int cd_drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 6; i++) + { + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + cd_drive = i; + } + } + + return cd_drive; +} + +static void win_settings_floppy_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + if (temp_fdd_types[i] > 0) + { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } + else + { + lvI.pszText = win_language_get_string_from_id(2151); + } + lvI.iImage = temp_fdd_types[i]; + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static void win_settings_cdrom_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + char s[256]; + WCHAR szText[256]; + int bid; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) + { + case 0: + default: + lvI.pszText = win_language_get_string_from_id(fsid); + break; + case 2: + case 3: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + break; + case 4: + wsprintf(szText, win_language_get_string_from_id(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + break; + } + + if (temp_cdrom_drives[i].bus_type) + { + lvI.iImage = temp_cdrom_drives[i].bus_type - 1; + } + else + { + lvI.iImage = 0; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + { + return; + } +} + +static void cdrom_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + for (i = 1; i < 5; i++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(combo_id_to_string_id(i))); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + for (i = 0; i < 16; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2088), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + for (i = 0; i < 8; i++) + { + wsprintf(lptsTemp, win_language_get_string_from_id(2169), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} +static void cdrom_recalc_location_controls(HWND hdlg) +{ + int i = 0; + HWND h; + + int bus = temp_cdrom_drives[cdlv_current_sel].bus_type; + + for (i = 1800; i < 1803; i++) + { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + switch(bus) + { + case 2: /* ATAPI (PIO-only) */ + case 3: /* ATAPI (PIO and DMA) */ + h = GetDlgItem(hdlg, 1802); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].ide_channel, 0); + break; + case 4: /* SCSI */ + h = GetDlgItem(hdlg, 1800); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, 1801); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +int rd_ignore_change = 0; + +static BOOL CALLBACK win_settings_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0; + int old_sel = 0; + int cid = 0; + WCHAR szText[256]; + + switch (message) + { + case WM_INITDIALOG: + rd_ignore_change = 1; + + fdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_init_columns(h); + win_settings_floppy_drives_image_list_init(h); + win_settings_floppy_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + for (i = 0; i < 14; i++) + { + if (i == 0) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) win_language_get_string_from_id(2151)); + } + else + { + mbstowcs(szText, fdd_getname(i), strlen(fdd_getname(i)) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + } + } + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + + cdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_init_columns(h); + win_settings_cdrom_drives_image_list_init(h); + win_settings_cdrom_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + cdrom_add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + if (temp_cdrom_drives[cdlv_current_sel].bus_type > 1) + { + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].bus_type, 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + cdrom_recalc_location_controls(hdlg); + + rd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (rd_ignore_change) + { + return FALSE; + } + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_FLOPPY_DRIVES)) + { + old_sel = fdlv_current_sel; + fdlv_current_sel = get_selected_floppy_drive(hdlg); + if (fdlv_current_sel == old_sel) + { + return FALSE; + } + else if (fdlv_current_sel == -1) + { + rd_ignore_change = 1; + fdlv_current_sel = old_sel; + ListView_SetItemState(h, fdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + rd_ignore_change = 0; + } + else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) + { + old_sel = cdlv_current_sel; + cdlv_current_sel = get_selected_cdrom_drive(hdlg); + if (cdlv_current_sel == old_sel) + { + return FALSE; + } + else if (cdlv_current_sel == -1) + { + rd_ignore_change = 1; + cdlv_current_sel = old_sel; + ListView_SetItemState(h, cdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + if (temp_cdrom_drives[cdlv_current_sel].bus_type > 1) + { + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].bus_type, 0); + } + else + { + SendMessage(h, CB_SETCURSEL, 0, 0); + } + cdrom_recalc_location_controls(hdlg); + rd_ignore_change = 0; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_COMBO_FD_TYPE: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + temp_fdd_types[fdlv_current_sel] = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_BUS: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + temp_cdrom_drives[cdlv_current_sel].bus_type = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + if (temp_cdrom_drives[cdlv_current_sel].bus_type == 1) + { + temp_cdrom_drives[cdlv_current_sel].bus_type = 0; + } + cdrom_recalc_location_controls(hdlg); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_ID: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + temp_cdrom_drives[cdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_LUN: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + temp_cdrom_drives[cdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + + case IDC_COMBO_CD_CHANNEL_IDE: + if (rd_ignore_change) + { + return FALSE; + } + + rd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + temp_cdrom_drives[cdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + rd_ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + +void win_settings_show_child(HWND hwndParent, DWORD child_id) +{ + if (child_id == displayed_category) + { + return; + } + else + { + displayed_category = child_id; + } + + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + + DestroyWindow(hwndChildDialog); + + switch(child_id) + { + case 0: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_MACHINE, hwndParent, win_settings_machine_proc); + break; + case 1: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_VIDEO, hwndParent, win_settings_video_proc); + break; + case 2: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_INPUT, hwndParent, win_settings_input_proc); + break; + case 3: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_SOUND, hwndParent, win_settings_sound_proc); + break; + case 4: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_NETWORK, hwndParent, win_settings_network_proc); + break; + case 5: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; + case 6: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); + break; + case 7: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR) CONFIGUREDLG_REMOVABLE_DEVICES, hwndParent, win_settings_removable_devices_proc); + break; + default: + fatal("Invalid child dialog ID\n"); + return; + } + + ShowWindow(hwndChildDialog, SW_SHOWNORMAL); +} + +static BOOL win_settings_main_image_list_init(HWND hwndList) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + for (i = 0; i < 8; i++) + { + hiconItem = LoadIcon(hinstance, (LPCWSTR) (256 + i)); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + +static BOOL win_settings_main_insert_categories(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 8; i++) + { + lvI.pszText = win_language_get_settings_category(i); + lvI.iItem = i; + lvI.iImage = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + +static BOOL CALLBACK win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int category; + int i = 0; + int j = 0; + + hwndParentDialog = hdlg; + + switch (message) + { + case WM_INITDIALOG: + pause = 1; + win_settings_init(); + displayed_category = -1; + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + win_settings_main_image_list_init(h); + win_settings_main_insert_categories(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + h = GetDlgItem(hdlg, IDC_COMBO_LANG); /* This is currently disabled, I am going to add localization options in the future. */ + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, 2047); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + return TRUE; + case WM_NOTIFY: + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) + { + category = -1; + for (i = 0; i < 8; i++) + { + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + { + category = i; + /* pclog("Category %i selected\n", i); */ + } + } + if (category != -1) + { + /* pclog("Showing child: %i\n", category); */ + win_settings_show_child(hdlg, category); + } + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + /* pclog("Saving settings...\n"); */ + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + i = settings_msgbox_reset(); + if (i > 0) + { + if (i == 2) + { + win_settings_save(); + } + + /* pclog("Destroying window...\n"); */ + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + } + else + { + return FALSE; + } + case IDCANCEL: + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + pause=0; + return TRUE; + } + break; + default: + return FALSE; + } + + return FALSE; +} + +void win_settings_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCWSTR) CONFIGUREDLG_MAIN, hwnd, win_settings_main_proc); +} diff --git a/src/WIN/win_status.c b/src/WIN/win_status.c new file mode 100644 index 000000000..59a7a5947 --- /dev/null +++ b/src/WIN/win_status.c @@ -0,0 +1,95 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "../ibm.h" +#include "../mem.h" +#include "../cpu/x86_ops.h" +#include "../cpu/codegen.h" +#include "../device.h" +#include "resource.h" +#include "win.h" + + +HWND status_hwnd; +int status_is_open = 0; + + +extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; + +extern uint64_t main_time; +static uint64_t status_time; + + +static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char device_s[4096]; + switch (message) + { + case WM_INITDIALOG: + status_is_open = 1; + case WM_USER: + { + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + sprintf(device_s, + "CPU speed : %f MIPS\n" + "FPU speed : %f MFLOPS\n\n" + + "Video throughput (read) : %i bytes/sec\n" + "Video throughput (write) : %i bytes/sec\n\n" + "Effective clockspeed : %iHz\n\n" + "Timer 0 frequency : %fHz\n\n" + "CPU time : %f%% (%f%%)\n" + + "New blocks : %i\nOld blocks : %i\nRecompiled speed : %f MIPS\nAverage size : %f\n" + "Flushes : %i\nEvicted : %i\nReused : %i\nRemoved : %i\nReal speed : %f MIPS" + ,mips, + flops, + segareads, + segawrites, + clockrate - scycles_lost, + pit_timer0_freq(), + ((double)main_time * 100.0) / status_diff, + ((double)main_time * 100.0) / timer_freq + + , cpu_new_blocks_latched, cpu_recomp_blocks_latched, (double)cpu_recomp_ins_latched / 1000000.0, (double)cpu_recomp_ins_latched/cpu_recomp_blocks_latched, + cpu_recomp_flushes_latched, cpu_recomp_evicted_latched, + cpu_recomp_reuse_latched, cpu_recomp_removed_latched, + + ((double)cpu_recomp_ins_latched / 1000000.0) / ((double)main_time / timer_freq) + ); + main_time = 0; + SendDlgItemMessage(hdlg, IDC_STEXT_DEVICE, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + + device_s[0] = 0; + device_add_status_info(device_s, 4096); + SendDlgItemMessage(hdlg, IDC_STEXT1, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + status_is_open = 0; + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + + return FALSE; +} + +void status_open(HWND hwnd) +{ + status_hwnd = CreateDialog(hinstance, TEXT("StatusDlg"), hwnd, status_dlgproc); + ShowWindow(status_hwnd, SW_SHOW); +} diff --git a/src/WIN/win_video.c b/src/WIN/win_video.c new file mode 100644 index 000000000..3a50f7b9f --- /dev/null +++ b/src/WIN/win_video.c @@ -0,0 +1,57 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include "../video/video.h" +#include "win_cgapal.h" + + +BITMAP *screen; + + +void hline(BITMAP *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + +void blit(BITMAP *src, BITMAP *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + +void stretch_blit(BITMAP *src, BITMAP *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + +void rectfill(BITMAP *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + +void set_palette(PALETTE p) +{ +} + +void destroy_bitmap(BITMAP *b) +{ +} + +BITMAP *create_bitmap(int x, int y) +{ + BITMAP *b = malloc(sizeof(BITMAP) + (y * sizeof(uint8_t *))); + int c; + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + { + b->line[c] = b->dat + (c * x * 4); + } + b->w = x; + b->h = y; + return b; +} diff --git a/src/cdrom_dosbox.cpp b/src/cdrom_dosbox.cpp new file mode 100644 index 000000000..e076fb9b1 --- /dev/null +++ b/src/cdrom_dosbox.cpp @@ -0,0 +1,565 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#include +#include +#include +#include +#include +#include +#include //GCC 2.95 +#include +#include +#include +#include "cdrom_dosbox.h" + +#if !defined(WIN32) +#include +#else +#include +#endif + +using namespace std; + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) +{ + file = new ifstream(filename, ios::in | ios::binary); + error = (file == NULL) || (file->fail()); +} + +CDROM_Interface_Image::BinaryFile::~BinaryFile() +{ + delete file; +} + +bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, int seek, int count) +{ + file->seekg(seek, ios::beg); + file->read((char*)buffer, count); + return !(file->fail()); +} + +int CDROM_Interface_Image::BinaryFile::getLength() +{ + file->seekg(0, ios::end); + int length = (int)file->tellg(); + if (file->fail()) return -1; + return length; +} + +CDROM_Interface_Image::CDROM_Interface_Image() +{ +} + +CDROM_Interface_Image::~CDROM_Interface_Image() +{ + ClearTracks(); +} + +void CDROM_Interface_Image::InitNewMedia() +{ +} + +bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) +{ + if (LoadCueSheet(path)) return true; + if (LoadIsoFile(path)) return true; + + // print error message on dosbox console + //printf("Could not load image file: %s\n", path); + return false; +} + +bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) +{ + attr = 0; + strcpy(upc, this->mcn.c_str()); + return true; +} + +bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) +{ + stTrack = 1; + end = (int)(tracks.size() - 1); + FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); + return true; +} + +bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + +bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + int cur_track = GetTrack(sector); + if (cur_track < 1) return false; + track = (unsigned char)cur_track; + attr = tracks[track - 1].attr; + index = 1; + FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); + FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); + return true; +} + +bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +} + +bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) +{ + int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + Bitu buflen = num * sectorSize; + Bit8u* buf = new Bit8u[buflen]; + + bool success = true; //Gobliiins reads 0 sectors + for(unsigned long i = 0; i < num; i++) { + success = ReadSector(&buf[i * sectorSize], raw, sector + i); + if (!success) break; + } + + memcpy((void*)buffer, buf, buflen); + delete[] buf; + + return success; +} + +bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) +{ + return true; +} + +int CDROM_Interface_Image::GetTrack(int sector) +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end() - 1; + + while(i != end) { + Track &curr = *i; + Track &next = *(i + 1); + if (curr.start <= sector && sector < next.start) return curr.number; + i++; + } + return -1; +} + +bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + int seek = tracks[track].skip + (sector - tracks[track].start) * tracks[track].sectorSize; + int length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; + if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; + if (tracks[track].mode2 && !raw) seek += 24; + + return tracks[track].file->read(buffer, seek, length); +} + +bool CDROM_Interface_Image::IsMode2(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + if (tracks[track].mode2) + { + return true; + } + else + { + return false; + } +} + +bool CDROM_Interface_Image::LoadIsoFile(char* filename) +{ + int shift = 0; + int totalPregap = 0; + + tracks.clear(); + + // data track + Track track = {0, 0, 0, 0, 0, 0, false, NULL}; + bool error; + track.file = new BinaryFile(filename, error); + if (error) { + delete track.file; + return false; + } + track.number = 1; + track.track_number = 1;//IMPORTANT: This is needed. + track.attr = DATA_TRACK;//data + + // try to detect iso type + if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, 2336, true)) { + track.sectorSize = 2336; + track.mode2 = true; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = true; + } else return false; + + track.length = track.file->getLength() / track.sectorSize; + tracks.push_back(track); + + // leadout track + track.number = 2; + track.track_number = 0xAA; + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = track.length; + track.length = 0; + track.file = NULL; + tracks.push_back(track); + + return true; +} + +bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, int sectorSize, bool mode2) +{ + Bit8u pvd[COOKED_SECTOR_SIZE]; + int seek = 16 * sectorSize; // first vd is located at sector 16 + if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; + if (mode2) seek += 24; + file->read(pvd, seek, COOKED_SECTOR_SIZE); + // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + +#if defined(WIN32) +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + +bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) +{ + Track track = {0, 0, 0, 0, 0, 0, false, NULL}; + tracks.clear(); + int shift = 0; + int currPregap = 0; + int totalPregap = 0; + int prestart = 0; + bool success; + bool canAddTrack = false; + char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); + string pathname(dirname(tmp)); + ifstream in; + in.open(cuefile, ios::in); + if (in.fail()) return false; + + while(!in.eof()) { + // get next line + char buf[MAX_LINE_LENGTH]; + in.getline(buf, MAX_LINE_LENGTH); + if (in.fail() && !in.eof()) return false; // probably a binary file + istringstream line(buf); + + string command; + GetCueKeyword(command, line); + + if (command == "TRACK") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + + track.start = 0; + track.skip = 0; + currPregap = 0; + prestart = 0; + + line >> track.number; + track.track_number = track.number; + string type; + GetCueKeyword(type, line); + + if (type == "AUDIO") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = AUDIO_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2048") { + track.sectorSize = COOKED_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE2/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else success = false; + + canAddTrack = true; + } + else if (command == "INDEX") { + int index; + line >> index; + int frame; + success = GetCueFrame(frame, line); + + if (index == 1) track.start = frame; + else if (index == 0) prestart = frame; + // ignore other indices + } + else if (command == "FILE") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + canAddTrack = false; + + string filename; + GetCueString(filename, line); + GetRealFileName(filename, pathname); + string type; + GetCueKeyword(type, line); + + track.file = NULL; + bool error = true; + if (type == "BINARY") { + track.file = new BinaryFile(filename.c_str(), error); + } + if (error) { + delete track.file; + success = false; + } + } + else if (command == "PREGAP") success = GetCueFrame(currPregap, line); + else if (command == "CATALOG") success = GetCueString(mcn, line); + // ignored commands + else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" + || command == "PERFORMER" || command == "POSTGAP" || command == "REM" + || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; + // failure + else success = false; + + if (!success) return false; + } + // add last track + if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; + + // add leadout track + track.number++; + track.track_number = 0xAA; + // track.attr = 0;//sync with load iso + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = 0; + track.length = 0; + track.file = NULL; + if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; + + return true; +} + +bool CDROM_Interface_Image::AddTrack(Track &curr, int &shift, int prestart, int &totalPregap, int currPregap) +{ + // frames between index 0(prestart) and 1(curr.start) must be skipped + int skip; + if (prestart > 0) { + if (prestart > curr.start) return false; + skip = curr.start - prestart; + } else skip = 0; + + // first track (track number must be 1) + if (tracks.empty()) { + if (curr.number != 1) return false; + curr.skip = skip * curr.sectorSize; + curr.start += currPregap; + totalPregap = currPregap; + tracks.push_back(curr); + return true; + } + + Track &prev = *(tracks.end() - 1); + + // current track consumes data from the same file as the previous + if (prev.file == curr.file) { + curr.start += shift; + prev.length = curr.start + totalPregap - prev.start - skip; + curr.skip += prev.skip + prev.length * prev.sectorSize + skip * curr.sectorSize; + totalPregap += currPregap; + curr.start += totalPregap; + // current track uses a different file as the previous track + } else { + int tmp = prev.file->getLength() - prev.skip; + prev.length = tmp / prev.sectorSize; + if (tmp % prev.sectorSize != 0) prev.length++; // padding + + curr.start += prev.start + prev.length + currPregap; + curr.skip = skip * curr.sectorSize; + shift += prev.start + prev.length; + totalPregap = currPregap; + } + + // error checks + if (curr.number <= 1) return false; + if (prev.number + 1 != curr.number) return false; + if (curr.start < prev.start + prev.length) return false; + if (curr.length < 0) return false; + + tracks.push_back(curr); + return true; +} + +bool CDROM_Interface_Image::HasDataTrack(void) +{ + //Data track has attribute 0x14 + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == DATA_TRACK) return true; + } + return false; +} + +bool CDROM_Interface_Image::HasAudioTracks(void) +{ + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; +} + + +bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +{ + // check if file exists + struct stat test; + if (stat(filename.c_str(), &test) == 0) return true; + + // check if file with path relative to cue file exists + string tmpstr(pathname + "/" + filename); + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } +#if defined (WIN32) || defined(OS2) + //Nothing +#else + //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) + //which is common for some commercial rereleases of DOS games using DOSBox + + string copy = filename; + size_t l = copy.size(); + for (size_t i = 0; i < l;i++) { + if(copy[i] == '\\') copy[i] = '/'; + } + + if (stat(copy.c_str(), &test) == 0) { + filename = copy; + return true; + } + + tmpstr = pathname + "/" + copy; + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } + +#endif + return false; +} + +bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) +{ + in >> keyword; + for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); + + return true; +} + +bool CDROM_Interface_Image::GetCueFrame(int &frames, istream &in) +{ + string msf; + in >> msf; + int min, sec, fr; + bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; + frames = MSF_TO_FRAMES(min, sec, fr); + + return success; +} + +bool CDROM_Interface_Image::GetCueString(string &str, istream &in) +{ + int pos = (int)in.tellg(); + in >> str; + if (str[0] == '\"') { + if (str[str.size() - 1] == '\"') { + str.assign(str, 1, str.size() - 2); + } else { + in.seekg(pos, ios::beg); + char buffer[MAX_FILENAME_LENGTH]; + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); + str = buffer; + } + } + return true; +} + +void CDROM_Interface_Image::ClearTracks() +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); + + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; + } + i++; + } + tracks.clear(); +} diff --git a/src/cdrom_dosbox.h b/src/cdrom_dosbox.h new file mode 100644 index 000000000..39ed79bed --- /dev/null +++ b/src/cdrom_dosbox.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#include +#include +#include +#include +#include +#include +//#include "dosbox.h" +//#include "mem.h" +//#include "mixer.h" +//#include "SDL.h" +//#include "SDL_thread.h" + +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +typedef size_t PhysPt; + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + int value = f; \ + *(F) = value%CD_FPS; \ + value /= CD_FPS; \ + *(S) = value%60; \ + value /= 60; \ + *(M) = value; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + +extern int CDROM_GetMountType(char* path, int force); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path, int forceCD) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; + + virtual void InitNewMedia (void) {}; +}; + +class CDROM_Interface_Image : public CDROM_Interface +{ +private: + class TrackFile { + public: + virtual bool read(Bit8u *buffer, int seek, int count) = 0; + virtual int getLength() = 0; + virtual ~TrackFile() { }; + }; + + class BinaryFile : public TrackFile { + public: + BinaryFile(const char *filename, bool &error); + ~BinaryFile(); + bool read(Bit8u *buffer, int seek, int count); + int getLength(); + private: + BinaryFile(); + std::ifstream *file; + }; + + struct Track { + int number; + int track_number; + int attr; + int start; + int length; + int skip; + int sectorSize; + bool mode2; + TrackFile *file; + }; + +public: + CDROM_Interface_Image (); + virtual ~CDROM_Interface_Image (void); + void InitNewMedia (void); + bool SetDevice (char* path, int forceCD); + bool GetUPC (unsigned char& attr, char* upc); + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); + bool LoadUnloadMedia (bool unload); + bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); + bool IsMode2 (unsigned long sector); + bool HasDataTrack (void); + bool HasAudioTracks (void); + + int GetTrack (int sector); + +private: + // player +static void CDAudioCallBack(Bitu len); + + void ClearTracks(); + bool LoadIsoFile(char *filename); + bool CanReadPVD(TrackFile *file, int sectorSize, bool mode2); + // cue sheet processing + bool LoadCueSheet(char *cuefile); + bool GetRealFileName(std::string& filename, std::string& pathname); + bool GetCueKeyword(std::string &keyword, std::istream &in); + bool GetCueFrame(int &frames, std::istream &in); + bool GetCueString(std::string &str, std::istream &in); + bool AddTrack(Track &curr, int &shift, int prestart, int &totalPregap, int currPregap); + + std::vector tracks; +typedef std::vector::iterator track_it; + std::string mcn; +}; + +#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom_image.cc b/src/cdrom_image.cc new file mode 100644 index 000000000..831255db8 --- /dev/null +++ b/src/cdrom_image.cc @@ -0,0 +1,1045 @@ +/* Copyright holders: RichardG867, Tenshi, bit + see COPYING for more details +*/ +/*CD-ROM image support*/ + +#include + +#include "config.h" +#include "cdrom_dosbox.h" +#include "cdrom.h" +#include "cdrom_image.h" +#include "cdrom_null.h" + +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE + +#include + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +extern CDROM image_cdrom; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +int cdrom_image_do_log = 0; + +CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; + +void cdrom_image_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_IMAGE_LOG + if (cdrom_image_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +void image_close(uint8_t id); + +void image_audio_callback(uint8_t id, int16_t *output, int len) +{ + if ((cdrom_image[id].cd_state != CD_PLAYING) || (cdrom_image[id].image_is_iso)) + { + memset(output, 0, len * 2); + return; + } + while (cdrom_image[id].cd_buflen < len) + { + if (cdrom[id].seek_pos < cdrom_image[id].cd_end) + { + if (!cdimg[id]->ReadSector((unsigned char*)&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos - 150)) + { + memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + cdrom_image[id].cd_state = CD_STOPPED; + cdrom_image[id].cd_buflen = len; + } + else + { + cdrom[id].seek_pos++; + cdrom_image[id].cd_buflen += (RAW_SECTOR_SIZE / 2); + } + } + else + { + memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + cdrom_image[id].cd_state = CD_STOPPED; + cdrom_image[id].cd_buflen = len; + } + } + memcpy(output, cdrom_image[id].cd_buffer, len * 2); + memmove(cdrom_image[id].cd_buffer, &cdrom_image[id].cd_buffer[len], (BUF_SIZE - len) * 2); + cdrom_image[id].cd_buflen -= len; +} + +void image_audio_stop(uint8_t id) +{ + cdrom_image[id].cd_state = CD_STOPPED; +} + +static void image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdimg[id]) return; + int number; + unsigned char attr; + TMSF tmsf; + int m = 0, s = 0, f = 0; + uint32_t start_msf = 0, end_msf = 0; + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + if (attr == DATA_TRACK) + { + cdrom_image_log("Can't play data track\n"); + cdrom[id].seek_pos = 0; + cdrom_image[id].cd_state = CD_STOPPED; + return; + } + cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf == 2) + { + cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); + pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr); + cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); + len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr); + } + else if (ismsf == 1) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + + if (pos == 0xffffff) + { + cdrom_image_log("Playing from current position (MSF)\n"); + pos = cdrom[id].seek_pos; + } + else + { + pos = MSFtoLBA(m, s, f); + } + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + + cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); + } + else if (ismsf == 0) + { + if (pos == 0xffffffff) + { + cdrom_image_log("Playing from current position\n"); + pos = cdrom[id].seek_pos; + } + len += pos; + } + cdrom[id].seek_pos = pos; + cdrom_image[id].cd_end = len; + cdrom_image[id].cd_state = CD_PLAYING; + if (cdrom[id].seek_pos < 150) + cdrom[id].seek_pos = 150; + cdrom_image[id].cd_buflen = 0; +} + +static void image_pause(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (cdrom_image[id].cd_state == CD_PLAYING) + cdrom_image[id].cd_state = CD_PAUSED; +} + +static void image_resume(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (cdrom_image[id].cd_state == CD_PAUSED) + cdrom_image[id].cd_state = CD_PLAYING; +} + +static void image_stop(uint8_t id) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + cdrom_image[id].cd_state = CD_STOPPED; +} + +static void image_seek(uint8_t id, uint32_t pos) +{ + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + cdrom_image[id].cd_pos = pos; + cdrom_image[id].cd_state = CD_STOPPED; +} + +static int image_ready(uint8_t id) +{ + if (!cdimg[id]) + return 0; + + if (wcslen(cdrom_image[id].image_path) == 0) + return 0; + + if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) + { + return 1; + } + + if (cdrom_image[id].image_changed) + { + cdrom_image[id].image_changed = 0; + return 1; + } + + return 1; +} + +static int image_get_last_block(uint8_t id, uint8_t starttrack, int msf, int maxlen, int single) +{ + int c; + uint32_t lb=0; + + if (!cdimg[id]) return 0; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + for (c = 0; c <= last_track; c++) + { + uint32_t address; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + if (address > lb) + lb = address; + } + return lb; +} + +static int image_medium_changed(uint8_t id) +{ + if (!cdimg[id]) + return 0; + + if (wcslen(cdrom_image[id].image_path) == 0) + { + return 0; + } + + if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + return 1; + } + + if (cdrom_image[id].image_changed) + { + cdrom_image[id].image_changed = 0; + return 1; + } + + return 0; +} + +static uint8_t image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + if (!cdimg[id]) return 0; + uint8_t ret; + int pos=0; + + uint32_t cdpos = cdrom[id].seek_pos; + if (cdpos >= 150) cdpos -= 150; + TMSF relPos, absPos; + unsigned char attr, track, index; + cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); + + if (cdrom_image[id].image_is_iso) + { + ret = 0x15; + } + else + { + if (cdrom_image[id].cd_state == CD_PLAYING) + ret = 0x11; + else if (cdrom_image[id].cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + } + + b[pos++] = attr; + b[pos++] = track; + b[pos++] = index; + + if (msf) + { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr); + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } + + return ret; +} + +static void image_eject(uint8_t id) +{ + return; +} + +static void image_load(uint8_t id) +{ + return; +} + +static int image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m, s, f; + unsigned char attr; + TMSF tmsf; + int number; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) return 0; + + if (ismsf) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + else + { + pos += 150; + } + + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + + return attr == AUDIO_TRACK; +} + +typedef struct __attribute__((__packed__)) +{ + uint8_t user_data[2048]; + uint8_t ecc[288]; +} m1_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sub_header[8]; + uint8_t user_data[2328]; +} m2_data_t; + +typedef union __attribute__((__packed__)) +{ + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2336]; +} sector_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; +} sector_raw_data_t; + +typedef union __attribute__((__packed__)) +{ + sector_raw_data_t sector_data; + uint8_t raw_data[2352]; +} sector_t; + +typedef struct __attribute__((__packed__)) +{ + sector_t sector; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union __attribute__((__packed__)) +{ + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; + +sector_buffer_t cdrom_sector_buffer; + +int cdrom_sector_size; +uint8_t raw_buffer[2352]; +uint8_t extra_buffer[296]; + +static int image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) +{ + uint8_t *b; + uint8_t *temp_b; + int real_pos; + int audio; + int mode2; + + if (!cdimg[id]) + { + return 0; + } + + if (!cdrom_drives[id].host_drive) + { + return 0; + } + + b = temp_b = buffer; + + *len = 0; + + if (ismsf) + { + real_pos = cdrom_lba_to_msf_accurate(sector); + } + else + { + real_pos = sector; + } + + if (cdrom_image[id].image_is_iso) + { + audio = 0; + mode2 = 0; + } + else + { + audio = image_is_track_audio(id, real_pos, 1); + mode2 = cdimg[id]->IsMode2(real_pos) ? 1 : 0; + } + + memset(raw_buffer, 0, 2352); + memset(extra_buffer, 0, 296); + + if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_type == 3) || (cdrom_sector_type > 4)) + { + if (cdrom_sector_type == 3) + { + cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); + } + if (cdrom_sector_type > 4) + { + cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); + } + return 0; + } + else if (cdrom_sector_type == 1) + { + if (!audio || cdrom_image[id].image_is_iso) + { + cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); + return 0; + } + +read_audio: + cdimg[id]->ReadSector(raw_buffer, true, real_pos); + memcpy(temp_b, raw_buffer, 2352); + } + else if (cdrom_sector_type == 2) + { + if (audio || mode2) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a non-Mode 1 sector from an audio track\n", id); + return 0; + } + +read_mode1: + if ((cdrom_sector_flags & 0x06) == 0x06) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) + { + cdrom_image_log("CD-ROM %i: [Mode 1] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (cdrom_image[id].image_is_iso) + { + cdimg[id]->ReadSector(raw_buffer + 16, false, real_pos); + + uint8_t *bb = raw_buffer; + + /* sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + bb[0] = (real_pos >> 16) & 0xff; + bb[1] = (real_pos >> 8) & 0xff; + bb[2] = real_pos & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += 4; + bb += 2048; + memset(bb, 0, 288); + } + else + { + cdimg[id]->ReadSector(raw_buffer, true, real_pos); + } + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) /* Sync */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); + memcpy(temp_b, raw_buffer, 12); + cdrom_sector_size += 12; + temp_b += 12; + } + + if (cdrom_sector_flags & 0x20) /* Header */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); + memcpy(temp_b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + temp_b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + if (!(cdrom_sector_flags & 0x10)) /* No user data */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); + memcpy(temp_b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + } + + if (cdrom_sector_flags & 0x10) /* User data */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); + memcpy(temp_b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); + memcpy(temp_b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + temp_b += 288; + } + } + else if (cdrom_sector_type == 4) + { + if (audio || !mode2 || cdrom_image[id].image_is_iso) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a non-XA Mode 2 Form 1 sector from an audio track\n", id); + return 0; + } + +read_mode2: + if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) /* 0xBx and 0xDx are illegal modes */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_flags & 0x06) == 0x06) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + cdimg[id]->ReadSector(cdrom_sector_buffer.buffer, true, real_pos); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) /* Sync */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); + memcpy(temp_b, raw_buffer, 12); + cdrom_sector_size += 12; + temp_b += 12; + } + + if (cdrom_sector_flags & 0x20) /* Header */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); + memcpy(temp_b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + temp_b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); + memcpy(temp_b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + + if (cdrom_sector_flags & 0x10) /* User data */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); + memcpy(temp_b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); + memcpy(temp_b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + temp_b += 280; + } + } + else + { + if (mode2) + { + goto read_mode2; + } + else + { + if (audio) + { + goto read_audio; + } + else + { + goto read_mode1; + } + } + } + + if ((cdrom_sector_flags & 0x06) == 0x02) + { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; + } + else if ((cdrom_sector_flags & 0x06) == 0x04) + { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Full error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) + { + cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 96); + cdrom_sector_size += 96; + } + else if ((cdrom_sector_flags & 0x700) == 0x200) + { + cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 16); + cdrom_sector_size += 16; + } + else if ((cdrom_sector_flags & 0x700) == 0x400) + { + cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 96); + cdrom_sector_size += 96; + } + + *len = cdrom_sector_size; + + return 1; +} + + +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +static uint32_t image_size(uint8_t id) +{ + return cdrom_image[id].cdrom_capacity; +} + +static int image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + if (!cdimg[id]) return 0; + int len=4; + int c,d; + uint32_t temp; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + d = 0; + for (c = 0; c <= last_track; c++) + { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + if (number >= starttrack) + { + d=c; + break; + } + } + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + b[2] = number; + + for (c = d; c <= last_track; c++) + { + if ((len + 8) > maxlen) + break; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + +// pclog("Len %i max %i Track %02X - %02X %02X %02i:%02i:%02i %08X\n",len,maxlen,toc[c].cdte_track,toc[c].cdte_adr,toc[c].cdte_ctrl,toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame,MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame)); + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); + /* + pclog("Table of Contents:\n"); + pclog("First track - %02X\n", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, number, attr, 0, 0, tmsf.min, tmsf.sec, tmsf.fr); + } + for (c = 0;c <= last_track; c++) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, number, attr, 0, MSF_TO_FRAMES(tmsf.min, tmsf.sec, tmsf.fr)); + } + */ + return len; +} + +static int image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int len = 4; + + int number; + TMSF tmsf; + unsigned char attr; + + if (!cdimg[id]) return 0; + + cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); + + if (number == 0) + { + number = 1; + } + + b[2] = 1; + b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + uint32_t temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (maxlen < len) + { + return maxlen; + } + + return len; +} + +static int image_readtoc_raw(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int track; + int len = 4; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + int lb; + + if (!cdimg[id]) return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) + { + if ((len + 11) > maxlen) + { + cdrom_image_log("image_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + return len; + } + + cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); + + b[len++] = track; + b[len++]= attr; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + return len; +} + +static int image_status(uint8_t id) +{ + if (!cdimg[id]) return CD_STATUS_EMPTY; + if (cdrom_image[id].image_is_iso) return CD_STATUS_DATA_ONLY; + if (cdimg[id]->HasAudioTracks()) + { + switch(cdrom_image[id].cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + default: + return CD_STATUS_STOPPED; + } + } + return CD_STATUS_DATA_ONLY; +} + +void image_reset(uint8_t id) +{ +} + +void image_close(uint8_t id) +{ + cdrom_image[id].cd_state = CD_STOPPED; + if (cdimg[id]) + { + delete cdimg[id]; + cdimg[id] = NULL; + } + memset(cdrom_image[id].image_path, 0, 2048); +} + +static char afn[1024]; + +int image_open(uint8_t id, wchar_t *fn) +{ + if (wcscmp(fn, cdrom_image[id].image_path) != 0) + { + cdrom_image[id].image_changed = 1; + } + + /* Make sure image_changed stays when changing from an image to another image. */ + if (!cdrom_image[id].image_inited && (cdrom_drives[id].host_drive != 200)) cdrom_image[id].image_changed = 0; + + if (!cdrom_image[id].image_inited || cdrom_image[id].image_changed) + { + _swprintf(cdrom_image[id].image_path, L"%ws", fn); + } + + if (!wcsicmp(get_extension_w(fn), L"ISO")) + { + cdrom_image[id].image_is_iso = 1; + } + else + { + cdrom_image[id].image_is_iso = 0; + } + + cdimg[id] = new CDROM_Interface_Image(); + wcstombs(afn, fn, (wcslen(fn) << 1) + 2); + if (!cdimg[id]->SetDevice(afn, false)) + { + image_close(id); + cdrom_set_null_handler(id); + return 1; + } + cdrom_image[id].cd_state = CD_STOPPED; + cdrom[id].seek_pos = 0; + cdrom_image[id].cd_buflen = 0; + cdrom_image[id].cdrom_capacity = image_get_last_block(id, 0, 0, 4096, 0) + 1; + cdrom_drives[id].handler = &image_cdrom; + + if (!cdrom_image[id].image_inited || cdrom_image[id].image_changed) + { + if (!cdrom_image[id].image_inited) + cdrom_image[id].image_inited = 1; + } + + update_status_bar_icon_state(0x10 | id, 0); + return 0; +} + +static void image_exit(uint8_t id) +{ + cdrom_image[id].image_inited = 0; +} + +/* TODO: Check for what data type a mixed CD is. */ +static int image_media_type_id(uint8_t id) +{ + if (!cdrom_image[id].image_is_iso) + { + return 3; /* Mixed mode CD. */ + } + + if (image_size(id) <= 405000) + { + return 1; /* Data CD. */ + } + else + { + return 65; /* DVD. */ + } +} + +CDROM image_cdrom = +{ + image_ready, + image_medium_changed, + image_media_type_id, + image_audio_callback, + image_audio_stop, + image_readtoc, + image_readtoc_session, + image_readtoc_raw, + image_getcurrentsubchannel, + NULL, + image_readsector_raw, + image_playaudio, + image_load, + image_eject, + image_pause, + image_resume, + image_size, + image_status, + image_is_track_audio, + image_stop, + image_exit +}; diff --git a/src/cdrom_image.h b/src/cdrom_image.h new file mode 100644 index 000000000..4ea4cb78f --- /dev/null +++ b/src/cdrom_image.h @@ -0,0 +1,28 @@ +/* Copyright holders: RichardG867, Tenshi + see COPYING for more details +*/ +#ifndef CDROM_IMAGE_H +#define CDROM_IMAGE_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int image_open(uint8_t id, wchar_t *fn); +extern void image_reset(uint8_t id); + +extern void image_close(uint8_t id); + +void update_status_bar_icon_state(int tag, int state); +extern void cdrom_set_null_handler(uint8_t id); + +void pclog(const char *format, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* ! CDROM_IMAGE_H */ diff --git a/src/cdrom_ioctl.c b/src/cdrom_ioctl.c new file mode 100644 index 000000000..8d8e28612 --- /dev/null +++ b/src/cdrom_ioctl.c @@ -0,0 +1,1099 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +/*Win32 CD-ROM support via IOCTL*/ + +#define WINVER 0x0600 +#include +#include +#include "ntddcdrm.h" +#include "ntddscsi.h" +#include "ibm.h" +#include "cdrom.h" +#include "cdrom_ioctl.h" +#include "scsi.h" + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +static CDROM ioctl_cdrom; + +typedef struct +{ + HANDLE hIOCTL; + CDROM_TOC toc; +} cdrom_ioctl_windows_t; + +cdrom_ioctl_windows_t cdrom_ioctl_windows[CDROM_NUM]; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +int cdrom_ioctl_do_log = 0; + +void cdrom_ioctl_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_LOG + if (cdrom_ioctl_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + +void ioctl_audio_callback(uint8_t id, int16_t *output, int len) +{ + RAW_READ_INFO in; + DWORD count; + + if (cdrom_ioctl[id].cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + while (cdrom_ioctl[id].cd_buflen < len) + { + if (cdrom[id].seek_pos < cdrom_ioctl[id].cd_end) + { + in.DiskOffset.LowPart = (cdrom[id].seek_pos - 150) * 2048; + in.DiskOffset.HighPart = 0; + in.SectorCount = 1; + in.TrackMode = CDDA; + ioctl_open(id, 0); + if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) + { + memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl[id].cd_buflen = len; + } + else + { + cdrom[id].seek_pos++; + cdrom_ioctl[id].cd_buflen += (2352 / 2); + } + ioctl_close(id); + } + else + { + memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl[id].cd_buflen = len; + } + } + memcpy(output, cdrom_ioctl[id].cd_buffer, len * 2); + memcpy(&cdrom_ioctl[id].cd_buffer[0], &(cdrom_ioctl[id].cd_buffer[len]), (BUF_SIZE - len) * 2); + cdrom_ioctl[id].cd_buflen -= len; +} + +void ioctl_audio_stop(uint8_t id) +{ + cdrom_ioctl[id].cd_state = CD_STOPPED; +} + +static int get_track_nr(uint8_t id, uint32_t pos) +{ + int c; + int track = 0; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + if (cdrom_ioctl[id].last_track_pos == pos) + { + return cdrom_ioctl[id].last_track_nr; + } + + for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + uint32_t track_address = cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] * 75) + + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + { + track = c; + } + } + cdrom_ioctl[id].last_track_pos = pos; + cdrom_ioctl[id].last_track_nr = track; + + return track; +} + +static uint32_t get_track_msf(uint8_t id, uint32_t track_no) +{ + int c; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + if (c == track_no) + { + return cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] << 8) + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] << 16); + } + } + return 0xffffffff; +} + +static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) +{ + int m = 0, s = 0, f = 0; + uint32_t start_msf = 0, end_msf = 0; + if (!cdrom_drives[id].host_drive) + { + return; + } + if (ismsf == 2) + { + start_msf = get_track_msf(id, pos); + end_msf = get_track_msf(id, len); + if (start_msf == 0xffffffff) + { + return; + } + if (end_msf == 0xffffffff) + { + return; + } + m = (start_msf >> 16) & 0xff; + s = (start_msf >> 8) & 0xff; + f = start_msf & 0xff; + pos = MSFtoLBA(m, s, f); + m = (end_msf >> 16) & 0xff; + s = (end_msf >> 8) & 0xff; + f = end_msf & 0xff; + len = MSFtoLBA(m, s, f); + } + else if (ismsf == 1) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + + if (pos == 0xffffff) + { + cdrom_ioctl_log("Playing from current position (MSF)\n"); + pos = cdrom[id].seek_pos; + } + else + { + pos = MSFtoLBA(m, s, f); + } + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + } + else if (ismsf == 0) + { + if (pos == 0xffffffff) + { + cdrom_ioctl_log("Playing from current position\n"); + pos = cdrom[id].seek_pos; + } + len += pos; + } + cdrom[id].seek_pos = pos; + cdrom_ioctl[id].cd_end = len; + if (cdrom[id].seek_pos < 150) + { + /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ + cdrom[id].seek_pos = 150; + } + cdrom_ioctl[id].cd_state = CD_PLAYING; +} + +static void ioctl_pause(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl[id].cd_state == CD_PLAYING) + { + cdrom_ioctl[id].cd_state = CD_PAUSED; + } +} + +static void ioctl_resume(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + if (cdrom_ioctl[id].cd_state == CD_PAUSED) + { + cdrom_ioctl[id].cd_state = CD_PLAYING; + } +} + +static void ioctl_stop(uint8_t id) +{ + if (!cdrom_drives[id].host_drive) + { + return; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; +} + +static int ioctl_ready(uint8_t id) +{ + unsigned long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + ioctl_open(id, 0); + temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(id); + if (!temp) + { + return 0; + } + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3]) || + !cdrom_ioctl[id].tocvalid || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + } + return 1; + } + return 1; +} + +static int ioctl_get_last_block(uint8_t id, unsigned char starttrack, int msf, int maxlen, int single) +{ + unsigned long size; + int c, d = 0; + CDROM_TOC lbtoc; + int lb = 0; + if (!cdrom_drives[id].host_drive) + { + return 0; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_open(id, 0); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, &lbtoc, sizeof(lbtoc), &size, NULL); + ioctl_close(id); + cdrom_ioctl[id].tocvalid=1; + for (c=d; c <= lbtoc.LastTrack; c++) + { + uint32_t address; + address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1], cdrom_ioctl_windows[id].toc.TrackData[c].Address[2], cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); + if (address > lb) + { + lb = address; + } + } + return lb; +} + +static int ioctl_medium_changed(uint8_t id) +{ + unsigned long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drives[id].host_drive) + { + return 0; /* This will be handled by the not ready handler instead. */ + } + ioctl_open(id, 0); + temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc,sizeof(ltoc), &size, NULL); + ioctl_close(id); + if (!temp) + { + return 0; /* Drive empty, a not ready handler matter, not disc change. */ + } + if (!cdrom_ioctl[id].tocvalid || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl_windows[id].toc = ltoc; + cdrom_ioctl[id].tocvalid = 1; + if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) + { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + } + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); + return 1; + } + else + { + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3])) + { + cdrom_ioctl[id].cd_state = CD_STOPPED; + cdrom_ioctl_log("Setting TOC...\n"); + cdrom_ioctl_windows[id].toc = ltoc; + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); + return 1; /* TOC mismatches. */ + } + } + return 0; /* None of the above, return 0. */ +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + unsigned long size; + int pos = 0, track; + uint32_t cdpos, track_address, dat; + + if (!cdrom_drives[id].host_drive) return 0; + + cdpos = cdrom[id].seek_pos; + + if (cdrom_ioctl[id].last_subchannel_pos == cdpos) + { + memcpy(&insub, cdrom_ioctl[id].sub_q_data_format, sizeof(insub)); + memcpy(&sub, cdrom_ioctl[id].sub_q_channel_data, sizeof(sub)); + } + else + { + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + ioctl_open(id, 0); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); + ioctl_close(id); + memset(cdrom_ioctl[id].sub_q_data_format, 0, 16); + memcpy(cdrom_ioctl[id].sub_q_data_format, &insub, sizeof(insub)); + memset(cdrom_ioctl[id].sub_q_channel_data, 0, 256); + memcpy(cdrom_ioctl[id].sub_q_channel_data, &sub, sizeof(sub)); + cdrom_ioctl[id].last_subchannel_pos = cdpos; + } + + if (cdrom_ioctl[id].cd_state == CD_PLAYING || cdrom_ioctl[id].cd_state == CD_PAUSED) + { + track = get_track_nr(id, cdpos); + track_address = cdrom_ioctl_windows[id].toc.TrackData[track].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[2] * 75) + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[1] * 75 * 60); + + cdrom_ioctl_log("cdpos = %i, track = %i, track_address = %i\n", cdpos, track, track_address); + + b[pos++] = sub.CurrentPosition.Control; + b[pos++] = track + 1; + b[pos++] = sub.CurrentPosition.IndexNumber; + + if (msf) + { + dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + if (cdrom_ioctl[id].cd_state == CD_PLAYING) return 0x11; + return 0x12; + } + + b[pos++]=sub.CurrentPosition.Control; + b[pos++]=sub.CurrentPosition.TrackNumber; + b[pos++]=sub.CurrentPosition.IndexNumber; + + cdrom_ioctl_log("cdpos = %i, track_address = %i\n", MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]), MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3])); + + if (msf) + { + int c; + for (c = 0; c < 4; c++) + { + b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; + } + for (c = 0; c < 4; c++) + { + b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; + } + } + else + { + uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + } + + return 0x13; +} + +static void ioctl_eject(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_open(id, 0); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(id); +} + +static void ioctl_load(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_open(id, 0); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(id); + cdrom_ioctl[id].cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); +} + +static int is_track_audio(uint8_t id, uint32_t pos) +{ + int c; + int control = 0; + + uint32_t track_address = 0; + + if (!cdrom_ioctl[id].tocvalid) + { + return 0; + } + + for (c = 0; c <= cdrom_ioctl_windows[id].toc.LastTrack; c++) + { + track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); + + if (track_address <= pos) + { + control = cdrom_ioctl_windows[id].toc.TrackData[c].Control; + } + } + + if ((control & 0xd) <= 1) + { + return 1; + } + else + { + return 0; + } +} + +static int ioctl_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m = 0, s = 0, f = 0; + + if (ismsf) + { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + else + { + pos += 150; + } + return is_track_audio(id, pos); +} + +/* 00, 08, 10, 18, 20, 28, 30, 38 */ +int flags_to_size[5][32] = { { 0, 0, 2352, 2352, 2352, 2352, 2352, 2352, /* 00-38 (CD-DA) */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 40-78 */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 80-B8 */ + 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352 }, /* C0-F8 */ + { 0, 0, 2048, 2336, 4, -296, 2052, 2344, /* 00-38 (Mode 1) */ + 8, -296, 2048, 2048, 12, -296, 2052, 2052, /* 40-78 */ + -296, -296, -296, -296, 16, -296, 2064, 2344, /* 80-B8 */ + -296, -296, 2048, 2048, 24, -296, 2064, 2352 }, /* C0-F8 */ + { 0, 0, 2336, 2336, 4, -296, 2340, 2340, /* 00-38 (Mode 2 non-XA) */ + 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, 2352, 2340, /* 80-B8 */ + -296, -296, 2336, 2336, 24, -296, 2352, 2352 }, /* C0-F8 */ + { 0, 0, 2048, 2336, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 1) */ + 8, -296, 2056, 2344, 12, -296, 2060, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ + -296, -296, -296, -296, 24, -296, 2072, 2352 }, /* C0-F8 */ + { 0, 0, 2328, 2328, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 2) */ + 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ + -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ + -296, -296, -296, -296, 24, -296, 2352, 2352 } /* C0-F8 */ + }; + +static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf); + +static void cdrom_illegal_mode(uint8_t id) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + cdrom_ascq = 0; +} + +struct sptd_with_sense +{ + SCSI_PASS_THROUGH s; + ULONG Filler; + UCHAR sense[32]; + UCHAR data[65536]; +} sptd; + +static int ioctl_get_block_length(uint8_t id, const UCHAR *cdb, int number_of_blocks, int no_length_check) +{ + int sector_type = 0; + int temp_len = 0; + + if (no_length_check) + { + switch (cdb[0]) + { + case 0x25: + /* READ CAPACITY */ + return 8; + case 0x42: /* READ SUBCHANNEL */ + case 0x43: /* READ TOC */ + case 0x51: /* READ DISC INFORMATION */ + case 0x52: /* READ TRACK INFORMATION */ + case 0x5A: /* MODE SENSE (10) */ + return ((uint16_t) cdb[8]) + (((uint16_t) cdb[7]) << 8); + default: + return 65534; + } + } + + switch (cdb[0]) + { + case 0x25: + /* READ CAPACITY */ + return 8; + case 0x42: /* READ SUBCHANNEL */ + case 0x43: /* READ TOC */ + case 0x51: /* READ DISC INFORMATION */ + case 0x52: /* READ TRACK INFORMATION */ + case 0x5A: /* MODE SENSE (10) */ + return ((uint16_t) cdb[8]) + (((uint16_t) cdb[7]) << 8); + case 0x08: + case 0x28: + case 0xa8: + /* READ (6), READ (10), READ (12) */ + return 2048 * number_of_blocks; + break; + case 0xb9: + sector_type = (cdb[1] >> 2) & 7; + if (sector_type == 0) + { + sector_type = ioctl_get_sector_data_type(id, 0, cdb[3], cdb[4], cdb[5], 1); + if (sector_type == 0) + { + cdrom_illegal_mode(id); + return -1; + } + } + goto common_handler; + case 0xbe: + /* READ CD MSF, READ CD */ + sector_type = (cdb[1] >> 2) & 7; + if (sector_type == 0) + { + sector_type = ioctl_get_sector_data_type(id, cdb[2], cdb[3], cdb[4], cdb[5], 0); + if (sector_type == 0) + { + cdrom_illegal_mode(id); + return -1; + } + } +common_handler: + temp_len = flags_to_size[sector_type - 1][cdb[9] >> 3]; + if ((cdb[9] & 6) == 2) + { + temp_len += 294; + } + else if ((cdb[9] & 6) == 4) + { + temp_len += 296; + } + if ((cdb[10] & 7) == 1) + { + temp_len += 96; + } + else if ((cdb[10] & 7) == 2) + { + temp_len += 16; + } + else if ((cdb[10] & 7) == 4) + { + temp_len += 96; + } + if (temp_len <= 0) + { + cdrom_illegal_mode(id); + return -1; + } + return temp_len * cdrom[id].requested_blocks; + break; + default: + /* Other commands */ + return 65534; + break; + } + +} + +static int SCSICommand(uint8_t id, const UCHAR *cdb, UCHAR *buf, uint32_t *len, int no_length_check) +{ + DWORD ioctl_bytes; + int ioctl_rv = 0; + + SCSISense.SenseKey = 0; + SCSISense.Asc = 0; + SCSISense.Ascq = 0; + + *len = 0; + memset(&sptd, 0, sizeof(sptd)); + sptd.s.Length = sizeof(SCSI_PASS_THROUGH); + sptd.s.CdbLength = 12; + sptd.s.DataIn = SCSI_IOCTL_DATA_IN; + sptd.s.TimeOutValue = 80 * 60; + sptd.s.DataTransferLength = ioctl_get_block_length(id, cdb, cdrom_ioctl[id].actual_requested_blocks, no_length_check); + sptd.s.SenseInfoOffset = (uintptr_t)&sptd.sense - (uintptr_t)&sptd; + sptd.s.SenseInfoLength = 32; + sptd.s.DataBufferOffset = (uintptr_t)&sptd.data - (uintptr_t)&sptd; + + memcpy(sptd.s.Cdb, cdb, 12); + ioctl_rv = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_SCSI_PASS_THROUGH, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + + if (sptd.s.SenseInfoLength) + { + cdrom_sense_key = sptd.sense[2]; + cdrom_asc = sptd.sense[12]; + cdrom_ascq = sptd.sense[13]; + } + + cdrom_ioctl_log("Transferred length: %i (command: %02X)\n", sptd.s.DataTransferLength, cdb[0]); + cdrom_ioctl_log("Sense length: %i (%02X %02X %02X %02X %02X)\n", sptd.s.SenseInfoLength, sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[12], sptd.sense[13]); + cdrom_ioctl_log("IOCTL bytes: %i; SCSI status: %i, status: %i, LastError: %08X\n", ioctl_bytes, sptd.s.ScsiStatus, ioctl_rv, GetLastError()); + cdrom_ioctl_log("DATA: %02X %02X %02X %02X %02X %02X\n", sptd.data[0], sptd.data[1], sptd.data[2], sptd.data[3], sptd.data[4], sptd.data[5]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[6], sptd.data[7], sptd.data[8], sptd.data[9], sptd.data[10], sptd.data[11]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[12], sptd.data[13], sptd.data[14], sptd.data[15], sptd.data[16], sptd.data[17]); + cdrom_ioctl_log("SENSE: %02X %02X %02X %02X %02X %02X\n", sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[3], sptd.sense[4], sptd.sense[5]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[6], sptd.sense[7], sptd.sense[8], sptd.sense[9], sptd.sense[10], sptd.sense[11]); + cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[12], sptd.sense[13], sptd.sense[14], sptd.sense[15], sptd.sense[16], sptd.sense[17]); + *len = sptd.s.DataTransferLength; + if (sptd.s.DataTransferLength != 0) + { + memcpy(buf, sptd.data, sptd.s.DataTransferLength); + } + + return ioctl_rv; +} + +static void ioctl_read_capacity(uint8_t id, uint8_t *b) +{ + uint32_t len = 0; + + const UCHAR cdb[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + UCHAR buf[16]; + + if (!cdrom_ioctl[id].capacity_read) + { + ioctl_open(id, 0); + + SCSICommand(id, cdb, buf, &len, 1); + + memcpy(cdrom_ioctl[id].rcbuf, buf, len); + cdrom_ioctl[id].capacity_read = 1; + } + else + { + memcpy(b, cdrom_ioctl[id].rcbuf, 16); + } + + ioctl_close(id); +} + +static int ioctl_media_type_id(uint8_t id) +{ + uint8_t old_sense[3] = { 0, 0, 0 }; + + UCHAR msbuf[28]; + uint32_t len = 0; + int sense = 0; + + const UCHAR cdb[] = { 0x5A, 0x00, 0x2A, 0, 0, 0, 0, 0, 28, 0, 0, 0 }; + + old_sense[0] = cdrom_sense_key; + old_sense[1] = cdrom_asc; + old_sense[2] = cdrom_asc; + + ioctl_open(id, 0); + + SCSICommand(id, cdb, msbuf, &len, 1); + + ioctl_close(id); + + sense = cdrom_sense_key; + cdrom_sense_key = old_sense[0]; + cdrom_asc = old_sense[1]; + cdrom_asc = old_sense[2]; + + if (sense == 0) + { + return msbuf[2]; + } + else + { + return 3; + } +} + +static uint32_t msf_to_lba32(int lba) +{ + int m = (lba >> 16) & 0xff; + int s = (lba >> 8) & 0xff; + int f = lba & 0xff; + return (m * 60 * 75) + (s * 75) + f; +} + +static int ioctl_get_type(uint8_t id, UCHAR *cdb, UCHAR *buf) +{ + int i = 0; + int ioctl_rv = 0; + + uint32_t len = 0; + + for (i = 2; i <= 5; i++) + { + cdb[1] = i << 2; + ioctl_rv = SCSICommand(id, cdb, buf, &len, 1); /* Bypass length check so we don't risk calling this again and getting stuck in an endless up. */ + if (ioctl_rv) + { + return i; + } + } + return 0; +} + +static int ioctl_sector_data_type(uint8_t id, int sector, int ismsf) +{ + int ioctl_rv = 0; + UCHAR cdb_lba[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 }; + UCHAR cdb_msf[] = { 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0 }; + UCHAR buf[2352]; + + cdb_lba[2] = (sector >> 24); + cdb_lba[3] = ((sector >> 16) & 0xff); + cdb_lba[4] = ((sector >> 8) & 0xff); + cdb_lba[5] = (sector & 0xff); + + cdb_msf[3] = cdb_msf[6] = ((sector >> 16) & 0xff); + cdb_msf[4] = cdb_msf[7] = ((sector >> 8) & 0xff); + cdb_msf[5] = cdb_msf[8] = (sector & 0xff); + + ioctl_open(id, 0); + + if (ioctl_is_track_audio(id, sector, ismsf)) + { + return 1; + } + + if (ismsf) + { + ioctl_rv = ioctl_get_type(id, cdb_msf, buf); + } + else + { + ioctl_rv = ioctl_get_type(id, cdb_lba, buf); + } + + if (ioctl_rv) + { + ioctl_close(id); + return ioctl_rv; + } + + if (ismsf) + { + sector = msf_to_lba32(sector); + if (sector < 150) + { + ioctl_close(id); + return 0; + } + sector -= 150; + ioctl_rv = ioctl_get_type(id, (UCHAR *) cdb_lba, buf); + } + + ioctl_close(id); + return ioctl_rv; +} + +static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf) +{ + int sector = b3; + sector |= ((uint32_t) b2) << 8; + sector |= ((uint32_t) b1) << 16; + sector |= ((uint32_t) b0) << 24; + return ioctl_sector_data_type(id, sector, ismsf); +} + +static void ioctl_validate_toc(uint8_t id) +{ + unsigned long size; + if (!cdrom_drives[id].host_drive) + { + return; + } + cdrom_ioctl[id].cd_state = CD_STOPPED; + ioctl_open(id, 0); + cdrom_ioctl_log("Validating TOC...\n"); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&cdrom_ioctl_windows[id].toc,sizeof(cdrom_ioctl_windows[id].toc),&size,NULL); + ioctl_close(id); + cdrom_ioctl[id].tocvalid=1; +} + +UCHAR buf[262144]; + +static int ioctl_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) +{ + const UCHAR cdb[12]; + + int ret = 0; + + int block_length = 0; + + int temp_block_length = 0; + int temp_pos = 0; + + int blocks_at_once = 0; + int buffer_pos = 0; + + int transferred_blocks = 0; + + uint32_t temp_len = 0; + int chunk = 0; + + if (in_cdb[0] == 0x43) + { + /* This is a read TOC, so we have to validate the TOC to make the rest of the emulator happy. */ + ioctl_validate_toc(id); + } + + ioctl_open(id, 0); + + memcpy((void *) cdb, in_cdb, 12); + + temp_block_length = ioctl_get_block_length(id, cdb, cdrom[id].requested_blocks, 0); + *len = 0; + if (temp_block_length != -1) + { + if (temp_block_length > 65534) + { + block_length = temp_block_length / cdrom[id].requested_blocks; + blocks_at_once = 32768 / block_length; + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is bigger than 65534, splitting the transfer into chunks of %i blocks...\n", id, temp_block_length, blocks_at_once); + + buffer_pos = 0; + temp_pos = cdrom[id].sector_pos; + transferred_blocks = 0; + temp_len = 0; + +split_block_read_iterate: + chunk = (cdrom[id].requested_blocks - transferred_blocks); + if (chunk < blocks_at_once) + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): The remaining chunk (%i blocks) is less than a complete split block\n", id, chunk); + cdrom_ioctl[id].actual_requested_blocks = chunk; + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): The remaining chunk (%i blocks) is more or equal than a complete split block\n", id, chunk); + cdrom_ioctl[id].actual_requested_blocks = blocks_at_once; + } + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Transferring %i blocks...\n", id, cdrom_ioctl[id].actual_requested_blocks); + cdrom_update_cdb((uint8_t *) cdb, temp_pos, cdrom_ioctl[id].actual_requested_blocks); + ret = SCSICommand(id, cdb, buf + buffer_pos, &temp_len, 0); + *len += temp_len; + transferred_blocks += cdrom_ioctl[id].actual_requested_blocks; + if (ret && (transferred_blocks < cdrom[id].requested_blocks)) + { + /* Return value was successful and there are still more blocks left to transfer. */ + temp_pos += cdrom_ioctl[id].actual_requested_blocks; + buffer_pos += (cdrom_ioctl[id].actual_requested_blocks * block_length); + goto split_block_read_iterate; + } + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Split transfer done\n", id); + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is smaller than 65534, transferring all at once...\n", id, temp_block_length); + cdrom_ioctl[id].actual_requested_blocks = cdrom[id].requested_blocks; + ret = SCSICommand(id, cdb, buf, len, 0); + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Single transfer done\n", id); + } + memcpy(b, buf, *len); + } + else + { + cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is -1, this indicates an illegal mode\n", id, temp_block_length); + } + + cdrom_ioctl_log("IOCTL DATA: %02X %02X %02X %02X %02X %02X %02X %02X\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); + + ioctl_close(id); + + cdrom_ioctl_log("IOCTL Returned value: %i\n", ret); + + return ret; +} + +static uint32_t ioctl_size(uint8_t id) +{ + uint8_t capacity_buffer[8]; + uint32_t capacity = 0; + ioctl_read_capacity(id, capacity_buffer); + capacity = ((uint32_t) capacity_buffer[0]) << 24; + capacity |= ((uint32_t) capacity_buffer[1]) << 16; + capacity |= ((uint32_t) capacity_buffer[2]) << 8; + capacity |= (uint32_t) capacity_buffer[3]; + return capacity + 1; +} + +static int ioctl_status(uint8_t id) +{ + if (!(ioctl_ready(id)) && (cdrom_drives[id].host_drive <= 0)) + { + return CD_STATUS_EMPTY; + } + + switch(cdrom_ioctl[id].cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + default: + return CD_STATUS_EMPTY; + } +} + +void ioctl_reset(uint8_t id) +{ + CDROM_TOC ltoc; + unsigned long size; + + if (!cdrom_drives[id].host_drive) + { + cdrom_ioctl[id].tocvalid = 0; + return; + } + + ioctl_open(id, 0); + DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(id); + + cdrom_ioctl_windows[id].toc = ltoc; + cdrom_ioctl[id].tocvalid = 1; +} + +int ioctl_open(uint8_t id, char d) +{ + if (!cdrom_ioctl[id].ioctl_inited) + { + sprintf(cdrom_ioctl[id].ioctl_path,"\\\\.\\%c:",d); + cdrom_ioctl[id].tocvalid=0; + } + cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + cdrom_drives[id].handler = &ioctl_cdrom; + if (!cdrom_ioctl[id].ioctl_inited) + { + cdrom_ioctl[id].ioctl_inited=1; + cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ + ioctl_read_capacity(id, NULL); + CloseHandle(cdrom_ioctl_windows[id].hIOCTL); + cdrom_ioctl_windows[id].hIOCTL = NULL; + update_status_bar_icon_state(0x10 | id, 0); + } + return 0; +} + +void ioctl_close(uint8_t id) +{ + if (cdrom_ioctl_windows[id].hIOCTL) + { + CloseHandle(cdrom_ioctl_windows[id].hIOCTL); + cdrom_ioctl_windows[id].hIOCTL = NULL; + } +} + +static void ioctl_exit(uint8_t id) +{ + ioctl_stop(id); + cdrom_ioctl[id].ioctl_inited=0; + cdrom_ioctl[id].tocvalid=0; +} + +static CDROM ioctl_cdrom= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_media_type_id, + ioctl_audio_callback, + ioctl_audio_stop, + NULL, + NULL, + NULL, + ioctl_getcurrentsubchannel, + ioctl_pass_through, + NULL, + ioctl_playaudio, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom_ioctl.h b/src/cdrom_ioctl.h new file mode 100644 index 000000000..e39f12ddf --- /dev/null +++ b/src/cdrom_ioctl.h @@ -0,0 +1,17 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern uint32_t cdrom_capacity; + +extern int ioctl_open(uint8_t id, char d); +extern void ioctl_reset(uint8_t id); + +extern void ioctl_close(uint8_t id); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom_ioctl_linux.c b/src/cdrom_ioctl_linux.c new file mode 100644 index 000000000..bf1f73994 --- /dev/null +++ b/src/cdrom_ioctl_linux.c @@ -0,0 +1,725 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +/*Linux CD-ROM support via IOCTL*/ + +#include +#include +#include +#include +#include "ibm.h" +#include "ide.h" +#include "cdrom_ioctl.h" + +static ATAPI ioctl_atapi; + +static uint32_t last_block = 0; +static uint32_t cdrom_capacity = 0; +static int ioctl_inited = 0; +static char ioctl_path[8]; +static int tocvalid = 0; +static struct cdrom_tocentry toc[100]; +static int first_track, last_track; + +int old_cdrom_drive; + +#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + int fd; + struct cdrom_read_audio read_audio; + +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + { + memset(output, 0, len * 2); + return; + } + + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + read_audio.addr.lba = ioctl_cd_pos - 150; + read_audio.addr_format = CDROM_LBA; + read_audio.nframes = 1; + read_audio.buf = (__u8 *)&cd_buffer[cd_buflen]; + + if (ioctl(fd, CDROMREADAUDIO, &read_audio) < 0) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + close(fd); + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static int get_track_nr(uint32_t pos) +{ + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + track = c; + } + return track; +} + +static int is_track_audio(uint32_t pos) +{ + int c; + int control = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + control = toc[c].cdte_ctrl; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + return is_track_audio(pos); +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ +// pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60); + len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60); +// pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = pos+len;// + 150; + ioctl_cd_state = CD_PLAYING; + if (ioctl_cd_pos < 150) + ioctl_cd_pos = 150; +// pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, 0, len); +} + +static void ioctl_pause(void) +{ + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +} + +static void ioctl_resume(void) +{ + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +} + +static void ioctl_stop(void) +{ + ioctl_cd_state = CD_STOPPED; +} + +static void ioctl_seek(uint32_t pos) +{ +// pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +} + +static int read_toc(int fd, struct cdrom_tocentry *btoc) +{ + struct cdrom_tochdr toc_hdr; + int track, err; +//pclog("read_toc\n"); + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + first_track = toc_hdr.cdth_trk0; + last_track = toc_hdr.cdth_trk1; +//pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(btoc, 0, sizeof(cdrom_tocentry)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + btoc[track].cdte_track = track; + btoc[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &btoc[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + } + return 1; +} + +static int ioctl_ready(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCHDR: start track=%i end track=%i\n", toc_hdr.cdth_trk0, toc_hdr.cdth_trk1); + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame ) || + !tocvalid) + { + int track; + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + close(fd); + return 1; + } + close(fd); + return 1; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int c; + int lb = 0; + int tv = 0; + struct cdrom_tocentry lbtoc[100]; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tv = read_toc(fd, lbtoc); + + close(fd); + + if (!tv) + return 0; + + last_block = 0; + for (c = 0; c <= last_track; c++) + { + uint32_t address; + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + lb = address; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame )) + { + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 1; + } + return 0; +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + struct cdrom_subchnl sub; + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = toc[track].cdte_addr.msf.frame + + (toc[track].cdte_addr.msf.second * 75) + + (toc[track].cdte_addr.msf.minute * 75 * 60); + long size; + int pos=0; + int err; + uint8_t ret; +//pclog("ioctl_getsubchannel: cdpos=%x track_address=%x track=%i\n", cdpos, track_address, track); + if (ioctl_cd_state == CD_PLAYING) + ret = 0x11; + else if (ioctl_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = (toc[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[pos++] = track; + b[pos++] = 0; + + if (msf) + { + uint32_t dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + return ret; +} + +static void ioctl_eject(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); +} + +static void ioctl_load(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); + + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); +} + +union +{ + struct cdrom_msf *msf; + char b[CD_FRAMESIZE_RAW]; +} raw_read_params; + +static int lba_to_msf(int lba) +{ + return (((lba / 75) / 60) << 16) + (((lba / 75) % 60) << 8) + (lba % 75); +} + +static int ioctl_sector_data_type(int sector, int ismsf) +{ + return 2; /* Always Mode 1 */ +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + int err; + int imsf = lba_to_msf(sector); + int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (cdrom <= 0) + return; + + raw_read_params.msf = malloc(sizeof(struct cdrom_msf)); + raw_read_params.msf->cdmsf_frame0 = imsf & 0xff; + raw_read_params.msf->cdmsf_sec0 = (imsf >> 8) & 0xff; + raw_read_params.msf->cdmsf_min0 = (imsf >> 16) & 0xff; + + /* This will read the actual raw sectors from the disc. */ + err = ioctl(cdrom, CDROMREADRAW, (void *) &raw_read_params); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return; + } + + memcpy(b, raw_read_params.b, 2352); + + close(cdrom); + + free(raw_read_params.msf); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + + close(fd); + + if (!tocvalid) + return 4; + +// pclog("Read TOC done! %i\n",single); + b[2] = first_track; + b[3] = last_track; + d = 0; +//pclog("Read TOC starttrack=%i\n", starttrack); + for (c = 1; c <= last_track; c++) + { + if (toc[c].cdte_track >= starttrack) + { + d = c; + break; + } + } + b[2] = toc[c].cdte_track; + last_block = 0; + for (c = d; c <= last_track; c++) + { + uint32_t address; + if ((len + 8) > maxlen) + break; +// pclog("Len %i max %i Track %02X - %02X %02X %02i:%02i:%02i %08X\n",len,maxlen,toc[c].cdte_track,toc[c].cdte_adr,toc[c].cdte_ctrl,toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame,MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame)); + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[c].cdte_adr << 4) | toc[c].cdte_ctrl; + b[len++] = toc[c].cdte_track; + b[len++] = 0; /*Reserved*/ + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++] = 0; + b[len++] = toc[c].cdte_addr.msf.minute; + b[len++] = toc[c].cdte_addr.msf.second; + b[len++] = toc[c].cdte_addr.msf.frame; + } + else + { + temp = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n", size); + pclog("First track - %02X\n", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, 0, toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + for (c = 0;c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame));*/ + return len; +} + +static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + struct cdrom_multisession session; + int len = 4; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + session.addr_format = CDROM_MSF; + err = ioctl(fd, CDROMMULTISESSION, &session); + + if (err == -1) + { + close(fd); + return 0; + } + + b[2] = 0; + b[3] = 0; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[0].cdte_adr << 4) | toc[0].cdte_ctrl; + b[len++] = toc[0].cdte_track; + b[len++] = 0; /*Reserved*/ + if (msf) + { + b[len++] = 0; + b[len++] = session.addr.msf.minute; + b[len++] = session.addr.msf.second; + b[len++] = session.addr.msf.frame; + } + else + { + uint32_t temp = MSFtoLBA(session.addr.msf.minute, session.addr.msf.second, session.addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + return len; +} + +static int ioctl_readtoc_raw(unsigned char *b, int maxlen) +{ + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc2[100]; + int track, err; + int len = 4; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("read_toc\n"); + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + b[2] = toc_hdr.cdth_trk0; + b[3] = toc_hdr.cdth_trk1; + + //pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(toc, 0, sizeof(toc)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + if ((len + 11) > maxlen) + { + pclog("ioctl_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + close(fd); + return len; + } + + toc2[track].cdte_track = track; + toc2[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc2[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + close(fd); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + + b[len++] = toc2[track].cdte_track; + b[len++]= (toc2[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = toc2[track].cdte_addr.msf.minute; + b[len++] = toc2[track].cdte_addr.msf.second; + b[len++] = toc2[track].cdte_addr.msf.frame; + } + close(fd); + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!(ioctl_ready) && (cdrom_drive <= 0)) return CD_STATUS_EMPTY; + + switch(ioctl_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + } +} +void ioctl_reset() +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("ioctl_reset: fd=%i\n", fd); + tocvalid = 0; + + if (fd <= 0) + return; + + tocvalid = read_toc(fd, toc); + + close(fd); +} + +int ioctl_open(char d) +{ + atapi=&ioctl_atapi; + return 0; +} + +void ioctl_close(void) +{ +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited = 0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + NULL, + NULL, + NULL, + ioctl_sector_data_type, + ioctl_readsector_raw, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom_null.c b/src/cdrom_null.c new file mode 100644 index 000000000..5d86b7992 --- /dev/null +++ b/src/cdrom_null.c @@ -0,0 +1,130 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include "ibm.h" +#include "cdrom.h" +#include "cdrom_ioctl.h" + +static CDROM null_cdrom; + +static int null_ready(uint8_t id) +{ + return 0; +} + +/* Always return 0, the contents of a null CD-ROM drive never change. */ +static int null_medium_changed(uint8_t id) +{ + return 0; +} + +static uint8_t null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + return 0x13; +} + +static void null_eject(uint8_t id) +{ +} + +static void null_load(uint8_t id) +{ +} + +static int null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) +{ + *len = 0; + return 0; +} + +static int null_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + return 0; +} + +static int null_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + return 0; +} + +static int null_readtoc_raw(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + return 0; +} + +static uint32_t null_size(uint8_t id) +{ + return 0; +} + +static int null_status(uint8_t id) +{ + return CD_STATUS_EMPTY; +} + +void cdrom_null_reset(uint8_t id) +{ +} + +void cdrom_set_null_handler(uint8_t id); + +int cdrom_null_open(uint8_t id, char d) +{ + cdrom_set_null_handler(id); + return 0; +} + +void null_close(uint8_t id) +{ +} + +static void null_exit(uint8_t id) +{ +} + +static int null_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + return 0; +} + +static int null_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) +{ + return 0; +} + +static int null_media_type_id(uint8_t id) +{ + return 0x70; +} + +void cdrom_set_null_handler(uint8_t id) +{ + cdrom_drives[id].handler = &null_cdrom; + cdrom_drives[id].host_drive = 0; + update_status_bar_icon_state(0x10 | id, 1); +} + +static CDROM null_cdrom = +{ + null_ready, + null_medium_changed, + null_media_type_id, + NULL, + NULL, + null_readtoc, + null_readtoc_session, + null_readtoc_raw, + null_getcurrentsubchannel, + null_pass_through, + null_readsector_raw, + NULL, + null_load, + null_eject, + NULL, + NULL, + null_size, + null_status, + null_is_track_audio, + NULL, + null_exit +}; diff --git a/src/cdrom_null.h b/src/cdrom_null.h new file mode 100644 index 000000000..7217760ca --- /dev/null +++ b/src/cdrom_null.h @@ -0,0 +1,14 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#ifndef CDROM_NULL_H +#define CDROM_NULL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +int cdrom_null_open(uint8_t id, char d); +void cdrom_null_reset(uint8_t id); +void null_close(uint8_t id); + +#endif /* ! CDROM_NULL_H */