# HG changeset patch # User nkeynes # Date 1245811272 0 # Node ID 7044e01148f059c9e3b60297492621e075734645 # Parent b77b081441b5b0a4850d512ab217f9624014ec1e Add initial VMU support --- a/po/POTFILES.in Wed Jun 24 02:27:34 2009 +0000 +++ b/po/POTFILES.in Wed Jun 24 02:41:12 2009 +0000 @@ -108,6 +108,7 @@ src/maple/maple.c src/maple/maple.h src/maple/mouse.c +src/maple/vmu.c src/mem.c src/mem.h src/mmio.h @@ -170,6 +171,10 @@ src/tools/insparse.c src/util.c src/version.c +src/vmu/vmulist.c +src/vmu/vmulist.h +src/vmu/vmuvol.c +src/vmu/vmuvol.h src/watch.c src/x86dasm/ansidecl.h src/x86dasm/bfd.h --- a/po/de.po Wed Jun 24 02:27:34 2009 +0000 +++ b/po/de.po Wed Jun 24 02:41:12 2009 +0000 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: lxdream 0.8.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-12 19:52+1000\n" +"POT-Creation-Date: 2009-06-24 12:36+1000\n" "PO-Revision-Date: 2007-11-10 18:53+0100\n" "Last-Translator: Thomas Kowaliczek (LinuxDonald) LinuxDonald@LinuxDonald.de\n" "Language-Team: DE \n" @@ -15,25 +15,30 @@ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/cocoaui/cocoa_ctrl.m:342 src/gtkui/gtk_ctrl.c:294 -#, c-format -msgid "Slot %d." +#: src/cocoaui/cocoa_ctrl.m:324 src/gtkui/gtk_ctrl.c:486 +#, fuzzy, c-format +msgid "Port %c." msgstr "Slot %d." -#: src/cocoaui/cocoaui.m:404 +#: src/cocoaui/cocoa_ctrl.m:326 src/gtkui/gtk_ctrl.c:515 +#, c-format +msgid "VMU %d." +msgstr "" + +#: src/cocoaui/cocoaui.m:412 #, c-format msgid "Running (%2.4f%%)" msgstr "" -#: src/cocoaui/cocoa_win.m:192 src/gtkui/gtk_win.c:356 +#: src/cocoaui/cocoa_win.m:193 src/gtkui/gtk_win.c:356 msgid "(Press to release grab)" msgstr "" -#: src/cocoaui/cocoa_win.m:204 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:205 src/gtkui/gtk_win.c:366 msgid "Running" msgstr "" -#: src/cocoaui/cocoa_win.m:207 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:208 src/gtkui/gtk_win.c:366 msgid "Stopped" msgstr "" @@ -56,32 +61,36 @@ msgid "Save-state path" msgstr "Speicherstand pfad" -#: src/config.c:45 src/gtkui/gtk_path.c:29 +#: src/config.c:45 +msgid "VMU path" +msgstr "" + +#: src/config.c:46 src/gtkui/gtk_path.c:29 msgid "Bootstrap IP.BIN" msgstr "Bootstrap IP.BIN" -#: src/config.c:51 +#: src/config.c:53 msgid "Serial device" msgstr "" -#: src/dreamcast.c:192 +#: src/dreamcast.c:193 msgid "" "No program is loaded, and no BIOS is configured (required to boot a CD " "image). To continue, either load a binary program, or set the path to your " "BIOS file in the Path Preferences" msgstr "" -#: src/dreamcast.c:324 +#: src/dreamcast.c:328 #, c-format msgid "File is not a %s save state" msgstr "" -#: src/dreamcast.c:329 +#: src/dreamcast.c:333 #, c-format msgid "Unsupported %s save state version" msgstr "" -#: src/dreamcast.c:334 +#: src/dreamcast.c:338 #, c-format msgid "%s save state is corrupted (bad module count)" msgstr "" @@ -134,7 +143,7 @@ msgid "OS X Cocoa GUI-based OpenGL driver" msgstr "" -#: src/gdlist.c:206 src/gdlist.c:229 +#: src/gdlist.c:187 src/gdlist.c:210 msgid "Empty" msgstr "Leer" @@ -142,48 +151,65 @@ msgid "All files" msgstr "Alle Dateien" -#: src/gtkui/gtkcb.c:139 +#: src/gtkui/gtkcb.c:162 msgid "Load state..." msgstr "Speicherpunkt laden..." -#: src/gtkui/gtkcb.c:144 src/gtkui/gtkcb.c:175 +#: src/gtkui/gtkcb.c:167 src/gtkui/gtkcb.c:198 msgid "lxDream Save State (*.dst)" msgstr "lxDream Speicherpunt (*.dst)" -#: src/gtkui/gtkcb.c:237 src/gtkui/gtk_dump.c:69 +#: src/gtkui/gtkcb.c:260 src/gtkui/gtk_dump.c:69 msgid "Memory dump" msgstr "Speicher dump" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "Save next scene..." msgstr "Nächste Szene speichern" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "lxdream scene file (*.dsc)" msgstr "lxdream szene Datei (*.dsc)" -#: src/gtkui/gtkcb.c:265 +#: src/gtkui/gtkcb.c:288 msgid "No address selected, so can't run to it" msgstr "Keine Adresse ausgewählt, also kann es nicht laufen" -#: src/gtkui/gtk_ctrl.c:72 src/gtkui/gtk_ctrl.c:101 src/gtkui/gtk_hotkeys.c:50 +#: src/gtkui/gtk_ctrl.c:80 src/gtkui/gtk_ctrl.c:109 src/gtkui/gtk_hotkeys.c:50 #: src/gtkui/gtk_hotkeys.c:79 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:201 +#: src/gtkui/gtk_ctrl.c:209 msgid "Controller Configuration" msgstr "Kontroller Konfiguration" -#: src/gtkui/gtk_ctrl.c:220 +#: src/gtkui/gtk_ctrl.c:228 msgid "No configuration page available for device type" msgstr "Keine Konfigurationseite für dieses Gerät" -#: src/gtkui/gtk_ctrl.c:297 +#: src/gtkui/gtk_ctrl.c:252 +msgid "Load VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:266 +msgid "Create VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:329 src/gtkui/gtk_ctrl.c:347 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:325 +#: src/gtkui/gtk_ctrl.c:356 +#, fuzzy +msgid "Load VMU..." +msgstr "Speicherpunkt laden..." + +#: src/gtkui/gtk_ctrl.c:357 +msgid "Create VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:551 msgid "Controller Settings" msgstr "Kontroller einstellungen" @@ -571,139 +597,139 @@ msgid "Select quick save state 9" msgstr "" -#: src/main.c:85 +#: src/main.c:86 msgid "Run the AICA SPU only, with the supplied program" msgstr "" -#: src/main.c:86 +#: src/main.c:87 msgid "Use the specified audio driver (? to list)" msgstr "" -#: src/main.c:87 +#: src/main.c:88 msgid "Load configuration from CONFFILE" msgstr "" -#: src/main.c:88 +#: src/main.c:89 msgid "Start in debugger mode" msgstr "" -#: src/main.c:89 +#: src/main.c:90 msgid "Start in fullscreen mode" msgstr "" -#: src/main.c:90 +#: src/main.c:91 msgid "Start GDB remote server on PORT for SH4" msgstr "" -#: src/main.c:91 +#: src/main.c:92 msgid "Start GDB remote server on PORT for ARM" msgstr "" -#: src/main.c:92 +#: src/main.c:93 msgid "Display this usage information" msgstr "" -#: src/main.c:93 +#: src/main.c:94 msgid "Run in headless (no video) mode" msgstr "" -#: src/main.c:94 +#: src/main.c:95 msgid "Set the output log level" msgstr "" -#: src/main.c:95 +#: src/main.c:96 msgid "Set the SH4 multiplier (1.0 = fullspeed)" msgstr "" -#: src/main.c:96 +#: src/main.c:97 msgid "Don't start running immediately" msgstr "" -#: src/main.c:97 +#: src/main.c:98 msgid "Start running immediately on startup" msgstr "" -#: src/main.c:98 +#: src/main.c:99 msgid "Run for the specified number of seconds" msgstr "" -#: src/main.c:99 +#: src/main.c:100 msgid "Output trace information for the named regions" msgstr "" -#: src/main.c:100 +#: src/main.c:101 msgid "Allow unsafe dcload syscalls" msgstr "" -#: src/main.c:101 +#: src/main.c:102 msgid "Print the lxdream version string" msgstr "" -#: src/main.c:102 +#: src/main.c:103 msgid "Use the specified video driver (? to list)" msgstr "" -#: src/main.c:103 +#: src/main.c:104 msgid "Disable the SH4 translator" msgstr "" -#: src/maple/controller.c:105 src/maple/lightgun.c:85 +#: src/maple/controller.c:106 src/maple/lightgun.c:86 msgid "Dpad left" msgstr "" -#: src/maple/controller.c:106 src/maple/lightgun.c:86 +#: src/maple/controller.c:107 src/maple/lightgun.c:87 msgid "Dpad right" msgstr "" -#: src/maple/controller.c:107 src/maple/lightgun.c:87 +#: src/maple/controller.c:108 src/maple/lightgun.c:88 msgid "Dpad up" msgstr "" -#: src/maple/controller.c:108 src/maple/lightgun.c:88 +#: src/maple/controller.c:109 src/maple/lightgun.c:89 msgid "Dpad down" msgstr "" -#: src/maple/controller.c:109 +#: src/maple/controller.c:110 msgid "Analog left" msgstr "" -#: src/maple/controller.c:110 +#: src/maple/controller.c:111 msgid "Analog right" msgstr "" -#: src/maple/controller.c:111 +#: src/maple/controller.c:112 msgid "Analog up" msgstr "" -#: src/maple/controller.c:112 +#: src/maple/controller.c:113 msgid "Analog down" msgstr "" -#: src/maple/controller.c:113 +#: src/maple/controller.c:114 msgid "Button X" msgstr "" -#: src/maple/controller.c:114 +#: src/maple/controller.c:115 msgid "Button Y" msgstr "" -#: src/maple/controller.c:115 src/maple/lightgun.c:89 +#: src/maple/controller.c:116 src/maple/lightgun.c:90 msgid "Button A" msgstr "" -#: src/maple/controller.c:116 src/maple/lightgun.c:90 +#: src/maple/controller.c:117 src/maple/lightgun.c:91 msgid "Button B" msgstr "" -#: src/maple/controller.c:117 +#: src/maple/controller.c:118 msgid "Trigger left" msgstr "" -#: src/maple/controller.c:118 +#: src/maple/controller.c:119 msgid "Trigger right" msgstr "" -#: src/maple/controller.c:119 src/maple/lightgun.c:91 +#: src/maple/controller.c:120 src/maple/lightgun.c:92 msgid "Start button" msgstr "" --- a/po/es.po Wed Jun 24 02:27:34 2009 +0000 +++ b/po/es.po Wed Jun 24 02:41:12 2009 +0000 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: lxdream 0.8.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-12 19:52+1000\n" +"POT-Creation-Date: 2009-06-24 12:36+1000\n" "PO-Revision-Date: 2007-12-18 17:29+0430\n" "Last-Translator:Jesus Segnini (the0ne) segnini75@hotmail.com\n" "Language-Team: ES \n" @@ -15,25 +15,30 @@ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/cocoaui/cocoa_ctrl.m:342 src/gtkui/gtk_ctrl.c:294 -#, c-format -msgid "Slot %d." +#: src/cocoaui/cocoa_ctrl.m:324 src/gtkui/gtk_ctrl.c:486 +#, fuzzy, c-format +msgid "Port %c." msgstr "Casilla %d" -#: src/cocoaui/cocoaui.m:404 +#: src/cocoaui/cocoa_ctrl.m:326 src/gtkui/gtk_ctrl.c:515 +#, c-format +msgid "VMU %d." +msgstr "" + +#: src/cocoaui/cocoaui.m:412 #, c-format msgid "Running (%2.4f%%)" msgstr "" -#: src/cocoaui/cocoa_win.m:192 src/gtkui/gtk_win.c:356 +#: src/cocoaui/cocoa_win.m:193 src/gtkui/gtk_win.c:356 msgid "(Press to release grab)" msgstr "" -#: src/cocoaui/cocoa_win.m:204 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:205 src/gtkui/gtk_win.c:366 msgid "Running" msgstr "" -#: src/cocoaui/cocoa_win.m:207 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:208 src/gtkui/gtk_win.c:366 msgid "Stopped" msgstr "" @@ -56,32 +61,36 @@ msgid "Save-state path" msgstr "Guardar ruta de estado" -#: src/config.c:45 src/gtkui/gtk_path.c:29 +#: src/config.c:45 +msgid "VMU path" +msgstr "" + +#: src/config.c:46 src/gtkui/gtk_path.c:29 msgid "Bootstrap IP.BIN" msgstr "Bootstrap IP.BIN" -#: src/config.c:51 +#: src/config.c:53 msgid "Serial device" msgstr "" -#: src/dreamcast.c:192 +#: src/dreamcast.c:193 msgid "" "No program is loaded, and no BIOS is configured (required to boot a CD " "image). To continue, either load a binary program, or set the path to your " "BIOS file in the Path Preferences" msgstr "" -#: src/dreamcast.c:324 +#: src/dreamcast.c:328 #, c-format msgid "File is not a %s save state" msgstr "" -#: src/dreamcast.c:329 +#: src/dreamcast.c:333 #, c-format msgid "Unsupported %s save state version" msgstr "" -#: src/dreamcast.c:334 +#: src/dreamcast.c:338 #, c-format msgid "%s save state is corrupted (bad module count)" msgstr "" @@ -134,7 +143,7 @@ msgid "OS X Cocoa GUI-based OpenGL driver" msgstr "" -#: src/gdlist.c:206 src/gdlist.c:229 +#: src/gdlist.c:187 src/gdlist.c:210 msgid "Empty" msgstr "" @@ -142,49 +151,66 @@ msgid "All files" msgstr "Todos los archivos" -#: src/gtkui/gtkcb.c:139 +#: src/gtkui/gtkcb.c:162 msgid "Load state..." msgstr "Cargar estado..." -#: src/gtkui/gtkcb.c:144 src/gtkui/gtkcb.c:175 +#: src/gtkui/gtkcb.c:167 src/gtkui/gtkcb.c:198 msgid "lxDream Save State (*.dst)" msgstr "Estado guardado LxDream (*.dst)" -#: src/gtkui/gtkcb.c:237 src/gtkui/gtk_dump.c:69 +#: src/gtkui/gtkcb.c:260 src/gtkui/gtk_dump.c:69 msgid "Memory dump" msgstr "Volcado de memoria" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "Save next scene..." msgstr "Guardar proxima escena" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "lxdream scene file (*.dsc)" msgstr "Archivo de escena de lxdream (*.dsc)" -#: src/gtkui/gtkcb.c:265 +#: src/gtkui/gtkcb.c:288 msgid "No address selected, so can't run to it" msgstr "No ha seleccionado una direccion, no puede ir alla entonces" -#: src/gtkui/gtk_ctrl.c:72 src/gtkui/gtk_ctrl.c:101 src/gtkui/gtk_hotkeys.c:50 +#: src/gtkui/gtk_ctrl.c:80 src/gtkui/gtk_ctrl.c:109 src/gtkui/gtk_hotkeys.c:50 #: src/gtkui/gtk_hotkeys.c:79 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:201 +#: src/gtkui/gtk_ctrl.c:209 msgid "Controller Configuration" msgstr "Configuracion del mando" -#: src/gtkui/gtk_ctrl.c:220 +#: src/gtkui/gtk_ctrl.c:228 msgid "No configuration page available for device type" msgstr "" "No hay pagina de configuracion disponible para este tipo de dispositivo" -#: src/gtkui/gtk_ctrl.c:297 +#: src/gtkui/gtk_ctrl.c:252 +msgid "Load VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:266 +msgid "Create VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:329 src/gtkui/gtk_ctrl.c:347 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:325 +#: src/gtkui/gtk_ctrl.c:356 +#, fuzzy +msgid "Load VMU..." +msgstr "Cargar estado..." + +#: src/gtkui/gtk_ctrl.c:357 +msgid "Create VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:551 msgid "Controller Settings" msgstr "Configuracion del mando" @@ -572,139 +598,139 @@ msgid "Select quick save state 9" msgstr "" -#: src/main.c:85 +#: src/main.c:86 msgid "Run the AICA SPU only, with the supplied program" msgstr "" -#: src/main.c:86 +#: src/main.c:87 msgid "Use the specified audio driver (? to list)" msgstr "" -#: src/main.c:87 +#: src/main.c:88 msgid "Load configuration from CONFFILE" msgstr "" -#: src/main.c:88 +#: src/main.c:89 msgid "Start in debugger mode" msgstr "" -#: src/main.c:89 +#: src/main.c:90 msgid "Start in fullscreen mode" msgstr "" -#: src/main.c:90 +#: src/main.c:91 msgid "Start GDB remote server on PORT for SH4" msgstr "" -#: src/main.c:91 +#: src/main.c:92 msgid "Start GDB remote server on PORT for ARM" msgstr "" -#: src/main.c:92 +#: src/main.c:93 msgid "Display this usage information" msgstr "" -#: src/main.c:93 +#: src/main.c:94 msgid "Run in headless (no video) mode" msgstr "" -#: src/main.c:94 +#: src/main.c:95 msgid "Set the output log level" msgstr "" -#: src/main.c:95 +#: src/main.c:96 msgid "Set the SH4 multiplier (1.0 = fullspeed)" msgstr "" -#: src/main.c:96 +#: src/main.c:97 msgid "Don't start running immediately" msgstr "" -#: src/main.c:97 +#: src/main.c:98 msgid "Start running immediately on startup" msgstr "" -#: src/main.c:98 +#: src/main.c:99 msgid "Run for the specified number of seconds" msgstr "" -#: src/main.c:99 +#: src/main.c:100 msgid "Output trace information for the named regions" msgstr "" -#: src/main.c:100 +#: src/main.c:101 msgid "Allow unsafe dcload syscalls" msgstr "" -#: src/main.c:101 +#: src/main.c:102 msgid "Print the lxdream version string" msgstr "" -#: src/main.c:102 +#: src/main.c:103 msgid "Use the specified video driver (? to list)" msgstr "" -#: src/main.c:103 +#: src/main.c:104 msgid "Disable the SH4 translator" msgstr "" -#: src/maple/controller.c:105 src/maple/lightgun.c:85 +#: src/maple/controller.c:106 src/maple/lightgun.c:86 msgid "Dpad left" msgstr "" -#: src/maple/controller.c:106 src/maple/lightgun.c:86 +#: src/maple/controller.c:107 src/maple/lightgun.c:87 msgid "Dpad right" msgstr "" -#: src/maple/controller.c:107 src/maple/lightgun.c:87 +#: src/maple/controller.c:108 src/maple/lightgun.c:88 msgid "Dpad up" msgstr "" -#: src/maple/controller.c:108 src/maple/lightgun.c:88 +#: src/maple/controller.c:109 src/maple/lightgun.c:89 msgid "Dpad down" msgstr "" -#: src/maple/controller.c:109 +#: src/maple/controller.c:110 msgid "Analog left" msgstr "" -#: src/maple/controller.c:110 +#: src/maple/controller.c:111 msgid "Analog right" msgstr "" -#: src/maple/controller.c:111 +#: src/maple/controller.c:112 msgid "Analog up" msgstr "" -#: src/maple/controller.c:112 +#: src/maple/controller.c:113 msgid "Analog down" msgstr "" -#: src/maple/controller.c:113 +#: src/maple/controller.c:114 msgid "Button X" msgstr "" -#: src/maple/controller.c:114 +#: src/maple/controller.c:115 msgid "Button Y" msgstr "" -#: src/maple/controller.c:115 src/maple/lightgun.c:89 +#: src/maple/controller.c:116 src/maple/lightgun.c:90 msgid "Button A" msgstr "" -#: src/maple/controller.c:116 src/maple/lightgun.c:90 +#: src/maple/controller.c:117 src/maple/lightgun.c:91 msgid "Button B" msgstr "" -#: src/maple/controller.c:117 +#: src/maple/controller.c:118 msgid "Trigger left" msgstr "" -#: src/maple/controller.c:118 +#: src/maple/controller.c:119 msgid "Trigger right" msgstr "" -#: src/maple/controller.c:119 src/maple/lightgun.c:91 +#: src/maple/controller.c:120 src/maple/lightgun.c:92 msgid "Start button" msgstr "" --- a/po/it.po Wed Jun 24 02:27:34 2009 +0000 +++ b/po/it.po Wed Jun 24 02:41:12 2009 +0000 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: lxdream 0.8.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-12 19:52+1000\n" +"POT-Creation-Date: 2009-06-24 12:36+1000\n" "PO-Revision-Date: 2008-04-10 00:00+0000\n" "Last-Translator: Ghost22 \n" "Language-Team: Italiano \n" @@ -15,25 +15,30 @@ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/cocoaui/cocoa_ctrl.m:342 src/gtkui/gtk_ctrl.c:294 -#, c-format -msgid "Slot %d." +#: src/cocoaui/cocoa_ctrl.m:324 src/gtkui/gtk_ctrl.c:486 +#, fuzzy, c-format +msgid "Port %c." msgstr "Slot %d." -#: src/cocoaui/cocoaui.m:404 +#: src/cocoaui/cocoa_ctrl.m:326 src/gtkui/gtk_ctrl.c:515 +#, c-format +msgid "VMU %d." +msgstr "" + +#: src/cocoaui/cocoaui.m:412 #, c-format msgid "Running (%2.4f%%)" msgstr "" -#: src/cocoaui/cocoa_win.m:192 src/gtkui/gtk_win.c:356 +#: src/cocoaui/cocoa_win.m:193 src/gtkui/gtk_win.c:356 msgid "(Press to release grab)" msgstr "" -#: src/cocoaui/cocoa_win.m:204 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:205 src/gtkui/gtk_win.c:366 msgid "Running" msgstr "" -#: src/cocoaui/cocoa_win.m:207 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:208 src/gtkui/gtk_win.c:366 msgid "Stopped" msgstr "" @@ -56,32 +61,36 @@ msgid "Save-state path" msgstr "Percorso del salvataggio dello stato" -#: src/config.c:45 src/gtkui/gtk_path.c:29 +#: src/config.c:45 +msgid "VMU path" +msgstr "" + +#: src/config.c:46 src/gtkui/gtk_path.c:29 msgid "Bootstrap IP.BIN" msgstr "Bootstrap IP.BIN" -#: src/config.c:51 +#: src/config.c:53 msgid "Serial device" msgstr "" -#: src/dreamcast.c:192 +#: src/dreamcast.c:193 msgid "" "No program is loaded, and no BIOS is configured (required to boot a CD " "image). To continue, either load a binary program, or set the path to your " "BIOS file in the Path Preferences" msgstr "" -#: src/dreamcast.c:324 +#: src/dreamcast.c:328 #, c-format msgid "File is not a %s save state" msgstr "" -#: src/dreamcast.c:329 +#: src/dreamcast.c:333 #, c-format msgid "Unsupported %s save state version" msgstr "" -#: src/dreamcast.c:334 +#: src/dreamcast.c:338 #, c-format msgid "%s save state is corrupted (bad module count)" msgstr "" @@ -134,7 +143,7 @@ msgid "OS X Cocoa GUI-based OpenGL driver" msgstr "" -#: src/gdlist.c:206 src/gdlist.c:229 +#: src/gdlist.c:187 src/gdlist.c:210 msgid "Empty" msgstr "Vuoto" @@ -142,48 +151,65 @@ msgid "All files" msgstr "Tutti i files" -#: src/gtkui/gtkcb.c:139 +#: src/gtkui/gtkcb.c:162 msgid "Load state..." msgstr "Carica stato..." -#: src/gtkui/gtkcb.c:144 src/gtkui/gtkcb.c:175 +#: src/gtkui/gtkcb.c:167 src/gtkui/gtkcb.c:198 msgid "lxDream Save State (*.dst)" msgstr "Salvataggio stato LxDream (*.dst)" -#: src/gtkui/gtkcb.c:237 src/gtkui/gtk_dump.c:69 +#: src/gtkui/gtkcb.c:260 src/gtkui/gtk_dump.c:69 msgid "Memory dump" msgstr "Memoria" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "Save next scene..." msgstr "Salva prossima scena..." -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "lxdream scene file (*.dsc)" msgstr "file scena lxdream (*.dsc)" -#: src/gtkui/gtkcb.c:265 +#: src/gtkui/gtkcb.c:288 msgid "No address selected, so can't run to it" msgstr "Nessun indirizzo selezionato, quindi non posso andarci" -#: src/gtkui/gtk_ctrl.c:72 src/gtkui/gtk_ctrl.c:101 src/gtkui/gtk_hotkeys.c:50 +#: src/gtkui/gtk_ctrl.c:80 src/gtkui/gtk_ctrl.c:109 src/gtkui/gtk_hotkeys.c:50 #: src/gtkui/gtk_hotkeys.c:79 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:201 +#: src/gtkui/gtk_ctrl.c:209 msgid "Controller Configuration" msgstr "Configura il controller" -#: src/gtkui/gtk_ctrl.c:220 +#: src/gtkui/gtk_ctrl.c:228 msgid "No configuration page available for device type" msgstr "Nessuna configurazione è attivabile per questo tipo di periferica" -#: src/gtkui/gtk_ctrl.c:297 +#: src/gtkui/gtk_ctrl.c:252 +msgid "Load VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:266 +msgid "Create VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:329 src/gtkui/gtk_ctrl.c:347 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:325 +#: src/gtkui/gtk_ctrl.c:356 +#, fuzzy +msgid "Load VMU..." +msgstr "Carica stato..." + +#: src/gtkui/gtk_ctrl.c:357 +msgid "Create VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:551 msgid "Controller Settings" msgstr "Opzioni del controller" @@ -571,139 +597,139 @@ msgid "Select quick save state 9" msgstr "" -#: src/main.c:85 +#: src/main.c:86 msgid "Run the AICA SPU only, with the supplied program" msgstr "" -#: src/main.c:86 +#: src/main.c:87 msgid "Use the specified audio driver (? to list)" msgstr "" -#: src/main.c:87 +#: src/main.c:88 msgid "Load configuration from CONFFILE" msgstr "" -#: src/main.c:88 +#: src/main.c:89 msgid "Start in debugger mode" msgstr "" -#: src/main.c:89 +#: src/main.c:90 msgid "Start in fullscreen mode" msgstr "" -#: src/main.c:90 +#: src/main.c:91 msgid "Start GDB remote server on PORT for SH4" msgstr "" -#: src/main.c:91 +#: src/main.c:92 msgid "Start GDB remote server on PORT for ARM" msgstr "" -#: src/main.c:92 +#: src/main.c:93 msgid "Display this usage information" msgstr "" -#: src/main.c:93 +#: src/main.c:94 msgid "Run in headless (no video) mode" msgstr "" -#: src/main.c:94 +#: src/main.c:95 msgid "Set the output log level" msgstr "" -#: src/main.c:95 +#: src/main.c:96 msgid "Set the SH4 multiplier (1.0 = fullspeed)" msgstr "" -#: src/main.c:96 +#: src/main.c:97 msgid "Don't start running immediately" msgstr "" -#: src/main.c:97 +#: src/main.c:98 msgid "Start running immediately on startup" msgstr "" -#: src/main.c:98 +#: src/main.c:99 msgid "Run for the specified number of seconds" msgstr "" -#: src/main.c:99 +#: src/main.c:100 msgid "Output trace information for the named regions" msgstr "" -#: src/main.c:100 +#: src/main.c:101 msgid "Allow unsafe dcload syscalls" msgstr "" -#: src/main.c:101 +#: src/main.c:102 msgid "Print the lxdream version string" msgstr "" -#: src/main.c:102 +#: src/main.c:103 msgid "Use the specified video driver (? to list)" msgstr "" -#: src/main.c:103 +#: src/main.c:104 msgid "Disable the SH4 translator" msgstr "" -#: src/maple/controller.c:105 src/maple/lightgun.c:85 +#: src/maple/controller.c:106 src/maple/lightgun.c:86 msgid "Dpad left" msgstr "" -#: src/maple/controller.c:106 src/maple/lightgun.c:86 +#: src/maple/controller.c:107 src/maple/lightgun.c:87 msgid "Dpad right" msgstr "" -#: src/maple/controller.c:107 src/maple/lightgun.c:87 +#: src/maple/controller.c:108 src/maple/lightgun.c:88 msgid "Dpad up" msgstr "" -#: src/maple/controller.c:108 src/maple/lightgun.c:88 +#: src/maple/controller.c:109 src/maple/lightgun.c:89 msgid "Dpad down" msgstr "" -#: src/maple/controller.c:109 +#: src/maple/controller.c:110 msgid "Analog left" msgstr "" -#: src/maple/controller.c:110 +#: src/maple/controller.c:111 msgid "Analog right" msgstr "" -#: src/maple/controller.c:111 +#: src/maple/controller.c:112 msgid "Analog up" msgstr "" -#: src/maple/controller.c:112 +#: src/maple/controller.c:113 msgid "Analog down" msgstr "" -#: src/maple/controller.c:113 +#: src/maple/controller.c:114 msgid "Button X" msgstr "" -#: src/maple/controller.c:114 +#: src/maple/controller.c:115 msgid "Button Y" msgstr "" -#: src/maple/controller.c:115 src/maple/lightgun.c:89 +#: src/maple/controller.c:116 src/maple/lightgun.c:90 msgid "Button A" msgstr "" -#: src/maple/controller.c:116 src/maple/lightgun.c:90 +#: src/maple/controller.c:117 src/maple/lightgun.c:91 msgid "Button B" msgstr "" -#: src/maple/controller.c:117 +#: src/maple/controller.c:118 msgid "Trigger left" msgstr "" -#: src/maple/controller.c:118 +#: src/maple/controller.c:119 msgid "Trigger right" msgstr "" -#: src/maple/controller.c:119 src/maple/lightgun.c:91 +#: src/maple/controller.c:120 src/maple/lightgun.c:92 msgid "Start button" msgstr "" --- a/po/lxdream.pot Wed Jun 24 02:27:34 2009 +0000 +++ b/po/lxdream.pot Wed Jun 24 02:41:12 2009 +0000 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-12 19:52+1000\n" +"POT-Creation-Date: 2009-06-24 12:36+1000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,25 +16,30 @@ "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/cocoaui/cocoa_ctrl.m:342 src/gtkui/gtk_ctrl.c:294 +#: src/cocoaui/cocoa_ctrl.m:324 src/gtkui/gtk_ctrl.c:486 #, c-format -msgid "Slot %d." +msgid "Port %c." msgstr "" -#: src/cocoaui/cocoaui.m:404 +#: src/cocoaui/cocoa_ctrl.m:326 src/gtkui/gtk_ctrl.c:515 +#, c-format +msgid "VMU %d." +msgstr "" + +#: src/cocoaui/cocoaui.m:412 #, c-format msgid "Running (%2.4f%%)" msgstr "" -#: src/cocoaui/cocoa_win.m:192 src/gtkui/gtk_win.c:356 +#: src/cocoaui/cocoa_win.m:193 src/gtkui/gtk_win.c:356 msgid "(Press to release grab)" msgstr "" -#: src/cocoaui/cocoa_win.m:204 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:205 src/gtkui/gtk_win.c:366 msgid "Running" msgstr "" -#: src/cocoaui/cocoa_win.m:207 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:208 src/gtkui/gtk_win.c:366 msgid "Stopped" msgstr "" @@ -54,32 +59,36 @@ msgid "Save-state path" msgstr "" -#: src/config.c:45 src/gtkui/gtk_path.c:29 +#: src/config.c:45 +msgid "VMU path" +msgstr "" + +#: src/config.c:46 src/gtkui/gtk_path.c:29 msgid "Bootstrap IP.BIN" msgstr "" -#: src/config.c:51 +#: src/config.c:53 msgid "Serial device" msgstr "" -#: src/dreamcast.c:192 +#: src/dreamcast.c:193 msgid "" "No program is loaded, and no BIOS is configured (required to boot a CD " "image). To continue, either load a binary program, or set the path to your " "BIOS file in the Path Preferences" msgstr "" -#: src/dreamcast.c:324 +#: src/dreamcast.c:328 #, c-format msgid "File is not a %s save state" msgstr "" -#: src/dreamcast.c:329 +#: src/dreamcast.c:333 #, c-format msgid "Unsupported %s save state version" msgstr "" -#: src/dreamcast.c:334 +#: src/dreamcast.c:338 #, c-format msgid "%s save state is corrupted (bad module count)" msgstr "" @@ -132,7 +141,7 @@ msgid "OS X Cocoa GUI-based OpenGL driver" msgstr "" -#: src/gdlist.c:206 src/gdlist.c:229 +#: src/gdlist.c:187 src/gdlist.c:210 msgid "Empty" msgstr "" @@ -140,48 +149,64 @@ msgid "All files" msgstr "" -#: src/gtkui/gtkcb.c:139 +#: src/gtkui/gtkcb.c:162 msgid "Load state..." msgstr "" -#: src/gtkui/gtkcb.c:144 src/gtkui/gtkcb.c:175 +#: src/gtkui/gtkcb.c:167 src/gtkui/gtkcb.c:198 msgid "lxDream Save State (*.dst)" msgstr "" -#: src/gtkui/gtkcb.c:237 src/gtkui/gtk_dump.c:69 +#: src/gtkui/gtkcb.c:260 src/gtkui/gtk_dump.c:69 msgid "Memory dump" msgstr "" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "Save next scene..." msgstr "" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "lxdream scene file (*.dsc)" msgstr "" -#: src/gtkui/gtkcb.c:265 +#: src/gtkui/gtkcb.c:288 msgid "No address selected, so can't run to it" msgstr "" -#: src/gtkui/gtk_ctrl.c:72 src/gtkui/gtk_ctrl.c:101 src/gtkui/gtk_hotkeys.c:50 +#: src/gtkui/gtk_ctrl.c:80 src/gtkui/gtk_ctrl.c:109 src/gtkui/gtk_hotkeys.c:50 #: src/gtkui/gtk_hotkeys.c:79 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:201 +#: src/gtkui/gtk_ctrl.c:209 msgid "Controller Configuration" msgstr "" -#: src/gtkui/gtk_ctrl.c:220 +#: src/gtkui/gtk_ctrl.c:228 msgid "No configuration page available for device type" msgstr "" -#: src/gtkui/gtk_ctrl.c:297 +#: src/gtkui/gtk_ctrl.c:252 +msgid "Load VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:266 +msgid "Create VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:329 src/gtkui/gtk_ctrl.c:347 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:325 +#: src/gtkui/gtk_ctrl.c:356 +msgid "Load VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:357 +msgid "Create VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:551 msgid "Controller Settings" msgstr "" @@ -561,139 +586,139 @@ msgid "Select quick save state 9" msgstr "" -#: src/main.c:85 +#: src/main.c:86 msgid "Run the AICA SPU only, with the supplied program" msgstr "" -#: src/main.c:86 +#: src/main.c:87 msgid "Use the specified audio driver (? to list)" msgstr "" -#: src/main.c:87 +#: src/main.c:88 msgid "Load configuration from CONFFILE" msgstr "" -#: src/main.c:88 +#: src/main.c:89 msgid "Start in debugger mode" msgstr "" -#: src/main.c:89 +#: src/main.c:90 msgid "Start in fullscreen mode" msgstr "" -#: src/main.c:90 +#: src/main.c:91 msgid "Start GDB remote server on PORT for SH4" msgstr "" -#: src/main.c:91 +#: src/main.c:92 msgid "Start GDB remote server on PORT for ARM" msgstr "" -#: src/main.c:92 +#: src/main.c:93 msgid "Display this usage information" msgstr "" -#: src/main.c:93 +#: src/main.c:94 msgid "Run in headless (no video) mode" msgstr "" -#: src/main.c:94 +#: src/main.c:95 msgid "Set the output log level" msgstr "" -#: src/main.c:95 +#: src/main.c:96 msgid "Set the SH4 multiplier (1.0 = fullspeed)" msgstr "" -#: src/main.c:96 +#: src/main.c:97 msgid "Don't start running immediately" msgstr "" -#: src/main.c:97 +#: src/main.c:98 msgid "Start running immediately on startup" msgstr "" -#: src/main.c:98 +#: src/main.c:99 msgid "Run for the specified number of seconds" msgstr "" -#: src/main.c:99 +#: src/main.c:100 msgid "Output trace information for the named regions" msgstr "" -#: src/main.c:100 +#: src/main.c:101 msgid "Allow unsafe dcload syscalls" msgstr "" -#: src/main.c:101 +#: src/main.c:102 msgid "Print the lxdream version string" msgstr "" -#: src/main.c:102 +#: src/main.c:103 msgid "Use the specified video driver (? to list)" msgstr "" -#: src/main.c:103 +#: src/main.c:104 msgid "Disable the SH4 translator" msgstr "" -#: src/maple/controller.c:105 src/maple/lightgun.c:85 +#: src/maple/controller.c:106 src/maple/lightgun.c:86 msgid "Dpad left" msgstr "" -#: src/maple/controller.c:106 src/maple/lightgun.c:86 +#: src/maple/controller.c:107 src/maple/lightgun.c:87 msgid "Dpad right" msgstr "" -#: src/maple/controller.c:107 src/maple/lightgun.c:87 +#: src/maple/controller.c:108 src/maple/lightgun.c:88 msgid "Dpad up" msgstr "" -#: src/maple/controller.c:108 src/maple/lightgun.c:88 +#: src/maple/controller.c:109 src/maple/lightgun.c:89 msgid "Dpad down" msgstr "" -#: src/maple/controller.c:109 +#: src/maple/controller.c:110 msgid "Analog left" msgstr "" -#: src/maple/controller.c:110 +#: src/maple/controller.c:111 msgid "Analog right" msgstr "" -#: src/maple/controller.c:111 +#: src/maple/controller.c:112 msgid "Analog up" msgstr "" -#: src/maple/controller.c:112 +#: src/maple/controller.c:113 msgid "Analog down" msgstr "" -#: src/maple/controller.c:113 +#: src/maple/controller.c:114 msgid "Button X" msgstr "" -#: src/maple/controller.c:114 +#: src/maple/controller.c:115 msgid "Button Y" msgstr "" -#: src/maple/controller.c:115 src/maple/lightgun.c:89 +#: src/maple/controller.c:116 src/maple/lightgun.c:90 msgid "Button A" msgstr "" -#: src/maple/controller.c:116 src/maple/lightgun.c:90 +#: src/maple/controller.c:117 src/maple/lightgun.c:91 msgid "Button B" msgstr "" -#: src/maple/controller.c:117 +#: src/maple/controller.c:118 msgid "Trigger left" msgstr "" -#: src/maple/controller.c:118 +#: src/maple/controller.c:119 msgid "Trigger right" msgstr "" -#: src/maple/controller.c:119 src/maple/lightgun.c:91 +#: src/maple/controller.c:120 src/maple/lightgun.c:92 msgid "Start button" msgstr "" --- a/po/pt_BR.po Wed Jun 24 02:27:34 2009 +0000 +++ b/po/pt_BR.po Wed Jun 24 02:41:12 2009 +0000 @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: lxdream 0.8.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-06-12 19:52+1000\n" +"POT-Creation-Date: 2009-06-24 12:36+1000\n" "PO-Revision-Date: 2009-04-03 11:05-0300\n" "Last-Translator: Gabriel Tillmann \n" "Language-Team: PT \n" @@ -15,25 +15,30 @@ "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/cocoaui/cocoa_ctrl.m:342 src/gtkui/gtk_ctrl.c:294 -#, c-format -msgid "Slot %d." +#: src/cocoaui/cocoa_ctrl.m:324 src/gtkui/gtk_ctrl.c:486 +#, fuzzy, c-format +msgid "Port %c." msgstr "Slot %d." -#: src/cocoaui/cocoaui.m:404 +#: src/cocoaui/cocoa_ctrl.m:326 src/gtkui/gtk_ctrl.c:515 +#, c-format +msgid "VMU %d." +msgstr "" + +#: src/cocoaui/cocoaui.m:412 #, c-format msgid "Running (%2.4f%%)" msgstr "Rodando (%2.4f%%)" -#: src/cocoaui/cocoa_win.m:192 src/gtkui/gtk_win.c:356 +#: src/cocoaui/cocoa_win.m:193 src/gtkui/gtk_win.c:356 msgid "(Press to release grab)" msgstr "(Pressione para desprender)" -#: src/cocoaui/cocoa_win.m:204 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:205 src/gtkui/gtk_win.c:366 msgid "Running" msgstr "Rodando" -#: src/cocoaui/cocoa_win.m:207 src/gtkui/gtk_win.c:366 +#: src/cocoaui/cocoa_win.m:208 src/gtkui/gtk_win.c:366 msgid "Stopped" msgstr "Parado" @@ -53,32 +58,36 @@ msgid "Save-state path" msgstr "Diretório de Estados Salvos" -#: src/config.c:45 src/gtkui/gtk_path.c:29 +#: src/config.c:45 +msgid "VMU path" +msgstr "" + +#: src/config.c:46 src/gtkui/gtk_path.c:29 msgid "Bootstrap IP.BIN" msgstr "Bootstrap IP.BIN" -#: src/config.c:51 +#: src/config.c:53 msgid "Serial device" msgstr "Dispositivo Serial" -#: src/dreamcast.c:192 +#: src/dreamcast.c:193 msgid "" "No program is loaded, and no BIOS is configured (required to boot a CD " "image). To continue, either load a binary program, or set the path to your " "BIOS file in the Path Preferences" msgstr "" -#: src/dreamcast.c:324 +#: src/dreamcast.c:328 #, c-format msgid "File is not a %s save state" msgstr "" -#: src/dreamcast.c:329 +#: src/dreamcast.c:333 #, c-format msgid "Unsupported %s save state version" msgstr "" -#: src/dreamcast.c:334 +#: src/dreamcast.c:338 #, c-format msgid "%s save state is corrupted (bad module count)" msgstr "" @@ -131,7 +140,7 @@ msgid "OS X Cocoa GUI-based OpenGL driver" msgstr "Driver GUI OS X Cocoa baseado em OpenGL " -#: src/gdlist.c:206 src/gdlist.c:229 +#: src/gdlist.c:187 src/gdlist.c:210 msgid "Empty" msgstr "Vazio" @@ -139,48 +148,65 @@ msgid "All files" msgstr "Todos os Arquivos" -#: src/gtkui/gtkcb.c:139 +#: src/gtkui/gtkcb.c:162 msgid "Load state..." msgstr "Carregar stado..." -#: src/gtkui/gtkcb.c:144 src/gtkui/gtkcb.c:175 +#: src/gtkui/gtkcb.c:167 src/gtkui/gtkcb.c:198 msgid "lxDream Save State (*.dst)" msgstr "lxDream Save State (*.dst)" -#: src/gtkui/gtkcb.c:237 src/gtkui/gtk_dump.c:69 +#: src/gtkui/gtkcb.c:260 src/gtkui/gtk_dump.c:69 msgid "Memory dump" msgstr "Dump de memória" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "Save next scene..." msgstr "Salvar próxima cena" -#: src/gtkui/gtkcb.c:250 +#: src/gtkui/gtkcb.c:273 msgid "lxdream scene file (*.dsc)" msgstr "lxdream scene file (*.dsc)" -#: src/gtkui/gtkcb.c:265 +#: src/gtkui/gtkcb.c:288 msgid "No address selected, so can't run to it" msgstr "Sem endereço selecionado, então impossível correr a ele" -#: src/gtkui/gtk_ctrl.c:72 src/gtkui/gtk_ctrl.c:101 src/gtkui/gtk_hotkeys.c:50 +#: src/gtkui/gtk_ctrl.c:80 src/gtkui/gtk_ctrl.c:109 src/gtkui/gtk_hotkeys.c:50 #: src/gtkui/gtk_hotkeys.c:79 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:201 +#: src/gtkui/gtk_ctrl.c:209 msgid "Controller Configuration" msgstr "Configuração de controle" -#: src/gtkui/gtk_ctrl.c:220 +#: src/gtkui/gtk_ctrl.c:228 msgid "No configuration page available for device type" msgstr "Não há página de configuração disponível para este tipo de dispositivo" -#: src/gtkui/gtk_ctrl.c:297 +#: src/gtkui/gtk_ctrl.c:252 +msgid "Load VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:266 +msgid "Create VMU" +msgstr "" + +#: src/gtkui/gtk_ctrl.c:329 src/gtkui/gtk_ctrl.c:347 msgid "" msgstr "" -#: src/gtkui/gtk_ctrl.c:325 +#: src/gtkui/gtk_ctrl.c:356 +#, fuzzy +msgid "Load VMU..." +msgstr "Carregar stado..." + +#: src/gtkui/gtk_ctrl.c:357 +msgid "Create VMU..." +msgstr "" + +#: src/gtkui/gtk_ctrl.c:551 msgid "Controller Settings" msgstr "Configurações de Controle" @@ -564,140 +590,140 @@ msgid "Select quick save state 9" msgstr "" -#: src/main.c:85 +#: src/main.c:86 msgid "Run the AICA SPU only, with the supplied program" msgstr "Correr Apenas o Spu AICA, com o programa dado" -#: src/main.c:86 +#: src/main.c:87 msgid "Use the specified audio driver (? to list)" msgstr "Usar Driver de audio específico (? para listar)" -#: src/main.c:87 +#: src/main.c:88 msgid "Load configuration from CONFFILE" msgstr "Carregar configurações de uma CONFFILE" -#: src/main.c:88 +#: src/main.c:89 msgid "Start in debugger mode" msgstr "Iniciar no modo debbugador" -#: src/main.c:89 +#: src/main.c:90 #, fuzzy msgid "Start in fullscreen mode" msgstr "Iniciar no modo debbugador" -#: src/main.c:90 +#: src/main.c:91 msgid "Start GDB remote server on PORT for SH4" msgstr "" -#: src/main.c:91 +#: src/main.c:92 msgid "Start GDB remote server on PORT for ARM" msgstr "" -#: src/main.c:92 +#: src/main.c:93 msgid "Display this usage information" msgstr "Mostrar informações de uso" -#: src/main.c:93 +#: src/main.c:94 msgid "Run in headless (no video) mode" msgstr "Rodar no Modo (sem vídeo) sem cabeça" -#: src/main.c:94 +#: src/main.c:95 msgid "Set the output log level" msgstr "Definir o nível de saída do Log" -#: src/main.c:95 +#: src/main.c:96 msgid "Set the SH4 multiplier (1.0 = fullspeed)" msgstr "Definir Multiplicador do SH4 (1.0 = Velocidade total)" -#: src/main.c:96 +#: src/main.c:97 msgid "Don't start running immediately" msgstr "Não Correr Imediatamente" -#: src/main.c:97 +#: src/main.c:98 msgid "Start running immediately on startup" msgstr "Correr Imediatamente " -#: src/main.c:98 +#: src/main.c:99 msgid "Run for the specified number of seconds" msgstr "Correr por um número específico de segundos" -#: src/main.c:99 +#: src/main.c:100 msgid "Output trace information for the named regions" msgstr "Traçar informação de saída para regiões nomeadas" -#: src/main.c:100 +#: src/main.c:101 msgid "Allow unsafe dcload syscalls" msgstr "Permitir chamadas de sistema não seguras do dcload" -#: src/main.c:101 +#: src/main.c:102 msgid "Print the lxdream version string" msgstr "Mostrar a String de versão do lxdream" -#: src/main.c:102 +#: src/main.c:103 msgid "Use the specified video driver (? to list)" msgstr "Usar driver de vídeo específico (? para listar)" -#: src/main.c:103 +#: src/main.c:104 msgid "Disable the SH4 translator" msgstr "Desabilitar o tradutor de SH4" -#: src/maple/controller.c:105 src/maple/lightgun.c:85 +#: src/maple/controller.c:106 src/maple/lightgun.c:86 msgid "Dpad left" msgstr "Dpad Esquerda" -#: src/maple/controller.c:106 src/maple/lightgun.c:86 +#: src/maple/controller.c:107 src/maple/lightgun.c:87 msgid "Dpad right" msgstr "Dpad Direita" -#: src/maple/controller.c:107 src/maple/lightgun.c:87 +#: src/maple/controller.c:108 src/maple/lightgun.c:88 msgid "Dpad up" msgstr "Dpad Cima" -#: src/maple/controller.c:108 src/maple/lightgun.c:88 +#: src/maple/controller.c:109 src/maple/lightgun.c:89 msgid "Dpad down" msgstr "Dpad Baixo" -#: src/maple/controller.c:109 +#: src/maple/controller.c:110 msgid "Analog left" msgstr "Analógico Esquerda" -#: src/maple/controller.c:110 +#: src/maple/controller.c:111 msgid "Analog right" msgstr "Analógico Direita" -#: src/maple/controller.c:111 +#: src/maple/controller.c:112 msgid "Analog up" msgstr "Analógico Cima" -#: src/maple/controller.c:112 +#: src/maple/controller.c:113 msgid "Analog down" msgstr "Analógico Baixo" -#: src/maple/controller.c:113 +#: src/maple/controller.c:114 msgid "Button X" msgstr "Botão X" -#: src/maple/controller.c:114 +#: src/maple/controller.c:115 msgid "Button Y" msgstr "Botão Y" -#: src/maple/controller.c:115 src/maple/lightgun.c:89 +#: src/maple/controller.c:116 src/maple/lightgun.c:90 msgid "Button A" msgstr "Botão A" -#: src/maple/controller.c:116 src/maple/lightgun.c:90 +#: src/maple/controller.c:117 src/maple/lightgun.c:91 msgid "Button B" msgstr "Botão B" -#: src/maple/controller.c:117 +#: src/maple/controller.c:118 msgid "Trigger left" msgstr "Gatilho Esquerda" -#: src/maple/controller.c:118 +#: src/maple/controller.c:119 msgid "Trigger right" msgstr "Gatilho Direita" -#: src/maple/controller.c:119 src/maple/lightgun.c:91 +#: src/maple/controller.c:120 src/maple/lightgun.c:92 msgid "Start button" msgstr "Botão Start" --- a/src/Makefile.am Wed Jun 24 02:27:34 2009 +0000 +++ b/src/Makefile.am Wed Jun 24 02:41:12 2009 +0000 @@ -63,8 +63,9 @@ pvr2/gl_sl.c pvr2/gl_slsrc.c pvr2/glutil.c pvr2/glutil.h pvr2/glrender.c \ pvr2/vertex.glsl pvr2/fragment.glsl \ maple/maple.c maple/maple.h \ - maple/controller.c maple/kbd.c maple/mouse.c maple/lightgun.c \ + maple/controller.c maple/kbd.c maple/mouse.c maple/lightgun.c maple/vmu.c \ loader.c loader.h elf.h bootstrap.c bootstrap.h util.c gdlist.c gdlist.h \ + vmu/vmuvol.c vmu/vmuvol.h vmu/vmulist.c vmu/vmulist.h \ display.c display.h dckeysyms.h \ drivers/audio_null.c drivers/video_null.c drivers/cd_mmc.c \ drivers/video_gl.c drivers/video_gl.h drivers/gl_fbo.c \ --- a/src/Makefile.in Wed Jun 24 02:27:34 2009 +0000 +++ b/src/Makefile.in Wed Jun 24 02:41:12 2009 +0000 @@ -161,8 +161,9 @@ pvr2/glutil.h pvr2/glrender.c pvr2/vertex.glsl \ pvr2/fragment.glsl maple/maple.c maple/maple.h \ maple/controller.c maple/kbd.c maple/mouse.c maple/lightgun.c \ - loader.c loader.h elf.h bootstrap.c bootstrap.h util.c \ - gdlist.c gdlist.h display.c display.h dckeysyms.h \ + maple/vmu.c loader.c loader.h elf.h bootstrap.c bootstrap.h \ + util.c gdlist.c gdlist.h vmu/vmuvol.c vmu/vmuvol.h \ + vmu/vmulist.c vmu/vmulist.h display.c display.h dckeysyms.h \ drivers/audio_null.c drivers/video_null.c drivers/cd_mmc.c \ drivers/video_gl.c drivers/video_gl.h drivers/gl_fbo.c \ sh4/sh4.def sh4/sh4core.in sh4/sh4x86.in sh4/sh4dasm.in \ @@ -259,18 +260,20 @@ lxdream-glutil.$(OBJEXT) lxdream-glrender.$(OBJEXT) \ lxdream-maple.$(OBJEXT) lxdream-controller.$(OBJEXT) \ lxdream-kbd.$(OBJEXT) lxdream-mouse.$(OBJEXT) \ - lxdream-lightgun.$(OBJEXT) lxdream-loader.$(OBJEXT) \ - lxdream-bootstrap.$(OBJEXT) lxdream-util.$(OBJEXT) \ - lxdream-gdlist.$(OBJEXT) lxdream-display.$(OBJEXT) \ - lxdream-audio_null.$(OBJEXT) lxdream-video_null.$(OBJEXT) \ - lxdream-cd_mmc.$(OBJEXT) lxdream-video_gl.$(OBJEXT) \ - lxdream-gl_fbo.$(OBJEXT) lxdream-hotkeys.$(OBJEXT) \ - $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) \ - $(am__objects_7) $(am__objects_8) $(am__objects_9) \ - $(am__objects_10) $(am__objects_11) $(am__objects_12) \ - $(am__objects_13) $(am__objects_14) $(am__objects_15) \ - $(am__objects_16) $(am__objects_17) $(am__objects_18) + lxdream-lightgun.$(OBJEXT) lxdream-vmu.$(OBJEXT) \ + lxdream-loader.$(OBJEXT) lxdream-bootstrap.$(OBJEXT) \ + lxdream-util.$(OBJEXT) lxdream-gdlist.$(OBJEXT) \ + lxdream-vmuvol.$(OBJEXT) lxdream-vmulist.$(OBJEXT) \ + lxdream-display.$(OBJEXT) lxdream-audio_null.$(OBJEXT) \ + lxdream-video_null.$(OBJEXT) lxdream-cd_mmc.$(OBJEXT) \ + lxdream-video_gl.$(OBJEXT) lxdream-gl_fbo.$(OBJEXT) \ + lxdream-hotkeys.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + $(am__objects_6) $(am__objects_7) $(am__objects_8) \ + $(am__objects_9) $(am__objects_10) $(am__objects_11) \ + $(am__objects_12) $(am__objects_13) $(am__objects_14) \ + $(am__objects_15) $(am__objects_16) $(am__objects_17) \ + $(am__objects_18) lxdream_OBJECTS = $(am_lxdream_OBJECTS) lxdream_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -558,9 +561,10 @@ pvr2/gl_sl.c pvr2/gl_slsrc.c pvr2/glutil.c pvr2/glutil.h \ pvr2/glrender.c pvr2/vertex.glsl pvr2/fragment.glsl \ maple/maple.c maple/maple.h maple/controller.c maple/kbd.c \ - maple/mouse.c maple/lightgun.c loader.c loader.h elf.h \ - bootstrap.c bootstrap.h util.c gdlist.c gdlist.h display.c \ - display.h dckeysyms.h drivers/audio_null.c \ + maple/mouse.c maple/lightgun.c maple/vmu.c loader.c loader.h \ + elf.h bootstrap.c bootstrap.h util.c gdlist.c gdlist.h \ + vmu/vmuvol.c vmu/vmuvol.h vmu/vmulist.c vmu/vmulist.h \ + display.c display.h dckeysyms.h drivers/audio_null.c \ drivers/video_null.c drivers/cd_mmc.c drivers/video_gl.c \ drivers/video_gl.h drivers/gl_fbo.c sh4/sh4.def sh4/sh4core.in \ sh4/sh4x86.in sh4/sh4dasm.in sh4/sh4stat.in hotkeys.c \ @@ -841,6 +845,9 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-video_nsgl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-video_null.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-video_osx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-vmu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-vmulist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-vmuvol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-x86dasm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lxdream-xltcache.Po@am__quote@ @@ -1726,6 +1733,20 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-lightgun.obj `if test -f 'maple/lightgun.c'; then $(CYGPATH_W) 'maple/lightgun.c'; else $(CYGPATH_W) '$(srcdir)/maple/lightgun.c'; fi` +lxdream-vmu.o: maple/vmu.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmu.o -MD -MP -MF "$(DEPDIR)/lxdream-vmu.Tpo" -c -o lxdream-vmu.o `test -f 'maple/vmu.c' || echo '$(srcdir)/'`maple/vmu.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmu.Tpo" "$(DEPDIR)/lxdream-vmu.Po"; else rm -f "$(DEPDIR)/lxdream-vmu.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='maple/vmu.c' object='lxdream-vmu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmu.o `test -f 'maple/vmu.c' || echo '$(srcdir)/'`maple/vmu.c + +lxdream-vmu.obj: maple/vmu.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmu.obj -MD -MP -MF "$(DEPDIR)/lxdream-vmu.Tpo" -c -o lxdream-vmu.obj `if test -f 'maple/vmu.c'; then $(CYGPATH_W) 'maple/vmu.c'; else $(CYGPATH_W) '$(srcdir)/maple/vmu.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmu.Tpo" "$(DEPDIR)/lxdream-vmu.Po"; else rm -f "$(DEPDIR)/lxdream-vmu.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='maple/vmu.c' object='lxdream-vmu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmu.obj `if test -f 'maple/vmu.c'; then $(CYGPATH_W) 'maple/vmu.c'; else $(CYGPATH_W) '$(srcdir)/maple/vmu.c'; fi` + lxdream-loader.o: loader.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-loader.o -MD -MP -MF "$(DEPDIR)/lxdream-loader.Tpo" -c -o lxdream-loader.o `test -f 'loader.c' || echo '$(srcdir)/'`loader.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-loader.Tpo" "$(DEPDIR)/lxdream-loader.Po"; else rm -f "$(DEPDIR)/lxdream-loader.Tpo"; exit 1; fi @@ -1782,6 +1803,34 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-gdlist.obj `if test -f 'gdlist.c'; then $(CYGPATH_W) 'gdlist.c'; else $(CYGPATH_W) '$(srcdir)/gdlist.c'; fi` +lxdream-vmuvol.o: vmu/vmuvol.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmuvol.o -MD -MP -MF "$(DEPDIR)/lxdream-vmuvol.Tpo" -c -o lxdream-vmuvol.o `test -f 'vmu/vmuvol.c' || echo '$(srcdir)/'`vmu/vmuvol.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmuvol.Tpo" "$(DEPDIR)/lxdream-vmuvol.Po"; else rm -f "$(DEPDIR)/lxdream-vmuvol.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vmu/vmuvol.c' object='lxdream-vmuvol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmuvol.o `test -f 'vmu/vmuvol.c' || echo '$(srcdir)/'`vmu/vmuvol.c + +lxdream-vmuvol.obj: vmu/vmuvol.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmuvol.obj -MD -MP -MF "$(DEPDIR)/lxdream-vmuvol.Tpo" -c -o lxdream-vmuvol.obj `if test -f 'vmu/vmuvol.c'; then $(CYGPATH_W) 'vmu/vmuvol.c'; else $(CYGPATH_W) '$(srcdir)/vmu/vmuvol.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmuvol.Tpo" "$(DEPDIR)/lxdream-vmuvol.Po"; else rm -f "$(DEPDIR)/lxdream-vmuvol.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vmu/vmuvol.c' object='lxdream-vmuvol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmuvol.obj `if test -f 'vmu/vmuvol.c'; then $(CYGPATH_W) 'vmu/vmuvol.c'; else $(CYGPATH_W) '$(srcdir)/vmu/vmuvol.c'; fi` + +lxdream-vmulist.o: vmu/vmulist.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmulist.o -MD -MP -MF "$(DEPDIR)/lxdream-vmulist.Tpo" -c -o lxdream-vmulist.o `test -f 'vmu/vmulist.c' || echo '$(srcdir)/'`vmu/vmulist.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmulist.Tpo" "$(DEPDIR)/lxdream-vmulist.Po"; else rm -f "$(DEPDIR)/lxdream-vmulist.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vmu/vmulist.c' object='lxdream-vmulist.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmulist.o `test -f 'vmu/vmulist.c' || echo '$(srcdir)/'`vmu/vmulist.c + +lxdream-vmulist.obj: vmu/vmulist.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-vmulist.obj -MD -MP -MF "$(DEPDIR)/lxdream-vmulist.Tpo" -c -o lxdream-vmulist.obj `if test -f 'vmu/vmulist.c'; then $(CYGPATH_W) 'vmu/vmulist.c'; else $(CYGPATH_W) '$(srcdir)/vmu/vmulist.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-vmulist.Tpo" "$(DEPDIR)/lxdream-vmulist.Po"; else rm -f "$(DEPDIR)/lxdream-vmulist.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='vmu/vmulist.c' object='lxdream-vmulist.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lxdream-vmulist.obj `if test -f 'vmu/vmulist.c'; then $(CYGPATH_W) 'vmu/vmulist.c'; else $(CYGPATH_W) '$(srcdir)/vmu/vmulist.c'; fi` + lxdream-display.o: display.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lxdream_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lxdream-display.o -MD -MP -MF "$(DEPDIR)/lxdream-display.Tpo" -c -o lxdream-display.o `test -f 'display.c' || echo '$(srcdir)/'`display.c; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lxdream-display.Tpo" "$(DEPDIR)/lxdream-display.Po"; else rm -f "$(DEPDIR)/lxdream-display.Tpo"; exit 1; fi --- a/src/cocoaui/cocoa_ctrl.m Wed Jun 24 02:27:34 2009 +0000 +++ b/src/cocoaui/cocoa_ctrl.m Wed Jun 24 02:41:12 2009 +0000 @@ -20,14 +20,20 @@ #include "config.h" #include "display.h" #include "maple/maple.h" +#include "vmu/vmulist.h" #include -#define MAX_DEVICES 4 +#define FIRST_SECONDARY_DEVICE MAPLE_PORTS + +#define FIRST_VMU_TAG 0x1000 +#define LOAD_VMU_TAG -1 +#define CREATE_VMU_TAG -2 #define KEYBINDING_SIZE 110 static void cocoa_config_keysym_hook(void *data, const gchar *keysym); +static gboolean cocoa_config_vmulist_hook(vmulist_change_type_t type, int idx, void *data); @interface KeyBindingEditor (Private) - (void)updateKeysym: (const gchar *)sym; @@ -188,7 +194,7 @@ @interface ControllerKeyBindingView : NSView { maple_device_t device; - KeyBindingField *field[MAX_KEY_BINDINGS][2]; + NSTextField *field[MAX_KEY_BINDINGS][2]; } - (id)initWithFrame: (NSRect)frameRect; - (void)setDevice: (maple_device_t)device; @@ -214,21 +220,25 @@ } - (void)controlTextDidChange: (NSNotification *)notify { + const gchar *p = NULL; int binding = [[notify object] tag]; NSString *val1 = [field[binding][0] stringValue]; - NSString *val2 = [field[binding][1] stringValue]; - char buf[ [val1 length] + [val2 length] + 2 ]; - const gchar *p = NULL; - - if( [val1 length] == 0 ) { - if( [val2 length] != 0 ) { - p = [val2 UTF8String]; - } - } else if( [val2 length] == 0 ) { + if( field[binding][1] == NULL ) { p = [val1 UTF8String]; } else { - sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] ); - p = buf; + NSString *val2 = [field[binding][1] stringValue]; + char buf[ [val1 length] + [val2 length] + 2 ]; + + if( [val1 length] == 0 ) { + if( [val2 length] != 0 ) { + p = [val2 UTF8String]; + } + } else if( [val2 length] == 0 ) { + p = [val1 UTF8String]; + } else { + sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] ); + p = buf; + } } maple_set_device_config_value( device, binding, p ); lxdream_save_config(); @@ -237,7 +247,7 @@ { device = newDevice; [self removeSubviews]; - if( device != NULL ) { + if( device != NULL && !MAPLE_IS_VMU(device) ) { lxdream_config_entry_t config = maple_get_device_config(device); if( config != NULL ) { int count, i, y, x; @@ -249,35 +259,51 @@ [self scrollRectToVisible: NSMakeRect(0,0,1,1)]; y = TEXT_GAP; for( i=0; config[i].key != NULL; i++ ) { + /* Add label */ NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT); NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame); [label setAlignment: NSRightTextAlignment]; + + switch(config[i].type) { + case CONFIG_TYPE_KEY: + frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT); + field[i][0] = [[KeyBindingField alloc] initWithFrame: frame]; + [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; + [field[i][0] setTag: i]; + [field[i][0] setDelegate: self]; + [self addSubview: field[i][0]]; - frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT); - field[i][0] = [[KeyBindingField alloc] initWithFrame: frame]; - [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; - [field[i][0] setTag: i]; - [field[i][0] setDelegate: self]; - [self addSubview: field[i][0]]; - - frame = NSMakeRect( x + 85 + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT); - field[i][1] = [[KeyBindingField alloc] initWithFrame: frame]; - [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; - [field[i][1] setTag: i]; - [field[i][1] setDelegate: self]; - [self addSubview: field[i][1]]; + frame = NSMakeRect( x + 85 + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT); + field[i][1] = [[KeyBindingField alloc] initWithFrame: frame]; + [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; + [field[i][1] setTag: i]; + [field[i][1] setDelegate: self]; + [self addSubview: field[i][1]]; - if( config[i].value != NULL ) { - gchar **parts = g_strsplit(config[i].value,",",3); - if( parts[0] != NULL ) { - [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]]; - if( parts[1] != NULL ) { - [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]]; + if( config[i].value != NULL ) { + gchar **parts = g_strsplit(config[i].value,",",3); + if( parts[0] != NULL ) { + [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]]; + if( parts[1] != NULL ) { + [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]]; + } } + g_strfreev(parts); } - g_strfreev(parts); - } - + break; + case CONFIG_TYPE_FILE: + case CONFIG_TYPE_PATH: + frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE*2+TEXT_GAP, TEXT_HEIGHT); + field[i][0] = [[NSTextField alloc] initWithFrame: frame]; + [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; + [field[i][0] setTag: i]; + [field[i][0] setDelegate: self]; + [self addSubview: field[i][0]]; + if( config[i].value != NULL ) { + [field[i][0] setStringValue: [NSString stringWithCString: config[i].value]]; + } + field[i][1] = NULL; + } y += (TEXT_HEIGHT + TEXT_GAP); } } else { @@ -290,16 +316,176 @@ @end /*************************** Top-level controller pane ***********************/ +static NSButton *addRadioButton( int port, int sub, int x, int y, id parent ) +{ + char buf[16]; + + if( sub == 0 ) { + snprintf( buf, sizeof(buf), _("Port %c."), 'A'+port ); + } else { + snprintf( buf, sizeof(buf), _("VMU %d."), sub ); + } + + NSButton *radio = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )]; + [radio setTitle: [NSString stringWithUTF8String: buf]]; + [radio setTag: MAPLE_DEVID(port,sub) ]; + [radio setButtonType: NSRadioButton]; + [radio setAlignment: NSRightTextAlignment]; + [radio setTarget: parent]; + [radio setAction: @selector(radioChanged:)]; + [radio setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; + [parent addSubview: radio]; + return radio; +} + +static void setDevicePopupSelection( NSPopUpButton *popup, maple_device_t device ) +{ + if( device == NULL ) { + [popup selectItemAtIndex: 0]; + } else if( MAPLE_IS_VMU(device) ) { + int idx = vmulist_get_index_by_filename( MAPLE_VMU_NAME(device) ); + if( idx == -1 ) { + [popup selectItemAtIndex: 0]; + } else { + [popup selectItemWithTag: FIRST_VMU_TAG + idx]; + } + } else { + const struct maple_device_class **devices = maple_get_device_classes(); + int i; + for( i=0; devices[i] != NULL; i++ ) { + if( devices[i] == device->device_class ) { + [popup selectItemWithTag: i+1]; + return; + } + } + // Should never get here, but if so... + [popup selectItemAtIndex: 0]; + } +} + +static void buildDevicePopupMenu( NSPopUpButton *popup, maple_device_t device, BOOL primary ) +{ + int j; + const struct maple_device_class **devices = maple_get_device_classes(); + + [popup removeAllItems]; + [popup addItemWithTitle: NS_("")]; + [[popup itemAtIndex: 0] setTag: 0]; + for( j=0; devices[j] != NULL; j++ ) { + int isPrimaryDevice = devices[j]->flags & MAPLE_TYPE_PRIMARY; + if( primary ? isPrimaryDevice : (!isPrimaryDevice && !MAPLE_IS_VMU_CLASS(devices[j])) ) { + [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]]; + if( device != NULL && device->device_class == devices[j] ) { + [popup selectItemAtIndex: ([popup numberOfItems]-1)]; + } + [[popup itemAtIndex: ([popup numberOfItems]-1)] setTag: (j+1)]; + } + } + + if( !primary ) { + BOOL vmu_selected = NO; + const char *vmu_name; + if( device != NULL && MAPLE_IS_VMU(device) ) { + vmu_selected = YES; + vmu_name = MAPLE_VMU_NAME(device); + } + if( [popup numberOfItems] > 0 ) { + [[popup menu] addItem: [NSMenuItem separatorItem]]; + } + + unsigned int vmu_count = vmulist_get_size(); + for( j=0; j")]; - [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; - [[popup itemAtIndex: 0] setTag: 0]; - for( j=0; devices[j] != NULL; j++ ) { - [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]]; - if( device != NULL && device->device_class == devices[j] ) { - [popup selectItemAtIndex: (j+1)]; + radio[i] = addRadioButton(i,0,TEXT_GAP,y,self); + popup[i] = addDevicePopup(i,0,60 + (TEXT_GAP*2),y,device, YES,self); + y -= (TEXT_HEIGHT+TEXT_GAP); + + int j,max = device == NULL ? 0 : MAPLE_SLOTS(device->device_class); + for( j=1; j<=MAPLE_USER_SLOTS; j++ ) { + radio[MAPLE_DEVID(i,j)] = addRadioButton(i, j, TEXT_GAP*2, y, self); + popup[MAPLE_DEVID(i,j)] = addDevicePopup(i, j, 60 + TEXT_GAP*2, y, maple_get_device(i,j), NO, self); + y -= (TEXT_HEIGHT+TEXT_GAP); + if( j > max ) { + [radio[MAPLE_DEVID(i,j)] setEnabled: NO]; + [popup[MAPLE_DEVID(i,j)] setEnabled: NO]; } - [[popup itemAtIndex: (j+1)] setTag: (j+1)]; } - [popup setTarget: self]; - [popup setAction: @selector(deviceChanged:)]; - [popup setTag: i]; - [self addSubview: popup]; - y -= (TEXT_HEIGHT+TEXT_GAP); } [radio[0] setState: NSOnState]; + + register_vmulist_change_hook(cocoa_config_vmulist_hook, self); return self; } } +- (void)dealloc +{ + unregister_vmulist_change_hook(cocoa_config_vmulist_hook,self); + [super dealloc]; +} +- (void)vmulistChanged: (id)sender +{ + int i; + for( i=FIRST_SECONDARY_DEVICE; i= FIRST_VMU_TAG ) { + vmu_filename = vmulist_get_filename( new_device_idx - FIRST_VMU_TAG ); + new_device_class = &vmu_class; + } else if( new_device_idx > 0) { + new_device_class = maple_get_device_classes()[new_device_idx-1]; } - if( current == NULL ? new_device_class == NULL : current->device_class == new_device_class ) { + + if( current == NULL ? new_device_class == NULL : + (current->device_class == new_device_class && + (!MAPLE_IS_VMU(current) || MAPLE_VMU_HAS_NAME(current, vmu_filename))) ) { // No change [key_bindings setDevice: current]; return; } if( current != NULL && current->device_class == &controller_class ) { - save_controller[slot] = current->clone(current); + save_controller[tag] = current->clone(current); } if( new_device_class == NULL ) { - maple_detach_device(slot,0); + maple_detach_device(port,slot); } else { - if( new_device_class == &controller_class && save_controller[slot] != NULL ) { - new_device = save_controller[slot]; - save_controller[slot] = NULL; + if( new_device_class == &controller_class && save_controller[tag] != NULL ) { + new_device = save_controller[tag]; + save_controller[tag] = NULL; } else { new_device = maple_new_device( new_device_class->name ); } - maple_attach_device(new_device,slot,0); + if( MAPLE_IS_VMU(new_device) ) { + MAPLE_SET_VMU_NAME(new_device,vmu_filename); + } + maple_attach_device(new_device,port,slot); } - [key_bindings setDevice: maple_get_device(slot,0)]; + [key_bindings setDevice: maple_get_device(port,slot)]; + + if( slot == 0 ) { /* Change primary */ + int max = new_device_class == NULL ? 0 : MAPLE_SLOTS(new_device_class); + for( i=1; i<=MAPLE_USER_SLOTS; i++ ) { + if( i <= max ) { + [radio[MAPLE_DEVID(port,i)] setEnabled: YES]; + [popup[MAPLE_DEVID(port,i)] setEnabled: YES]; + } else { + [radio[MAPLE_DEVID(port,i)] setEnabled: NO]; + [popup[MAPLE_DEVID(port,i)] setEnabled: NO]; + } + } + } lxdream_save_config(); } @end --- a/src/cocoaui/cocoa_prefs.m Wed Jun 24 02:27:34 2009 +0000 +++ b/src/cocoaui/cocoa_prefs.m Wed Jun 24 02:41:12 2009 +0000 @@ -184,7 +184,7 @@ void cocoa_gui_show_preferences() { if( prefs_panel == NULL ) { - prefs_panel = [[LxdreamPrefsPanel alloc] initWithContentRect: NSMakeRect(0,0,640,400)]; + prefs_panel = [[LxdreamPrefsPanel alloc] initWithContentRect: NSMakeRect(0,0,640,540)]; } [prefs_panel makeKeyAndOrderFront: prefs_panel]; } \ No newline at end of file --- a/src/config.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/config.c Wed Jun 24 02:41:12 2009 +0000 @@ -42,9 +42,11 @@ { "flash", N_("Flash ROM"), CONFIG_TYPE_FILE, "dcflash.rom" }, { "default path", N_("Default disc path"), CONFIG_TYPE_PATH, "." }, { "save path", N_("Save-state path"), CONFIG_TYPE_PATH, "save" }, + { "vmu path", N_("VMU path"), CONFIG_TYPE_PATH, "vmu" }, { "bootstrap", N_("Bootstrap IP.BIN"), CONFIG_TYPE_FILE, "IP.BIN" }, { "gdrom", NULL, CONFIG_TYPE_FILE, NULL }, - { "recent", NULL, CONFIG_TYPE_FILE, NULL }, + { "recent", NULL, CONFIG_TYPE_FILELIST, NULL }, + { "vmu", NULL, CONFIG_TYPE_FILELIST, NULL }, { NULL, CONFIG_TYPE_NONE }}; static struct lxdream_config_entry serial_config[] = @@ -139,6 +141,42 @@ return global_config[key].value; } +GList *lxdream_get_global_config_list_value( int key ) +{ + GList *result = NULL; + const gchar *str = lxdream_get_config_value( key ); + if( str != NULL ) { + gchar **strv = g_strsplit(str, ":",0); + int i; + for( i=0; strv[i] != NULL; i++ ) { + result = g_list_append( result, g_strdup(strv[i]) ); + } + g_strfreev(strv); + } + return result; +} + +void lxdream_set_global_config_list_value( int key, const GList *list ) +{ + if( list == NULL ) { + lxdream_set_global_config_value( key, NULL ); + } else { + GList *ptr; + int size = 0; + + for( ptr = list; ptr != NULL; ptr = g_list_next(ptr) ) { + size += strlen( (gchar *)ptr->data ) + 1; + } + char buf[size]; + strcpy( buf, (gchar *)list->data ); + for( ptr = g_list_next(list); ptr != NULL; ptr = g_list_next(ptr) ) { + strcat( buf, ":" ); + strcat( buf, (gchar *)ptr->data ); + } + lxdream_set_global_config_value( key, buf ); + } +} + void lxdream_set_config_value( lxdream_config_entry_t param, const gchar *value ) { if( param->value != value ) { --- a/src/config.h Wed Jun 24 02:27:34 2009 +0000 +++ b/src/config.h Wed Jun 24 02:41:12 2009 +0000 @@ -20,6 +20,7 @@ #define lxdream_config_H 1 #include +#include #include "gettext.h" #ifdef __cplusplus @@ -30,6 +31,7 @@ #define CONFIG_TYPE_FILE 1 #define CONFIG_TYPE_PATH 2 #define CONFIG_TYPE_KEY 3 +#define CONFIG_TYPE_FILELIST 4 #define DEFAULT_CONFIG_FILENAME "lxdreamrc" @@ -50,10 +52,12 @@ #define CONFIG_FLASH_PATH 1 #define CONFIG_DEFAULT_PATH 2 #define CONFIG_SAVE_PATH 3 -#define CONFIG_BOOTSTRAP 4 -#define CONFIG_GDROM 5 -#define CONFIG_RECENT 6 -#define CONFIG_KEY_MAX CONFIG_RECENT +#define CONFIG_VMU_PATH 4 +#define CONFIG_BOOTSTRAP 5 +#define CONFIG_GDROM 6 +#define CONFIG_RECENT 7 +#define CONFIG_VMU 8 +#define CONFIG_KEY_MAX CONFIG_VMU extern struct lxdream_config_group lxdream_config_root[]; @@ -67,6 +71,16 @@ void lxdream_copy_config_list( lxdream_config_entry_t dest, lxdream_config_entry_t src ); /** + * Construct a list of strings for the given config key - The caller is + * responsible for freeing the list and its values. + */ +GList *lxdream_get_global_config_list_value( int key ); + +/** + * Set a config key based on a list of strings. + */ +void lxdream_set_global_config_list_value( int key, const GList *list ); +/** * Search the standard locations for the configuration file: * $HOME/.lxdreamrc * $CWD/lxdreamrc --- a/src/dreamcast.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/dreamcast.c Wed Jun 24 02:41:12 2009 +0000 @@ -32,6 +32,7 @@ #include "pvr2/pvr2.h" #include "sh4/sh4.h" #include "sh4/sh4core.h" +#include "vmu/vmulist.h" /** * Current state of the DC virtual machine @@ -242,6 +243,8 @@ if( modules[i]->stop != NULL ) modules[i]->stop(); } + + vmulist_save_all(); dreamcast_state = STATE_STOPPED; if( dreamcast_exit_on_stop ) { @@ -264,6 +267,7 @@ if( dreamcast_state == STATE_RUNNING ) dreamcast_state = STATE_STOPPING; dreamcast_save_flash(); + vmulist_save_all(); #ifdef ENABLE_SH4STATS sh4_stats_print(stdout); #endif --- a/src/gdlist.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/gdlist.c Wed Jun 24 02:41:12 2009 +0000 @@ -65,18 +65,7 @@ */ void gdrom_list_update_config() { - GList *ptr; - int size = 0; - for( ptr = gdrom_recent_list; ptr != NULL; ptr = g_list_next(ptr) ) { - size += strlen( (gchar *)ptr->data ) + 1; - } - char buf[size]; - strcpy( buf, (gchar *)gdrom_recent_list->data ); - for( ptr = g_list_next(gdrom_recent_list); ptr != NULL; ptr = g_list_next(ptr) ) { - strcat( buf, ":" ); - strcat( buf, (gchar *)ptr->data ); - } - lxdream_set_global_config_value( CONFIG_RECENT, buf ); + lxdream_set_global_config_list_value( CONFIG_RECENT, gdrom_recent_list ); } @@ -146,17 +135,9 @@ void gdrom_list_init() { - const gchar *recent = lxdream_get_config_value( CONFIG_RECENT ); + gdrom_recent_list = lxdream_get_global_config_list_value( CONFIG_RECENT ); register_gdrom_disc_change_hook( gdrom_list_disc_changed, NULL ); gdrom_device_list = cdrom_get_native_devices(); - if( recent != NULL ) { - gchar **list = g_strsplit(recent, ":", MAX_RECENT_ITEMS); - int i; - for( i=0; list[i] != NULL; i++ ) { - gdrom_recent_list = g_list_append( gdrom_recent_list, g_strdup(list[i]) ); - } - g_strfreev(list); - } gdrom_device_count = g_list_length(gdrom_device_list); gdrom_recent_count = g_list_length(gdrom_recent_list); --- a/src/gtkui/gtk_ctrl.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/gtkui/gtk_ctrl.c Wed Jun 24 02:41:12 2009 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -26,10 +27,15 @@ #include "display.h" #include "gtkui/gtkui.h" #include "maple/maple.h" +#include "vmu/vmulist.h" #define MAX_DEVICES 4 +#define LOAD_VMU_TAG ((void *)-1) +#define CREATE_VMU_TAG ((void *)-2) + static void controller_device_configure(maple_device_t device); +static void maple_set_device_selection( GtkWidget *combo, maple_device_t device ); struct maple_config_class { const char *name; @@ -41,14 +47,16 @@ maple_device_t new_device; GtkWidget *button; GtkWidget *combo; + gboolean primarySlot; } *maple_slot_data_t; + static struct maple_config_class maple_device_config[] = { { "Sega Controller", controller_device_configure }, { "Sega Lightgun", controller_device_configure }, { NULL, NULL } }; -static struct maple_slot_data maple_data[MAX_DEVICES]; +static struct maple_slot_data maple_data[MAPLE_MAX_DEVICES]; static void config_keysym_hook( void *data, const gchar *keysym ) { @@ -201,7 +209,7 @@ gtk_gui_run_property_dialog( _("Controller Configuration"), table, controller_config_done ); } -gboolean maple_properties_activated( GtkButton *button, gpointer user_data ) +static gboolean maple_properties_activated( GtkButton *button, gpointer user_data ) { maple_slot_data_t data = (maple_slot_data_t)user_data; if( data->new_device != NULL ) { @@ -223,26 +231,76 @@ return TRUE; } -gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data ) +static gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data ) { maple_slot_data_t data = (maple_slot_data_t)user_data; - int active = gtk_combo_box_get_active(combo); + int active = gtk_combo_box_get_active(combo), i; gboolean has_config = FALSE; + gboolean set_selection = FALSE; + int has_slots = 0; if( active != 0 ) { - gchar *devname = gtk_combo_box_get_active_text(combo); - const maple_device_class_t devclz = maple_get_device_class(devname); - assert(devclz != NULL); + GtkTreeIter iter; + maple_device_class_t devclz; + const gchar *vmu_filename; + + GtkTreeModel *model = gtk_combo_box_get_model(combo); + gtk_combo_box_get_active_iter(combo, &iter); + gtk_tree_model_get(model, &iter, 1, &devclz, 2, &vmu_filename, -1 ); + + if( devclz == LOAD_VMU_TAG ) { + devclz = NULL; + vmu_filename = open_file_dialog( _("Load VMU"), "*.vmu", "VMU Files", + lxdream_get_config_value(CONFIG_VMU_PATH) ); + if( vmu_filename != NULL ) { + vmu_volume_t vol = vmu_volume_load( vmu_filename ); + if( vol != NULL ) { + devclz = &vmu_class; + vmulist_add_vmu(vmu_filename, vol); + set_selection = TRUE; + } else { + ERROR( "Unable to load VMU file (not a valid VMU)" ); + } + } + } else if( devclz == CREATE_VMU_TAG ) { + devclz = NULL; + vmu_filename = save_file_dialog( _("Create VMU"), "*.vmu", "VMU Files", + lxdream_get_config_value(CONFIG_VMU_PATH) ); + if( vmu_filename != NULL ) { + devclz = &vmu_class; + set_selection = TRUE; + int idx = vmulist_create_vmu( vmu_filename, FALSE ); + if( idx == -1 ) { + ERROR( "Unable to save VMU file: %s", strerror(errno) ); + } + } + } else if( vmu_filename != NULL ) { + devclz = &vmu_class; + } + + if( devclz == NULL ) { + maple_set_device_selection(data->combo, data->new_device); + return TRUE; + } + if( data->new_device != NULL ) { if( data->new_device->device_class != devclz ) { if( data->new_device != data->old_device ) { data->new_device->destroy(data->new_device); } - data->new_device = maple_new_device(devname); + data->new_device = devclz->new_device(); } } else { - data->new_device = maple_new_device(devname); + data->new_device = devclz->new_device(); } has_config = data->new_device != NULL && data->new_device->get_config != NULL; + has_slots = data->new_device == NULL ? 0 : MAPLE_SLOTS(devclz); + if( MAPLE_IS_VMU(data->new_device) ) { + MAPLE_SET_VMU_NAME(data->new_device,vmu_filename); + } + + if( set_selection ) { + maple_set_device_selection(data->combo, data->new_device); + } } else { if( data->new_device != NULL && data->new_device != data->old_device ) { data->new_device->destroy(data->new_device); @@ -250,27 +308,146 @@ data->new_device = NULL; } gtk_widget_set_sensitive(data->button, has_config); + + if( data->primarySlot ) { + for( i=0; icombo, i < has_slots ); + gtk_widget_set_sensitive(subdata->button, i < has_slots && subdata->new_device != NULL && subdata->new_device->get_config != NULL ); + } + } return TRUE; } -void maple_dialog_done( GtkWidget *panel, gboolean isOK ) +static void maple_build_device_model( GtkListStore *dev_model ) { + const struct maple_device_class **devices = maple_get_device_classes(); + int i; + + gtk_list_store_clear(dev_model); + gtk_list_store_insert_with_values( dev_model, NULL, 0, 0, _(""), 1, NULL, 2, NULL, -1 ); + for( i=0; devices[i] != NULL; i++ ) { + if( devices[i]->flags & MAPLE_TYPE_PRIMARY ) { + gtk_list_store_insert_with_values( dev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 ); + } + } + +} + +/** + * (Re)build the subdevice combo-box model. + */ +static void maple_build_subdevice_model( GtkListStore *subdev_model ) +{ + int i, j; + const struct maple_device_class **devices = maple_get_device_classes(); + + gtk_list_store_clear(subdev_model); + gtk_list_store_insert_with_values( subdev_model, NULL, 0, 0, _(""), 1, NULL, 2, NULL, -1 ); + for( i=0; devices[i] != NULL; i++ ) { + if( !(devices[i]->flags & MAPLE_TYPE_PRIMARY) && !MAPLE_IS_VMU_CLASS(devices[i]) ) { + gtk_list_store_insert_with_values( subdev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 ); + } + } + for( j=0; j < vmulist_get_size(); j++ ) { + gtk_list_store_insert_with_values( subdev_model, NULL, i+j+1, 0, vmulist_get_name(j), 1, NULL, 2, vmulist_get_filename(j), -1 ); + } + gtk_list_store_insert_with_values( subdev_model, NULL, i+j+1, 0, _("Load VMU..."), 1, LOAD_VMU_TAG, 2, NULL, -1 ); + gtk_list_store_insert_with_values( subdev_model, NULL, i+j+2, 0, _("Create VMU..."), 1, CREATE_VMU_TAG, 2, NULL, -1 ); +} + +static gboolean maple_vmulist_changed( vmulist_change_type_t type, int idx, void *data ) +{ + GtkListStore *list = (GtkListStore *)data; + GtkTreeIter iter; + int i,j; + + /* Search for the row and update accordingly. There's probably better ways + * to do this + */ + + gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter); + while( valid ) { + gchar *vmu_filename; + gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, 2, &vmu_filename, -1 ); + if( vmu_filename != NULL ) + break; + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter); + } + if( valid ) { + for( i=0; idevice_class == clz ) { + gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter ); + return; + } else if( vmu_filename != NULL && MAPLE_IS_VMU(device) && + MAPLE_VMU_HAS_NAME(device, vmu_filename) ) { + gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter ); + return; + } + + valid = gtk_tree_model_iter_next(model, &iter); + } + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); +} + +static void maple_dialog_done( GtkWidget *panel, gboolean isOK ) +{ + void *p = g_object_get_data( G_OBJECT(panel), "subdev_model" ); + unregister_vmulist_change_hook( maple_vmulist_changed, p ); + if( isOK ) { int i; - for( i=0; idestroy(maple_data[i].new_device); @@ -280,42 +457,91 @@ } -GtkWidget *maple_panel_new() +static GtkWidget *maple_panel_new() { - GtkWidget *table = gtk_table_new(4, 3, TRUE); - int i,j; + GtkWidget *table = gtk_table_new( MAPLE_PORTS * (MAPLE_USER_SLOTS+1), 3, TRUE); + int i,j,k; const struct maple_device_class **devices = maple_get_device_classes(); - for( i=0; i< MAX_DEVICES; i++ ) { + gtk_table_set_row_spacings(GTK_TABLE(table), 3); + gtk_table_set_col_spacings(GTK_TABLE(table), 5); + + /* Device models */ + GtkListStore *dev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING); + maple_build_device_model(dev_model); + + GtkListStore *subdev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING); + maple_build_subdevice_model(subdev_model); + g_object_set_data( G_OBJECT(table), "subdev_model", subdev_model ); + register_vmulist_change_hook( maple_vmulist_changed, subdev_model ); + + int y =0; + for( i=0; i< MAPLE_PORTS; i++ ) { char buf[16]; GtkWidget *combo, *button; - int active = 0; + int active = 0, length = 1; maple_device_t device = maple_get_device(i,0); - snprintf( buf, sizeof(buf), _("Slot %d."), i ); - gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, i, i+1 ); - combo = gtk_combo_box_new_text(); - gtk_combo_box_append_text( GTK_COMBO_BOX(combo), _("") ); - for( j=0; devices[j] != NULL; j++ ) { - gtk_combo_box_append_text(GTK_COMBO_BOX(combo), devices[j]->name); - if( device != NULL && device->device_class == devices[j] ) { - active = j+1; - } - } - gtk_combo_box_set_active(GTK_COMBO_BOX(combo), active); - gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, i, i+1 ); + int has_slots = device == NULL ? 0 : MAPLE_SLOTS(device->device_class); + + snprintf( buf, sizeof(buf), _("Port %c."), 'A'+i ); + gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, y, y+1 ); + + combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dev_model)); + GtkCellRenderer *rend = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE); + gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 ); + maple_set_device_selection(combo,device); + gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 ); + button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES ); gtk_widget_set_sensitive(button, active != 0 && device->get_config != NULL); - gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, i, i+1 ); + gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 ); - maple_data[i].old_device = device; - maple_data[i].new_device = device; - maple_data[i].combo = combo; - maple_data[i].button = button; + maple_data[MAPLE_DEVID(i,0)].old_device = device; + maple_data[MAPLE_DEVID(i,0)].new_device = device; + maple_data[MAPLE_DEVID(i,0)].combo = combo; + maple_data[MAPLE_DEVID(i,0)].button = button; + maple_data[MAPLE_DEVID(i,0)].primarySlot = TRUE; g_signal_connect( button, "clicked", - G_CALLBACK( maple_properties_activated ), &maple_data[i] ); + G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,0)] ); g_signal_connect( combo, "changed", - G_CALLBACK( maple_device_changed ), &maple_data[i] ); - + G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,0)] ); + y++; + + for( k=0; k< MAPLE_USER_SLOTS; k++ ) { + char tmp[32] = " "; + device = maple_get_device(i,k+1); + active = 0; + snprintf( tmp+8, sizeof(tmp)-8, _("VMU %d."), (k+1) ); + gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(tmp), 0, 1, y, y+1 ); + combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(subdev_model)); + GtkCellRenderer *rend = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE); + gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 ); + maple_set_device_selection(combo, device); + + gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 ); + button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES ); + gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 ); + if( k >= has_slots ) { + gtk_widget_set_sensitive(combo, FALSE); + gtk_widget_set_sensitive(button, FALSE); + } else { + gtk_widget_set_sensitive(button, device != NULL && device->get_config != NULL && !MAPLE_IS_VMU(device)); + } + + maple_data[MAPLE_DEVID(i,k+1)].old_device = device; + maple_data[MAPLE_DEVID(i,k+1)].new_device = device; + maple_data[MAPLE_DEVID(i,k+1)].combo = combo; + maple_data[MAPLE_DEVID(i,k+1)].button = button; + maple_data[MAPLE_DEVID(i,k+1)].primarySlot = FALSE; + g_signal_connect( button, "clicked", + G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,k+1)] ); + g_signal_connect( combo, "changed", + G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,k+1)] ); + y++; + } + gtk_table_set_row_spacing( GTK_TABLE(table), y-1, 10 ); } return table; } --- a/src/gtkui/gtk_gd.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/gtkui/gtk_gd.c Wed Jun 24 02:41:12 2009 +0000 @@ -31,7 +31,7 @@ { if( !gdrom_menu_adjusting ) { const gchar *dir = lxdream_get_config_value(CONFIG_DEFAULT_PATH); - open_file_dialog( _("Open..."), gdrom_mount_image, NULL, NULL, dir ); + open_file_dialog_cb( _("Open..."), gdrom_mount_image, NULL, NULL, dir ); } } --- a/src/gtkui/gtkcb.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/gtkui/gtkcb.c Wed Jun 24 02:41:12 2009 +0000 @@ -39,10 +39,11 @@ } } -void open_file_dialog( const char *title, file_callback_t action, const char *pattern, const char *patname, - const gchar *initial_dir ) +gchar *open_file_dialog( const char *title, const char *pattern, const char *patname, + const gchar *initial_dir ) { GtkWidget *file; + gchar *filename = NULL; gchar *initial_path = get_absolute_path(initial_dir); file = gtk_file_chooser_dialog_new( title, NULL, GTK_FILE_CHOOSER_ACTION_OPEN, @@ -55,17 +56,19 @@ gtk_dialog_set_default_response( GTK_DIALOG(file), GTK_RESPONSE_ACCEPT ); int result = gtk_dialog_run( GTK_DIALOG(file) ); if( result == GTK_RESPONSE_ACCEPT ) { - gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(file) ); - action( filename ); + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(file) ); } gtk_widget_destroy(file); g_free(initial_path); + + return filename; } -void save_file_dialog( const char *title, file_callback_t action, const char *pattern, const char *patname, +gchar *save_file_dialog( const char *title, const char *pattern, const char *patname, const gchar *initial_dir ) { GtkWidget *file; + gchar *filename; gchar *initial_path = get_absolute_path(initial_dir); file = gtk_file_chooser_dialog_new( title, NULL, GTK_FILE_CHOOSER_ACTION_SAVE, @@ -78,17 +81,37 @@ gtk_dialog_set_default_response( GTK_DIALOG(file), GTK_RESPONSE_ACCEPT ); int result = gtk_dialog_run( GTK_DIALOG(file) ); if( result == GTK_RESPONSE_ACCEPT ) { - gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(file) ); - action( filename ); + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(file) ); } gtk_widget_destroy(file); g_free(initial_path); + return filename; +} + +void open_file_dialog_cb( const char *title, file_callback_t action, const char *pattern, const char *patname, + const gchar *initial_dir ) +{ + gchar *filename = open_file_dialog( title, pattern, patname, initial_dir ); + if( filename != NULL ) { + action( filename ); + g_free(filename); + } +} + +void save_file_dialog_cb( const char *title, file_callback_t action, const char *pattern, const char *patname, + const gchar *initial_dir ) +{ + gchar *filename = save_file_dialog( title, pattern, patname, initial_dir ); + if( filename != NULL ) { + action(filename); + g_free(filename); + } } void mount_action_callback( GtkAction *action, gpointer user_data) { const gchar *dir = lxdream_get_config_value(CONFIG_DEFAULT_PATH); - open_file_dialog( "Open...", gdrom_mount_image, NULL, NULL, dir ); + open_file_dialog_cb( "Open...", gdrom_mount_image, NULL, NULL, dir ); } void reset_action_callback( GtkAction *action, gpointer user_data) { @@ -108,7 +131,7 @@ void load_binary_action_callback( GtkAction *action, gpointer user_data) { const gchar *dir = lxdream_get_config_value(CONFIG_DEFAULT_PATH); - open_file_dialog( "Open Binary...", file_load_magic, NULL, NULL, dir ); + open_file_dialog_cb( "Open Binary...", file_load_magic, NULL, NULL, dir ); } void load_state_preview_callback( GtkFileChooser *chooser, gpointer user_data ) @@ -172,7 +195,7 @@ void save_state_action_callback( GtkAction *action, gpointer user_data) { const gchar *dir = lxdream_get_config_value(CONFIG_SAVE_PATH); - save_file_dialog( "Save state...", dreamcast_save_state, "*.dst", _("lxDream Save State (*.dst)"), dir ); + save_file_dialog_cb( "Save state...", dreamcast_save_state, "*.dst", _("lxDream Save State (*.dst)"), dir ); } void about_action_callback( GtkAction *action, gpointer user_data) { @@ -247,7 +270,7 @@ void save_scene_action_callback( GtkAction *action, gpointer user_data) { const gchar *dir = lxdream_get_config_value(CONFIG_SAVE_PATH); - save_file_dialog( _("Save next scene..."), pvr2_save_next_scene, "*.dsc", _("lxdream scene file (*.dsc)"), dir ); + save_file_dialog_cb( _("Save next scene..."), pvr2_save_next_scene, "*.dsc", _("lxdream scene file (*.dsc)"), dir ); } int debug_window_get_selected_row( debug_window_t data ); --- a/src/gtkui/gtkui.h Wed Jun 24 02:27:34 2009 +0000 +++ b/src/gtkui/gtkui.h Wed Jun 24 02:41:12 2009 +0000 @@ -88,8 +88,14 @@ typedef gboolean (*file_callback_t)( const gchar *filename ); -void open_file_dialog( const char *title, file_callback_t action, const char *pattern, const char *patname, +gchar *open_file_dialog( const char *title, const char *pattern, const char *patname, const gchar *initial_dir ); +gchar *save_file_dialog( const char *title, const char *pattern, const char *patname, + const gchar *initial_dir ); +void open_file_dialog_cb( const char *title, file_callback_t action, const char *pattern, const char *patname, + const gchar *initial_dir ); +void save_file_dialog_cb( const char *title, file_callback_t action, const char *pattern, const char *patname, + const gchar *initial_dir ); /** * Extract the keyval of the key event if no modifier keys were pressed - * in other words get the keyval of the key by itself. The other way around --- a/src/hook.h Wed Jun 24 02:27:34 2009 +0000 +++ b/src/hook.h Wed Jun 24 02:41:12 2009 +0000 @@ -22,7 +22,7 @@ #include /** - * Hook functions are generally useful, so we'd let to limit the overhead (and + * Hook functions are generally useful, so we'd like to limit the overhead (and * opportunity for stupid bugs) by minimizing the amount of code involved. Glib * has GHook (and of course signals), but they don't actually simplify anything * at this level. @@ -46,6 +46,7 @@ #define FOREACH_HOOK( h, name ) struct name##_hook_struct *h; for( h = name##_hook_list; h != NULL; h = h->next ) +#define CALL_HOOKS0( name ) FOREACH_HOOK(h,name) { h->fn(h->user_data); } #define CALL_HOOKS( name, args... ) FOREACH_HOOK(h, name) { h->fn(args, h->user_data); } #define DEFINE_HOOK( name, fn_type ) \ --- a/src/main.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/main.c Wed Jun 24 02:41:12 2009 +0000 @@ -35,6 +35,7 @@ #include "maple/maple.h" #include "sh4/sh4.h" #include "aica/armdasm.h" +#include "vmu/vmulist.h" #include "hotkeys.h" #include "plugin.h" @@ -216,6 +217,7 @@ } gdrom_list_init(); + vmulist_init(); if( aica_program == NULL ) { dreamcast_init(); --- a/src/maple/controller.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/controller.c Wed Jun 24 02:41:12 2009 +0000 @@ -93,14 +93,15 @@ struct lxdream_config_entry config[CONTROLLER_CONFIG_ENTRIES+1]; } *controller_device_t; -struct maple_device_class controller_class = { "Sega Controller", controller_new }; +struct maple_device_class controller_class = { "Sega Controller", + MAPLE_TYPE_PRIMARY|MAPLE_GRAB_DONTCARE|MAPLE_SLOTS_2, controller_new }; static struct controller_device base_controller = { - { MAPLE_DEVICE_TAG, &controller_class, MAPLE_GRAB_DONTCARE, + { MAPLE_DEVICE_TAG, &controller_class, CONTROLLER_IDENT, CONTROLLER_VERSION, controller_get_config, controller_set_config_value, controller_attach, controller_detach, controller_destroy, - controller_clone, NULL, NULL, controller_get_cond, NULL, NULL, NULL, NULL, NULL }, + controller_clone, NULL, NULL, controller_get_cond, NULL, NULL, NULL, NULL, NULL, NULL }, {0x0000FFFF, 0x80808080}, {{ "dpad left", N_("Dpad left"), CONFIG_TYPE_KEY }, { "dpad right", N_("Dpad right"), CONFIG_TYPE_KEY }, --- a/src/maple/kbd.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/kbd.c Wed Jun 24 02:41:12 2009 +0000 @@ -52,13 +52,14 @@ uint8_t condition[8]; } *keyboard_device_t; -struct maple_device_class keyboard_class = { "Sega Keyboard", keyboard_new }; +struct maple_device_class keyboard_class = { "Sega Keyboard", MAPLE_GRAB_DONTCARE|MAPLE_TYPE_PRIMARY, keyboard_new }; static struct keyboard_device base_keyboard = { - { MAPLE_DEVICE_TAG, &keyboard_class, MAPLE_GRAB_DONTCARE, + { MAPLE_DEVICE_TAG, &keyboard_class, KEYBOARD_IDENT, KEYBOARD_VERSION, NULL, NULL, keyboard_attach, keyboard_detach, maple_default_destroy, - keyboard_clone, NULL, NULL, keyboard_get_cond, NULL, NULL, NULL }, + keyboard_clone, NULL, NULL, keyboard_get_cond, NULL, NULL, NULL, + NULL, NULL, NULL}, {0,0,0,0,0,0,0,0}, }; --- a/src/maple/lightgun.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/lightgun.c Wed Jun 24 02:41:12 2009 +0000 @@ -72,14 +72,15 @@ struct lxdream_config_entry config[LIGHTGUN_CONFIG_ENTRIES+1]; } *lightgun_device_t; -struct maple_device_class lightgun_class = { "Sega Lightgun", lightgun_new }; +struct maple_device_class lightgun_class = { "Sega Lightgun", + MAPLE_TYPE_PRIMARY|MAPLE_GRAB_NO|MAPLE_SLOTS_2, lightgun_new }; static struct lightgun_device base_lightgun = { - { MAPLE_DEVICE_TAG, &lightgun_class, MAPLE_GRAB_NO, + { MAPLE_DEVICE_TAG, &lightgun_class, LIGHTGUN_IDENT, LIGHTGUN_VERSION, lightgun_get_config, lightgun_set_config_value, lightgun_attach, lightgun_detach, lightgun_destroy, - lightgun_clone, NULL, NULL, lightgun_get_cond, NULL, NULL, NULL, + lightgun_clone, NULL, NULL, lightgun_get_cond, NULL, NULL, NULL, NULL, lightgun_start_gun, lightgun_stop_gun}, {0x0000FFFF, 0x80808080}, 0, -1, -1, {{ "dpad left", N_("Dpad left"), CONFIG_TYPE_KEY }, --- a/src/maple/maple.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/maple.c Wed Jun 24 02:41:12 2009 +0000 @@ -30,7 +30,7 @@ NULL, NULL, NULL }; struct maple_device_class *maple_device_classes[] = { - &controller_class, &keyboard_class, &lightgun_class, &mouse_class, NULL }; + &controller_class, &keyboard_class, &lightgun_class, &mouse_class, &vmu_class, NULL }; void maple_init( void ) { @@ -175,13 +175,26 @@ /* no device attached */ *((uint32_t *)return_buf) = -1; } else { - int status, func, block; + int status, func; + unsigned int pt, phase, block; out_length = 0; switch( cmd ) { case MAPLE_CMD_INFO: status = MAPLE_RESP_INFO; memcpy( return_buf+4, dev->ident, 112 ); out_length = 0x1C; + if( periph == 0 ) { + /* Identify command on the primary device also sets the + * bits in the address in the response according to the + * sub-peripherals present. + */ + recv_addr &= 0xE0; + for( i=0; i<5; i++ ) { + if( maple_devices[port][i+1] != NULL ) { + recv_addr |= (1<set_condition(dev, func, buf+16, - length); + length-1); if( status == 0 ) status = MAPLE_RESP_ACK; break; + case MAPLE_CMD_MEM_INFO: + func = GETWORD(12); + pt = GETWORD(16); + if( dev->get_memory_info == NULL ) + status = MAPLE_ERR_CMD_UNKNOWN; + else status = dev->get_memory_info(dev,func, pt, return_buf+8, &out_length); + if( status == 0 ) { + status = MAPLE_RESP_DATA; + PUTWORD(4,func); + } + break; case MAPLE_CMD_READ_BLOCK: func = GETWORD(12); - block = GETWORD(16); + pt = GETBYTE(16); + phase = GETBYTE(17); + block = (GETBYTE(18)<<8) | GETBYTE(19); if( dev->read_block == NULL ) status = MAPLE_ERR_CMD_UNKNOWN; - else status = dev->read_block(dev, func, block, + else status = dev->read_block(dev, func, pt, block, phase, return_buf+12, &out_length ); if( status == 0 ) { @@ -237,16 +263,26 @@ break; case MAPLE_CMD_WRITE_BLOCK: func = GETWORD(12); - block = GETWORD(16); + pt = GETBYTE(16); + phase = GETBYTE(17); + block = (GETBYTE(18)<<8) | GETBYTE(19); if( dev->write_block == NULL ) status = MAPLE_ERR_CMD_UNKNOWN; else { - status = dev->write_block(dev, func, block, - buf+20, length); + status = dev->write_block(dev, func, pt, block, phase, + buf+20, length-2); if( status == 0 ) status = MAPLE_RESP_ACK; } break; + case MAPLE_CMD_SYNC_BLOCK: + func = GETWORD(12); + pt = GETBYTE(16); + phase = GETBYTE(17); + block = (GETBYTE(18)<<8) | GETBYTE(19); + /* TODO: something? */ + status = MAPLE_RESP_ACK; + break; default: status = MAPLE_ERR_CMD_UNKNOWN; } @@ -352,8 +388,8 @@ for( j=0; j<6; j++ ) { if( maple_devices[i][j] != NULL ) { maple_device_t dev = maple_devices[i][j]; - if( dev->grab_mode > mode ) { - mode = dev->grab_mode; + if( (dev->device_class->flags&MAPLE_GRAB_MASK) > mode ) { + mode = dev->device_class->flags & MAPLE_GRAB_MASK; } } } --- a/src/maple/maple.h Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/maple.h Wed Jun 24 02:41:12 2009 +0000 @@ -26,6 +26,18 @@ #include #include "config.h" +#define MAPLE_PORTS 4 +#define MAPLE_MAX_DEVICES 24 /* 1 Primary + 5 secondary per port */ +#define MAPLE_USER_SLOTS 2 /* Number of slots to show in configuration */ + +/* Map devices to a single id from 0..MAPLE_MAX_DEVICES, to simplify + * configuration. Port is 0..3 (A..D) representing the primary ports, and + * slot is 0 for the primary, or 1..5 for for one the secondary slots. + */ +#define MAPLE_DEVID(port,slot) ( (port)|((slot)<<2) ) +#define MAPLE_DEVID_PORT(id) ((id)&0x03) +#define MAPLE_DEVID_SLOT(id) ((id)>>2) + #define MAPLE_CMD_INFO 1 /* Request device information */ #define MAPLE_CMD_EXT_INFO 2 /* Request extended information */ #define MAPLE_CMD_RESET 3 /* Reset device */ @@ -34,6 +46,7 @@ #define MAPLE_CMD_MEM_INFO 10 /* Get memory information */ #define MAPLE_CMD_READ_BLOCK 11 /* Block read */ #define MAPLE_CMD_WRITE_BLOCK 12 /* Block write */ +#define MAPLE_CMD_SYNC_BLOCK 13 /* Block sync */ #define MAPLE_CMD_SET_COND 14 /* Set condition */ #define MAPLE_RESP_INFO 5 /* Device information response */ #define MAPLE_RESP_EXT_INFO 6 /* Extended device information response */ @@ -56,18 +69,36 @@ #define MAPLE_FUNC_PURU_PURU 0x00010000 #define MAPLE_FUNC_MOUSE 0x00020000 -#define MAPLE_GRAB_DONTCARE 0 -#define MAPLE_GRAB_YES 1 -#define MAPLE_GRAB_NO 2 +/* Internal flags, mainly for UI consumption */ +#define MAPLE_GRAB_DONTCARE 0x00 +#define MAPLE_GRAB_YES 0x01 +#define MAPLE_GRAB_NO 0x02 +#define MAPLE_GRAB_MASK 0x03 +#define MAPLE_TYPE_PRIMARY 0x08 /* attaches directly to maple port */ +#define MAPLE_SLOTS_MASK 0xF0 /* number of slots on device (primaries only) */ +#define MAPLE_SLOTS_1 0x10 +#define MAPLE_SLOTS_2 0x20 +#define MAPLE_SLOTS(x) ((((x)->flags)&MAPLE_SLOTS_MASK)>>4) #define MAPLE_DEVICE_TAG 0x4D41504C #define MAPLE_DEVICE(x) ((maple_device_t)x) +/* Some convenience methods for VMU handling */ +#define MAPLE_IS_VMU(dev) ((dev)->device_class == &vmu_class) +#define MAPLE_IS_VMU_CLASS(clz) ((clz) == &vmu_class) +#define MAPLE_VMU_NAME(dev) (((dev)->get_config(dev))[0].value) +#define MAPLE_SET_VMU_NAME(dev,name) ((dev)->set_config_value((dev),0,(name))) +#define MAPLE_VMU_HAS_NAME(d1,name) (MAPLE_VMU_NAME(d1) == NULL ? name == NULL : \ + name != NULL && strcmp(MAPLE_VMU_NAME(d1),name) == 0) +#define MAPLE_IS_SAME_VMU(d1,d2) (MAPLE_VMU_NAME(d1) == NULL ? MAPLE_VMU_NAME(d2) == NULL : \ + MAPLE_VMU_NAME(d2) != NULL && strcmp(MAPLE_VMU_NAME(d1),MAPLE_VMU_NAME(d2)) == 0) + typedef const struct maple_device_class *maple_device_class_t; typedef struct maple_device *maple_device_t; struct maple_device_class { const char *name; + int flags; maple_device_t (*new_device)(); }; @@ -77,7 +108,6 @@ struct maple_device { uint32_t _tag; maple_device_class_t device_class; - int grab_mode; unsigned char ident[112]; unsigned char version[80]; lxdream_config_entry_t (*get_config)(struct maple_device *dev); @@ -92,10 +122,12 @@ int function, unsigned char *outbuf, unsigned int *buflen); int (*set_condition)(struct maple_device *dev, int function, unsigned char *inbuf, unsigned int buflen); - int (*read_block)(struct maple_device *dev, - int function, uint32_t block, unsigned char *outbuf, unsigned int *buflen); - int (*write_block)(struct maple_device *dev, - int function, uint32_t block, unsigned char *inbuf, unsigned int buflen); + int (*get_memory_info)(struct maple_device *dev, int function, unsigned int partition, + unsigned char *outbuf, unsigned int *buflen); + int (*read_block)(struct maple_device *dev, int function, unsigned int partition, + uint32_t block, unsigned int phase, unsigned char *outbuf, unsigned int *buflen); + int (*write_block)(struct maple_device *dev, int function, unsigned int partition, + uint32_t block, unsigned int phase, unsigned char *inbuf, unsigned int buflen); void (*start_gun)(struct maple_device *dev); void (*stop_gun)(struct maple_device *dev); }; @@ -104,6 +136,7 @@ extern struct maple_device_class keyboard_class; extern struct maple_device_class lightgun_class; extern struct maple_device_class mouse_class; +extern struct maple_device_class vmu_class; maple_device_t maple_new_device( const gchar *name ); maple_device_t maple_get_device( unsigned int port, unsigned int periph ); --- a/src/maple/mouse.c Wed Jun 24 02:27:34 2009 +0000 +++ b/src/maple/mouse.c Wed Jun 24 02:41:12 2009 +0000 @@ -55,13 +55,13 @@ int32_t axis[8]; } *mouse_device_t; -struct maple_device_class mouse_class = { "Sega Mouse", mouse_new }; +struct maple_device_class mouse_class = { "Sega Mouse", MAPLE_GRAB_YES|MAPLE_TYPE_PRIMARY, mouse_new }; static struct mouse_device base_mouse = { - { MAPLE_DEVICE_TAG, &mouse_class, MAPLE_GRAB_YES, + { MAPLE_DEVICE_TAG, &mouse_class, MOUSE_IDENT, MOUSE_VERSION, NULL, NULL, mouse_attach, mouse_detach, maple_default_destroy, - mouse_clone, NULL, NULL, mouse_get_cond, NULL, NULL, NULL, NULL, NULL }, + mouse_clone, NULL, NULL, mouse_get_cond, NULL, NULL, NULL, NULL, NULL, NULL }, 0, {0,0,0,0,0,0,0,0}, }; --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/maple/vmu.c Wed Jun 24 02:41:12 2009 +0000 @@ -0,0 +1,241 @@ +/** + * $Id: vmu.c 858 2008-09-02 03:34:00Z nkeynes $ + * + * Implementation of the SEGA VMU device + * Part No. HKT-7000 + * + * The standard VMU implements 3 functions - Clock, LCD, and memory card, + * in addition to having it's own little CPU, buttons, etc. The CPU isn't + * implemented just yet. + * + * Copyright (c) 2009 Nathan Keynes. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "display.h" +#include "maple/maple.h" +#include "vmu/vmuvol.h" +#include "vmu/vmulist.h" + +#define VMU_LCD_SIZE (48*4) +#define VMU_BLOCK_COUNT 256 +#define VMU_BLOCK_SIZE 512 +#define VMU_PHASE_SIZE 128 +#define VMU_CONFIG_ENTRIES 1 + +#define VMU_IDENT { 0x00, 0x00, 0x00, 0x0E, 0x7E, 0x7E, 0x3F, 0x40, 0x00, 0x05, 0x10, 0x00, \ + 0x00, 0x0F, 0x41, 0x00, 0xFF, 0x00, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6C, 0x20, 0x4D, 0x65, 0x6D, \ + 0x6F, 0x72, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \ + 0x20, 0x20, 0x20, 0x20, 0x50, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x42, 0x79, 0x20, \ + 0x6F, 0x72, 0x20, 0x55, 0x6E, 0x64, 0x65, 0x72, 0x20, 0x4C, 0x69, 0x63, 0x65, 0x6E, 0x73, 0x65, \ + 0x20, 0x46, 0x72, 0x6F, 0x6D, 0x20, 0x53, 0x45, 0x47, 0x41, 0x20, 0x45, 0x4E, 0x54, 0x45, 0x52, \ + 0x50, 0x52, 0x49, 0x53, 0x45, 0x53, 0x2C, 0x4C, 0x54, 0x44, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, \ + 0x7C, 0x00, 0x82, 0x00 } +#define VMU_VERSION { 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x30, 0x30, \ + 0x35, 0x2C, 0x31, 0x39, 0x39, 0x39, 0x2F, 0x30, 0x34, 0x2F, 0x31, 0x35, 0x2C, 0x33, 0x31, 0x35, \ + 0x2D, 0x36, 0x32, 0x30, 0x38, 0x2D, 0x30, 0x33, 0x2C, 0x53, 0x45, 0x47, 0x41, 0x20, 0x56, 0x69, \ + 0x73, 0x75, 0x61, 0x6C, 0x20, 0x4D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x20, 0x53, 0x79, 0x73, 0x74, \ + 0x65, 0x6D, 0x20, 0x42, 0x49, 0x4F, 0x53, 0x20, 0x50, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x65, 0x64, \ + 0x20, 0x62, 0x79, 0x20 } + +static void vmu_destroy( maple_device_t dev ); +static maple_device_t vmu_clone( maple_device_t dev ); +static maple_device_t vmu_new(); +static lxdream_config_entry_t vmu_get_config( maple_device_t dev ); +static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value ); +static int vmu_get_condition( maple_device_t dev, int function, unsigned char *outbuf, + unsigned int *outlen ); +static int vmu_get_meminfo( maple_device_t dev, int function, unsigned int pt, + unsigned char *outbuf, unsigned int *outlen ); +static void vmu_attach(struct maple_device *dev); +static void vmu_detach(struct maple_device *dev); +static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt, + uint32_t block, unsigned int phase, + unsigned char *outbuf, unsigned int *buflen); +static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt, + uint32_t block, unsigned int phase, + unsigned char *inbuf, unsigned int buflen); + +typedef struct vmu_device { + struct maple_device dev; + vmu_volume_t vol; + char lcd_bitmap[VMU_LCD_SIZE]; /* 48x32 bitmap */ + struct lxdream_config_entry config[VMU_CONFIG_ENTRIES+1]; +} *vmu_device_t; + +struct maple_device_class vmu_class = { "Sega VMU", MAPLE_GRAB_DONTCARE, vmu_new }; + +static struct vmu_device base_vmu = { + { MAPLE_DEVICE_TAG, &vmu_class, + VMU_IDENT, VMU_VERSION, + vmu_get_config, vmu_set_config_value, + vmu_attach, vmu_detach, vmu_destroy, + vmu_clone, NULL, NULL, vmu_get_condition, NULL, + vmu_get_meminfo, vmu_read_block, vmu_write_block, NULL, NULL }, + NULL, {0}, + {{ "volume", N_("Volume"), CONFIG_TYPE_FILE }, + { NULL, CONFIG_TYPE_NONE }} }; + +static maple_device_t vmu_new( ) +{ + vmu_device_t dev = malloc( sizeof(struct vmu_device) ); + memcpy( dev, &base_vmu, sizeof(base_vmu) ); + return MAPLE_DEVICE(dev); +} + +static maple_device_t vmu_clone( maple_device_t srcdevice ) +{ + vmu_device_t src = (vmu_device_t)srcdevice; + vmu_device_t dev = (vmu_device_t)vmu_new(); + lxdream_copy_config_list( dev->config, src->config ); + return MAPLE_DEVICE(dev); +} + +static lxdream_config_entry_t vmu_get_config( maple_device_t mdev ) +{ + vmu_device_t dev = (vmu_device_t)mdev; + return dev->config; +} + +static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value ) +{ + vmu_device_t vmu = (vmu_device_t)dev; + assert( key < VMU_CONFIG_ENTRIES ); + + if( value == vmu->config[key].value || + value != NULL && vmu->config[key].value != NULL && strcmp(vmu->config[key].value, value) == 0 ) { + return; /* Unchanged */ + } + + if( vmu->vol != NULL ) { + vmulist_detach_vmu(vmu->vol); + } + lxdream_set_config_value( &vmu->config[key], value ); + vmu->vol = vmulist_get_vmu_by_filename( value ); + if( vmu->vol != NULL ) { + vmulist_attach_vmu(vmu->vol, "MAPLE"); + } +} + +void vmu_attach(struct maple_device *dev) +{ + vmu_device_t vmu = (vmu_device_t)dev; + if( vmu->config[0].value != NULL ) { + vmu->vol = vmulist_get_vmu_by_filename(vmu->config[0].value); + if( vmu->vol != NULL ) { + vmulist_attach_vmu(vmu->vol, "MAPLE"); + } + } +} + +static void vmu_detach(struct maple_device *dev) +{ + vmu_device_t vmu = (vmu_device_t)dev; + if( vmu->vol != NULL ) { + vmulist_detach_vmu(vmu->vol); + vmu->vol = NULL; + } +} + +static void vmu_destroy( maple_device_t dev ) +{ + vmu_device_t vmu = (vmu_device_t)dev; + free( dev ); +} + +static int vmu_get_condition(struct maple_device *dev, int function, + unsigned char *outbuf, unsigned int *buflen) +{ +} +static int vmu_set_condition(struct maple_device *dev, int function, + unsigned char *inbuf, unsigned int buflen) +{ + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */ +} + +static int vmu_get_meminfo(struct maple_device *dev, int function, unsigned int pt, + unsigned char *outbuf, unsigned int *buflen) +{ + struct vmu_device *vmu = (struct vmu_device *)dev; + switch(function) { + case MAPLE_FUNC_MEMORY: + if( vmu->vol != NULL ) { + const struct vmu_volume_metadata *md = vmu_volume_get_metadata( vmu->vol, pt ); + memcpy( outbuf, md, sizeof(struct vmu_volume_metadata) ); + *buflen = sizeof(struct vmu_volume_metadata); + return 0; + } // Else fallthrough + case MAPLE_FUNC_LCD: + case MAPLE_FUNC_CLOCK: + return MAPLE_ERR_NO_RESPONSE; + default: + return MAPLE_ERR_FUNC_UNSUP; + } + +} +static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt, + uint32_t block, unsigned int phase, + unsigned char *outbuf, unsigned int *buflen) +{ + struct vmu_device *vmu = (struct vmu_device *)dev; + switch( function ) { + case MAPLE_FUNC_LCD: + if( pt == 0 && block == 0 ) { + *buflen = VMU_LCD_SIZE/4; + memcpy( outbuf, vmu->lcd_bitmap, VMU_LCD_SIZE/4 ); + } + return 0; + break; + case MAPLE_FUNC_MEMORY: + if( vmu->vol != NULL ) { + vmu_volume_read_block( vmu->vol, pt, block, outbuf ); + return 0; + } + // Else fallthrough for now + case MAPLE_FUNC_CLOCK: + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */ + default: + return MAPLE_ERR_FUNC_UNSUP; + } +} + +static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt, + uint32_t block, unsigned int phase, + unsigned char *inbuf, unsigned int buflen) +{ + struct vmu_device *vmu = (struct vmu_device *)dev; + switch( function ) { + case MAPLE_FUNC_LCD: + if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) { + memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE ); + } + return 0; + break; + case MAPLE_FUNC_MEMORY: + if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) { + vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf ); + return 0; + } + // Else fallthrough for now + case MAPLE_FUNC_CLOCK: + return MAPLE_ERR_NO_RESPONSE; /* CHECKME */ + default: + return MAPLE_ERR_FUNC_UNSUP; + } +} --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vmu/vmulist.c Wed Jun 24 02:41:12 2009 +0000 @@ -0,0 +1,314 @@ +/** + * $Id: vmulist.c 869 2008-09-08 07:56:33Z nkeynes $ + * + * VMU management - maintains a list of all known VMUs + * + * Copyright (c) 2009 Nathan Keynes. + * + * 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. + */ + +#include +#include +#include +#include +#include "vmulist.h" +#include "config.h" + +DEFINE_HOOK(vmulist_change_hook, vmulist_change_hook_t); + +typedef struct vmulist_entry { + const gchar *filename; + vmu_volume_t vol; + int attach_count; +} *vmulist_entry_t; + +/** + * Doubly-linked list of vmulist_entry_t maintained in sorted order by display name. + * Could be augmented with a hashtable if it gets too long + */ +static GList *vmu_list; + +#define ENTRY(it) ((vmulist_entry_t)(it)->data) +#define VOLUME(it) (ENTRY(it)->vol) +#define DISPLAY_NAME(it) vmulist_display_name(ENTRY(it)) + +static const char *vmulist_display_name(vmulist_entry_t ent) +{ + if( ent->filename == NULL ) { + return NULL; + } + const char *s = strrchr(ent->filename, '/' ); + if( s == NULL || *(s+1) == '\0' ) { + return ent->filename; + } else { + return s+1; + } +} + +static void vmulist_update_config( void ) +{ + GList *temp = NULL, *it; + + for( it = vmu_list; it != NULL; it = g_list_next(it) ) { + vmulist_entry_t entry = ENTRY(it); + temp = g_list_append( temp, (char *)entry->filename ); + } + lxdream_set_global_config_list_value( CONFIG_VMU, temp ); + g_list_free( temp ); +} + +static vmulist_entry_t vmulist_get_entry_by_name( const gchar *name ) +{ + GList *it; + for( it = vmu_list; it != NULL; it = g_list_next(it) ) { + const gchar *vmu_name = DISPLAY_NAME(it); + if( name == NULL ? vmu_name == NULL : vmu_name != NULL && strcmp( vmu_name, name ) == 0 ) { + return ENTRY(it); + } + } + return NULL; // not found +} + +static vmulist_entry_t vmulist_get_entry_by_filename( const gchar *name ) +{ + GList *it; + for( it = vmu_list; it != NULL; it = g_list_next(it) ) { + const gchar *vmu_name = ENTRY(it)->filename; + if( name == NULL ? vmu_name == NULL : vmu_name != NULL && strcmp( vmu_name, name ) == 0 ) { + return ENTRY(it); + } + } + return NULL; // not found +} + +static vmulist_entry_t vmulist_get_entry_by_volume( vmu_volume_t vol ) +{ + GList *it; + for( it = vmu_list; it != NULL; it = g_list_next(it) ) { + if( VOLUME(it) == vol ) { + return ENTRY(it); + } + } + return NULL; // not found +} + +static vmulist_entry_t vmulist_get_entry_by_index( unsigned int index ) +{ + return (vmulist_entry_t)g_list_nth_data(vmu_list,index); +} + +static gint vmulist_display_name_compare( gconstpointer a, gconstpointer b ) +{ + const char *aname = vmulist_display_name((vmulist_entry_t)a); + const char *bname = vmulist_display_name((vmulist_entry_t)b); + if( aname == bname ) + return 0; + if( aname == NULL ) + return -1; + if( bname == NULL ) + return 1; + return strcmp(aname,bname); +} + +/** + * Add a new entry into the list, maintaining the sorted order. + * If the filename is already in the list, it is updated instead. + */ +static vmulist_entry_t vmulist_add_entry( const gchar *filename, vmu_volume_t vol ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_filename(filename); + if( entry == NULL ) { + entry = g_malloc( sizeof(struct vmulist_entry) ); + entry->filename = g_strdup(filename); + entry->vol = vol; + vmu_list = g_list_insert_sorted(vmu_list, entry, vmulist_display_name_compare ); + } else { + if( entry->vol != vol && entry->vol != NULL ) + vmu_volume_destroy( entry->vol ); + entry->vol = vol; + /* NOTE: at the moment this can't require a resort, but if we allow + * user-editable display names it will + */ + } + entry->attach_count = 0; + + vmulist_update_config(); + CALL_HOOKS( vmulist_change_hook, VMU_ADDED, g_list_index(vmu_list,entry) ); + return entry; +} + +static void vmulist_remove_entry( vmulist_entry_t entry ) +{ + int idx = g_list_index(vmu_list, entry); + vmu_list = g_list_remove( vmu_list, entry ); + g_free( (char *)entry->filename ); + g_free( entry ); + vmulist_update_config(); + CALL_HOOKS( vmulist_change_hook, VMU_REMOVED, idx ); +} + +static unsigned int vmulist_get_index( vmulist_entry_t entry ) +{ + return g_list_index( vmu_list, entry ); +} + +int vmulist_add_vmu( const gchar *filename, vmu_volume_t vol ) +{ + vmulist_entry_t entry = vmulist_add_entry( filename, vol ); + return vmulist_get_index(entry); +} + +void vmulist_remove_vmu( vmu_volume_t vol ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_volume(vol); + if( entry != NULL ) { + vmulist_remove_entry(entry); + } +} + +const char *vmulist_get_name( unsigned int idx ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_index(idx); + if( entry != NULL ) { + return vmulist_display_name(entry); + } + return NULL; +} + +const char *vmulist_get_filename( unsigned int idx ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_index(idx); + if( entry != NULL ) { + return entry->filename; + } + return NULL; +} + +const char *vmulist_get_volume_name( vmu_volume_t vol ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_volume(vol); + if( entry != NULL ) { + return entry->filename; + } + return NULL; +} + +vmu_volume_t vmulist_get_vmu( unsigned int idx ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_index(idx); + if( entry != NULL ) { + if( entry->vol == NULL ) { + entry->vol = vmu_volume_load(entry->filename); + } + return entry->vol; + } + return NULL; +} + +vmu_volume_t vmulist_get_vmu_by_name( const gchar *name ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_name(name); + if( entry != NULL ) { + if( entry->vol == NULL ) { + entry->vol = vmu_volume_load(entry->filename); + } + return entry->vol; + } + return NULL; +} + +vmu_volume_t vmulist_get_vmu_by_filename( const gchar *name ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_filename(name); + if( entry != NULL ) { + if( entry->vol == NULL ) { + entry->vol = vmu_volume_load(entry->filename); + } + return entry->vol; + } else { + vmu_volume_t vol = vmu_volume_load( name ); + vmulist_add_entry( name, vol ); + return vol; + } +} + +int vmulist_get_index_by_filename( const gchar *name ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_filename(name); + if( entry != NULL ) { + return g_list_index( vmu_list, entry ); + } + return -1; +} + + +int vmulist_create_vmu( const gchar *filename, gboolean create_only ) +{ + vmu_volume_t vol = vmu_volume_new_default(filename); + + if( vmu_volume_save( filename, vol, create_only ) ) { + return vmulist_add_vmu( filename, vol ); + } else { + vmu_volume_destroy(vol); + } + return -1; +} + +gboolean vmulist_attach_vmu( vmu_volume_t vol, const gchar *where ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_volume(vol); + if( entry == NULL ) { + return FALSE; + } + entry->attach_count++; + return TRUE; +} + +void vmulist_detach_vmu( vmu_volume_t vol ) +{ + vmulist_entry_t entry = vmulist_get_entry_by_volume(vol); + if( entry != NULL && entry->attach_count > 0 ) { + entry->attach_count--; + } +} + +unsigned int vmulist_get_size(void) +{ + return g_list_length(vmu_list); +} + +void vmulist_init( void ) +{ + GList *filenames = lxdream_get_global_config_list_value( CONFIG_VMU ); + GList *ptr; + for( ptr = filenames; ptr != NULL; ptr = g_list_next(ptr) ) { + vmulist_add_entry( (gchar *)ptr->data, NULL ); + g_free( ptr->data ); + } + g_list_free( filenames ); +} + +void vmulist_save_all( void ) +{ + GList *it; + for( it = vmu_list; it != NULL; it = g_list_next(it) ) { + vmulist_entry_t entry = ENTRY(it); + if( entry->vol != NULL && vmu_volume_is_dirty(entry->vol) ) { + vmu_volume_save(entry->filename, entry->vol, FALSE); + } + } +} + +void vmulist_shutdown( void ) +{ + vmulist_save_all(); +} --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vmu/vmulist.h Wed Jun 24 02:41:12 2009 +0000 @@ -0,0 +1,95 @@ +/** + * $Id: vmulist.h 869 2008-09-08 07:56:33Z nkeynes $ + * + * VMU management - maintains a list of all known VMUs + * + * Copyright (c) 2009 Nathan Keynes. + * + * 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. + */ + + +#ifndef lxdream_vmulist_H +#define lxdream_vmulist_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hook.h" +#include "vmu/vmuvol.h" + +typedef enum { VMU_ADDED, VMU_MODIFIED, VMU_REMOVED } vmulist_change_type_t; + +/* Hook for notification of list change events */ +typedef gboolean (*vmulist_change_hook_t)(vmulist_change_type_t change, int rowidx, void *user_data); +DECLARE_HOOK(vmulist_change_hook, vmulist_change_hook_t); + +vmu_volume_t vmulist_get_vmu(unsigned int index); + +/** Retrieve a known vmu by name */ +vmu_volume_t vmulist_get_vmu_by_name(const gchar *name); + +/** Retrieve a vmu by filename. The filename/vmu will be added to the list if it's + * not already in it. + */ +vmu_volume_t vmulist_get_vmu_by_filename(const gchar *name); + +const char *vmulist_get_name(unsigned int index); + +const char *vmulist_get_filename(unsigned int index); + +const char *vmulist_get_volume_name( vmu_volume_t vol ); + + + +/** Mark a VMU as being attached. + * @return FALSE if the VMU was already attached, otherwise TRUE + */ +gboolean vmulist_attach_vmu( vmu_volume_t vol, const gchar *where ); + +/** Mark a VMU as detached. */ +void vmulist_detach_vmu( vmu_volume_t vol ); + +/** + * Create a new VMU at the given filename, and add it to the list + * @param filename to save the new VMU as + * @param create_only if TRUE, the file must not already exist. If FALSE, + * the create will overwrite any existing file at that filename. + * @return index of the VMU in the list, or -1 if the call failed. + **/ +int vmulist_create_vmu(const gchar *filename, gboolean create_only); + +/** Add a VMU volume to the list. Returns the index of the added volume */ +int vmulist_add_vmu(const gchar *filename, vmu_volume_t vol); + +int vmulist_get_index_by_filename( const gchar *name ); + +/** Remove a VMU volume from the list */ +void vmulist_remove_vmu(vmu_volume_t vol); + +/** Initialize the list */ +void vmulist_init(void); + +/** Save all VMUs in the list (actually only ones which have been written to + * some point) + **/ +void vmulist_save_all(void); + +void vmulist_shutdown(void); + +unsigned int vmulist_get_size(void); + +#ifdef __cplusplus +} +#endif + +#endif /* !lxdream_vmulist_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vmu/vmuvol.c Wed Jun 24 02:41:12 2009 +0000 @@ -0,0 +1,375 @@ +/** + * $Id: vmuvol.h 869 2008-09-08 07:56:33Z nkeynes $ + * + * VMU volume (ie block device) support + * + * Copyright (c) 2009 Nathan Keynes. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "vmu/vmuvol.h" +#include "dream.h" + +#define VMU_MAX_PARTITIONS 256 +#define VMU_MAX_BLOCKS 65536 /* Actually slightly less than this, but it'll do */ + +typedef struct vmu_partition { + struct vmu_volume_metadata metadata; + uint32_t block_count; + char *blocks; +} *vmu_partition_t; + +struct vmu_volume { + const gchar *display_name; + vmu_partnum_t part_count; + gboolean dirty; + struct vmu_partition part[0]; +}; + +/* On-VMU structures, courtesy of Marcus Comstedt */ +struct vmu_superblock { + char magic[16]; + uint8_t colour_flag; + uint8_t bgra[4]; + uint8_t pad1[27]; + char timestamp[8]; + char pad2[8]; + char unknown[6]; + uint16_t fat_block; + uint16_t fat_size; + uint16_t dir_block; + uint16_t dir_size; + uint16_t icon_shape; + uint16_t user_size; + /* remainder unknown */ +}; + +struct vmu_direntry { + uint8_t filetype; + uint8_t copy_flag; + uint16_t blkno; + char filename[12]; + char timestamp[8]; + uint16_t blksize; /* Size in blocks*/ + uint16_t hdroff; /* Header offset in blocks */ + char pad[4]; +}; + +#define MD(vmu,ptno) ((vmu)->part[ptno].metadata) + +#define VMU_BLOCK(vmu,ptno,blkno) (&(vmu)->part[ptno].blocks[(blkno)*VMU_BLOCK_SIZE]) + +#define VMU_FAT_ENTRY(vmu,pt,ent) ((uint16_t *)VMU_BLOCK(vmu, pt, (MD(vmu,pt).fat_block - ((ent)>>8))))[(ent)&0xFF] + +#define FAT_EMPTY 0xFFFC +#define FAT_EOF 0xFFFA + +static const struct vmu_volume_metadata default_metadata = { 255, 255, 254, 1, 253, 13, 0, 200, 31, 0, 128 }; + +vmu_volume_t vmu_volume_new_default( const gchar *display_name ) +{ + vmu_volume_t vol = g_malloc0( sizeof(struct vmu_volume) + sizeof(struct vmu_partition) ); + vol->part_count = 1; + vol->dirty = FALSE; + memcpy( &vol->part[0].metadata, &default_metadata, sizeof(struct vmu_volume_metadata) ); + vol->part[0].block_count = VMU_DEFAULT_VOL_BLOCKS; + vol->part[0].blocks = g_malloc0( VMU_DEFAULT_VOL_BLOCKS * VMU_BLOCK_SIZE ); + vol->display_name = display_name == NULL ? NULL : g_strdup(display_name); + vmu_volume_format( vol, 0, TRUE ); + return vol; +} + +void vmu_volume_destroy( vmu_volume_t vol ) +{ + int i; + if( vol == NULL ) + return; + + for( i=0; ipart_count; i++ ) { + g_free( vol->part[i].blocks ); + vol->part[i].blocks = NULL; + } + if( vol->display_name ) { + g_free( (char *)vol->display_name ); + vol->display_name = NULL; + } + g_free(vol); +} + +void vmu_volume_format( vmu_volume_t vol, vmu_partnum_t pt, gboolean quick ) +{ + if( pt >= vol->part_count ) { + return; + } + + if( !quick ) { + /* Wipe it completely first */ + memset( vol->part[pt].blocks, 0, (vol->part[pt].block_count) * VMU_BLOCK_SIZE ); + } + + struct vmu_volume_metadata *meta = &vol->part[pt].metadata; + unsigned int fatblkno = meta->fat_block; + unsigned int dirblkno = meta->dir_block; + + /* Write superblock */ + struct vmu_superblock *super = (struct vmu_superblock *)VMU_BLOCK(vol,pt, meta->super_block); + memset( super->magic, 0x55, 16 ); + memset( &super->colour_flag, 0, 240 ); /* Blank the rest for now */ + super->fat_block = meta->fat_block; + super->fat_size = meta->fat_size; + super->dir_block = meta->dir_block; + super->user_size = meta->user_size; + + /* Write file allocation tables */ + int i,j; + for( j=0; jfat_size; j++ ) { + uint16_t *fat = (uint16_t *)VMU_BLOCK(vol,pt,fatblkno-j); + for( i=0; i<256; i++ ) { + fat[i] = FAT_EMPTY; + } + } + + /* Fill in the system allocations in the FAT */ + for( i=0; ifat_size-1; i++ ) { + VMU_FAT_ENTRY(vol,pt,fatblkno-i) = fatblkno-i-1; + } + VMU_FAT_ENTRY(vol,pt,fatblkno - i) = FAT_EOF; + for( i=0; idir_size-1; i++ ) { + VMU_FAT_ENTRY(vol,pt,dirblkno-i) = dirblkno-i-1; + } + VMU_FAT_ENTRY(vol,pt,dirblkno-i) = FAT_EOF; + + /* If quick-format, blank the directory. Otherwise it's already been done */ + if( quick ) { + memset( VMU_BLOCK(vol,pt,dirblkno-meta->dir_size+1), + 0, meta->dir_size * VMU_BLOCK_SIZE ); + } +} + +/*************************** File load/save ********************************/ + +/** + * Current file has 1 META chunk for all volume metadata, followed by a + * DATA chunk for each partition's block data. The META chunk is required to + * occur before any DATA blocks. + * Unknown chunks are skipped to allow for forwards compatibility if/when + * we add the VMU runtime side of things + */ + +struct vmu_file_header { + char magic[16]; + uint32_t version; + uint32_t head_len; + uint32_t part_count; + uint32_t display_name_len; + char display_name[0]; +}; + +struct vmu_chunk_header { + char name[4]; + uint32_t length; +}; + + + +gboolean vmu_volume_save( const gchar *filename, vmu_volume_t vol, gboolean create_only ) +{ + struct vmu_file_header head; + struct vmu_chunk_header chunk; + int i; + + FILE *f = fopen( filename, (create_only ? "wx" : "w") ); /* Portable? */ + if( f == NULL ) { + return FALSE; + } + + /* File header */ + memcpy( head.magic, VMU_FILE_MAGIC, 16 ); + head.version = VMU_FILE_VERSION; + head.part_count = vol->part_count; + head.display_name_len = vol->display_name == NULL ? 0 : (strlen(vol->display_name)+1); + head.head_len = sizeof(head) + head.display_name_len; + fwrite( &head, sizeof(head), 1, f ); + if( vol->display_name != NULL ) { + fwrite( vol->display_name, head.display_name_len, 1, f ); + } + + /* METAdata chunk */ + memcpy( chunk.name, "META", 4 ); + chunk.length = sizeof(struct vmu_volume_metadata) * vol->part_count; + fwrite( &chunk, sizeof(chunk), 1, f ); + for( i=0; i < vol->part_count; i++ ) { + fwrite( &vol->part[i].metadata, sizeof(struct vmu_volume_metadata), 1, f ); + } + + /* partition DATA chunks */ + for( i=0; i< vol->part_count; i++ ) { + memcpy( chunk.name, "DATA", 4 ); + chunk.length = 0; + fwrite( &chunk, sizeof(chunk), 1, f ); + long posn = ftell(f); + fwrite( &vol->part[i].block_count, sizeof(vol->part[i].block_count), 1, f ); + fwrite_gzip( vol->part[i].blocks, vol->part[i].block_count, VMU_BLOCK_SIZE, f ); + long end = ftell(f); + fseek( f, posn - sizeof(chunk.length), SEEK_SET ); + chunk.length = end-posn; + fwrite( &chunk.length, sizeof(chunk.length), 1, f ); + fseek( f, end, SEEK_SET ); + } + fclose(f); + vol->dirty = FALSE; + return TRUE; +} + +vmu_volume_t vmu_volume_load( const gchar *filename ) +{ + struct vmu_file_header head; + struct vmu_chunk_header chunk; + vmu_volume_t vol; + int i; + + FILE *f = fopen( filename, "ro" ); + if( f == NULL ) { + ERROR( "Unable to open VMU file '%s': %s", filename, strerror(errno) ); + return FALSE; + } + + if( fread( &head, sizeof(head), 1, f ) != 1 || + memcmp(head.magic, VMU_FILE_MAGIC, 16) != 0 || + head.part_count > VMU_MAX_PARTITIONS || + head.head_len < (sizeof(head) + head.display_name_len) ) { + fclose(f); + ERROR( "Unable to load VMU '%s': bad file header", filename ); + return NULL; + } + + vol = (vmu_volume_t)g_malloc0( sizeof(struct vmu_volume) + sizeof(struct vmu_partition)*head.part_count ); + vol->part_count = head.part_count; + vol->dirty = FALSE; + if( head.display_name_len != 0 ) { + vol->display_name = g_malloc( head.display_name_len ); + fread( (char *)vol->display_name, head.display_name_len, 1, f ); + } + fseek( f, head.head_len, SEEK_SET ); + + gboolean have_meta = FALSE; + int next_part = 0; + while( !feof(f) && fread( &chunk, sizeof(chunk), 1, f ) == 1 ) { + if( memcmp( &chunk.name, "META", 4 ) == 0 ) { + if( have_meta || chunk.length != head.part_count * sizeof(struct vmu_volume_metadata) ) { + vmu_volume_destroy(vol); + fclose(f); + ERROR( "Unable to load VMU '%s': bad metadata size (expected %d but was %d)", filename, + head.part_count * sizeof(struct vmu_volume_metadata), chunk.length ); + return NULL; + } + for( i=0; ipart[i].metadata, sizeof(struct vmu_volume_metadata), 1, f ); + } + have_meta = TRUE; + } else if( memcmp( &chunk.name, "DATA", 4 ) == 0 ) { + uint32_t block_count; + fread( &block_count, sizeof(block_count), 1, f ); + if( next_part >= vol->part_count || block_count >= VMU_MAX_BLOCKS ) { + // Too many partitions / blocks + vmu_volume_destroy(vol); + fclose(f); + ERROR( "Unable to load VMU '%s': too large (%d/%d)", filename, next_part, block_count ); + return NULL; + } + vol->part[next_part].block_count = block_count; + vol->part[next_part].blocks = g_malloc(block_count*VMU_BLOCK_SIZE); + fread_gzip(vol->part[next_part].blocks, VMU_BLOCK_SIZE, block_count, f ); + next_part++; + } else { + // else skip unknown block + fseek( f, SEEK_CUR, chunk.length ); + WARN( "Unexpected VMU data chunk: '%4.4s'", chunk.name ); + } + } + + fclose(f); + + if( !have_meta || next_part != vol->part_count ) { + vmu_volume_destroy( vol ); + return NULL; + } + + return vol; +} + +/*************************** Accessing data ********************************/ +const char *vmu_volume_get_display_name( vmu_volume_t vol ) +{ + return vol->display_name; +} + +void vmu_volume_set_display_name( vmu_volume_t vol, const gchar *name ) +{ + if( vol->display_name != NULL ) { + g_free( (char *)vol->display_name ); + } + if( name == NULL ) { + vol->display_name = NULL; + } else { + vol->display_name = g_strdup(name); + } +} + +gboolean vmu_volume_is_dirty( vmu_volume_t vol ) +{ + return vol->dirty; +} + +gboolean vmu_volume_read_block( vmu_volume_t vol, vmu_partnum_t pt, unsigned int block, unsigned char *out ) +{ + if( pt >= vol->part_count || block >= vol->part[pt].block_count ) { + return FALSE; + } + + memcpy( out, VMU_BLOCK(vol,pt,block), VMU_BLOCK_SIZE ); + return TRUE; +} + +gboolean vmu_volume_write_block( vmu_volume_t vol, vmu_partnum_t pt, unsigned int block, unsigned char *in ) +{ + if( pt >= vol->part_count || block >= vol->part[pt].block_count ) { + return FALSE; + } + memcpy( VMU_BLOCK(vol,pt,block), in, VMU_BLOCK_SIZE ); + vol->dirty = TRUE; +} + +gboolean vmu_volume_write_phase( vmu_volume_t vol, vmu_partnum_t pt, unsigned int block, unsigned int phase, unsigned char *in ) +{ + if( pt >= vol->part_count || block >= vol->part[pt].block_count || phase >= 4 ) { + return FALSE; + } + memcpy( VMU_BLOCK(vol,pt,block) + (phase*128), in, VMU_BLOCK_SIZE/4 ); + vol->dirty = TRUE; +} + +const struct vmu_volume_metadata *vmu_volume_get_metadata( vmu_volume_t vol, vmu_partnum_t partition ) +{ + if( partition >= vol->part_count ) { + return NULL; + } else { + return &vol->part[partition].metadata; + } +} --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vmu/vmuvol.h Wed Jun 24 02:41:12 2009 +0000 @@ -0,0 +1,116 @@ +/** + * $Id: vmuvol.h 869 2008-09-08 07:56:33Z nkeynes $ + * + * VMU volume (ie block device) declarations + * + * Copyright (c) 2009 Nathan Keynes. + * + * 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. + */ + +#ifndef lxdream_vmuvol_H +#define lxdream_vmuvol_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lxdream.h" + +typedef struct vmu_volume *vmu_volume_t; +typedef unsigned int vmu_partnum_t; + +#define VMU_FILE_MAGIC "%!Dreamcast$VMU\0" +#define VMU_FILE_VERSION 0x00010000 + +/** VMU block size is 512 bytes */ +#define VMU_BLOCK_SIZE 512 + +/** Default VMU volume is 256 blocks */ +#define VMU_DEFAULT_VOL_BLOCKS 256 + +/** Default VMU has 200 user blocks */ +#define VMU_DEFAULT_VOL_USERBLOCKS 200 + +/** Default superblock is at block 255 */ +#define VMU_DEFAULT_VOL_SUPERBLOCK 255 + +/** Default file allocation table is at block 254 */ +#define VMU_DEFAULT_VOL_FATBLOCK 254 + +/** Default root directory block starts at block 253 */ +#define VMU_DEFAULT_VOL_ROOTDIR 253 + +/** + * VMU metadata structure. Note that this is structured to match the maple + * memory info result packet. + */ +struct vmu_volume_metadata { + uint32_t last_block; + uint16_t super_block; + uint16_t fat_block; + uint16_t fat_size; + uint16_t dir_block; + uint16_t dir_size; + uint16_t user_block; /* ?? */ + uint16_t user_size; + uint16_t unknown[3]; /* 0x001F, 0x0000, 0x0080 */ +}; + +/** + * Construct a new VMU volume with a single partition of the default size + * (128Kb). The partitions is formatted using the default filesystem + * organization. + */ +vmu_volume_t vmu_volume_new_default( const gchar *display_name ); + +void vmu_volume_destroy( vmu_volume_t vol ); + +void vmu_volume_set_display_name( vmu_volume_t vol, const gchar *display_name ); + +const gchar *vmu_volume_get_display_name( vmu_volume_t vol ); + +gboolean vmu_volume_is_dirty( vmu_volume_t vol ); + +/** + * Format a VMU partition according to the standard layout + */ +void vmu_volume_format( vmu_volume_t vol, vmu_partnum_t partition, gboolean quick ); + + + +/** + * Load a VMU volume from a file. + */ +vmu_volume_t vmu_volume_load( const gchar *filename ); + +/** + * Save a VMU volume to a file. + */ +gboolean vmu_volume_save( const gchar *filename, vmu_volume_t vol, gboolean create_only ); + +gboolean vmu_volume_read_block( vmu_volume_t vol, vmu_partnum_t partition, unsigned int block, unsigned char *out ); +gboolean vmu_volume_write_block( vmu_volume_t vol, vmu_partnum_t partition, unsigned int block, unsigned char *in ); +gboolean vmu_volume_write_phase( vmu_volume_t vol, vmu_partnum_t partition, unsigned int block, + unsigned int phase, unsigned char *in ); + +/** + * Retrieve the metadata for the given volume. The metadata is owned by the + * volume and should not be modified or freed. + */ +const struct vmu_volume_metadata *vmu_volume_get_metadata( vmu_volume_t vol, vmu_partnum_t partition ); + + +#ifdef __cplusplus +} +#endif + +#endif /* !lxdream_vmuvol_H */