Merge branch 'master' into master
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.c eol=lf
|
||||
*.h eol=lf
|
16
.gitignore
vendored
@ -10,3 +10,19 @@ src/16inst_c.h
|
||||
src/8inst_c.h
|
||||
src/size_c.h
|
||||
|
||||
gsplus
|
||||
gsportx
|
||||
gsport
|
||||
*.exe
|
||||
|
||||
*.gsp
|
||||
|
||||
# Storage for many disk images for testing the emulator.
|
||||
# Games, demos, apps, etc. Not part of the project.
|
||||
images/
|
||||
|
||||
# Screenshot dir
|
||||
screens/
|
||||
|
||||
# build tools that are often kept/tested locally as well as on the ci machines
|
||||
yoursway-create-dmg/
|
||||
|
259
.gitlab-ci.yml
@ -1,7 +1,12 @@
|
||||
|
||||
stages:
|
||||
- build
|
||||
- package
|
||||
- deploy
|
||||
- updatewebsite
|
||||
|
||||
|
||||
|
||||
# TARGET SYSTEM: UBUNTU X
|
||||
build-ubuntu-x:
|
||||
tags:
|
||||
- ubuntu
|
||||
@ -11,29 +16,119 @@ build-ubuntu-x:
|
||||
- cd src
|
||||
- ln -s vars_x86linux_x11 vars
|
||||
- make clean ; make
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplusx
|
||||
expire_in: 10 minutes
|
||||
only:
|
||||
- master
|
||||
|
||||
package-ubuntu-x:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: package
|
||||
script:
|
||||
- cp src/config.txt .
|
||||
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
|
||||
- cp LICENSE.txt doc/
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplusx
|
||||
- config.txt
|
||||
- doc/gsplusmanual.pdf
|
||||
- doc/LICENSE.txt
|
||||
expire_in: 10 minutes
|
||||
only:
|
||||
- master
|
||||
|
||||
|
||||
# TARGET SYSTEM: DEPRECATED, UBUNTU SDL
|
||||
build-ubuntu-sdl:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: build
|
||||
script:
|
||||
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev
|
||||
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev libsdl2-image-dev
|
||||
- cd src
|
||||
- ln -s vars_x86linux_sdl vars
|
||||
- make clean ; make
|
||||
only:
|
||||
- master
|
||||
|
||||
|
||||
# TARGET SYSTEM: REALLY ANY LINUX, BUT UBUNTU W SDL2
|
||||
build-ubuntu-sdl2:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: build
|
||||
script:
|
||||
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev
|
||||
- sudo apt-get update -qq && sudo apt-get install -y -qq g++ libpcap0.8-dev libx11-dev libsdl2-dev libfreetype6-dev libsdl2-image-dev
|
||||
- cd src
|
||||
- ln -s vars_x86linux_sdl2 vars
|
||||
- make clean ; make
|
||||
- mv ../gsplus ../gsplus-ubuntu-sdl.bin
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus-ubuntu-sdl.bin
|
||||
expire_in: 10 minutes
|
||||
|
||||
package-ubuntu-sdl2:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: package
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
PACKAGE_DIR: gsplus-ubuntu-sdl
|
||||
script:
|
||||
- mkdir $PACKAGE_DIR
|
||||
- mkdir $PACKAGE_DIR/doc
|
||||
- cp gsplus-ubuntu-sdl.bin $PACKAGE_DIR/gsplus
|
||||
- cp src/config.txt $PACKAGE_DIR
|
||||
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> $PACKAGE_DIR/config.txt'
|
||||
- cp src/parallel.rom %PACKAGE_DIR%
|
||||
- cp LICENSE.txt $PACKAGE_DIR/doc/
|
||||
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
|
||||
- cp doc/README.txt %PACKAGE_DIR%
|
||||
- tar -cvjf gsplus-ubuntu-sdl.tar.bz2 $PACKAGE_DIR
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus-ubuntu-sdl.tar.bz2
|
||||
expire_in: 10 minutes
|
||||
|
||||
package-ubuntu-sdl2-deb:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: package
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
PACKAGE_NAME: gsplus_$CI_VERSION-0
|
||||
script:
|
||||
- mkdir -p $PACKAGE_NAME/usr/local/bin
|
||||
- mkdir -p $PACKAGE_NAME/DEBIAN
|
||||
- cp gsplus-ubuntu-sdl.bin $PACKAGE_NAME/usr/local/bin/gsplus
|
||||
- cp assets/control $PACKAGE_NAME/DEBIAN
|
||||
- dpkg-deb --build $PACKAGE_NAME
|
||||
artifacts:
|
||||
paths:
|
||||
- $PACKAGE_NAME.deb
|
||||
expire_in: 10 minutes
|
||||
|
||||
deploy-ubuntu:
|
||||
tags:
|
||||
- ubuntu
|
||||
stage: deploy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
PACKAGE_NAME: gsplus_$CI_VERSION-0
|
||||
|
||||
script:
|
||||
- aws s3 cp gsplus-ubuntu-sdl.tar.bz2 s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/ubuntu-sdl/$CI_BUILD_ID/ --acl public-read
|
||||
- aws s3 cp $PACKAGE_NAME.deb s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/ubuntu-sdl-deb/$CI_BUILD_ID/ --acl public-read
|
||||
|
||||
|
||||
|
||||
|
||||
# TARGET SYSTEM: OSX 10.SOMETHING
|
||||
build-osx:
|
||||
tags:
|
||||
- osx
|
||||
@ -42,14 +137,166 @@ build-osx:
|
||||
- cd src
|
||||
- ln -s vars_osx_sdl2 vars
|
||||
- make clean ; make
|
||||
- mv ../gsplus ../gsplus-osx
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus-osx
|
||||
expire_in: 10 minutes
|
||||
|
||||
package-osx:
|
||||
tags:
|
||||
- osx
|
||||
stage: package
|
||||
script:
|
||||
- mv gsplus-osx gsplus
|
||||
- cp src/config.txt .
|
||||
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
|
||||
- chmod +x make_dist_mac.sh
|
||||
- ./make_dist_mac.sh
|
||||
- chmod +x make_dmg_mac.sh
|
||||
- ./make_dmg_mac.sh
|
||||
artifacts:
|
||||
paths:
|
||||
- GSplus-Install.dmg
|
||||
expire_in: 10 minutes
|
||||
|
||||
deploy-osx:
|
||||
tags:
|
||||
- osx
|
||||
stage: deploy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- aws s3 cp GSplus-Install.dmg s3://$AWS_BUCKET/$CI_TAG/$CI_VERSION/$CI_PIPELINE_ID/osx/$CI_BUILD_ID/ --acl public-read
|
||||
|
||||
|
||||
|
||||
# TARGET SYSTEM: WIN32 WIN API UNDER CYGWIN
|
||||
build-win32:
|
||||
tags:
|
||||
- windows
|
||||
stage: build
|
||||
script:
|
||||
- bash -c "cd src; ln -s vars_win32 vars; make clean ; make"
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus32.exe
|
||||
expire_in: 10 minutes
|
||||
only:
|
||||
- master
|
||||
- /^win.*/
|
||||
|
||||
package-win32:
|
||||
tags:
|
||||
- windows
|
||||
stage: package
|
||||
script:
|
||||
- cp src/config.txt .
|
||||
- 'echo "# CI_BUILD_ID: $CI_BUILD_ID" >> config.txt'
|
||||
- cp LICENSE.txt doc/
|
||||
- cp /bin/cyggcc_s-1.dll .
|
||||
- cp /bin/cygstdc++-6.dll .
|
||||
- cp /bin/cygwin1.dll .
|
||||
- cp /bin/cygfreetype-6.dll .
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
PACKAGE_DIR: gsplus-win32
|
||||
script:
|
||||
- mkdir %PACKAGE_DIR%
|
||||
- cp gsplus32.exe %PACKAGE_DIR%
|
||||
- cp LICENSE.txt %PACKAGE_DIR%
|
||||
- cp src/config.txt %PACKAGE_DIR%
|
||||
- cp src/parallel.rom %PACKAGE_DIR%
|
||||
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
|
||||
- cp doc/README.txt %PACKAGE_DIR%
|
||||
- cp /bin/cyggcc_s-1.dll %PACKAGE_DIR%
|
||||
- cp /bin/cygstdc++-6.dll %PACKAGE_DIR%
|
||||
- cp /bin/cygwin1.dll %PACKAGE_DIR%
|
||||
- cp /bin/cygfreetype-6.dll %PACKAGE_DIR%
|
||||
- zip gsplus-win32.zip -r %PACKAGE_DIR%
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus-win32.zip
|
||||
expire_in: 10 minutes
|
||||
only:
|
||||
- master
|
||||
- /^win.*/
|
||||
|
||||
deploy-win32:
|
||||
tags:
|
||||
- windows
|
||||
stage: deploy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- aws s3 cp gsplus-win32.zip s3://%AWS_BUCKET%/%CI_TAG%/%CI_VERSION%/%CI_PIPELINE_ID%/win32/%CI_BUILD_ID%/ --acl public-read
|
||||
only:
|
||||
- master
|
||||
- /^win.*/
|
||||
|
||||
# TARGET SYSTEM: WIN32 SDL2 UNDER CYGWIN W MINGW64 SDL2 LIBS
|
||||
build-win-sdl2:
|
||||
tags:
|
||||
- windows
|
||||
stage: build
|
||||
script:
|
||||
- cd src
|
||||
- ln -s vars_win32 vars
|
||||
- make clean ; make
|
||||
- ln -s vars_win32_sdl2 vars
|
||||
- make clean
|
||||
- make
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus.exe
|
||||
expire_in: 10 minutes
|
||||
|
||||
package-win-sdl2:
|
||||
tags:
|
||||
- windows
|
||||
stage: package
|
||||
variables:
|
||||
GIT_STRATEGY: fetch
|
||||
PACKAGE_DIR: gsplus-win-sdl
|
||||
script:
|
||||
- mkdir %PACKAGE_DIR%
|
||||
- cp gsplus.exe %PACKAGE_DIR%
|
||||
- cp LICENSE.txt %PACKAGE_DIR%
|
||||
- cp src/config.txt %PACKAGE_DIR%
|
||||
- cp src/parallel.rom %PACKAGE_DIR%
|
||||
- cp doc/gsplusmanual.pdf %PACKAGE_DIR%
|
||||
- cp doc/README.txt %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygbz2-1.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygfreetype-6.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cyggcc_s-1.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygjpeg-8.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygpng16-16.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygjpeg-8.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygstdc++-6.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygwin1.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/cygwin/bin/cygz.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/mingw/i686-w64-mingw32/bin/SDL2.dll %PACKAGE_DIR%
|
||||
- cp /cygdrive/c/mingw/i686-w64-mingw32/bin/SDL2_image.dll %PACKAGE_DIR%
|
||||
- zip gsplus-win-sdl.zip -r %PACKAGE_DIR%
|
||||
artifacts:
|
||||
paths:
|
||||
- gsplus-win-sdl.zip
|
||||
expire_in: 10 minutes
|
||||
deploy-win-sdl2:
|
||||
tags:
|
||||
- windows
|
||||
stage: deploy
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- aws s3 cp gsplus-win-sdl.zip s3://%AWS_BUCKET%/%CI_TAG%/%CI_VERSION%/%CI_PIPELINE_ID%/win-sdl/%CI_BUILD_ID%/ --acl public-read
|
||||
|
||||
update-website-universal:
|
||||
tags:
|
||||
- osx
|
||||
stage: updatewebsite
|
||||
variables:
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
- aws s3 ls gsplus-artifacts/ --recursive > s3artifacts.txt
|
||||
- php assets/updatewebsite.php s3artifacts.txt public > index.html
|
||||
- php assets/updatewebsite.php s3artifacts.txt auto > index_auto.html
|
||||
- aws s3 cp index.html s3://$AWS_BUCKET/ --acl public-read
|
||||
- aws s3 cp index_auto.html s3://$AWS_BUCKET/ --acl public-read
|
||||
|
19
COPYRIGHT.txt
Normal file
@ -0,0 +1,19 @@
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
Copyright (C) 2016 - 2018 Dagen Brock
|
||||
Copyright (C) 2010 - 2014 GSport contributors
|
||||
Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
22
README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# GSplus
|
||||
An Apple IIgs emulator for Mac OSX, Windows, and Linux.
|
||||
|
||||

|
||||
|
||||
# About
|
||||
This is an early release of an experimental project to modernize the
|
||||
KEGS/GSport emulator platform and eventually extend it.
|
||||
|
||||
# Install
|
||||
Go to https://apple2.gs/plus to get the latest downloads for your system.
|
||||
|
||||
# Usage Notes
|
||||
You need to provide the ROM file and disk images and a config file. I'd
|
||||
recommend you just drop it in your current GSport or KEGS folder and run it
|
||||
from there.
|
||||
|
||||
See the doc/gsplusmanual.pdf file for much more complete documentation.
|
||||
|
||||
# Build Instructions
|
||||
See the /doc/ directory for "Developer-Quickstart" docs which cover building
|
||||
for the various platforms.
|
55
README.txt
@ -1,55 +0,0 @@
|
||||
GSPLUS ALPHA
|
||||
============
|
||||
|
||||
This is an early release of an experimental project to modernize the
|
||||
KEGS/GSport emulator platform and eventually extend it.
|
||||
|
||||
The first steps are represented here. This release features a new SDL2 driver.
|
||||
SDL or "Simple DirectMedia Layer" allows me to write one driver to handle input
|
||||
and output (video, mouse, keyboard, audio, joystick). The hope is that I can
|
||||
leverage the multi-platform nature of SDL to provide first-class support for
|
||||
the major plaforms supported by SDL, which includes Mac OSX, Windows and Linux.
|
||||
|
||||
I'm not a huge fan of OSX, but I keep a MacBook Pro nearby for work, so the
|
||||
first version to be release is this OSX build. I'll try to have builds for
|
||||
other platforms available in a few weeks.
|
||||
|
||||
|
||||
|
||||
Some notes:
|
||||
You need to provide the ROM file and disk images and a config file. I'd
|
||||
recommend you just drop it in your current GSport or KEGS folder and run it
|
||||
from there.
|
||||
|
||||
I took out the "middle-click to enter debug" because it's stupid. No one wants
|
||||
to use their mouse wheel to enter a debugger. *smacks forehead*
|
||||
If you want to enter debug, it's shift-F6. F6 is speed up, same as right and
|
||||
middle mouse.
|
||||
|
||||
The big feature is FULLSCREEN SUPPORT! Yaya! Hit F11 for full-screen. My Mac
|
||||
has some stupid expose feature mapped over this, so I basically hit
|
||||
control-fn-F11 and it works. Stupid Macs. :P
|
||||
|
||||
I haven't changed much else at this point. This is an experimental driver and
|
||||
a very early release, so I'm not looking for feedback. Please don't tell me
|
||||
about it rendering weird, making funny noises, crashing your computer, stealing
|
||||
your car, or blowing up your house.
|
||||
|
||||
Please be aware that this is based on KEGS original source by Kent Dickey, so
|
||||
I must provide the source as per the original license.
|
||||
|
||||
I'd recommend you not really try building it at this time, but if you want, go
|
||||
for it.
|
||||
|
||||
https://github.com/digarok/gsplus
|
||||
|
||||
I'll keep a page for this at http://apple2.gs/plus
|
||||
|
||||
Dagen Brock
|
||||
Saturday, January 30, 2016 1:18PM
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Build Instructions
|
||||
==========================
|
||||
See the /doc/ directory for "Developer-Quickstart" docs which cover building
|
||||
for the various platforms. (as fast as I can write them :P )
|
33
assets/Info.plist
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>gsplus</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>0.14, Copyright 2018 Dagen Brock</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>gsp-icons.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.dagenbrock.gsplus</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
</array>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>gsplus</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.14</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2018 Dagen Brock</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.3</string>
|
||||
</dict>
|
||||
</plist>
|
10
assets/control
Normal file
@ -0,0 +1,10 @@
|
||||
Package: gsplus
|
||||
Version: 0.14-0
|
||||
Section: base
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
Depends: libsdl2-2.0-0, libfreetype6, libsdl2-image-2.0-0
|
||||
Maintainer: Dagen Brock <dagenbrock@gmail.com>
|
||||
Description: GSplus
|
||||
An Apple IIgs emulator for multiple platforms,
|
||||
based on KEGS
|
26
assets/dump_icon.py
Normal file
@ -0,0 +1,26 @@
|
||||
# need pil/pillow
|
||||
# sudo pip install pillow
|
||||
# ^^ on mac osx
|
||||
from PIL import Image
|
||||
#im = Image.open("gsp_icon_128.png") #Can be many different formats.
|
||||
im = Image.open("gsp_icon_256.png") #Can be many different formats.
|
||||
pix = im.load()
|
||||
print im.size #Get the width and hight of the image for iterating over
|
||||
width = im.size[0]
|
||||
height = im.size[1]
|
||||
count = 0
|
||||
for y in range(0,width):
|
||||
for x in range(0,height):
|
||||
# print pix[x,y]
|
||||
print("0x%02x%02x%02x%02x, " % pix[x,y]),
|
||||
# RRGGBBAA
|
||||
count = count + 1
|
||||
if count == 32:
|
||||
count = 0
|
||||
print
|
||||
|
||||
|
||||
#print pix[x,y] #Get the RGBA Value of the a pixel of an image
|
||||
#pix[x,y] = value # Set the RGBA Value of the image (tuple)
|
||||
|
||||
|
BIN
assets/gsback.png
Normal file
After Width: | Height: | Size: 116 KiB |
BIN
assets/gsback.psd
Normal file
BIN
assets/gsp-dmg-icons.icns
Normal file
BIN
assets/gsp-icons.icns
Normal file
BIN
assets/gsp_dmg_bg_600x500.png
Normal file
After Width: | Height: | Size: 193 KiB |
BIN
assets/gsp_dmg_bg_600x500.psd
Normal file
BIN
assets/gsp_dmg_icon_1024.png
Normal file
After Width: | Height: | Size: 502 KiB |
BIN
assets/gsp_dmg_icon_128.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
assets/gsp_dmg_icon_16.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/gsp_dmg_icon_256.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
assets/gsp_dmg_icon_32.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/gsp_dmg_icon_512.png
Normal file
After Width: | Height: | Size: 224 KiB |
BIN
assets/gsp_dmg_icon_64.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/gsp_icon.psd
Normal file
BIN
assets/gsp_icon_1024.png
Normal file
After Width: | Height: | Size: 299 KiB |
BIN
assets/gsp_icon_128.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
assets/gsp_icon_16.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/gsp_icon_256.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
assets/gsp_icon_32.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
assets/gsp_icon_512.png
Normal file
After Width: | Height: | Size: 114 KiB |
BIN
assets/gsp_icon_64.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/gsp_icon_dmg.psd
Normal file
88
assets/make_ico.pl
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use constant SIZEOF_HEADER => 6;
|
||||
use constant SIZEOF_ENTRY => 16;
|
||||
|
||||
use Getopt::Long;
|
||||
|
||||
sub load_png {
|
||||
|
||||
my ($file, $width, $height) = @_;
|
||||
|
||||
print "Opening $file\n";
|
||||
open(my $io, "<", $file) or return "";
|
||||
binmode $io;
|
||||
|
||||
local $/;
|
||||
my $data = <$io>;
|
||||
|
||||
my @header = unpack("C[8] NN NNC[5] N", $data);
|
||||
close($io);
|
||||
|
||||
# png header
|
||||
return "" unless $header[0] == 0x89;
|
||||
return "" unless $header[1] == 0x50;
|
||||
return "" unless $header[2] == 0x4e;
|
||||
return "" unless $header[3] == 0x47;
|
||||
return "" unless $header[4] == 0x0d;
|
||||
return "" unless $header[5] == 0x0a;
|
||||
return "" unless $header[6] == 0x1a;
|
||||
return "" unless $header[7] == 0x0a;
|
||||
|
||||
# ihdr
|
||||
return "" unless $header[8] == 0x0d;
|
||||
return "" unless $header[9] == 0x49484452;
|
||||
$$width = $header[10];
|
||||
$$height = $header[11];
|
||||
|
||||
# bit depth, color type, compression method, filter method, interface method
|
||||
# crc
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
GetOptions();
|
||||
|
||||
|
||||
|
||||
|
||||
my $count = scalar @ARGV;
|
||||
|
||||
die "Usage: make_ico file.png ..." unless $count;
|
||||
|
||||
open(my $ico, ">", "icon.ico") or die "unable to open icon.ico";
|
||||
binmode $ico;
|
||||
|
||||
my $height = 0;
|
||||
my $width = 0;
|
||||
my $size = 0;
|
||||
|
||||
my $offset = SIZEOF_HEADER + SIZEOF_ENTRY * $count;
|
||||
my $header = pack("vvv", 0, 1, $count);
|
||||
|
||||
my $entry = "";
|
||||
|
||||
seek $ico, $offset, 0;
|
||||
|
||||
foreach my $file (@ARGV) {
|
||||
my $data = load_png($file, \$height, \$width);
|
||||
my $size = length($data);
|
||||
|
||||
die "Icon too large ($file)" if ($height > 256 || $width > 256);
|
||||
$height = 0 if ($height == 256);
|
||||
$width = 0 if ($width == 256);
|
||||
|
||||
$entry = $entry . pack("CCCCvvVV", $width, $height, 0, 0, 0, 0, $size, $offset);
|
||||
$offset += $size;
|
||||
|
||||
print $ico $data;
|
||||
}
|
||||
|
||||
seek $ico, 0, 0;
|
||||
print $ico $header;
|
||||
print $ico $entry;
|
||||
|
||||
close($ico);
|
||||
exit 0;
|
||||
|
19
assets/uncrustify.cfg
Normal file
@ -0,0 +1,19 @@
|
||||
output_tab_size = 2 # new tab size
|
||||
indent_columns = output_tab_size
|
||||
indent_switch_case = output_tab_size
|
||||
indent_with_tabs = 0
|
||||
pp_indent_if = 0 # number
|
||||
pp_if_indent_code = false # false/true
|
||||
pp_define_at_level = false # false/true
|
||||
nl_assign_leave_one_liners = true # false/true
|
||||
nl_class_leave_one_liners = true # false/true
|
||||
nl_enum_leave_one_liners = true # false/true
|
||||
nl_getset_leave_one_liners = true # false/true
|
||||
nl_func_leave_one_liners = true # false/true
|
||||
nl_if_leave_one_liners = true # false/true
|
||||
nl_while_leave_one_liners = true # false/true
|
||||
nl_func_type_name = remove
|
||||
nl_fdef_brace = remove
|
||||
sp_fparen_brace = add
|
||||
|
||||
|
65
assets/updatewebsite.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
$d = file_get_contents($argv[1]);
|
||||
$filter = (isset($argv[2])) ? $argv[2] : false;
|
||||
$builds = [];
|
||||
foreach(explode("\n", $d) as $line) {
|
||||
if (!stristr($line, 'gsplus')) { continue; } // only gsplus files
|
||||
$data = explode(" ", $line);
|
||||
$data = preg_split('/\s+/', $line);
|
||||
if (!$data || empty($data) || !isset($data[1])) { continue; } // one more check for validity
|
||||
$b = explode("/", $data[3]);
|
||||
$time = $data[0] . ' ' . $data[1];
|
||||
$date = $data[0];
|
||||
$bytes = $data[2];
|
||||
$k = $b[0].$b[1].$b[2]; // lookup key
|
||||
if (!$k) { continue; } // something isn't right, skip
|
||||
$row = array('k' => $k, 'bytes' => $bytes, 'tag' => $b[0], 'version' => $b[1],
|
||||
'pipeline' => $b[2], 'platform' => $b[3], 'job' => $b[4],
|
||||
'time' => $time, 'date' => $date,
|
||||
'filename' => $b[5], 's3url' => 'https://s3.amazonaws.com/gsplus-artifacts/'.$data[3]
|
||||
);
|
||||
if (!$filter || ($filter && $b[0] == $filter)) {
|
||||
$builds[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$pipeline = array_column($builds, 'pipeline');
|
||||
$platform = array_column($builds, 'platform');
|
||||
|
||||
array_multisort($pipeline, SORT_DESC, $platform, SORT_ASC, $builds);
|
||||
|
||||
|
||||
|
||||
$style = <<<EOF
|
||||
.builddiv {
|
||||
width: 80%;
|
||||
-moz-border-radius: 1em 4em 1em 4em;
|
||||
border-radius: 1em 4em 1em 4em;
|
||||
padding: 2em;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
margin: auto;
|
||||
}
|
||||
body { font-family: verdana, sans-serif; font-size: 12px; color: #000; background-color: #18BC9C; font-style: normal; font-weight: normal; font-variant: normal; text-align: left; letter-spacing: 0px; line-height: 20px; }
|
||||
EOF;
|
||||
|
||||
print("<html><head><title>GS+ builds page</title><style>$style</style></head><body>\n");
|
||||
$lastk = null;
|
||||
foreach ($builds as $l) {
|
||||
$k = $l['k'];
|
||||
if ($k != $lastk) {
|
||||
if ($lastk != null) {
|
||||
print("</div><br/><br/>"); // close last build if not first pass
|
||||
}
|
||||
print("<div class='builddiv'>\n");
|
||||
print("<h1>GSPLUS V".$l['version']." - Pipeline #".$l['pipeline']." @ ".$l['date']." <span style='font-size:0.r68em'>(".$l['tag'].")</span></H1><hr/>\n");
|
||||
$lastk = $k;
|
||||
}
|
||||
print("<h2>Platform: ".$l['platform']."</h2>\n");
|
||||
print("<ul><li>Build Job: ".$l['job']." Date: ".$l['time']." Size(Bytes): ".$l['bytes']."</li>\n");
|
||||
print("<li>Download: <a href='".$l['s3url']."'>".$l['filename']."</a></li></ul>\n");
|
||||
}
|
||||
print("</div></body></html>\n");
|
||||
|
||||
#2018-08-07 14:33:11 256833 auto/0.14rc/260/ubuntu-sdl/2481/gsplus-ubuntu-sdl.tar.bz2
|
BIN
bin/osx/gsplus
@ -1,9 +0,0 @@
|
||||
# GSport configuration file
|
||||
|
||||
s5d1 =
|
||||
s5d2 =
|
||||
|
||||
s6d1 =
|
||||
s6d2 =
|
||||
|
||||
s7d1 = NoBoot.po
|
@ -1,4 +1,10 @@
|
||||
# ubuntu - X11 version
|
||||
# This is basically what you need to install to build this yourself,
|
||||
# or the pre-requisites of what you need to do to set up a build
|
||||
# machine as a gitlab ci runner.
|
||||
#
|
||||
# All instructions based on a Debian/Ubuntu OS, but should be
|
||||
# relatively straightforward to modify for something like yum
|
||||
|
||||
|
||||
# system prep
|
||||
sudo apt-get -y update
|
||||
@ -6,16 +12,23 @@ sudo apt-get -y upgrade
|
||||
sudo apt-get -y install git
|
||||
sudo apt-get -y install g++
|
||||
sudo apt-get -y install libpcap0.8-dev
|
||||
sudo apt-get -y install libfreetype6-dev
|
||||
|
||||
# X11 version
|
||||
sudo apt-get -y install libx11-dev
|
||||
sudo apt-get -y install libxext-dev
|
||||
|
||||
# build
|
||||
git clone git@github.com:digarok/gsplus.git
|
||||
# SDL version
|
||||
sudo apt-get -y install libsdl1.2-dev
|
||||
sudo apt-get -y install libsdl-image1.2-dev
|
||||
|
||||
# SDL2 version
|
||||
sudo apt-get -y install libsdl2-dev
|
||||
sudo apt-get -y install libsdl2-image-dev
|
||||
|
||||
|
||||
# Example build to test out our system
|
||||
cd gsplus/src
|
||||
ln -s vars_x86linux_x11 vars
|
||||
ln -s vars_x86linux_sdl2 vars
|
||||
make clean ; make
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,27 +1,25 @@
|
||||
# Mac OSX - SDL2 version
|
||||
# Install 'brew' if you don't already have it installed.
|
||||
#
|
||||
# This should build a `gsplus` executable and copy it to the project root dir.
|
||||
# You can run it, though as always you need to supply an Apple IIgs ROM file.
|
||||
# Have fun, and please note any errors on the issues page of the project.
|
||||
|
||||
# system prep
|
||||
|
||||
# Prerequisite: You must install Xcode on your system from the App Store
|
||||
|
||||
# Also, install Xcode cli tools.
|
||||
xcode-select --install
|
||||
|
||||
# Install 'brew'.
|
||||
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
||||
# Use brew to install dependencies.
|
||||
brew install sdl2
|
||||
brew install sdl2_image
|
||||
brew install freetype
|
||||
|
||||
# build
|
||||
# Build.
|
||||
git clone git@github.com:digarok/gsplus.git
|
||||
cd gsplus/src
|
||||
ln -s vars_osx_sdl2 vars
|
||||
make clean ; make
|
||||
|
||||
#Note that installing freetype via brew will install the library, but I think
|
||||
# maybe you have to install the source and build it to link it in properly.
|
||||
|
||||
# You could use /usr/local/src instead of /tmp
|
||||
cd /tmp
|
||||
curl --remote-name --location http://sourceforge.net/projects/freetype/files/freetype2/2.6.2/freetype-2.6.2.tar.gz
|
||||
tar -xzvf freetype-2.6.2.tar.gz
|
||||
cd freetype-2.6.2
|
||||
./configure --prefix=/usr/local/freetype-2.6.2
|
||||
make
|
||||
make install
|
||||
ln -s freetype-2.6.2 /usr/local/freetype
|
||||
|
||||
|
||||
|
40
doc/Developer-QuickStart-Win32_SDL2.txt
Normal file
@ -0,0 +1,40 @@
|
||||
# Win32 - SDL2 version
|
||||
#
|
||||
# This should build a `gsplus.exe` executable and copy it to the project root dir.
|
||||
# You can run it, though as always you need to supply an Apple IIgs ROM file.
|
||||
# Have fun, and please note any errors on the issues page of the project.
|
||||
|
||||
|
||||
# Prerequisites: You must install Cygwin on your system.
|
||||
# I install Cygwin with all "Devel" and "Perl" packages.
|
||||
# I also search for and add any FreeType libs.
|
||||
# If you want to deploy to s3 (gitlabci) then also add pip for python.
|
||||
# If you are deploying the packages then you also need zip.
|
||||
# You will not use the Cygwin SDL2/image libraries as they are deprecated.
|
||||
# Instead you must download the mingw64-w64 libraries and link against those.
|
||||
wget https://www.libsdl.org/release/SDL2-devel-2.0.8-mingw.tar.gz
|
||||
tar -xvzf SDL2-devel-2.0.8-mingw.tar.gz
|
||||
cd SDL2-2.0.8
|
||||
mkdir /cygdrive/c/mingw
|
||||
mv i686-w64-mingw32/ /cygdrive/c/mingw/
|
||||
cd ..
|
||||
|
||||
wget https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.3-mingw.tar.gz
|
||||
tar -xvzf SDL2_image-devel-2.0.3-mingw.tar.gz
|
||||
rsync -a SDL2_image-2.0.3/i686-w64-mingw32/ /cygdrive/c/mingw/i686-w64-mingw32/
|
||||
|
||||
# Build.
|
||||
git clone git@github.com:digarok/gsplus.git
|
||||
cd gsplus/src
|
||||
ln -s vars_win32_sdl2 vars
|
||||
make clean ; make
|
||||
|
||||
|
||||
# if you want to make a machine that can also deploy to s3 (gitlabci):
|
||||
pip2.7 install awscli
|
||||
|
||||
# aws creds are to be passed via CI environment variables
|
||||
# also, you have to fix the behavior for windows to run this.
|
||||
# open an Administrator CMD prompt and run:
|
||||
assoc .py=pyautofile
|
||||
ftype pyautofile="c:\cygwin\bin\python" "%1" %*
|
@ -1,6 +1,4 @@
|
||||
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON LINUX/UBUNTU
|
||||
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/linux-repository.md
|
||||
|
||||
|
||||
## STEP 1 - Install Gitlab Runner
|
||||
sudo apt-get install -y curl
|
||||
@ -9,6 +7,14 @@ sudo apt-get install -y gitlab-ci-multi-runner
|
||||
|
||||
|
||||
## STEP 2 - Register it with your server
|
||||
sudo gitlab-ci-multi-runner register -n \
|
||||
--url http://centralserv.gotgeeks.com/ci \
|
||||
--registration-token UqGC2qvJmvU1QBK3mx4b \
|
||||
--executor shell \
|
||||
--description "LinBuild" \
|
||||
--tag-list "ubuntu"
|
||||
|
||||
# or manually
|
||||
sudo gitlab-ci-multi-runner register
|
||||
# "Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/ci )"
|
||||
# https://centralserv.gotgeeks.com/ci
|
||||
|
@ -1,5 +1,4 @@
|
||||
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON LINUX/UBUNTU
|
||||
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/osx.md
|
||||
|
||||
## STEP 1 - Install Gitlab Runner
|
||||
sudo curl --output /usr/local/bin/gitlab-ci-multi-runner https://gitlab-ci-multi-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-ci-multi-runner-darwin-amd64
|
||||
@ -16,3 +15,18 @@ gitlab-ci-multi-runner register -n \
|
||||
--registration-token a1f60647cf7fe3eb5c7fa87e59bf7 \
|
||||
--executor shell \
|
||||
--description "My-Mac"
|
||||
|
||||
# this one is better - adds tags simultaneously
|
||||
gitlab-ci-multi-runner register -n \
|
||||
--url http://yourgitlab.com/ci \
|
||||
--registration-token 5b2f60647cf7fe3eb5c7fa87e59bf7 \
|
||||
--executor shell \
|
||||
--description "MBP" \
|
||||
--tag-list "osx"
|
||||
|
||||
# maybe also needs
|
||||
gitlab-ci-multi-runner install
|
||||
# to run correctly
|
||||
|
||||
# you can always check with
|
||||
gitlab-ci-multi-runner status
|
||||
|
66
doc/GitlabCI-Runner-Win32-SDL.txt
Normal file
@ -0,0 +1,66 @@
|
||||
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WIN32 FOR SDL2 BUILDS
|
||||
|
||||
## PREREQUISITE AKA SETTING UP A FRESH VM OR DEV COMPUTER
|
||||
#
|
||||
# Install your Win7/Win10 VM
|
||||
# Install VirtualBox additions in your VM
|
||||
#
|
||||
# (optional, but seems to help) add build user
|
||||
# Make user an admin, give it service privs
|
||||
# ... Local Security Policy -> Local Policies -> User Rights Assignment -> Log on as a service
|
||||
#
|
||||
# install Cygwin & SDL2 Libraries according to the steps in the Quickstart doc
|
||||
# add cygwin bin dir to env path
|
||||
|
||||
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WINDOWS
|
||||
|
||||
## STEP 1 - Install Gitlab Runner
|
||||
# https://docs.gitlab.com/runner/install/windows.html
|
||||
# Download from page above, run CMD prompt as Administrator and then run the runner exe in there
|
||||
|
||||
## STEP 2 - Register it with your server
|
||||
# First open Administrator CMD prompt then run the following commands.
|
||||
|
||||
# REGISTER: Enter your Gitlab CI details - (Token is in Gitlab->Admin-Runners)
|
||||
gitlab-ci-multi-runner-windows-386.exe register
|
||||
# enter gitlab url
|
||||
# enter gitlab runner token
|
||||
# enter tag of "windows"
|
||||
gitlab-runner-windows-386.exe register -n \
|
||||
--url http://yourgitlab.com/ci \
|
||||
--registration-token UqGC2qvJmU1QBK3mx4b \
|
||||
--executor shell \
|
||||
--description "WinBuild"
|
||||
--tag-list "windows"
|
||||
|
||||
## STEP 3 - Install Service
|
||||
# Note the use of ".\builder" to indicate local account!
|
||||
gitlab-runner-windows-386.exe install --user .\builder --password builder
|
||||
|
||||
## STEP 4 - Start service
|
||||
gitlab-runner-windows-386.exe start
|
||||
|
||||
## STEP 4.5 - if you get a "failed due to logon" message above, you may need to grant "logon as a service" privs
|
||||
#To add the "Log on as a service" right to an account on your local computer
|
||||
#To open Local Security Policy, click Start, point to Control Panel, point to Administrative Tools, and then double-click Local Security Policy.
|
||||
#In the console tree, double-click Local Policies, and then click User Rights Assignment.
|
||||
#In the details pane, double-click Log on as a service.
|
||||
#Click Add User or Group, and then add the appropriate account to the list of accounts that possess the Log on as a service right.
|
||||
|
||||
# If you have any other problems with the service not starting due to:
|
||||
# "Failed to start gitlab-runner: The service did not start due to a logon failure."
|
||||
# Try going to Services and edit the properties of the gitlab-runner service.
|
||||
# Go to the "Log On" tab and re-enter the password/credentials and see if
|
||||
# that helps.
|
||||
|
||||
|
||||
## STEP 5 - Make sure gitlab-runner is using the correct shell
|
||||
# It defaults to CMD, go to the directory where the gitlab-runner
|
||||
# commands were run and edit the "config.toml" file. Under the line
|
||||
# that says: executor = "shell"
|
||||
# add: shell = "bash"
|
||||
#
|
||||
# Also, make sure that if you type "bash" <enter> from a CMD prompt,
|
||||
# that it runs the Cygwin shell. If it can't find the bash command,
|
||||
# go to the Environment Variables Control Panel for your computer and
|
||||
# add "c:\cygwin\bin" to your PATH variable.
|
@ -1,50 +0,0 @@
|
||||
## SOME NOTES ON SETTING UP GITLAB RUNNER TO BUILD ON WINDOWS
|
||||
# Based on: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/install/windows.md
|
||||
|
||||
## STEP 1 - Install Gitlab Runner
|
||||
# Download from page above, run CMD prompt as Administrator and then run the runner exe in there
|
||||
|
||||
## STEP 2 - Register it with your server
|
||||
# First open Administrator CMD prompt then run the following commands.
|
||||
|
||||
# REGISTER: Enter your Gitlab CI details
|
||||
gitlab-ci-multi-runner-windows-386.exe register
|
||||
|
||||
## STEP 3 - Install Service
|
||||
# Note the use of ".\IEUser" to indicate local account!
|
||||
gitlab-ci-multi-runner-windows-386.exe install --user .\IEUser --password Passw0rd!
|
||||
|
||||
## STEP 4 - Start service
|
||||
gitlab-ci-multi-runner-windows-386.exe start
|
||||
|
||||
# If you have any problems with the service not starting due to:
|
||||
# "Failed to start gitlab-runner: The service did not start due to a
|
||||
# logon failure."
|
||||
# Try going to Services and edit the properties of the gitlab-runner service.
|
||||
# Go to the "Log On" tab and re-enter the password/credentials and see if
|
||||
# that helps.
|
||||
|
||||
|
||||
## STEP 5 - Make sure gitlab-runner is using the correct shell
|
||||
# It defaults to CMD, go to the directory where the gitlab-runner
|
||||
# commands were run and edit the "config.toml" file. Under the line
|
||||
# that says: executor = "shell"
|
||||
# add: shell = "bash"
|
||||
#
|
||||
# Also, make sure that if you type "bash" <enter> from a CMD prompt,
|
||||
# that it runs the Cygwin shell. If it can't find the bash command,
|
||||
# go to the Environment Variables Control Panel for your computer and
|
||||
# add "c:\cygwin\bin" to your PATH variable.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## PREREQUISITE
|
||||
# The project is currently being build in Cygwin.
|
||||
# I install Cygwin with all "Devel" and "Perl" packages.
|
||||
# I also search for and add any SDL2 or FreeType libs just in case.
|
||||
# You'll also need git installed for cmdline usage on Windows.
|
||||
# Add your ~/.ssh/id_rsa using git bash (or cygwin) so that
|
||||
# gitlab runner can check out your project
|
||||
|
50
doc/README.txt
Normal file
@ -0,0 +1,50 @@
|
||||
Getting started
|
||||
===============
|
||||
|
||||
1. Download the emulator package from https://apple2.gs/plus and put it in a folder.
|
||||
Yes, you can drag it into your Applications on a Mac, but be aware that it is
|
||||
meant to be launched from a command line. If you put it in Applications, you
|
||||
should be able to run it with the terminal command:
|
||||
/Applications/GSplus.app/Contents/MacOS/gsplus
|
||||
|
||||
2. Download the Apple IIgs Firmware ROMs, for either a ROM01 or ROM03 machine.
|
||||
(If you have a real IIgs, there are ways to save it from your machine too.)
|
||||
Try: ftp://ftp.apple.asimov.net/pub/apple_II/emulators/rom_images/
|
||||
a. Put the ROM image in the same folder where you run the emulator from.
|
||||
It will search for: "ROM", "ROM.01", "ROM.03"
|
||||
If your ROM file has some other name, launch gsplus and hit F4 to go to
|
||||
the config menu to choose your ROM under "ROM File Selection"
|
||||
... or ...
|
||||
|
||||
3. Edit your config:
|
||||
You can manually edit the config.txt file (or use the F4 menu.)
|
||||
You can set disks using a slot/number syntax like:
|
||||
s5d1 = images/ArkanoidII.po
|
||||
s6d1 = images/ProDOS_2_4_1.dsk
|
||||
s7d1 = images/gsos.2mg
|
||||
|
||||
You can also manually set your ROM path like:
|
||||
g_cfg_rom_path = ../roms/gsrom03
|
||||
|
||||
3. Get some Apple IIgs software.
|
||||
I recommend the excellent Apple IIgs dedicated site:
|
||||
http://www.whatisthe2gs.apple2.org.za/
|
||||
If you have a real IIgs, you can transfer your disks using ADTPro
|
||||
http://adtpro.sourceforge.net/
|
||||
|
||||
5. Boot the Apple IIgs by running the emulator
|
||||
Windows: gsplus32.exe
|
||||
Mac/Ubuntu: ./gsplus
|
||||
Mac (if in Apps) /Applications/GSplus.app/Contents/MacOS/gsplus
|
||||
|
||||
If the config file can’t be found, it will try to create a config.txt file for you,
|
||||
with all of the defaults.
|
||||
|
||||
Note: You can also specify a config file. This is very useful as you can have specific
|
||||
disks/setting pre-set in a config file and launch directly into your favorite game with
|
||||
that config. They can be named anything you want, though the officially recognized
|
||||
extensions are .txt and .gsp.
|
||||
|
||||
Examples:
|
||||
Windows: gsplus32.exe -config arkanoid.gsp
|
||||
Mac/Ubuntu: ./gsplus -config choplifter_config.txt
|
BIN
doc/gsplusmanual.pdf
Normal file
BIN
doc/web/Screenshot.png
Normal file
After Width: | Height: | Size: 180 KiB |
0
lib/arch/mac/setfileicon
Executable file → Normal file
20
make_dist_mac.sh
Executable file
@ -0,0 +1,20 @@
|
||||
DEXTRAS=gsplus-osx/
|
||||
DDIR=$DEXTRAS/GSplus.app
|
||||
ADIR=assets
|
||||
mkdir -p $DEXTRAS/license
|
||||
mkdir -p $DDIR/Contents/MacOS
|
||||
mkdir -p $DDIR/Contents/Resources
|
||||
|
||||
cp gsplus $DDIR/Contents/MacOS
|
||||
cp config.txt $DDIR/Contents/MacOS
|
||||
cp $ADIR/Info.plist $DDIR/Contents
|
||||
cp $ADIR/gsp-icons.icns $DDIR/Contents/Resources
|
||||
dylibbundler -od -b -x $DDIR/Contents/MacOS/gsplus -d $DDIR/Contents/libs/
|
||||
|
||||
# files to include in dmg
|
||||
cp doc/gsplusmanual.pdf $DEXTRAS
|
||||
cp doc/README.txt $DEXTRAS
|
||||
cp LICENSE.txt $DEXTRAS/license
|
||||
cp COPYRIGHT.txt $DEXTRAS/license
|
||||
|
||||
# packaging now in DMG script
|
21
make_dmg_mac.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
git clone https://github.com/andreyvit/yoursway-create-dmg.git
|
||||
cd yoursway-create-dmg
|
||||
|
||||
test -f GSplus-Install.dmg && rm GSplus-Install.dmg
|
||||
./create-dmg \
|
||||
--volname "GSplus" \
|
||||
--volicon "../assets/gsp-dmg-icons.icns" \
|
||||
--background "../assets/gsback.png" \
|
||||
--window-pos 200 120 \
|
||||
--window-size 710 600 \
|
||||
--icon-size 64 \
|
||||
--icon GSplus.app 250 210 \
|
||||
--hide-extension GSplus.app \
|
||||
--app-drop-link 440 210 \
|
||||
--icon README.txt 225 350 \
|
||||
--icon gsplusmanual.pdf 350 350 \
|
||||
--icon license 470 350 \
|
||||
GSplus-Install.dmg \
|
||||
../gsplus-osx/
|
||||
cp GSplus-Install.dmg ..
|
61
src/Makefile
@ -1,13 +1,14 @@
|
||||
# GSport central makefile - you need a 'vars' file linked/copied from a 'vars_xxx' template to build.
|
||||
# GSplus central makefile - you need a 'vars' file linked/copied from a 'vars_xxx' template to build.
|
||||
#@todo: check for vars file and do something useful if missing :P
|
||||
|
||||
OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \
|
||||
joystick_driver.o moremem.o paddles.o parallel.o printer.o \
|
||||
sim65816.o smartport.o sound.o sound_driver.o video.o \
|
||||
scc_socket_driver.o imagewriter.o scc_imagewriter.o scc_llap.o
|
||||
ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o
|
||||
#@todo: remove all packaging junk and move to packaging scripts in CI
|
||||
OBJECTS1 = adb.o clock.o config.o debug.o dis.o engine_c.o scc.o iwm.o \
|
||||
joystick_driver.o moremem.o paddles.o parallel.o printer.o sim65816.o \
|
||||
smartport.o sound.o sound_driver.o video.o scc_socket_driver.o glog.o \
|
||||
imagewriter.o scc_imagewriter.o scc_llap.o options.o
|
||||
ATOBJ = atbridge/aarp.o atbridge/atbridge.o atbridge/elap.o atbridge/llap.o atbridge/port.o
|
||||
PCAPOBJ = atbridge/pcap_delay.o
|
||||
TFEOBJ = tfe/tfe.o tfe/tfearch.o tfe/tfesupp.o
|
||||
FSTOBJ = host_common.o host_fst.o host_mli.o
|
||||
|
||||
include vars
|
||||
|
||||
@ -32,12 +33,11 @@ specials: 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s
|
||||
specials_clean:
|
||||
rm -f 8inst_s 16inst_s 8size 16size 8inst_c 16inst_c size_c size_s
|
||||
|
||||
# Linux/OSX SDL builds
|
||||
# Linux/OSX/RPi SDL builds
|
||||
gsplus: $(OBJECTS) compile_time.o
|
||||
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
|
||||
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
|
||||
echo $(OBJECTS)
|
||||
cp gsplus ..
|
||||
cp gsplus ../bin/osx
|
||||
|
||||
# Linux/OSX XWindows builds
|
||||
gsplusx: $(OBJECTS) compile_time.o
|
||||
@ -45,28 +45,35 @@ gsplusx: $(OBJECTS) compile_time.o
|
||||
echo $(OBJECTS)
|
||||
mv gsplusx ..
|
||||
|
||||
# NOT CURRENTLY SUPPORTED
|
||||
# NOT CURRENTLY SUPPORTED
|
||||
# Linux framebuffer builds:
|
||||
gsplusfb: $(OBJECTS) compile_time.o
|
||||
$(LD) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS)
|
||||
echo $(OBJECTS)
|
||||
mv gsplusfb ..
|
||||
cp -f ../config.template ../config.txt
|
||||
|
||||
# Mingw32 (native windows) / Cygwin builds:
|
||||
gsplus.exe: $(OBJECTS) compile_time.o
|
||||
# Mingw32 / Cygwin builds: The Win32 API version
|
||||
gsplus32.exe: $(OBJECTS) compile_time.o
|
||||
g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
|
||||
mkdir -p ../GSplus.app/lib
|
||||
cp -f gsplus.exe ../GSplus.app/GSplus.exe
|
||||
cp -f ../config.template ../GSplus.app/config.txt
|
||||
cp -f ../lib/*.ttf ../GSplus.app/lib
|
||||
cp -f ../lib/arch/win32/*.dll ../GSplus.app
|
||||
cp -f ../lib/NoBoot.po ../GSplus.app
|
||||
cp -f GSplus.bat ../GSplus.app/GSplus.bat
|
||||
cp -f parallel.rom ../GSplus.app
|
||||
cp -f ../COPYING.txt ../GSplus.app
|
||||
#mkdir -p ../GSplus.app/lib
|
||||
#cp -f gsplus.exe ../GSplus.app/GSplus.exe
|
||||
#cp -f ../config.template ../GSplus.app/config.txt
|
||||
#cp -f ../lib/*.ttf ../GSplus.app/lib
|
||||
#cp -f ../lib/arch/win32/*.dll ../GSplus.app
|
||||
#cp -f ../lib/NoBoot.po ../GSplus.app
|
||||
#cp -f GSplus.bat ../GSplus.app/GSplus.bat
|
||||
#cp -f parallel.rom ../GSplus.app
|
||||
#cp -f ../COPYING.txt ../GSplus.app
|
||||
cp gsplus32.exe ..
|
||||
|
||||
# NOT CURRENTLY SUPPORTED
|
||||
# Mingw32 / Cygwin builds: The SDL version (builds, but non-functioning)
|
||||
gsplus.exe: $(OBJECTS) compile_time.o
|
||||
#g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
|
||||
#g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -mwindows
|
||||
g++ $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 -lshell32
|
||||
cp gsplus.exe ..
|
||||
|
||||
# NOT CURRENTLY SUPPORTED
|
||||
# Mac build - old style (deprecated)
|
||||
gsportmac: $(OBJECTS) compile_time.o
|
||||
$(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o gsport $(EXTRA_LIBS)
|
||||
@ -139,8 +146,8 @@ partls: partls.c
|
||||
to_pro: prodos.h prodos_protos.h to_pro.c
|
||||
cc $(CCOPTS) $(XOPTS) $(OPTS) -o to_pro to_pro.c
|
||||
|
||||
gsport32.o: win32.rc winresource.h
|
||||
windres win32.rc -o gsport32.o
|
||||
gsplus32.o: win32.rc winresource.h
|
||||
windres win32.rc -o gsplus32.o
|
||||
|
||||
compile_time.o: $(OBJECTS)
|
||||
|
||||
@ -183,7 +190,7 @@ macdriver.o: macdriver.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
|
||||
macdriver_console.o: macdriver_console.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
|
||||
macdriver_generic.o: macdriver_generic.c defc.h defcomm.h iwm.h protos.h protos_macdriver.h
|
||||
macsnd_driver.o: macsnd_driver.c defc.h defcomm.h iwm.h protos.h sound.h
|
||||
windriver.o: windriver.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h gsport32.o
|
||||
windriver.o: windriver.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h gsplus32.o
|
||||
win_console.o: win_console.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h
|
||||
win_generic.o: win_generic.c defc.h defcomm.h iwm.h protos.h protos_windriver.h winresource.h
|
||||
win32snd_driver.o: win32snd_driver.c defc.h defcomm.h iwm.h protos.h sound.h
|
||||
|
24
src/adb.h
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "defc.h"
|
||||
|
0
src/arch/mac/classes.nib
generated
Executable file → Normal file
0
src/arch/mac/makedmg.sh
Executable file → Normal file
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include <os2.h>
|
||||
|
@ -1,24 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "../../defc.h"
|
||||
#include "../../protos.h"
|
||||
@ -30,13 +15,13 @@
|
||||
#include <string.h>
|
||||
#include "gsportos2.h" /* Resource symbolic identifiers*/
|
||||
|
||||
HAB g_hab; /* PM anchor block handle */
|
||||
PSZ pszErrMsg;
|
||||
HAB g_hab; /* PM anchor block handle */
|
||||
PSZ pszErrMsg;
|
||||
QMSG qmsg; /* Message from message queue */
|
||||
HWND g_hwnd_frame = NULLHANDLE; /* Frame window handle */
|
||||
HWND g_hwnd_client = NULLHANDLE; /* Client area window handle */
|
||||
|
||||
HMQ g_hmq; /* Message queue handle */
|
||||
HMQ g_hmq; /* Message queue handle */
|
||||
|
||||
extern int Verbose;
|
||||
|
||||
@ -47,15 +32,15 @@ int g_screen_mdepth = 0;
|
||||
|
||||
extern int g_quit_sim_now;
|
||||
|
||||
int g_use_shmem = 1;
|
||||
int g_has_focus = 0;
|
||||
int g_auto_repeat_on = -1;
|
||||
int g_use_shmem = 1;
|
||||
int g_has_focus = 0;
|
||||
int g_auto_repeat_on = -1;
|
||||
|
||||
extern Kimage g_mainwin_kimage;
|
||||
|
||||
int g_main_height = 0;
|
||||
int g_main_height = 0;
|
||||
|
||||
int g_win_capslock_down = 0;
|
||||
int g_win_capslock_down = 0;
|
||||
|
||||
extern int g_border_sides_refresh_needed;
|
||||
extern int g_border_special_refresh_needed;
|
||||
@ -83,87 +68,79 @@ extern char *g_status_ptrs[MAX_STATUS_LINES];
|
||||
|
||||
VOID DispErrorMessage();
|
||||
|
||||
int
|
||||
win_nonblock_read_stdin(int fd, char *bufptr, int len)
|
||||
{
|
||||
int win_nonblock_read_stdin(int fd, char *bufptr, int len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
x_dialog_create_gsport_conf(const char *str)
|
||||
{
|
||||
void x_dialog_create_gsport_conf(const char *str) {
|
||||
}
|
||||
|
||||
int
|
||||
x_show_alert(int is_fatal, const char *str)
|
||||
{
|
||||
return 0;
|
||||
int x_show_alert(int is_fatal, const char *str) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
DEVOPENSTRUC pszData;
|
||||
ULONG flCreate; /* Window creation control flags*/
|
||||
int height;
|
||||
SIZEL sizel;
|
||||
int main(int argc, char **argv) {
|
||||
DEVOPENSTRUC pszData;
|
||||
ULONG flCreate; /* Window creation control flags*/
|
||||
int height;
|
||||
SIZEL sizel;
|
||||
|
||||
if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
if ((g_hab = WinInitialize(0)) == 0L) /* Initialize PM */
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
|
||||
if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L)/* Create a msg queue */
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
if ((g_hmq = WinCreateMsgQueue( g_hab, 0 )) == 0L) /* Create a msg queue */
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
|
||||
if (!WinRegisterClass( /* Register window class */
|
||||
g_hab, /* Anchor block handle */
|
||||
(PSZ)"MyWindow", /* Window class name */
|
||||
(PFNWP)MyWindowProc, /* Address of window procedure */
|
||||
CS_SIZEREDRAW, /* Class style */
|
||||
0 /* No extra window words */
|
||||
))
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
if (!WinRegisterClass( /* Register window class */
|
||||
g_hab, /* Anchor block handle */
|
||||
(PSZ)"MyWindow", /* Window class name */
|
||||
(PFNWP)MyWindowProc, /* Address of window procedure */
|
||||
CS_SIZEREDRAW, /* Class style */
|
||||
0 /* No extra window words */
|
||||
))
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
|
||||
height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16);
|
||||
g_main_height = height;
|
||||
height = X_A2_WINDOW_HEIGHT + (MAX_STATUS_LINES*16);
|
||||
g_main_height = height;
|
||||
|
||||
flCreate = FCF_STANDARD & /* Set frame control flags to */
|
||||
~FCF_SHELLPOSITION; /* standard except for shell */
|
||||
/* positioning. */
|
||||
flCreate = FCF_STANDARD & /* Set frame control flags to */
|
||||
~FCF_SHELLPOSITION; /* standard except for shell */
|
||||
/* positioning. */
|
||||
|
||||
if ((g_hwnd_frame = WinCreateStdWindow(
|
||||
HWND_DESKTOP, /* Desktop window is parent */
|
||||
0, /* STD. window styles */
|
||||
&flCreate, /* Frame control flag */
|
||||
"MyWindow", /* Client window class name */
|
||||
"", /* No window text */
|
||||
0, /* No special class style */
|
||||
(HMODULE)0L, /* Resource is in .EXE file */
|
||||
ID_WINDOW, /* Frame window identifier */
|
||||
&g_hwnd_client /* Client window handle */
|
||||
)) == 0L)
|
||||
os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */
|
||||
if ((g_hwnd_frame = WinCreateStdWindow(
|
||||
HWND_DESKTOP, /* Desktop window is parent */
|
||||
0, /* STD. window styles */
|
||||
&flCreate, /* Frame control flag */
|
||||
"MyWindow", /* Client window class name */
|
||||
"", /* No window text */
|
||||
0, /* No special class style */
|
||||
(HMODULE)0L, /* Resource is in .EXE file */
|
||||
ID_WINDOW, /* Frame window identifier */
|
||||
&g_hwnd_client /* Client window handle */
|
||||
)) == 0L)
|
||||
os2_abort(HWND_DESKTOP, HWND_DESKTOP); /* Terminate the application */
|
||||
|
||||
WinSetWindowText(g_hwnd_frame, "GSport");
|
||||
WinSetWindowText(g_hwnd_frame, "GSport");
|
||||
|
||||
if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */
|
||||
HWND_TOP, /* window at position 100, 100, */
|
||||
100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */
|
||||
SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW
|
||||
))
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
if (!WinSetWindowPos( g_hwnd_frame, /* Shows and activates frame */
|
||||
HWND_TOP, /* window at position 100, 100, */
|
||||
100, 100, X_A2_WINDOW_WIDTH, height, /* and size 200, 200. */
|
||||
SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW
|
||||
))
|
||||
os2_abort(g_hwnd_frame, g_hwnd_client); /* Terminate the application */
|
||||
|
||||
g_hdc_screen = WinOpenWindowDC(g_hwnd_client);
|
||||
sizel.cx = X_A2_WINDOW_WIDTH;
|
||||
sizel.cy = height;
|
||||
g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC);
|
||||
g_hdc_screen = WinOpenWindowDC(g_hwnd_client);
|
||||
sizel.cx = X_A2_WINDOW_WIDTH;
|
||||
sizel.cy = height;
|
||||
g_hps_screen = GpiCreatePS(g_hab,g_hdc_screen, &sizel, PU_PELS | GPIF_LONG | GPIA_ASSOC);
|
||||
|
||||
g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL);
|
||||
g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);
|
||||
g_hdc_memory = DevOpenDC(g_hab, OD_MEMORY, "*", 4, (PDEVOPENDATA)&pszData, NULL);
|
||||
g_hps_memory = GpiCreatePS(g_hab,g_hdc_memory, &sizel, PU_ARBITRARY | GPIT_MICRO | GPIA_ASSOC);
|
||||
|
||||
// Call gsplusmain
|
||||
return gsplusmain(argc, argv);
|
||||
// Call gsplusmain
|
||||
return gsplusmain(argc, argv);
|
||||
|
||||
}
|
||||
|
||||
@ -178,10 +155,9 @@ SIZEL sizel;
|
||||
* the message command and parameters.
|
||||
*
|
||||
*************************************************************************/
|
||||
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
|
||||
{
|
||||
HPS hps;
|
||||
RECTL rcl;
|
||||
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
|
||||
HPS hps;
|
||||
RECTL rcl;
|
||||
|
||||
switch( msg )
|
||||
{
|
||||
@ -200,7 +176,7 @@ RECTL rcl;
|
||||
* When Exit is chosen, the application posts itself a WM_CLOSE
|
||||
* message.
|
||||
*/
|
||||
{
|
||||
{
|
||||
USHORT command; /* WM_COMMAND command value */
|
||||
command = SHORT1FROMMP(mp1); /* Extract the command value */
|
||||
switch (command)
|
||||
@ -213,7 +189,7 @@ RECTL rcl;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
case WM_ERASEBACKGROUND:
|
||||
/*
|
||||
* Return TRUE to request PM to paint the window background
|
||||
@ -224,16 +200,16 @@ RECTL rcl;
|
||||
/*
|
||||
* Window contents are drawn here in WM_PAINT processing.
|
||||
*/
|
||||
hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
|
||||
WinEndPaint(hps);
|
||||
g_needfullrefreshfornextframe = 1;
|
||||
hps = WinBeginPaint(hwnd, NULLHANDLE, &rcl);
|
||||
WinEndPaint(hps);
|
||||
g_needfullrefreshfornextframe = 1;
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
/*
|
||||
* This is the place to put your termination routines
|
||||
*/
|
||||
WinPostMsg( hwnd, WM_QUIT, (MPARAM)0,(MPARAM)0 ); /* Cause termination*/
|
||||
exit(0);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
@ -247,262 +223,232 @@ RECTL rcl;
|
||||
return (MRESULT)FALSE;
|
||||
} /* End of MyWindowProc */
|
||||
|
||||
void
|
||||
check_input_events()
|
||||
{
|
||||
void check_input_events() {
|
||||
|
||||
/*
|
||||
* Get and dispatch messages from the application message queue
|
||||
* until WinGetMsg returns FALSE, indicating a WM_QUIT message.
|
||||
*/
|
||||
|
||||
while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) {
|
||||
if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) {
|
||||
//TranslateMessage(&qmsg);
|
||||
WinDispatchMsg(g_hab, &qmsg);
|
||||
} else {
|
||||
printf("GetMessage returned <= 0\n");
|
||||
my_exit(2);
|
||||
}
|
||||
}
|
||||
while(WinPeekMsg(g_hab, &qmsg, g_hwnd_frame, 0, 0, PM_NOREMOVE)) {
|
||||
if(WinGetMsg(g_hab, &qmsg, 0L, 0, 0) > 0) {
|
||||
//TranslateMessage(&qmsg);
|
||||
WinDispatchMsg(g_hab, &qmsg);
|
||||
} else {
|
||||
printf("GetMessage returned <= 0\n");
|
||||
my_exit(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x_update_color(int col_num, int red, int green, int blue, word32 rgb)
|
||||
{
|
||||
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) {
|
||||
}
|
||||
|
||||
void
|
||||
x_update_physical_colormap()
|
||||
{
|
||||
void x_update_physical_colormap() {
|
||||
}
|
||||
|
||||
void
|
||||
show_xcolor_array()
|
||||
{
|
||||
void show_xcolor_array() {
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xdriver_end()
|
||||
{
|
||||
printf("OS/2 driver_end\n");
|
||||
void xdriver_end() {
|
||||
printf("OS/2 driver_end\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x_get_kimage(Kimage *kimage_ptr)
|
||||
{
|
||||
byte *ptr;
|
||||
int width;
|
||||
int height;
|
||||
int depth, mdepth;
|
||||
int size;
|
||||
void x_get_kimage(Kimage *kimage_ptr) {
|
||||
byte *ptr;
|
||||
int width;
|
||||
int height;
|
||||
int depth, mdepth;
|
||||
int size;
|
||||
|
||||
width = kimage_ptr->width_req;
|
||||
height = kimage_ptr->height;
|
||||
depth = kimage_ptr->depth;
|
||||
mdepth = kimage_ptr->mdepth;
|
||||
width = kimage_ptr->width_req;
|
||||
height = kimage_ptr->height;
|
||||
depth = kimage_ptr->depth;
|
||||
mdepth = kimage_ptr->mdepth;
|
||||
|
||||
size = 0;
|
||||
size = 0;
|
||||
|
||||
if(depth == g_screen_depth) {
|
||||
/* Use g_bmapinfo_ptr, adjusting width, height */
|
||||
g_bmaphdr_ptr->cx = width;
|
||||
g_bmaphdr_ptr->cy = height;
|
||||
if(depth == g_screen_depth) {
|
||||
/* Use g_bmapinfo_ptr, adjusting width, height */
|
||||
g_bmaphdr_ptr->cx = width;
|
||||
g_bmaphdr_ptr->cy = height;
|
||||
|
||||
kimage_ptr->dev_handle = GpiCreateBitmap(
|
||||
kimage_ptr->dev_handle = GpiCreateBitmap(
|
||||
|
||||
(HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr,
|
||||
0L, (PBYTE)kimage_ptr->data_ptr,
|
||||
(PBITMAPINFO2)g_bmapinfo_ptr);
|
||||
(HPS)g_hps_memory, (PBITMAPINFOHEADER2)g_bmaphdr_ptr,
|
||||
0L, (PBYTE)kimage_ptr->data_ptr,
|
||||
(PBITMAPINFO2)g_bmapinfo_ptr);
|
||||
|
||||
size = (width*height*mdepth) >> 3;
|
||||
ptr = (byte *)malloc(size);
|
||||
size = (width*height*mdepth) >> 3;
|
||||
ptr = (byte *)malloc(size);
|
||||
|
||||
if(ptr == 0) {
|
||||
printf("malloc for data failed, mdepth: %d\n", mdepth);
|
||||
exit(2);
|
||||
}
|
||||
if(ptr == 0) {
|
||||
printf("malloc for data failed, mdepth: %d\n", mdepth);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
kimage_ptr->data_ptr = ptr;
|
||||
kimage_ptr->data_ptr = ptr;
|
||||
|
||||
} else {
|
||||
/* allocate buffers for video.c to draw into */
|
||||
} else {
|
||||
/* allocate buffers for video.c to draw into */
|
||||
|
||||
size = (width*height*mdepth) >> 3;
|
||||
ptr = (byte *)malloc(size);
|
||||
size = (width*height*mdepth) >> 3;
|
||||
ptr = (byte *)malloc(size);
|
||||
|
||||
if(ptr == 0) {
|
||||
printf("malloc for data failed, mdepth: %d\n", mdepth);
|
||||
exit(2);
|
||||
}
|
||||
if(ptr == 0) {
|
||||
printf("malloc for data failed, mdepth: %d\n", mdepth);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
kimage_ptr->data_ptr = ptr;
|
||||
kimage_ptr->data_ptr = ptr;
|
||||
|
||||
kimage_ptr->dev_handle = (void *)-1;
|
||||
kimage_ptr->dev_handle = (void *)-1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dev_video_init()
|
||||
{
|
||||
int lores_col;
|
||||
int i;
|
||||
void dev_video_init() {
|
||||
int lores_col;
|
||||
int i;
|
||||
|
||||
printf("Preparing graphics system\n");
|
||||
printf("Preparing graphics system\n");
|
||||
|
||||
g_screen_depth = 24;
|
||||
g_screen_mdepth = 32;
|
||||
g_screen_depth = 24;
|
||||
g_screen_mdepth = 32;
|
||||
|
||||
g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2));
|
||||
g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr;
|
||||
g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2);
|
||||
g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH;
|
||||
g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT;
|
||||
g_bmaphdr_ptr->cPlanes = 1;
|
||||
g_bmaphdr_ptr->cBitCount = g_screen_mdepth;
|
||||
g_bmaphdr_ptr->ulCompression = BCA_UNCOMP;
|
||||
g_bmaphdr_ptr->cclrUsed = 0;
|
||||
g_bmapinfo_ptr = (BITMAPINFO2 *)malloc(sizeof(BITMAPINFOHEADER2));
|
||||
g_bmaphdr_ptr = (BITMAPINFOHEADER2 *)g_bmapinfo_ptr;
|
||||
g_bmaphdr_ptr->cbFix = sizeof(BITMAPINFOHEADER2);
|
||||
g_bmaphdr_ptr->cx = A2_WINDOW_WIDTH;
|
||||
g_bmaphdr_ptr->cy = A2_WINDOW_HEIGHT;
|
||||
g_bmaphdr_ptr->cPlanes = 1;
|
||||
g_bmaphdr_ptr->cBitCount = g_screen_mdepth;
|
||||
g_bmaphdr_ptr->ulCompression = BCA_UNCOMP;
|
||||
g_bmaphdr_ptr->cclrUsed = 0;
|
||||
|
||||
video_get_kimages();
|
||||
video_get_kimages();
|
||||
|
||||
if(g_screen_depth != 8) {
|
||||
// Allocate g_mainwin_kimage
|
||||
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,
|
||||
g_screen_mdepth);
|
||||
}
|
||||
if(g_screen_depth != 8) {
|
||||
// Allocate g_mainwin_kimage
|
||||
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth,
|
||||
g_screen_mdepth);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; i++) {
|
||||
lores_col = g_lores_colors[i & 0xf];
|
||||
video_update_color_raw(i, lores_col);
|
||||
g_a2palette_8to1624[i] = g_palette_8to1624[i];
|
||||
}
|
||||
for(i = 0; i < 256; i++) {
|
||||
lores_col = g_lores_colors[i & 0xf];
|
||||
video_update_color_raw(i, lores_col);
|
||||
g_a2palette_8to1624[i] = g_palette_8to1624[i];
|
||||
}
|
||||
|
||||
g_installed_full_superhires_colormap = 1;
|
||||
g_installed_full_superhires_colormap = 1;
|
||||
|
||||
printf("Done with dev_video_init\n");
|
||||
fflush(stdout);
|
||||
printf("Done with dev_video_init\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
x_redraw_status_lines()
|
||||
{
|
||||
void x_redraw_status_lines() {
|
||||
|
||||
int line,len,height;
|
||||
POINTL pt;
|
||||
char *buf;
|
||||
int line,len,height;
|
||||
POINTL pt;
|
||||
char *buf;
|
||||
|
||||
printf("x_redraw_status_lines() called\n");
|
||||
printf("x_redraw_status_lines() called\n");
|
||||
/*
|
||||
if (g_status_ptrs[0] != NULL)
|
||||
{
|
||||
height = 16;
|
||||
pt.x = 5; pt.y = 0;
|
||||
GpiSetColor( g_hps_screen, CLR_NEUTRAL );
|
||||
GpiSetBackColor( g_hps_screen, CLR_BACKGROUND );
|
||||
GpiSetBackMix( g_hps_screen, BM_OVERPAINT );
|
||||
if (g_status_ptrs[0] != NULL)
|
||||
{
|
||||
height = 16;
|
||||
pt.x = 5; pt.y = 0;
|
||||
GpiSetColor( g_hps_screen, CLR_NEUTRAL );
|
||||
GpiSetBackColor( g_hps_screen, CLR_BACKGROUND );
|
||||
GpiSetBackMix( g_hps_screen, BM_OVERPAINT );
|
||||
|
||||
for (line = 0; line < MAX_STATUS_LINES; line++)
|
||||
{
|
||||
buf = g_status_ptrs[line];
|
||||
if (buf != 0)
|
||||
{
|
||||
pt.y = height * (line+1);
|
||||
len = strlen(buf);
|
||||
GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
for (line = 0; line < MAX_STATUS_LINES; line++)
|
||||
{
|
||||
buf = g_status_ptrs[line];
|
||||
if (buf != 0)
|
||||
{
|
||||
pt.y = height * (line+1);
|
||||
len = strlen(buf);
|
||||
GpiCharStringAt( g_hps_screen, &pt, (LONG)strlen( buf ), buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
|
||||
int width, int height)
|
||||
{
|
||||
RECTL rc;
|
||||
POINTL pt[4];
|
||||
HBITMAP hbmOld, hbmNew;
|
||||
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy,
|
||||
int width, int height) {
|
||||
RECTL rc;
|
||||
POINTL pt[4];
|
||||
HBITMAP hbmOld, hbmNew;
|
||||
|
||||
char *szString = "Hello, world!\0";
|
||||
char *szString = "Hello, world!\0";
|
||||
|
||||
printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height);
|
||||
pt[0].x = destx; /* Target X1 */
|
||||
pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */
|
||||
pt[1].x = destx+width; /* Target X2 */
|
||||
pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */
|
||||
pt[2].x = srcx; /* Source X */
|
||||
pt[2].y = srcy; /* Source Y */
|
||||
pt[3].x = srcx+width;
|
||||
pt[3].y = srcy+height;
|
||||
printf("x_push_kimage() called: Src: (%d,%d) Dest: (%d,%d) Width: %d Height: %d\n",srcx,srcy,destx,desty,width,height);
|
||||
pt[0].x = destx; /* Target X1 */
|
||||
pt[0].y = desty+(MAX_STATUS_LINES*16); /* Target Y1 */
|
||||
pt[1].x = destx+width; /* Target X2 */
|
||||
pt[1].y = desty+height+(MAX_STATUS_LINES*16); /* Target Y2: Translate up, make room for status border */
|
||||
pt[2].x = srcx; /* Source X */
|
||||
pt[2].y = srcy; /* Source Y */
|
||||
pt[3].x = srcx+width;
|
||||
pt[3].y = srcy+height;
|
||||
|
||||
if (width == 560)
|
||||
{
|
||||
/* Paint a known-good bitmap until we can figure out why images aren't showing up */
|
||||
hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400);
|
||||
hbmOld = GpiSetBitmap(g_hps_memory, hbmNew);
|
||||
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
|
||||
GpiSetBitmap(g_hps_memory, hbmOld);
|
||||
GpiDeleteBitmap(hbmNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle);
|
||||
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
|
||||
GpiSetBitmap(g_hps_memory, hbmOld);
|
||||
}
|
||||
if (width == 560)
|
||||
{
|
||||
/* Paint a known-good bitmap until we can figure out why images aren't showing up */
|
||||
hbmNew = GpiLoadBitmap(g_hps_memory,NULLHANDLE,ID_BITMAP,560,400);
|
||||
hbmOld = GpiSetBitmap(g_hps_memory, hbmNew);
|
||||
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
|
||||
GpiSetBitmap(g_hps_memory, hbmOld);
|
||||
GpiDeleteBitmap(hbmNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
hbmOld = GpiSetBitmap(g_hps_memory, (HBITMAP)kimage_ptr->dev_handle);
|
||||
GpiBitBlt(g_hps_screen,g_hps_memory,4L,pt,ROP_SRCCOPY, BBO_IGNORE);
|
||||
GpiSetBitmap(g_hps_memory, hbmOld);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// OG Adding release
|
||||
void x_release_kimage(Kimage* kimage_ptr)
|
||||
{
|
||||
if (kimage_ptr->dev_handle == (void*)-1)
|
||||
{
|
||||
free(kimage_ptr->data_ptr);
|
||||
kimage_ptr->data_ptr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
void x_release_kimage(Kimage* kimage_ptr) {
|
||||
if (kimage_ptr->dev_handle == (void*)-1)
|
||||
{
|
||||
free(kimage_ptr->data_ptr);
|
||||
kimage_ptr->data_ptr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
x_push_done()
|
||||
{
|
||||
void x_push_done() {
|
||||
}
|
||||
|
||||
void
|
||||
x_auto_repeat_on(int must)
|
||||
{
|
||||
void x_auto_repeat_on(int must) {
|
||||
}
|
||||
|
||||
void
|
||||
x_auto_repeat_off(int must)
|
||||
{
|
||||
void x_auto_repeat_off(int must) {
|
||||
}
|
||||
|
||||
void
|
||||
x_hide_pointer(int do_hide)
|
||||
{
|
||||
void x_hide_pointer(int do_hide) {
|
||||
}
|
||||
|
||||
void
|
||||
x_full_screen(int do_full)
|
||||
{
|
||||
return;
|
||||
void x_full_screen(int do_full) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x_calc_ratio(float ratiox,float ratioy)
|
||||
{
|
||||
return 0; // not stretched
|
||||
int x_calc_ratio(float ratiox,float ratioy) {
|
||||
return 0; // not stretched
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
@ -511,33 +457,30 @@ int x_calc_ratio(float ratiox,float ratioy)
|
||||
/* The error message is displayed using a message box */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID DispErrorMessage()
|
||||
{
|
||||
PERRINFO pErrInfoBlk;
|
||||
PSZ pszOffSet, pszErrMsg;
|
||||
ERRORID ErrorId;
|
||||
PCH ErrorStr;
|
||||
VOID DispErrorMessage() {
|
||||
PERRINFO pErrInfoBlk;
|
||||
PSZ pszOffSet, pszErrMsg;
|
||||
ERRORID ErrorId;
|
||||
PCH ErrorStr;
|
||||
|
||||
ErrorId = WinGetLastError(g_hab);
|
||||
ErrorId = WinGetLastError(g_hab);
|
||||
|
||||
if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL)
|
||||
{
|
||||
pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
|
||||
pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
|
||||
if ((pErrInfoBlk = WinGetErrorInfo(g_hab)) != (PERRINFO)NULL)
|
||||
{
|
||||
pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
|
||||
pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
|
||||
|
||||
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
|
||||
g_hwnd_frame, /* Owner window is our frame */
|
||||
pszErrMsg, /* PMWIN Error message */
|
||||
"Error", /* Title bar message */
|
||||
0, /* Message identifier */
|
||||
MB_MOVEABLE | MB_CANCEL ); /* Flags */
|
||||
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
|
||||
g_hwnd_frame, /* Owner window is our frame */
|
||||
pszErrMsg, /* PMWIN Error message */
|
||||
"Error", /* Title bar message */
|
||||
0, /* Message identifier */
|
||||
MB_MOVEABLE | MB_CANCEL ); /* Flags */
|
||||
|
||||
WinFreeErrorInfo(pErrInfoBlk);
|
||||
}
|
||||
WinFreeErrorInfo(pErrInfoBlk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client)
|
||||
{
|
||||
void os2_abort(HWND g_hwnd_frame, HWND g_hwnd_client) {
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -1,23 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
int g_preferred_rate = 48000;
|
||||
|
@ -18,48 +18,45 @@
|
||||
* 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dirport.h"
|
||||
|
||||
DIR *opendir (char *path)
|
||||
{
|
||||
APIRET ulrc;
|
||||
ULONG cnt = 1;
|
||||
DIR *dir;
|
||||
char *name;
|
||||
|
||||
if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) {
|
||||
return NULL;
|
||||
}
|
||||
if (name = (char*)calloc(1, strlen(path) + 3)) {
|
||||
strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*");
|
||||
dir->handle = HDIR_CREATE;
|
||||
ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD);
|
||||
free(name);
|
||||
}
|
||||
if (!name || ulrc) {
|
||||
DosFindClose (dir->handle);
|
||||
free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
struct dirent *readdir (DIR *dir)
|
||||
{
|
||||
ULONG cnt = 1;
|
||||
|
||||
return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer);
|
||||
}
|
||||
|
||||
int closedir (DIR *dir)
|
||||
{
|
||||
APIRET ulrc = DosFindClose (dir->handle);
|
||||
DIR *opendir (char *path) {
|
||||
APIRET ulrc;
|
||||
ULONG cnt = 1;
|
||||
DIR *dir;
|
||||
char *name;
|
||||
|
||||
if (!(dir = (DIR*)calloc(1, sizeof(DIR)))) {
|
||||
return NULL;
|
||||
}
|
||||
if (name = (char*)calloc(1, strlen(path) + 3)) {
|
||||
strcat(strcpy(name, path),path[strlen(path) - 1] == '\\' ? "*" : "\\*");
|
||||
dir->handle = HDIR_CREATE;
|
||||
ulrc = DosFindFirst(name, &(dir->handle), _A_ANY, &(dir->buffer), sizeof(struct _FILEFINDBUF3), &cnt, FIL_STANDARD);
|
||||
free(name);
|
||||
}
|
||||
if (!name || ulrc) {
|
||||
DosFindClose (dir->handle);
|
||||
free(dir);
|
||||
return (int)ulrc;
|
||||
dir = NULL;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
struct dirent *readdir (DIR *dir) {
|
||||
ULONG cnt = 1;
|
||||
|
||||
return DosFindNext (dir->handle, &(dir->buffer), sizeof(struct _FILEFINDBUF), &cnt) ? NULL : &(dir->buffer);
|
||||
}
|
||||
|
||||
int closedir (DIR *dir) {
|
||||
APIRET ulrc = DosFindClose (dir->handle);
|
||||
|
||||
free(dir);
|
||||
return (int)ulrc;
|
||||
}
|
||||
|
||||
|
||||
@ -71,7 +68,7 @@ int closedir (DIR *dir)
|
||||
snprintf.c
|
||||
- a portable implementation of snprintf,
|
||||
including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf
|
||||
|
||||
|
||||
snprintf is a routine to convert numeric and string arguments to
|
||||
formatted strings. It is similar to sprintf(3) provided in a system's
|
||||
C library, yet it requires an additional argument - the buffer size -
|
||||
@ -81,10 +78,10 @@ int closedir (DIR *dir)
|
||||
not or do provide an inadequate (slow or idiosyncratic) version, which
|
||||
calls for a portable implementation of this routine.
|
||||
|
||||
Author
|
||||
Author
|
||||
|
||||
Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000
|
||||
Copyright © 1999, Mark Martinec
|
||||
Copyright <EFBFBD> 1999, Mark Martinec
|
||||
|
||||
*/
|
||||
|
||||
@ -167,14 +164,14 @@ Author
|
||||
#define fast_memcpy(d,s,n) \
|
||||
{ register size_t nn = (size_t)(n); \
|
||||
if (nn >= breakeven_point) memcpy((d), (s), nn); \
|
||||
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
|
||||
else if (nn > 0) { /* proc call overhead is worth only for large strings*/ \
|
||||
register char *dd; register const char *ss; \
|
||||
for (ss=(s), dd=(d); nn>0; nn--) *dd++ = *ss++; } }
|
||||
|
||||
#define fast_memset(d,c,n) \
|
||||
{ register size_t nn = (size_t)(n); \
|
||||
if (nn >= breakeven_point) memset((d), (int)(c), nn); \
|
||||
else if (nn > 0) { /* proc call overhead is worth only for large strings*/\
|
||||
else if (nn > 0) { /* proc call overhead is worth only for large strings*/ \
|
||||
register char *dd; register const int cc=(int)(c); \
|
||||
for (dd=(d); nn>0; nn--) *dd++ = cc; } }
|
||||
|
||||
@ -251,8 +248,7 @@ int vasprintf(char **ptr, const char *fmt, va_list ap) {
|
||||
{ va_list ap2;
|
||||
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
|
||||
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
|
||||
va_end(ap2);
|
||||
}
|
||||
va_end(ap2);}
|
||||
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
|
||||
*ptr = (char *) malloc(str_m = (size_t)str_l + 1);
|
||||
if (*ptr == NULL) { errno = ENOMEM; str_l = -1; }
|
||||
@ -300,8 +296,7 @@ int vasnprintf (char **ptr, size_t str_m, const char *fmt, va_list ap) {
|
||||
{ va_list ap2;
|
||||
va_copy(ap2, ap); /* don't consume the original ap, we'll need it again */
|
||||
str_l = portable_vsnprintf(NULL, (size_t)0, fmt, ap2);/*get required size*/
|
||||
va_end(ap2);
|
||||
}
|
||||
va_end(ap2);}
|
||||
assert(str_l >= 0); /* possible integer overflow if str_m > INT_MAX */
|
||||
if ((size_t)str_l + 1 < str_m) str_m = (size_t)str_l + 1; /* truncate */
|
||||
/* if str_m is 0, no buffer is allocated, just set *ptr to NULL */
|
||||
@ -358,14 +353,14 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
if (!p) p = "";
|
||||
while (*p) {
|
||||
if (*p != '%') {
|
||||
/* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
|
||||
/* but the following code achieves better performance for cases
|
||||
* where format string is long and contains few conversions */
|
||||
/* if (str_l < str_m) str[str_l++] = *p++; -- this would be sufficient */
|
||||
/* but the following code achieves better performance for cases
|
||||
* where format string is long and contains few conversions */
|
||||
const char *q = strchr(p+1,'%');
|
||||
size_t n = !q ? strlen(p) : (q-p);
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memcpy(str+str_l, p, (n>avail?avail:n));
|
||||
fast_memcpy(str+str_l, p, (n>avail ? avail : n));
|
||||
}
|
||||
p += n; str_l += n;
|
||||
} else {
|
||||
@ -382,45 +377,45 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
size_t str_arg_l; /* natural field width of arg without padding
|
||||
and sign */
|
||||
unsigned char uchar_arg;
|
||||
/* unsigned char argument value - only defined for c conversion.
|
||||
N.B. standard explicitly states the char argument for
|
||||
the c conversion is unsigned */
|
||||
/* unsigned char argument value - only defined for c conversion.
|
||||
N.B. standard explicitly states the char argument for
|
||||
the c conversion is unsigned */
|
||||
|
||||
size_t number_of_zeros_to_pad = 0;
|
||||
/* number of zeros to be inserted for numeric conversions
|
||||
as required by the precision or minimal field width */
|
||||
/* number of zeros to be inserted for numeric conversions
|
||||
as required by the precision or minimal field width */
|
||||
|
||||
size_t zero_padding_insertion_ind = 0;
|
||||
/* index into tmp where zero padding is to be inserted */
|
||||
/* index into tmp where zero padding is to be inserted */
|
||||
|
||||
char fmt_spec = '\0';
|
||||
/* current conversion specifier character */
|
||||
/* current conversion specifier character */
|
||||
|
||||
str_arg = credits;/* just to make compiler happy (defined but not used)*/
|
||||
str_arg = NULL;
|
||||
starting_p = p; p++; /* skip '%' */
|
||||
/* parse flags */
|
||||
/* parse flags */
|
||||
while (*p == '0' || *p == '-' || *p == '+' ||
|
||||
*p == ' ' || *p == '#' || *p == '\'') {
|
||||
switch (*p) {
|
||||
case '0': zero_padding = 1; break;
|
||||
case '-': justify_left = 1; break;
|
||||
case '+': force_sign = 1; space_for_positive = 0; break;
|
||||
case ' ': force_sign = 1;
|
||||
/* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
|
||||
case '0': zero_padding = 1; break;
|
||||
case '-': justify_left = 1; break;
|
||||
case '+': force_sign = 1; space_for_positive = 0; break;
|
||||
case ' ': force_sign = 1;
|
||||
/* If both the ' ' and '+' flags appear, the ' ' flag should be ignored */
|
||||
#ifdef PERL_COMPATIBLE
|
||||
/* ... but in Perl the last of ' ' and '+' applies */
|
||||
space_for_positive = 1;
|
||||
/* ... but in Perl the last of ' ' and '+' applies */
|
||||
space_for_positive = 1;
|
||||
#endif
|
||||
break;
|
||||
case '#': alternate_form = 1; break;
|
||||
case '\'': break;
|
||||
break;
|
||||
case '#': alternate_form = 1; break;
|
||||
case '\'': break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
/* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
|
||||
/* If the '0' and '-' flags both appear, the '0' flag should be ignored. */
|
||||
|
||||
/* parse field width */
|
||||
/* parse field width */
|
||||
if (*p == '*') {
|
||||
int j;
|
||||
p++; j = va_arg(ap, int);
|
||||
@ -433,7 +428,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
while (isdigit((int)(*p))) uj = 10*uj + (unsigned int)(*p++ - '0');
|
||||
min_field_width = uj;
|
||||
}
|
||||
/* parse precision */
|
||||
/* parse precision */
|
||||
if (*p == '.') {
|
||||
p++; precision_specified = 1;
|
||||
if (*p == '*') {
|
||||
@ -442,12 +437,12 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
if (j >= 0) precision = j;
|
||||
else {
|
||||
precision_specified = 0; precision = 0;
|
||||
/* NOTE:
|
||||
* Solaris 2.6 man page claims that in this case the precision
|
||||
* should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
|
||||
* claim that this case should be treated as unspecified precision,
|
||||
* which is what we do here.
|
||||
*/
|
||||
/* NOTE:
|
||||
* Solaris 2.6 man page claims that in this case the precision
|
||||
* should be set to 0. Digital Unix 4.0, HPUX 10 and BSD man page
|
||||
* claim that this case should be treated as unspecified precision,
|
||||
* which is what we do here.
|
||||
*/
|
||||
}
|
||||
} else if (isdigit((int)(*p))) {
|
||||
/* size_t could be wider than unsigned int;
|
||||
@ -457,7 +452,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
precision = uj;
|
||||
}
|
||||
}
|
||||
/* parse 'h', 'l' and 'll' length modifiers */
|
||||
/* parse 'h', 'l' and 'll' length modifiers */
|
||||
if (*p == 'h' || *p == 'l') {
|
||||
length_modifier = *p; p++;
|
||||
if (length_modifier == 'l' && *p == 'l') { /* double l = long long */
|
||||
@ -470,336 +465,334 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
}
|
||||
}
|
||||
fmt_spec = *p;
|
||||
/* common synonyms: */
|
||||
/* common synonyms: */
|
||||
switch (fmt_spec) {
|
||||
case 'i': fmt_spec = 'd'; break;
|
||||
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
|
||||
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
|
||||
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
|
||||
default: break;
|
||||
case 'i': fmt_spec = 'd'; break;
|
||||
case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
|
||||
case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
|
||||
case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
|
||||
default: break;
|
||||
}
|
||||
/* get parameter value, do initial processing */
|
||||
/* get parameter value, do initial processing */
|
||||
switch (fmt_spec) {
|
||||
case '%': /* % behaves similar to 's' regarding flags and field widths */
|
||||
case 'c': /* c behaves similar to 's' regarding flags and field widths */
|
||||
case 's':
|
||||
length_modifier = '\0'; /* wint_t and wchar_t not supported */
|
||||
/* the result of zero padding flag with non-numeric conversion specifier*/
|
||||
/* is undefined. Solaris and HPUX 10 does zero padding in this case, */
|
||||
/* Digital Unix and Linux does not. */
|
||||
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
|
||||
zero_padding = 0; /* turn zero padding off for string conversions */
|
||||
#endif
|
||||
str_arg_l = 1;
|
||||
switch (fmt_spec) {
|
||||
case '%':
|
||||
str_arg = p; break;
|
||||
case 'c': {
|
||||
int j = va_arg(ap, int);
|
||||
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
|
||||
str_arg = (const char *) &uchar_arg;
|
||||
break;
|
||||
}
|
||||
case '%': /* % behaves similar to 's' regarding flags and field widths */
|
||||
case 'c': /* c behaves similar to 's' regarding flags and field widths */
|
||||
case 's':
|
||||
str_arg = va_arg(ap, const char *);
|
||||
if (!str_arg) str_arg_l = 0;
|
||||
/* make sure not to address string beyond the specified precision !!! */
|
||||
else if (!precision_specified) str_arg_l = strlen(str_arg);
|
||||
/* truncate string if necessary as requested by precision */
|
||||
else if (precision == 0) str_arg_l = 0;
|
||||
else {
|
||||
/* memchr on HP does not like n > 2^31 !!! */
|
||||
const char *q = memchr(str_arg, '\0',
|
||||
precision <= 0x7fffffff ? precision : 0x7fffffff);
|
||||
str_arg_l = !q ? precision : (q-str_arg);
|
||||
length_modifier = '\0'; /* wint_t and wchar_t not supported */
|
||||
/* the result of zero padding flag with non-numeric conversion specifier*/
|
||||
/* is undefined. Solaris and HPUX 10 does zero padding in this case, */
|
||||
/* Digital Unix and Linux does not. */
|
||||
#if !defined(SOLARIS_COMPATIBLE) && !defined(HPUX_COMPATIBLE)
|
||||
zero_padding = 0; /* turn zero padding off for string conversions */
|
||||
#endif
|
||||
str_arg_l = 1;
|
||||
switch (fmt_spec) {
|
||||
case '%':
|
||||
str_arg = p; break;
|
||||
case 'c': {
|
||||
int j = va_arg(ap, int);
|
||||
uchar_arg = (unsigned char) j; /* standard demands unsigned char */
|
||||
str_arg = (const char *) &uchar_arg;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
str_arg = va_arg(ap, const char *);
|
||||
if (!str_arg) str_arg_l = 0;
|
||||
/* make sure not to address string beyond the specified precision !!! */
|
||||
else if (!precision_specified) str_arg_l = strlen(str_arg);
|
||||
/* truncate string if necessary as requested by precision */
|
||||
else if (precision == 0) str_arg_l = 0;
|
||||
else {
|
||||
/* memchr on HP does not like n > 2^31 !!! */
|
||||
const char *q = memchr(str_arg, '\0',
|
||||
precision <= 0x7fffffff ? precision : 0x7fffffff);
|
||||
str_arg_l = !q ? precision : (q-str_arg);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
|
||||
/* NOTE: the u, o, x, X and p conversion specifiers imply
|
||||
the value is unsigned; d implies a signed value */
|
||||
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
|
||||
/* NOTE: the u, o, x, X and p conversion specifiers imply
|
||||
the value is unsigned; d implies a signed value */
|
||||
|
||||
int arg_sign = 0;
|
||||
int arg_sign = 0;
|
||||
/* 0 if numeric argument is zero (or if pointer is NULL for 'p'),
|
||||
+1 if greater than zero (or nonzero for unsigned arguments),
|
||||
-1 if negative (unsigned argument is never negative) */
|
||||
+1 if greater than zero (or nonzero for unsigned arguments),
|
||||
-1 if negative (unsigned argument is never negative) */
|
||||
|
||||
int int_arg = 0; unsigned int uint_arg = 0;
|
||||
int int_arg = 0; unsigned int uint_arg = 0;
|
||||
/* only defined for length modifier h, or for no length modifiers */
|
||||
|
||||
long int long_arg = 0; unsigned long int ulong_arg = 0;
|
||||
long int long_arg = 0; unsigned long int ulong_arg = 0;
|
||||
/* only defined for length modifier l */
|
||||
|
||||
void *ptr_arg = NULL;
|
||||
void *ptr_arg = NULL;
|
||||
/* pointer argument value -only defined for p conversion */
|
||||
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
long long int long_long_arg = 0;
|
||||
unsigned long long int ulong_long_arg = 0;
|
||||
long long int long_long_arg = 0;
|
||||
unsigned long long int ulong_long_arg = 0;
|
||||
/* only defined for length modifier ll */
|
||||
#endif
|
||||
if (fmt_spec == 'p') {
|
||||
/* HPUX 10: An l, h, ll or L before any other conversion character
|
||||
* (other than d, i, u, o, x, or X) is ignored.
|
||||
* Digital Unix:
|
||||
* not specified, but seems to behave as HPUX does.
|
||||
* Solaris: If an h, l, or L appears before any other conversion
|
||||
* specifier (other than d, i, u, o, x, or X), the behavior
|
||||
* is undefined. (Actually %hp converts only 16-bits of address
|
||||
* and %llp treats address as 64-bit data which is incompatible
|
||||
* with (void *) argument on a 32-bit system).
|
||||
*/
|
||||
if (fmt_spec == 'p') {
|
||||
/* HPUX 10: An l, h, ll or L before any other conversion character
|
||||
* (other than d, i, u, o, x, or X) is ignored.
|
||||
* Digital Unix:
|
||||
* not specified, but seems to behave as HPUX does.
|
||||
* Solaris: If an h, l, or L appears before any other conversion
|
||||
* specifier (other than d, i, u, o, x, or X), the behavior
|
||||
* is undefined. (Actually %hp converts only 16-bits of address
|
||||
* and %llp treats address as 64-bit data which is incompatible
|
||||
* with (void *) argument on a 32-bit system).
|
||||
*/
|
||||
#ifdef SOLARIS_COMPATIBLE
|
||||
# ifdef SOLARIS_BUG_COMPATIBLE
|
||||
/* keep length modifiers even if it represents 'll' */
|
||||
/* keep length modifiers even if it represents 'll' */
|
||||
# else
|
||||
if (length_modifier == '2') length_modifier = '\0';
|
||||
if (length_modifier == '2') length_modifier = '\0';
|
||||
# endif
|
||||
#else
|
||||
length_modifier = '\0';
|
||||
length_modifier = '\0';
|
||||
#endif
|
||||
ptr_arg = va_arg(ap, void *);
|
||||
if (ptr_arg != NULL) arg_sign = 1;
|
||||
} else if (fmt_spec == 'd') { /* signed */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h':
|
||||
/* It is non-portable to specify a second argument of char or short
|
||||
* to va_arg, because arguments seen by the called function
|
||||
* are not char or short. C converts char and short arguments
|
||||
* to int before passing them to a function.
|
||||
*/
|
||||
int_arg = va_arg(ap, int);
|
||||
if (int_arg > 0) arg_sign = 1;
|
||||
else if (int_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
case 'l':
|
||||
long_arg = va_arg(ap, long int);
|
||||
if (long_arg > 0) arg_sign = 1;
|
||||
else if (long_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
ptr_arg = va_arg(ap, void *);
|
||||
if (ptr_arg != NULL) arg_sign = 1;
|
||||
} else if (fmt_spec == 'd') { /* signed */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h':
|
||||
/* It is non-portable to specify a second argument of char or short
|
||||
* to va_arg, because arguments seen by the called function
|
||||
* are not char or short. C converts char and short arguments
|
||||
* to int before passing them to a function.
|
||||
*/
|
||||
int_arg = va_arg(ap, int);
|
||||
if (int_arg > 0) arg_sign = 1;
|
||||
else if (int_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
case 'l':
|
||||
long_arg = va_arg(ap, long int);
|
||||
if (long_arg > 0) arg_sign = 1;
|
||||
else if (long_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
case '2':
|
||||
long_long_arg = va_arg(ap, long long int);
|
||||
if (long_long_arg > 0) arg_sign = 1;
|
||||
else if (long_long_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
case '2':
|
||||
long_long_arg = va_arg(ap, long long int);
|
||||
if (long_long_arg > 0) arg_sign = 1;
|
||||
else if (long_long_arg < 0) arg_sign = -1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
} else { /* unsigned */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h':
|
||||
uint_arg = va_arg(ap, unsigned int);
|
||||
if (uint_arg) arg_sign = 1;
|
||||
break;
|
||||
case 'l':
|
||||
ulong_arg = va_arg(ap, unsigned long int);
|
||||
if (ulong_arg) arg_sign = 1;
|
||||
break;
|
||||
}
|
||||
} else { /* unsigned */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h':
|
||||
uint_arg = va_arg(ap, unsigned int);
|
||||
if (uint_arg) arg_sign = 1;
|
||||
break;
|
||||
case 'l':
|
||||
ulong_arg = va_arg(ap, unsigned long int);
|
||||
if (ulong_arg) arg_sign = 1;
|
||||
break;
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
case '2':
|
||||
ulong_long_arg = va_arg(ap, unsigned long long int);
|
||||
if (ulong_long_arg) arg_sign = 1;
|
||||
break;
|
||||
case '2':
|
||||
ulong_long_arg = va_arg(ap, unsigned long long int);
|
||||
if (ulong_long_arg) arg_sign = 1;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
str_arg = tmp; str_arg_l = 0;
|
||||
/* NOTE:
|
||||
* For d, i, u, o, x, and X conversions, if precision is specified,
|
||||
* the '0' flag should be ignored. This is so with Solaris 2.6,
|
||||
* Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
|
||||
*/
|
||||
str_arg = tmp; str_arg_l = 0;
|
||||
/* NOTE:
|
||||
* For d, i, u, o, x, and X conversions, if precision is specified,
|
||||
* the '0' flag should be ignored. This is so with Solaris 2.6,
|
||||
* Digital UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
|
||||
*/
|
||||
#ifndef PERL_COMPATIBLE
|
||||
if (precision_specified) zero_padding = 0;
|
||||
if (precision_specified) zero_padding = 0;
|
||||
#endif
|
||||
if (fmt_spec == 'd') {
|
||||
if (force_sign && arg_sign >= 0)
|
||||
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
|
||||
/* leave negative numbers for sprintf to handle,
|
||||
to avoid handling tricky cases like (short int)(-32768) */
|
||||
if (fmt_spec == 'd') {
|
||||
if (force_sign && arg_sign >= 0)
|
||||
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
|
||||
/* leave negative numbers for sprintf to handle,
|
||||
to avoid handling tricky cases like (short int)(-32768) */
|
||||
#ifdef LINUX_COMPATIBLE
|
||||
} else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
|
||||
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
|
||||
} else if (fmt_spec == 'p' && force_sign && arg_sign > 0) {
|
||||
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
|
||||
#endif
|
||||
} else if (alternate_form) {
|
||||
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
|
||||
} else if (alternate_form) {
|
||||
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') )
|
||||
{ tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = fmt_spec; }
|
||||
/* alternate form should have no effect for p conversion, but ... */
|
||||
/* alternate form should have no effect for p conversion, but ... */
|
||||
#ifdef HPUX_COMPATIBLE
|
||||
else if (fmt_spec == 'p'
|
||||
/* HPUX 10: for an alternate form of p conversion,
|
||||
* a nonzero result is prefixed by 0x. */
|
||||
else if (fmt_spec == 'p'
|
||||
/* HPUX 10: for an alternate form of p conversion,
|
||||
* a nonzero result is prefixed by 0x. */
|
||||
#ifndef HPUX_BUG_COMPATIBLE
|
||||
/* Actually it uses 0x prefix even for a zero value. */
|
||||
&& arg_sign != 0
|
||||
/* Actually it uses 0x prefix even for a zero value. */
|
||||
&& arg_sign != 0
|
||||
#endif
|
||||
) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
|
||||
) { tmp[str_arg_l++] = '0'; tmp[str_arg_l++] = 'x'; }
|
||||
#endif
|
||||
}
|
||||
zero_padding_insertion_ind = str_arg_l;
|
||||
if (!precision_specified) precision = 1; /* default precision is 1 */
|
||||
if (precision == 0 && arg_sign == 0
|
||||
}
|
||||
zero_padding_insertion_ind = str_arg_l;
|
||||
if (!precision_specified) precision = 1; /* default precision is 1 */
|
||||
if (precision == 0 && arg_sign == 0
|
||||
#if defined(HPUX_BUG_COMPATIBLE) || defined(LINUX_COMPATIBLE)
|
||||
&& fmt_spec != 'p'
|
||||
/* HPUX 10 man page claims: With conversion character p the result of
|
||||
* converting a zero value with a precision of zero is a null string.
|
||||
* Actually HP returns all zeroes, and Linux returns "(nil)". */
|
||||
&& fmt_spec != 'p'
|
||||
/* HPUX 10 man page claims: With conversion character p the result of
|
||||
* converting a zero value with a precision of zero is a null string.
|
||||
* Actually HP returns all zeroes, and Linux returns "(nil)". */
|
||||
#endif
|
||||
) {
|
||||
/* converted to null string */
|
||||
/* When zero value is formatted with an explicit precision 0,
|
||||
the resulting formatted string is empty (d, i, u, o, x, X, p). */
|
||||
} else {
|
||||
char f[5]; int f_l = 0;
|
||||
f[f_l++] = '%'; /* construct a simple format string for sprintf */
|
||||
if (!length_modifier) { }
|
||||
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
|
||||
else f[f_l++] = length_modifier;
|
||||
f[f_l++] = fmt_spec; f[f_l++] = '\0';
|
||||
if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
|
||||
else if (fmt_spec == 'd') { /* signed */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
|
||||
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
|
||||
) {
|
||||
/* converted to null string */
|
||||
/* When zero value is formatted with an explicit precision 0,
|
||||
the resulting formatted string is empty (d, i, u, o, x, X, p). */
|
||||
} else {
|
||||
char f[5]; int f_l = 0;
|
||||
f[f_l++] = '%'; /* construct a simple format string for sprintf */
|
||||
if (!length_modifier) { }
|
||||
else if (length_modifier=='2') { f[f_l++] = 'l'; f[f_l++] = 'l'; }
|
||||
else f[f_l++] = length_modifier;
|
||||
f[f_l++] = fmt_spec; f[f_l++] = '\0';
|
||||
if (fmt_spec == 'p') str_arg_l += sprintf(tmp+str_arg_l, f, ptr_arg);
|
||||
else if (fmt_spec == 'd') { /* signed */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, int_arg); break;
|
||||
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, long_arg); break;
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
|
||||
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,long_long_arg); break;
|
||||
#endif
|
||||
}
|
||||
} else { /* unsigned */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
|
||||
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg); break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else { /* unsigned */
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h': str_arg_l+=sprintf(tmp+str_arg_l, f, uint_arg); break;
|
||||
case 'l': str_arg_l+=sprintf(tmp+str_arg_l, f, ulong_arg); break;
|
||||
#ifdef SNPRINTF_LONGLONG_SUPPORT
|
||||
case '2': str_arg_l+=sprintf(tmp+str_arg_l,f,ulong_long_arg);break;
|
||||
#endif
|
||||
/* include the optional minus sign and possible "0x"
|
||||
in the region before the zero padding insertion point */
|
||||
if (zero_padding_insertion_ind < str_arg_l &&
|
||||
tmp[zero_padding_insertion_ind] == '-') {
|
||||
zero_padding_insertion_ind++;
|
||||
}
|
||||
if (zero_padding_insertion_ind+1 < str_arg_l &&
|
||||
tmp[zero_padding_insertion_ind] == '0' &&
|
||||
(tmp[zero_padding_insertion_ind+1] == 'x' ||
|
||||
tmp[zero_padding_insertion_ind+1] == 'X') ) {
|
||||
zero_padding_insertion_ind += 2;
|
||||
}
|
||||
}
|
||||
/* include the optional minus sign and possible "0x"
|
||||
in the region before the zero padding insertion point */
|
||||
if (zero_padding_insertion_ind < str_arg_l &&
|
||||
tmp[zero_padding_insertion_ind] == '-') {
|
||||
zero_padding_insertion_ind++;
|
||||
}
|
||||
if (zero_padding_insertion_ind+1 < str_arg_l &&
|
||||
tmp[zero_padding_insertion_ind] == '0' &&
|
||||
(tmp[zero_padding_insertion_ind+1] == 'x' ||
|
||||
tmp[zero_padding_insertion_ind+1] == 'X') ) {
|
||||
zero_padding_insertion_ind += 2;
|
||||
}
|
||||
}
|
||||
{ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
|
||||
if (alternate_form && fmt_spec == 'o'
|
||||
{ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
|
||||
if (alternate_form && fmt_spec == 'o'
|
||||
#ifdef HPUX_COMPATIBLE /* ("%#.o",0) -> "" */
|
||||
&& (str_arg_l > 0)
|
||||
&& (str_arg_l > 0)
|
||||
#endif
|
||||
#ifdef DIGITAL_UNIX_BUG_COMPATIBLE /* ("%#o",0) -> "00" */
|
||||
#else
|
||||
/* unless zero is already the first character */
|
||||
&& !(zero_padding_insertion_ind < str_arg_l
|
||||
&& tmp[zero_padding_insertion_ind] == '0')
|
||||
/* unless zero is already the first character */
|
||||
&& !(zero_padding_insertion_ind < str_arg_l
|
||||
&& tmp[zero_padding_insertion_ind] == '0')
|
||||
#endif
|
||||
) { /* assure leading zero for alternate-form octal numbers */
|
||||
if (!precision_specified || precision < num_of_digits+1) {
|
||||
/* precision is increased to force the first character to be zero,
|
||||
except if a zero value is formatted with an explicit precision
|
||||
of zero */
|
||||
precision = num_of_digits+1; precision_specified = 1;
|
||||
) { /* assure leading zero for alternate-form octal numbers */
|
||||
if (!precision_specified || precision < num_of_digits+1) {
|
||||
/* precision is increased to force the first character to be zero,
|
||||
except if a zero value is formatted with an explicit precision
|
||||
of zero */
|
||||
precision = num_of_digits+1; precision_specified = 1;
|
||||
}
|
||||
}
|
||||
/* zero padding to specified precision? */
|
||||
if (num_of_digits < precision)
|
||||
number_of_zeros_to_pad = precision - num_of_digits; }
|
||||
/* zero padding to specified minimal field width? */
|
||||
if (!justify_left && zero_padding) {
|
||||
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
|
||||
if (n > 0) number_of_zeros_to_pad += n;
|
||||
}
|
||||
/* zero padding to specified precision? */
|
||||
if (num_of_digits < precision)
|
||||
number_of_zeros_to_pad = precision - num_of_digits;
|
||||
break;
|
||||
}
|
||||
/* zero padding to specified minimal field width? */
|
||||
if (!justify_left && zero_padding) {
|
||||
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
|
||||
if (n > 0) number_of_zeros_to_pad += n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: /* unrecognized conversion specifier, keep format string as-is*/
|
||||
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
|
||||
default: /* unrecognized conversion specifier, keep format string as-is*/
|
||||
zero_padding = 0; /* turn zero padding off for non-numeric convers. */
|
||||
#ifndef DIGITAL_UNIX_COMPATIBLE
|
||||
justify_left = 1; min_field_width = 0; /* reset flags */
|
||||
justify_left = 1; min_field_width = 0; /* reset flags */
|
||||
#endif
|
||||
#if defined(PERL_COMPATIBLE) || defined(LINUX_COMPATIBLE)
|
||||
/* keep the entire format string unchanged */
|
||||
str_arg = starting_p; str_arg_l = p - starting_p;
|
||||
/* well, not exactly so for Linux, which does something inbetween,
|
||||
* and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
|
||||
/* keep the entire format string unchanged */
|
||||
str_arg = starting_p; str_arg_l = p - starting_p;
|
||||
/* well, not exactly so for Linux, which does something inbetween,
|
||||
* and I don't feel an urge to imitate it: "%+++++hy" -> "%+y" */
|
||||
#else
|
||||
/* discard the unrecognized conversion, just keep *
|
||||
* the unrecognized conversion character */
|
||||
str_arg = p; str_arg_l = 0;
|
||||
/* discard the unrecognized conversion, just keep *
|
||||
* the unrecognized conversion character */
|
||||
str_arg = p; str_arg_l = 0;
|
||||
#endif
|
||||
if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
|
||||
if not at end-of-string */
|
||||
break;
|
||||
if (*p) str_arg_l++; /* include invalid conversion specifier unchanged
|
||||
if not at end-of-string */
|
||||
break;
|
||||
}
|
||||
if (*p) p++; /* step over the just processed conversion specifier */
|
||||
/* insert padding to the left as requested by min_field_width;
|
||||
this does not include the zero padding in case of numerical conversions*/
|
||||
/* insert padding to the left as requested by min_field_width;
|
||||
this does not include the zero padding in case of numerical conversions*/
|
||||
if (!justify_left) { /* left padding with blank or zero */
|
||||
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
|
||||
if (n > 0) {
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memset(str+str_l, (zero_padding?'0':' '), (n>avail?avail:n));
|
||||
fast_memset(str+str_l, (zero_padding ? '0' : ' '), (n>avail ? avail : n));
|
||||
}
|
||||
str_l += n;
|
||||
}
|
||||
}
|
||||
/* zero padding as requested by the precision or by the minimal field width
|
||||
* for numeric conversions required? */
|
||||
/* zero padding as requested by the precision or by the minimal field width
|
||||
* for numeric conversions required? */
|
||||
if (number_of_zeros_to_pad <= 0) {
|
||||
/* will not copy first part of numeric right now, *
|
||||
* force it to be copied later in its entirety */
|
||||
/* will not copy first part of numeric right now, *
|
||||
* force it to be copied later in its entirety */
|
||||
zero_padding_insertion_ind = 0;
|
||||
} else {
|
||||
/* insert first part of numerics (sign or '0x') before zero padding */
|
||||
/* insert first part of numerics (sign or '0x') before zero padding */
|
||||
int n = zero_padding_insertion_ind;
|
||||
if (n > 0) {
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memcpy(str+str_l, str_arg, (n>avail?avail:n));
|
||||
fast_memcpy(str+str_l, str_arg, (n>avail ? avail : n));
|
||||
}
|
||||
str_l += n;
|
||||
}
|
||||
/* insert zero padding as requested by the precision or min field width */
|
||||
/* insert zero padding as requested by the precision or min field width */
|
||||
n = number_of_zeros_to_pad;
|
||||
if (n > 0) {
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memset(str+str_l, '0', (n>avail?avail:n));
|
||||
fast_memset(str+str_l, '0', (n>avail ? avail : n));
|
||||
}
|
||||
str_l += n;
|
||||
}
|
||||
}
|
||||
/* insert formatted string
|
||||
* (or as-is conversion specifier for unknown conversions) */
|
||||
/* insert formatted string
|
||||
* (or as-is conversion specifier for unknown conversions) */
|
||||
{ int n = str_arg_l - zero_padding_insertion_ind;
|
||||
if (n > 0) {
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memcpy(str+str_l, str_arg+zero_padding_insertion_ind,
|
||||
(n>avail?avail:n));
|
||||
(n>avail ? avail : n));
|
||||
}
|
||||
str_l += n;
|
||||
}
|
||||
}
|
||||
/* insert right padding */
|
||||
}}
|
||||
/* insert right padding */
|
||||
if (justify_left) { /* right blank padding to the field width */
|
||||
int n = min_field_width - (str_arg_l+number_of_zeros_to_pad);
|
||||
if (n > 0) {
|
||||
if (str_l < str_m) {
|
||||
size_t avail = str_m-str_l;
|
||||
fast_memset(str+str_l, ' ', (n>avail?avail:n));
|
||||
fast_memset(str+str_l, ' ', (n>avail ? avail : n));
|
||||
}
|
||||
str_l += n;
|
||||
}
|
||||
@ -829,7 +822,7 @@ int portable_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) {
|
||||
#endif
|
||||
#endif /* ndef HAVE_SNPRINTF */
|
||||
/*
|
||||
Local Variables:
|
||||
tab-width: 3
|
||||
end:
|
||||
*/
|
||||
Local Variables:
|
||||
tab-width: 3
|
||||
end:
|
||||
*/
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** This module implements AARP, a necessary protocol for ELAP communication. **/
|
||||
|
||||
@ -38,10 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
struct amt_entry_t
|
||||
{
|
||||
struct at_addr_t protocol;
|
||||
struct ether_addr_t hardware;
|
||||
struct at_addr_t protocol;
|
||||
struct ether_addr_t hardware;
|
||||
|
||||
struct amt_entry_t* next;
|
||||
struct amt_entry_t* next;
|
||||
};
|
||||
|
||||
typedef struct amt_entry_t* amt_t;
|
||||
@ -52,253 +38,237 @@ static unsigned int retry_count;
|
||||
static clock_t retry_timer;
|
||||
|
||||
|
||||
void aarp_init()
|
||||
{
|
||||
aarp_retry_reset();
|
||||
void aarp_init() {
|
||||
aarp_retry_reset();
|
||||
}
|
||||
|
||||
void aarp_shutdown()
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
struct amt_entry_t* next = entry->next;
|
||||
free(entry);
|
||||
entry = next;
|
||||
}
|
||||
void aarp_shutdown() {
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
struct amt_entry_t* next = entry->next;
|
||||
free(entry);
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr)
|
||||
{
|
||||
if (source_at_addr && dest_at_addr && dest_hw_addr)
|
||||
{
|
||||
struct aarp_header_t response;
|
||||
response.hardware_type = htons(AARP_HARDWARE_ETHER);
|
||||
response.protocol_type = htons(AARP_PROTOCOL_TYPE);
|
||||
response.hw_addr_len = AARP_HW_ADDR_LEN;
|
||||
response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN;
|
||||
response.function = htons(function);
|
||||
static void aarp_send_packet(enum AARP_FUNCTION function, const struct at_addr_t* source_at_addr, const struct at_addr_t* dest_at_addr, const struct ether_addr_t* dest_hw_addr) {
|
||||
if (source_at_addr && dest_at_addr && dest_hw_addr)
|
||||
{
|
||||
struct aarp_header_t response;
|
||||
response.hardware_type = htons(AARP_HARDWARE_ETHER);
|
||||
response.protocol_type = htons(AARP_PROTOCOL_TYPE);
|
||||
response.hw_addr_len = AARP_HW_ADDR_LEN;
|
||||
response.protocol_addr_len = AARP_PROTOCOL_ADDR_LEN;
|
||||
response.function = htons(function);
|
||||
|
||||
memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr));
|
||||
response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network);
|
||||
response.source_proto_addr.zero = 0x00;
|
||||
memcpy(&response.source_proto_addr.addr, source_at_addr, sizeof(response.source_proto_addr.addr));
|
||||
response.source_proto_addr.addr.network = htons(response.source_proto_addr.addr.network);
|
||||
response.source_proto_addr.zero = 0x00;
|
||||
|
||||
memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr));
|
||||
response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network);
|
||||
response.dest_proto_addr.zero = 0x00;
|
||||
memcpy(&response.dest_proto_addr.addr, dest_at_addr, sizeof(response.dest_proto_addr.addr));
|
||||
response.dest_proto_addr.addr.network = htons(response.dest_proto_addr.addr.network);
|
||||
response.dest_proto_addr.zero = 0x00;
|
||||
|
||||
memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac));
|
||||
memcpy(response.source_hw_addr.mac, elap_get_mac()->mac, sizeof(response.source_hw_addr.mac));
|
||||
|
||||
memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac));
|
||||
memcpy(response.dest_hw_addr.mac, &dest_hw_addr->mac, sizeof(response.dest_hw_addr.mac));
|
||||
|
||||
if (dest_hw_addr == &HW_ZERO)
|
||||
elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
|
||||
else
|
||||
elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
|
||||
}
|
||||
if (dest_hw_addr == &HW_ZERO)
|
||||
elap_send(&HW_APPLETALK_BROADCAST, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
|
||||
else
|
||||
elap_send(&response.dest_hw_addr, &SNAP_AARP, sizeof(struct aarp_header_t), (byte*)&response);
|
||||
}
|
||||
}
|
||||
|
||||
void aarp_probe(const struct at_addr_t* addr)
|
||||
{
|
||||
if (addr)
|
||||
{
|
||||
aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO);
|
||||
}
|
||||
void aarp_probe(const struct at_addr_t* addr) {
|
||||
if (addr)
|
||||
{
|
||||
aarp_send_packet(AARP_FUNCTION_PROBE, addr, addr, &HW_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
static void aarp_request(const struct at_addr_t* addr)
|
||||
{
|
||||
if (addr)
|
||||
{
|
||||
aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO);
|
||||
}
|
||||
static void aarp_request(const struct at_addr_t* addr) {
|
||||
if (addr)
|
||||
{
|
||||
aarp_send_packet(AARP_FUNCTION_REQUEST, atbridge_get_addr(), addr, &HW_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware)
|
||||
{
|
||||
if (hardware)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0)
|
||||
return entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
static struct amt_entry_t* amt_lookup_entry_hardware(const struct ether_addr_t* hardware) {
|
||||
if (hardware)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->hardware, hardware, sizeof(entry->hardware)) == 0)
|
||||
return entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol)
|
||||
{
|
||||
if (protocol)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
|
||||
return entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
static struct amt_entry_t* amt_lookup_entry_protocol(const struct at_addr_t* protocol) {
|
||||
if (protocol)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
|
||||
return entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amt_delete_entry_protocol(const struct at_addr_t* protocol)
|
||||
{
|
||||
if (protocol)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
struct amt_entry_t* previous = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
|
||||
{
|
||||
previous->next = entry->next;
|
||||
free(entry);
|
||||
break;
|
||||
}
|
||||
previous = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
static void amt_delete_entry_protocol(const struct at_addr_t* protocol) {
|
||||
if (protocol)
|
||||
{
|
||||
struct amt_entry_t* entry = amt;
|
||||
struct amt_entry_t* previous = amt;
|
||||
while (entry)
|
||||
{
|
||||
if (memcmp(&entry->protocol, protocol, sizeof(entry->protocol)) == 0)
|
||||
{
|
||||
previous->next = entry->next;
|
||||
free(entry);
|
||||
break;
|
||||
}
|
||||
previous = entry;
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware)
|
||||
{
|
||||
// Does an entry matching one of the protocol or hardware addresses exist? If so, update it.
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
{
|
||||
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
|
||||
return;
|
||||
}
|
||||
static void amt_add(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) {
|
||||
// Does an entry matching one of the protocol or hardware addresses exist? If so, update it.
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
{
|
||||
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
|
||||
return;
|
||||
}
|
||||
|
||||
entry = amt_lookup_entry_hardware(hardware);
|
||||
if (entry)
|
||||
{
|
||||
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
|
||||
return;
|
||||
}
|
||||
entry = amt_lookup_entry_hardware(hardware);
|
||||
if (entry)
|
||||
{
|
||||
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, add a new entry.
|
||||
entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t));
|
||||
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
|
||||
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
|
||||
entry->next = amt;
|
||||
amt = entry;
|
||||
// Otherwise, add a new entry.
|
||||
entry = (struct amt_entry_t*)malloc(sizeof(struct amt_entry_t));
|
||||
memcpy(&entry->hardware, hardware, sizeof(entry->hardware));
|
||||
memcpy(&entry->protocol, protocol, sizeof(entry->protocol));
|
||||
entry->next = amt;
|
||||
amt = entry;
|
||||
}
|
||||
|
||||
const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol)
|
||||
{
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
{
|
||||
aarp_retry_reset();
|
||||
return (const struct ether_addr_t*)&entry->hardware;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period.
|
||||
if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) &&
|
||||
(retry_count > 0))
|
||||
{
|
||||
aarp_request(protocol);
|
||||
|
||||
retry_count--;
|
||||
retry_timer = clock();
|
||||
|
||||
//atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer);
|
||||
}
|
||||
const struct ether_addr_t* aarp_request_hardware(const struct at_addr_t* protocol) {
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
{
|
||||
aarp_retry_reset();
|
||||
return (const struct ether_addr_t*)&entry->hardware;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The AMT doesn't have this protocol address so issue a request at no more than the AARP_PROBE_INTERVAL period.
|
||||
if (((clock() - retry_timer) >= (AARP_REQUEST_INTERVAL * CLOCKS_PER_SEC / 1000)) &&
|
||||
(retry_count > 0))
|
||||
{
|
||||
aarp_request(protocol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
retry_count--;
|
||||
retry_timer = clock();
|
||||
|
||||
//atbridge_printf("AARP request count %d timer %d.\n", retry_count, retry_timer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware)
|
||||
{
|
||||
struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware);
|
||||
if (entry)
|
||||
return (const struct at_addr_t*)&entry->protocol;
|
||||
else
|
||||
return 0;
|
||||
const struct at_addr_t* aarp_request_protocol(const struct ether_addr_t* hardware) {
|
||||
struct amt_entry_t* entry = amt_lookup_entry_hardware(hardware);
|
||||
if (entry)
|
||||
return (const struct at_addr_t*)&entry->protocol;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool aarp_retry()
|
||||
{
|
||||
return retry_count > 0;
|
||||
bool aarp_retry() {
|
||||
return retry_count > 0;
|
||||
}
|
||||
|
||||
void aarp_retry_reset()
|
||||
{
|
||||
retry_count = AARP_REQUEST_COUNT;
|
||||
retry_timer = clock();
|
||||
void aarp_retry_reset() {
|
||||
retry_count = AARP_REQUEST_COUNT;
|
||||
retry_timer = clock();
|
||||
}
|
||||
|
||||
void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware)
|
||||
{
|
||||
amt_add(protocol, hardware);
|
||||
void aarp_glean(const struct at_addr_t* protocol, const struct ether_addr_t* hardware) {
|
||||
amt_add(protocol, hardware);
|
||||
}
|
||||
|
||||
bool aarp_address_used(const struct at_addr_t* protocol)
|
||||
{
|
||||
// reference 2-8
|
||||
if (protocol)
|
||||
{
|
||||
// Check for reserved node numbers, per reference 3-9.
|
||||
if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff)
|
||||
return true;
|
||||
bool aarp_address_used(const struct at_addr_t* protocol) {
|
||||
// reference 2-8
|
||||
if (protocol)
|
||||
{
|
||||
// Check for reserved node numbers, per reference 3-9.
|
||||
if (protocol->node == 0x00 || protocol->node == 0xfe || protocol->node == 0xff)
|
||||
return true;
|
||||
|
||||
// Look for the address in the AMT. If it's there, another node is using this address.
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
return true;
|
||||
// Look for the address in the AMT. If it's there, another node is using this address.
|
||||
struct amt_entry_t* entry = amt_lookup_entry_protocol(protocol);
|
||||
if (entry)
|
||||
return true;
|
||||
|
||||
// Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet.
|
||||
// Return true to advise the caller that the address is not known to be in use. The caller should
|
||||
// retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT),
|
||||
// per the AARP protocol definition, before choosing this address.
|
||||
aarp_probe(protocol);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
// Try a probe. If this address is in use, another node will reply with an AARP RESPONSE packet.
|
||||
// Return true to advise the caller that the address is not known to be in use. The caller should
|
||||
// retry aarp_try_address() every 200 ms (AARP_PROBE_INTERVAL) and 10 times (AARP_PROBE_COUNT),
|
||||
// per the AARP protocol definition, before choosing this address.
|
||||
aarp_probe(protocol);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
void aarp_handle_packet(const struct aarp_header_t* aarp)
|
||||
{
|
||||
if (aarp &&
|
||||
aarp->hardware_type == AARP_HARDWARE_ETHER &&
|
||||
aarp->protocol_type == AARP_PROTOCOL_TYPE &&
|
||||
aarp->hw_addr_len == AARP_HW_ADDR_LEN &&
|
||||
aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN)
|
||||
{
|
||||
switch (aarp->function)
|
||||
{
|
||||
case AARP_FUNCTION_REQUEST:
|
||||
if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) ||
|
||||
(aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) &&
|
||||
(aarp->dest_proto_addr.addr.node == atbridge_get_node()))
|
||||
{
|
||||
// Generate a response for the AARP request.
|
||||
aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr);
|
||||
}
|
||||
break;
|
||||
case AARP_FUNCTION_RESPONSE:
|
||||
aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr);
|
||||
aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr);
|
||||
break;
|
||||
case AARP_FUNCTION_PROBE:
|
||||
// AMT entry aging, method 2, reference 2-11
|
||||
amt_delete_entry_protocol(&aarp->dest_proto_addr.addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void aarp_handle_packet(const struct aarp_header_t* aarp) {
|
||||
if (aarp &&
|
||||
aarp->hardware_type == AARP_HARDWARE_ETHER &&
|
||||
aarp->protocol_type == AARP_PROTOCOL_TYPE &&
|
||||
aarp->hw_addr_len == AARP_HW_ADDR_LEN &&
|
||||
aarp->protocol_addr_len == AARP_PROTOCOL_ADDR_LEN)
|
||||
{
|
||||
switch (aarp->function)
|
||||
{
|
||||
case AARP_FUNCTION_REQUEST:
|
||||
if (((aarp->dest_proto_addr.addr.network == atbridge_get_net()) ||
|
||||
(aarp->dest_proto_addr.addr.network == 0x00 /* reference 4-6 */)) &&
|
||||
(aarp->dest_proto_addr.addr.node == atbridge_get_node()))
|
||||
{
|
||||
// Generate a response for the AARP request.
|
||||
aarp_send_packet(AARP_FUNCTION_RESPONSE, &aarp->dest_proto_addr.addr, &aarp->source_proto_addr.addr, &aarp->source_hw_addr);
|
||||
}
|
||||
break;
|
||||
case AARP_FUNCTION_RESPONSE:
|
||||
aarp_glean(&aarp->source_proto_addr.addr, &aarp->source_hw_addr);
|
||||
aarp_glean(&aarp->dest_proto_addr.addr, &aarp->dest_hw_addr);
|
||||
break;
|
||||
case AARP_FUNCTION_PROBE:
|
||||
// AMT entry aging, method 2, reference 2-11
|
||||
amt_delete_entry_protocol(&aarp->dest_proto_addr.addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
struct at_addr_t;
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
typedef byte at_node_t;
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** This module is the "heart" of the bridge and provides the connection between the ELAP and LLAP ports. **/
|
||||
|
||||
@ -51,378 +37,357 @@ static const at_node_t NODE_STARTUP_HIGH = 0xFE;
|
||||
|
||||
static void send_rtmp_request();
|
||||
|
||||
bool atbridge_init()
|
||||
{
|
||||
// If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT.
|
||||
if (local_address.network == 0)
|
||||
{
|
||||
// Obtain a provisional node address and startup range network.
|
||||
//
|
||||
// This isn't correct for an extended network (like ELAP) but works adequately on small networks.
|
||||
// The bridge should follow the complicated process on page 4-9 to obtain the network and node number.
|
||||
srand((unsigned int)time(0));
|
||||
local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW);
|
||||
local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01);
|
||||
bool atbridge_init() {
|
||||
// If the GS reboots, we may try to reinitialize the bridge. If this is the case, keep the old address and AMT.
|
||||
if (local_address.network == 0)
|
||||
{
|
||||
// Obtain a provisional node address and startup range network.
|
||||
//
|
||||
// This isn't correct for an extended network (like ELAP) but works adequately on small networks.
|
||||
// The bridge should follow the complicated process on page 4-9 to obtain the network and node number.
|
||||
srand((unsigned int)time(0));
|
||||
local_address.network = (at_network_t)((double)rand()/RAND_MAX * (NET_STARTUP_HIGH - NET_STARTUP_LOW) + NET_STARTUP_LOW);
|
||||
local_address.node = (at_node_t)((double)rand()/RAND_MAX + (NODE_STARTUP_HIGH - NODE_STARTUP_LOW) + 0x01);
|
||||
|
||||
aarp_init();
|
||||
llap_init();
|
||||
if (!elap_init())
|
||||
{
|
||||
atbridge_shutdown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
aarp_init();
|
||||
llap_init();
|
||||
if (!elap_init())
|
||||
{
|
||||
atbridge_shutdown();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void atbridge_shutdown()
|
||||
{
|
||||
llap_shutdown();
|
||||
elap_shutdown();
|
||||
aarp_shutdown();
|
||||
void atbridge_shutdown() {
|
||||
llap_shutdown();
|
||||
elap_shutdown();
|
||||
aarp_shutdown();
|
||||
}
|
||||
|
||||
void atbridge_set_diagnostics(bool enabled)
|
||||
{
|
||||
diagnostics = enabled;
|
||||
void atbridge_set_diagnostics(bool enabled) {
|
||||
diagnostics = enabled;
|
||||
}
|
||||
|
||||
bool atbridge_get_diagnostics()
|
||||
{
|
||||
return diagnostics;
|
||||
bool atbridge_get_diagnostics() {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
void atbridge_printf(const char *fmt, ...)
|
||||
{
|
||||
if (atbridge_get_diagnostics())
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
void atbridge_printf(const char *fmt, ...) {
|
||||
if (atbridge_get_diagnostics())
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
const struct at_addr_t* atbridge_get_addr()
|
||||
{
|
||||
return &local_address;
|
||||
const struct at_addr_t* atbridge_get_addr() {
|
||||
return &local_address;
|
||||
}
|
||||
|
||||
const at_network_t atbridge_get_net()
|
||||
{
|
||||
return local_address.network;
|
||||
const at_network_t atbridge_get_net() {
|
||||
return local_address.network;
|
||||
}
|
||||
|
||||
const at_node_t atbridge_get_node()
|
||||
{
|
||||
return local_address.node;
|
||||
const at_node_t atbridge_get_node() {
|
||||
return local_address.node;
|
||||
}
|
||||
|
||||
void atbridge_set_net(at_network_t net)
|
||||
{
|
||||
local_address.network = net;
|
||||
void atbridge_set_net(at_network_t net) {
|
||||
local_address.network = net;
|
||||
}
|
||||
|
||||
void atbridge_set_node(at_node_t node)
|
||||
{
|
||||
local_address.node = node;
|
||||
void atbridge_set_node(at_node_t node) {
|
||||
local_address.node = node;
|
||||
}
|
||||
|
||||
bool atbridge_address_used(const struct at_addr_t* addr)
|
||||
{
|
||||
if (!sent_rtmp_request)
|
||||
send_rtmp_request();
|
||||
return aarp_address_used(addr);
|
||||
bool atbridge_address_used(const struct at_addr_t* addr) {
|
||||
if (!sent_rtmp_request)
|
||||
send_rtmp_request();
|
||||
return aarp_address_used(addr);
|
||||
}
|
||||
|
||||
/* Calculate a DDP checksum, per Apple's documented algorithm in 4-17 of "Inside AppleTalk". */
|
||||
static word16 get_checksum(size_t size, byte data[])
|
||||
{
|
||||
word16 cksum = 0;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
{
|
||||
cksum += data[i];
|
||||
cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left
|
||||
}
|
||||
if (cksum == 0)
|
||||
cksum = 0xffff;
|
||||
return cksum;
|
||||
static word16 get_checksum(size_t size, byte data[]) {
|
||||
word16 cksum = 0;
|
||||
for (unsigned int i = 0; i < size; i++)
|
||||
{
|
||||
cksum += data[i];
|
||||
cksum = (cksum << 1) | ((cksum & 0x8000) >> 15); // roll left
|
||||
}
|
||||
if (cksum == 0)
|
||||
cksum = 0xffff;
|
||||
return cksum;
|
||||
}
|
||||
|
||||
static void calculate_checksum(struct packet_t* packet)
|
||||
{
|
||||
if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG))
|
||||
{
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)(packet->data);
|
||||
header->checksum = htons(get_checksum(
|
||||
packet->size - offsetof(struct DDP_LONG, dest_net),
|
||||
(byte*)&header->dest_net));
|
||||
}
|
||||
static void calculate_checksum(struct packet_t* packet) {
|
||||
if (packet && packet->data && (packet->size >= sizeof(struct DDP_LONG)) && (packet->type == LAP_DDP_LONG))
|
||||
{
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)(packet->data);
|
||||
header->checksum = htons(get_checksum(
|
||||
packet->size - offsetof(struct DDP_LONG, dest_net),
|
||||
(byte*)&header->dest_net));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a long-form DDP header to a short-form header. This function only converts the headers. */
|
||||
static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out)
|
||||
{
|
||||
word16 size;
|
||||
static word16 convert_ddp_header_to_short(const struct DDP_LONG* in, struct DDP_SHORT* out) {
|
||||
word16 size;
|
||||
|
||||
if (!in || !out)
|
||||
return 0;
|
||||
|
||||
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
|
||||
if (!in || !out)
|
||||
return 0;
|
||||
|
||||
out->length[0] = (size >> 8) & 0x03;
|
||||
out->length[1] = size & 0xff;
|
||||
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) - (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
|
||||
|
||||
out->dest_socket = in->dest_socket;
|
||||
out->source_socket = in->source_socket;
|
||||
|
||||
out->type = in->type;
|
||||
out->length[0] = (size >> 8) & 0x03;
|
||||
out->length[1] = size & 0xff;
|
||||
|
||||
return size;
|
||||
out->dest_socket = in->dest_socket;
|
||||
out->source_socket = in->source_socket;
|
||||
|
||||
out->type = in->type;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Convert a short-form DDP header to a long-form header. ELAP requires long-form, but LLAP often uses short-form. */
|
||||
/* This function only converts the headers. */
|
||||
static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out)
|
||||
{
|
||||
word16 size;
|
||||
static word16 convert_ddp_header_to_long(const struct at_addr_t dest, const struct at_addr_t source, const struct DDP_SHORT* in, struct DDP_LONG* out) {
|
||||
word16 size;
|
||||
|
||||
if (!in || !out)
|
||||
return 0;
|
||||
|
||||
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
|
||||
out->length[0] = (size >> 8) & 0x03;
|
||||
out->length[1] = size & 0xff;
|
||||
|
||||
out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */
|
||||
|
||||
if (dest.network)
|
||||
out->dest_net = dest.network;
|
||||
else
|
||||
out->dest_net = atbridge_get_net();
|
||||
out->dest_net = (at_network_t)htons(out->dest_net);
|
||||
if (!in || !out)
|
||||
return 0;
|
||||
|
||||
if (source.network)
|
||||
out->source_net = source.network;
|
||||
else
|
||||
out->source_net = atbridge_get_net();
|
||||
out->source_net = (at_network_t)htons(out->source_net);
|
||||
size = ((in->length[0] & 0x3) << 8) + (in->length[1]) + (sizeof(struct DDP_LONG) - sizeof(struct DDP_SHORT));
|
||||
out->length[0] = (size >> 8) & 0x03;
|
||||
out->length[1] = size & 0xff;
|
||||
|
||||
out->dest_node = dest.node;
|
||||
out->source_node = source.node;
|
||||
out->checksum = 0x0000; /* 0x0000 == no checksum calculated, reference 4-17 */
|
||||
|
||||
out->dest_socket = in->dest_socket;
|
||||
out->source_socket = in->source_socket;
|
||||
if (dest.network)
|
||||
out->dest_net = dest.network;
|
||||
else
|
||||
out->dest_net = atbridge_get_net();
|
||||
out->dest_net = (at_network_t)htons(out->dest_net);
|
||||
|
||||
out->type = in->type;
|
||||
if (source.network)
|
||||
out->source_net = source.network;
|
||||
else
|
||||
out->source_net = atbridge_get_net();
|
||||
out->source_net = (at_network_t)htons(out->source_net);
|
||||
|
||||
return size;
|
||||
out->dest_node = dest.node;
|
||||
out->source_node = source.node;
|
||||
|
||||
out->dest_socket = in->dest_socket;
|
||||
out->source_socket = in->source_socket;
|
||||
|
||||
out->type = in->type;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Convert a short-form DDP packet to a long-form packet. */
|
||||
/* This function converts an entire packet, not just the header. */
|
||||
static void convert_ddp_packet_to_long(struct packet_t* packet)
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT)))
|
||||
{
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
|
||||
static void convert_ddp_packet_to_long(struct packet_t* packet) {
|
||||
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data && (packet->size >= sizeof(struct DDP_SHORT)))
|
||||
{
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
|
||||
|
||||
const size_t payload_size = packet->size - sizeof(struct DDP_SHORT);
|
||||
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG));
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
|
||||
const size_t payload_size = packet->size - sizeof(struct DDP_SHORT);
|
||||
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_LONG));
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
|
||||
|
||||
const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
|
||||
packet->dest.network = ntohs(header_long->dest_net);
|
||||
packet->source.network = ntohs(header_long->source_net);
|
||||
const word16 size = convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
|
||||
packet->dest.network = ntohs(header_long->dest_net);
|
||||
packet->source.network = ntohs(header_long->source_net);
|
||||
|
||||
memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size);
|
||||
memcpy(data + sizeof(struct DDP_LONG), packet->data + sizeof(struct DDP_SHORT), payload_size);
|
||||
|
||||
packet->type = LAP_DDP_LONG;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_LONG;
|
||||
packet->size = size;
|
||||
|
||||
// Replace the original short-form packet data.
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
// Replace the original short-form packet data.
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
|
||||
calculate_checksum(packet);
|
||||
}
|
||||
calculate_checksum(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a long-form DDP packet to short-form. */
|
||||
static void convert_ddp_packet_to_short(struct packet_t* packet)
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
static void convert_ddp_packet_to_short(struct packet_t* packet) {
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
|
||||
const size_t payload_size = packet->size - sizeof(struct DDP_LONG);
|
||||
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT));
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
|
||||
const size_t payload_size = packet->size - sizeof(struct DDP_LONG);
|
||||
byte* data = (byte*)malloc(payload_size + sizeof(struct DDP_SHORT));
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
|
||||
|
||||
const word16 size = convert_ddp_header_to_short(header_long, header_short);
|
||||
const word16 size = convert_ddp_header_to_short(header_long, header_short);
|
||||
|
||||
memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size);
|
||||
memcpy(data + sizeof(struct DDP_SHORT), packet->data + sizeof(struct DDP_LONG), payload_size);
|
||||
|
||||
packet->type = LAP_DDP_SHORT;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_SHORT;
|
||||
packet->size = size;
|
||||
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
}
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/*static void convert_rtmp_to_extended(struct packet_t* packet)
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data)
|
||||
{
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
|
||||
if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_SHORT) && packet->data)
|
||||
{
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)packet->data;
|
||||
if (header_short->type != DDP_TYPE_RTMP || header_short->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
|
||||
struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT));
|
||||
struct rtmp_nonextended_data_t* in = (struct rtmp_nonextended_data_t*)(packet->data + sizeof(struct DDP_SHORT));
|
||||
|
||||
// Construct a new long-form DDP packet header.
|
||||
size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t);
|
||||
byte* data = (byte*)malloc(size);
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
|
||||
convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
|
||||
|
||||
struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG));
|
||||
out->net = in->net;
|
||||
out->id_length = in->id_length;
|
||||
out->node = in->node;
|
||||
// Construct a new long-form DDP packet header.
|
||||
size_t size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_extended_data_t);
|
||||
byte* data = (byte*)malloc(size);
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)data;
|
||||
convert_ddp_header_to_long(packet->dest, packet->source, header_short, header_long);
|
||||
|
||||
// Copy the routing tuples.
|
||||
struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t));
|
||||
struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size);
|
||||
while ((byte*)in_tuple < (packet->data + packet->size))
|
||||
{
|
||||
size += sizeof(struct rtmp_extended_tuple_t);
|
||||
realloc(data, size);
|
||||
out_tuple->range_start = in_tuple->net;
|
||||
out_tuple->distance = in_tuple->distance | 0x80;
|
||||
out_tuple->range_end = in_tuple->net;
|
||||
out_tuple->delimiter = RTMP_TUPLE_DELIMITER;
|
||||
in_tuple++;
|
||||
}
|
||||
struct rtmp_extended_data_t* out = (struct rtmp_extended_data_t*)(data + sizeof(struct DDP_LONG));
|
||||
out->net = in->net;
|
||||
out->id_length = in->id_length;
|
||||
out->node = in->node;
|
||||
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_LONG;
|
||||
}
|
||||
}*/
|
||||
// Copy the routing tuples.
|
||||
struct rtmp_nonextended_tuple_t* in_tuple = (struct rtmp_nonextended_tuple_t*)(packet->data + sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_data_t));
|
||||
struct rtmp_extended_tuple_t* out_tuple = (struct rtmp_extended_tuple_t*)(data + size);
|
||||
while ((byte*)in_tuple < (packet->data + packet->size))
|
||||
{
|
||||
size += sizeof(struct rtmp_extended_tuple_t);
|
||||
realloc(data, size);
|
||||
out_tuple->range_start = in_tuple->net;
|
||||
out_tuple->distance = in_tuple->distance | 0x80;
|
||||
out_tuple->range_end = in_tuple->net;
|
||||
out_tuple->delimiter = RTMP_TUPLE_DELIMITER;
|
||||
in_tuple++;
|
||||
}
|
||||
|
||||
static void convert_rtmp_to_nonextended(struct packet_t* packet)
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_LONG;
|
||||
}
|
||||
}*/
|
||||
|
||||
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
static void convert_rtmp_to_nonextended(struct packet_t* packet) {
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
|
||||
size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t);
|
||||
byte* data = (byte*)malloc(size);
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
|
||||
convert_ddp_header_to_short(header_long, header_short);
|
||||
header_short->length[0] = (size >> 8) & 0x03;
|
||||
header_short->length[1] = size & 0xff;
|
||||
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
|
||||
struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT));
|
||||
out->net = in->net;
|
||||
out->id_length = in->id_length;
|
||||
out->node = in->node;
|
||||
size_t size = sizeof(struct DDP_SHORT) + sizeof(struct rtmp_nonextended_response_t);
|
||||
byte* data = (byte*)malloc(size);
|
||||
struct DDP_SHORT* header_short = (struct DDP_SHORT*)data;
|
||||
convert_ddp_header_to_short(header_long, header_short);
|
||||
header_short->length[0] = (size >> 8) & 0x03;
|
||||
header_short->length[1] = size & 0xff;
|
||||
|
||||
/*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t));
|
||||
rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size);
|
||||
while ((byte*)in_tuple < (packet->data + packet->size))
|
||||
{
|
||||
size += sizeof(rtmp_nonextended_tuple_t);
|
||||
realloc(data, size);
|
||||
out_tuple->net = in_tuple->range_start;
|
||||
out_tuple->distance = in_tuple->distance & 0x7f;
|
||||
in_tuple++;
|
||||
}*/
|
||||
struct rtmp_nonextended_response_t* out = (struct rtmp_nonextended_response_t*)(data + sizeof(struct DDP_SHORT));
|
||||
out->net = in->net;
|
||||
out->id_length = in->id_length;
|
||||
out->node = in->node;
|
||||
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_SHORT;
|
||||
}
|
||||
/*rtmp_extended_tuple_t* in_tuple = (rtmp_extended_tuple_t*)(packet->data + sizeof(DDP_LONG) + sizeof(rtmp_extended_data_t));
|
||||
rtmp_nonextended_tuple_t* out_tuple = (rtmp_nonextended_tuple_t*)(data + size);
|
||||
while ((byte*)in_tuple < (packet->data + packet->size))
|
||||
{
|
||||
size += sizeof(rtmp_nonextended_tuple_t);
|
||||
realloc(data, size);
|
||||
out_tuple->net = in_tuple->range_start;
|
||||
out_tuple->distance = in_tuple->distance & 0x7f;
|
||||
in_tuple++;
|
||||
}*/
|
||||
|
||||
free(packet->data);
|
||||
packet->data = data;
|
||||
packet->size = size;
|
||||
packet->type = LAP_DDP_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Learn our network number from RTMP packets. */
|
||||
/* "Inside AppleTalk", section 4-8, describes this approach for non-extended networks.
|
||||
Technically, we probably should be doing the more complicated extended network approach (also on 4-8),
|
||||
but the easy approach using RTMP seems adequate for now. */
|
||||
static void glean_net_from_rtmp(struct packet_t* packet)
|
||||
{
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
static void glean_net_from_rtmp(struct packet_t* packet) {
|
||||
if (packet && (packet->type == LAP_DDP_LONG) && packet->data)
|
||||
{
|
||||
struct DDP_LONG* header_long = (struct DDP_LONG*)packet->data;
|
||||
if (header_long->type != DDP_TYPE_RTMP || header_long->dest_socket != DDP_SOCKET_RTMP)
|
||||
return;
|
||||
|
||||
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
struct rtmp_extended_data_t* in = (struct rtmp_extended_data_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
|
||||
atbridge_set_net(ntohs(in->net));
|
||||
}
|
||||
atbridge_set_net(ntohs(in->net));
|
||||
}
|
||||
}
|
||||
|
||||
static void send_rtmp_request()
|
||||
{
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
|
||||
packet->type = LAP_DDP_LONG;
|
||||
packet->dest.network = atbridge_get_net();
|
||||
packet->dest.node = 255;
|
||||
packet->source.network = atbridge_get_net();
|
||||
packet->source.node = atbridge_get_node();
|
||||
packet->next = 0;
|
||||
packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t);
|
||||
packet->data = (byte*)malloc(packet->size);
|
||||
static void send_rtmp_request() {
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)packet->data;
|
||||
header->type = DDP_TYPE_RTMP_REQUEST;
|
||||
header->source_net = htons(packet->source.network);
|
||||
header->source_node = packet->source.node;
|
||||
header->source_socket = DDP_SOCKET_RTMP;
|
||||
header->dest_net = htons(packet->dest.network);
|
||||
header->dest_node = packet->dest.node;
|
||||
header->dest_socket = DDP_SOCKET_RTMP;
|
||||
header->length[0] = (packet->size >> 8) & 0x03;
|
||||
header->length[1] = packet->size & 0xff;
|
||||
packet->type = LAP_DDP_LONG;
|
||||
packet->dest.network = atbridge_get_net();
|
||||
packet->dest.node = 255;
|
||||
packet->source.network = atbridge_get_net();
|
||||
packet->source.node = atbridge_get_node();
|
||||
packet->next = 0;
|
||||
packet->size = sizeof(struct DDP_LONG) + sizeof(struct rtmp_request_t);
|
||||
packet->data = (byte*)malloc(packet->size);
|
||||
|
||||
struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
request->function = RTMP_FUNCTION_REQUEST;
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)packet->data;
|
||||
header->type = DDP_TYPE_RTMP_REQUEST;
|
||||
header->source_net = htons(packet->source.network);
|
||||
header->source_node = packet->source.node;
|
||||
header->source_socket = DDP_SOCKET_RTMP;
|
||||
header->dest_net = htons(packet->dest.network);
|
||||
header->dest_node = packet->dest.node;
|
||||
header->dest_socket = DDP_SOCKET_RTMP;
|
||||
header->length[0] = (packet->size >> 8) & 0x03;
|
||||
header->length[1] = packet->size & 0xff;
|
||||
|
||||
calculate_checksum(packet);
|
||||
|
||||
elap_enqueue_out(packet);
|
||||
sent_rtmp_request = true;
|
||||
struct rtmp_request_t* request = (struct rtmp_request_t*)(packet->data + sizeof(struct DDP_LONG));
|
||||
request->function = RTMP_FUNCTION_REQUEST;
|
||||
|
||||
calculate_checksum(packet);
|
||||
|
||||
elap_enqueue_out(packet);
|
||||
sent_rtmp_request = true;
|
||||
}
|
||||
|
||||
void atbridge_process()
|
||||
{
|
||||
elap_process();
|
||||
//llap_process();
|
||||
|
||||
struct packet_t* packet = elap_dequeue_in();
|
||||
if (packet)
|
||||
{
|
||||
glean_net_from_rtmp(packet);
|
||||
convert_rtmp_to_nonextended(packet);
|
||||
// The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process).
|
||||
convert_ddp_packet_to_short(packet);
|
||||
llap_enqueue_out(packet);
|
||||
}
|
||||
packet = llap_dequeue_in();
|
||||
if (packet)
|
||||
{
|
||||
// ELAP does not support short-form DDP, so convert such packets to long-form.
|
||||
convert_ddp_packet_to_long(packet);
|
||||
elap_enqueue_out(packet);
|
||||
}
|
||||
void atbridge_process() {
|
||||
elap_process();
|
||||
//llap_process();
|
||||
|
||||
struct packet_t* packet = elap_dequeue_in();
|
||||
if (packet)
|
||||
{
|
||||
glean_net_from_rtmp(packet);
|
||||
convert_rtmp_to_nonextended(packet);
|
||||
// The GS should understand long-form DDP, but converting to short-form ought to slightly improve performance (fewer bytes for the GS to process).
|
||||
convert_ddp_packet_to_short(packet);
|
||||
llap_enqueue_out(packet);
|
||||
}
|
||||
packet = llap_dequeue_in();
|
||||
if (packet)
|
||||
{
|
||||
// ELAP does not support short-form DDP, so convert such packets to long-form.
|
||||
convert_ddp_packet_to_long(packet);
|
||||
elap_enqueue_out(packet);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -46,4 +32,3 @@ const at_node_t atbridge_get_node();
|
||||
void atbridge_set_net(at_network_t net);
|
||||
void atbridge_set_node(at_node_t node);
|
||||
bool atbridge_address_used(const struct at_addr_t* addr);
|
||||
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** This module implements the ELAP port of the bridge. **/
|
||||
|
||||
@ -51,350 +37,338 @@ static struct packet_port_t elap_port;
|
||||
static struct ether_addr_t HW_LOCAL;
|
||||
|
||||
/*static void dump_device_list(pcap_if_t* devices)
|
||||
{
|
||||
int i = 0;
|
||||
for(pcap_if_t* device = devices; device; device = device->next)
|
||||
{
|
||||
printf("%d. %s", ++i, device->name);
|
||||
if (device->description)
|
||||
printf(" (%s)\n", device->description);
|
||||
else
|
||||
printf(" (No description available)\n");
|
||||
}
|
||||
}*/
|
||||
{
|
||||
int i = 0;
|
||||
for(pcap_if_t* device = devices; device; device = device->next)
|
||||
{
|
||||
printf("%d. %s", ++i, device->name);
|
||||
if (device->description)
|
||||
printf(" (%s)\n", device->description);
|
||||
else
|
||||
printf(" (No description available)\n");
|
||||
}
|
||||
}*/
|
||||
|
||||
static void elap_clone_host_mac(pcap_if_t* device)
|
||||
{
|
||||
if (!device)
|
||||
return;
|
||||
static void elap_clone_host_mac(pcap_if_t* device) {
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
#ifdef WIN32
|
||||
////
|
||||
// Extract the device GUID, which Windows uses to identify the device.
|
||||
char* name = device->name;
|
||||
while (name && *name != '{')
|
||||
name++;
|
||||
size_t guidLen = strlen(name);
|
||||
////
|
||||
// Extract the device GUID, which Windows uses to identify the device.
|
||||
char* name = device->name;
|
||||
while (name && *name != '{')
|
||||
name++;
|
||||
size_t guidLen = strlen(name);
|
||||
|
||||
////
|
||||
// Find and copy the device MAC address.
|
||||
ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15;
|
||||
IP_ADAPTER_ADDRESSES* addresses = malloc(size);
|
||||
|
||||
ULONG result = GetAdaptersAddresses(AF_UNSPEC,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
|
||||
|
||||
if (result == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
// The addresses buffer is too small. Allocate a bigger buffer.
|
||||
free(addresses);
|
||||
addresses = malloc(size);
|
||||
result = GetAdaptersAddresses(AF_UNSPEC,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
|
||||
}
|
||||
////
|
||||
// Find and copy the device MAC address.
|
||||
ULONG size = sizeof(IP_ADAPTER_ADDRESSES) * 15;
|
||||
IP_ADAPTER_ADDRESSES* addresses = malloc(size);
|
||||
|
||||
if (result == NO_ERROR)
|
||||
{
|
||||
// Search for the desired adapter address.
|
||||
IP_ADAPTER_ADDRESSES* current = addresses;
|
||||
while (current)
|
||||
{
|
||||
if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0)
|
||||
{
|
||||
memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac));
|
||||
break;
|
||||
}
|
||||
current = current->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
halt_printf("ATBridge: Failed to find host MAC address (%d).", result);
|
||||
}
|
||||
ULONG result = GetAdaptersAddresses(AF_UNSPEC,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
|
||||
|
||||
free(addresses);
|
||||
if (result == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
// The addresses buffer is too small. Allocate a bigger buffer.
|
||||
free(addresses);
|
||||
addresses = malloc(size);
|
||||
result = GetAdaptersAddresses(AF_UNSPEC,
|
||||
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, addresses, &size);
|
||||
}
|
||||
|
||||
if (result == NO_ERROR)
|
||||
{
|
||||
// Search for the desired adapter address.
|
||||
IP_ADAPTER_ADDRESSES* current = addresses;
|
||||
while (current)
|
||||
{
|
||||
if (current->PhysicalAddressLength == ETHER_ADDR_LEN && memcmp(current->AdapterName, name, guidLen) == 0)
|
||||
{
|
||||
memcpy(&HW_LOCAL.mac, ¤t->PhysicalAddress, sizeof(HW_LOCAL.mac));
|
||||
break;
|
||||
}
|
||||
current = current->Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
halt_printf("ATBridge: Failed to find host MAC address (%d).", result);
|
||||
}
|
||||
|
||||
free(addresses);
|
||||
#else
|
||||
#ifdef AF_PACKET
|
||||
struct pcap_addr* address;
|
||||
for (address = device->addresses; address != 0; address = address->next)
|
||||
if (address->addr->sa_family == AF_PACKET)
|
||||
{
|
||||
struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr;
|
||||
memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac));
|
||||
}
|
||||
struct pcap_addr* address;
|
||||
for (address = device->addresses; address != 0; address = address->next)
|
||||
if (address->addr->sa_family == AF_PACKET)
|
||||
{
|
||||
struct sockaddr_ll* ll = (struct sockaddr_ll*)address->addr;
|
||||
memcpy(&HW_LOCAL.mac, ll->sll_addr, sizeof(HW_LOCAL.mac));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct ether_addr_t* elap_get_mac()
|
||||
{
|
||||
return &HW_LOCAL;
|
||||
const struct ether_addr_t* elap_get_mac() {
|
||||
return &HW_LOCAL;
|
||||
}
|
||||
|
||||
bool elap_init()
|
||||
{
|
||||
port_init(&elap_port);
|
||||
bool elap_init() {
|
||||
port_init(&elap_port);
|
||||
|
||||
memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL));
|
||||
memcpy(&HW_LOCAL, &HW_LOCAL_DEFAULT, sizeof(HW_LOCAL));
|
||||
|
||||
pcap_if_t* device;
|
||||
pcap_if_t* alldevs;
|
||||
int i = 0;
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
// Load the PCAP library.
|
||||
if (!pcapdelay_load())
|
||||
{
|
||||
halt_printf("ATBridge: PCAP not available.\n");
|
||||
return false;
|
||||
}
|
||||
pcap_if_t* device;
|
||||
pcap_if_t* alldevs;
|
||||
int i = 0;
|
||||
|
||||
// Retrieve the device list.
|
||||
if(pcapdelay_findalldevs(&alldevs, errbuf) == -1)
|
||||
{
|
||||
atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf);
|
||||
return false;
|
||||
}
|
||||
//dump_device_list(alldevs);
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
// Jump to the selected adapter.
|
||||
for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++);
|
||||
if (!device)
|
||||
{
|
||||
halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n");
|
||||
return false;
|
||||
}
|
||||
// Load the PCAP library.
|
||||
if (!pcapdelay_load())
|
||||
{
|
||||
halt_printf("ATBridge: PCAP not available.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback
|
||||
// interface), the interface, even in promiscous mode, filters foreign MAC addresses.
|
||||
elap_clone_host_mac(device);
|
||||
// Retrieve the device list.
|
||||
if(pcapdelay_findalldevs(&alldevs, errbuf) == -1)
|
||||
{
|
||||
atbridge_printf("ATBridge: Error enumerating PCAP devices: %s\n", errbuf);
|
||||
return false;
|
||||
}
|
||||
//dump_device_list(alldevs);
|
||||
|
||||
// Open the adapter,
|
||||
if ((pcap_session = pcapdelay_open_live(device->name, // name of the device
|
||||
65536, // portion of the packet to capture.
|
||||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||||
1, // promiscuous mode (nonzero means promiscuous)
|
||||
1, // read timeout
|
||||
errbuf // error buffer
|
||||
)) == NULL)
|
||||
{
|
||||
halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name);
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return false;
|
||||
}
|
||||
// Jump to the selected adapter.
|
||||
for (device = alldevs, i = 0; i < g_ethernet_interface; device = device->next, i++);
|
||||
if (!device)
|
||||
{
|
||||
halt_printf("ATBridge: PCAP device not found. Check interface number in settings.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// The device must support Ethernet because the bridge "speaks" EtherTalk.
|
||||
if (pcapdelay_datalink(pcap_session) == DLT_EN10MB)
|
||||
{
|
||||
pcapdelay_setnonblock(pcap_session, 1, errbuf);
|
||||
// Clone the MAC address of the underlying interface. In certain configurations (e.g. Windows with an MS Loopback
|
||||
// interface), the interface, even in promiscous mode, filters foreign MAC addresses.
|
||||
elap_clone_host_mac(device);
|
||||
|
||||
atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n",
|
||||
device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]);
|
||||
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcapdelay_close(pcap_session);
|
||||
pcap_session = 0;
|
||||
halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description);
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return false;
|
||||
}
|
||||
// Open the adapter,
|
||||
if ((pcap_session = pcapdelay_open_live(device->name, // name of the device
|
||||
65536, // portion of the packet to capture.
|
||||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||||
1, // promiscuous mode (nonzero means promiscuous)
|
||||
1, // read timeout
|
||||
errbuf // error buffer
|
||||
)) == NULL)
|
||||
{
|
||||
halt_printf("ATBridge: Unable to open the adapter. Pcap does not support %s.\n", device->name);
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The device must support Ethernet because the bridge "speaks" EtherTalk.
|
||||
if (pcapdelay_datalink(pcap_session) == DLT_EN10MB)
|
||||
{
|
||||
pcapdelay_setnonblock(pcap_session, 1, errbuf);
|
||||
|
||||
atbridge_printf("ATBridge: AppleTalk bridging using network device '%s' with Ethernet address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X.\n",
|
||||
device->description, HW_LOCAL.mac[0], HW_LOCAL.mac[1], HW_LOCAL.mac[2], HW_LOCAL.mac[3], HW_LOCAL.mac[4], HW_LOCAL.mac[5]);
|
||||
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcapdelay_close(pcap_session);
|
||||
pcap_session = 0;
|
||||
halt_printf("ATBridge: Selected network device %s must support Ethernet.\n", device->description);
|
||||
pcapdelay_freealldevs(alldevs);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void elap_shutdown()
|
||||
{
|
||||
port_shutdown(&elap_port);
|
||||
if (pcap_session)
|
||||
{
|
||||
pcapdelay_close(pcap_session);
|
||||
pcap_session = 0;
|
||||
}
|
||||
pcapdelay_unload();
|
||||
void elap_shutdown() {
|
||||
port_shutdown(&elap_port);
|
||||
if (pcap_session)
|
||||
{
|
||||
pcapdelay_close(pcap_session);
|
||||
pcap_session = 0;
|
||||
}
|
||||
pcapdelay_unload();
|
||||
}
|
||||
|
||||
void elap_enqueue_out(struct packet_t* packet)
|
||||
{
|
||||
enqueue_packet(&elap_port.out, packet);
|
||||
void elap_enqueue_out(struct packet_t* packet) {
|
||||
enqueue_packet(&elap_port.out, packet);
|
||||
}
|
||||
|
||||
struct packet_t* elap_dequeue_in()
|
||||
{
|
||||
return dequeue(&elap_port.in);
|
||||
struct packet_t* elap_dequeue_in() {
|
||||
return dequeue(&elap_port.in);
|
||||
}
|
||||
|
||||
void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[])
|
||||
{
|
||||
if (pcap_session && dest && discriminator)
|
||||
{
|
||||
// Allocate heap space for the frame.
|
||||
const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size;
|
||||
u_char* frame_data;
|
||||
size_t pad = 0;
|
||||
if (frame_size < ETHER_MIN_SIZE)
|
||||
pad = ETHER_MIN_SIZE - frame_size;
|
||||
frame_data = (u_char*)malloc(frame_size + pad);
|
||||
void elap_send(const struct ether_addr_t* dest, const struct snap_discriminator_t* discriminator, size_t size, byte data[]) {
|
||||
if (pcap_session && dest && discriminator)
|
||||
{
|
||||
// Allocate heap space for the frame.
|
||||
const size_t frame_size = sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t) + size;
|
||||
u_char* frame_data;
|
||||
size_t pad = 0;
|
||||
if (frame_size < ETHER_MIN_SIZE)
|
||||
pad = ETHER_MIN_SIZE - frame_size;
|
||||
frame_data = (u_char*)malloc(frame_size + pad);
|
||||
|
||||
// Build the 802.3 header.
|
||||
struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data;
|
||||
memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac));
|
||||
memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac));
|
||||
ether->length = htons(frame_size - sizeof(struct ethernet_header_t));
|
||||
// Build the 802.3 header.
|
||||
struct ethernet_header_t* ether = (struct ethernet_header_t*)frame_data;
|
||||
memcpy(ether->dest.mac, dest, sizeof(ether->dest.mac));
|
||||
memcpy(ether->source.mac, HW_LOCAL.mac, sizeof(ether->source.mac));
|
||||
ether->length = htons(frame_size - sizeof(struct ethernet_header_t));
|
||||
|
||||
// Build the 802.2 header.
|
||||
struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t));
|
||||
snap->dsap = SNAP_DSAP;
|
||||
snap->ssap = SNAP_SSAP;
|
||||
snap->control = SNAP_CONTROL;
|
||||
memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator));
|
||||
// Build the 802.2 header.
|
||||
struct snap_header_t* snap = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t));
|
||||
snap->dsap = SNAP_DSAP;
|
||||
snap->ssap = SNAP_SSAP;
|
||||
snap->control = SNAP_CONTROL;
|
||||
memcpy(&snap->discriminator, discriminator, sizeof(snap->discriminator));
|
||||
|
||||
// Add the data payload.
|
||||
struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
|
||||
memcpy(payload, data, size);
|
||||
// Add the data payload.
|
||||
struct snap_header_t* payload = (struct snap_header_t*)(frame_data + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
|
||||
memcpy(payload, data, size);
|
||||
|
||||
// Add padding to meet minimum Ethernet frame size.
|
||||
if (pad > 0)
|
||||
memset(frame_data + frame_size, 0, pad);
|
||||
// Add padding to meet minimum Ethernet frame size.
|
||||
if (pad > 0)
|
||||
memset(frame_data + frame_size, 0, pad);
|
||||
|
||||
pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad);
|
||||
}
|
||||
pcapdelay_sendpacket(pcap_session, frame_data, frame_size + pad);
|
||||
}
|
||||
}
|
||||
|
||||
static bool elap_send_one_queued()
|
||||
{
|
||||
// Attempt to send one packet out the host network interface.
|
||||
struct packet_t* packet = queue_peek(&elap_port.out);
|
||||
if (packet)
|
||||
{
|
||||
// Find the MAC address.
|
||||
const struct ether_addr_t* dest;
|
||||
if (packet->dest.node == at_broadcast_node)
|
||||
dest = &HW_APPLETALK_BROADCAST;
|
||||
else
|
||||
dest = aarp_request_hardware(&packet->dest);
|
||||
static bool elap_send_one_queued() {
|
||||
// Attempt to send one packet out the host network interface.
|
||||
struct packet_t* packet = queue_peek(&elap_port.out);
|
||||
if (packet)
|
||||
{
|
||||
// Find the MAC address.
|
||||
const struct ether_addr_t* dest;
|
||||
if (packet->dest.node == at_broadcast_node)
|
||||
dest = &HW_APPLETALK_BROADCAST;
|
||||
else
|
||||
dest = aarp_request_hardware(&packet->dest);
|
||||
|
||||
// Send it.
|
||||
if (dest)
|
||||
{
|
||||
elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data);
|
||||
// Send it.
|
||||
if (dest)
|
||||
{
|
||||
elap_send(dest, &SNAP_APPLETALK, packet->size, packet->data);
|
||||
|
||||
dequeue(&elap_port.out);
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet.
|
||||
if (!aarp_retry())
|
||||
{
|
||||
// However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on.
|
||||
atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node);
|
||||
aarp_retry_reset();
|
||||
dequeue(&elap_port.out);
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
dequeue(&elap_port.out);
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// AARP does not have the needed hardware address. Give AARP time to obtain the address and keep the current packet.
|
||||
if (!aarp_retry())
|
||||
{
|
||||
// However, if AARP has reached the retry limit, the packet is undeliverable. Discard the packet and move on.
|
||||
atbridge_printf("ATBridge: AARP failed to find MAC address for network %d node %d. Dropping packet.\n", packet->dest.network, packet->dest.node);
|
||||
aarp_retry_reset();
|
||||
dequeue(&elap_port.out);
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void elap_send_all_queued()
|
||||
{
|
||||
while (elap_send_one_queued());
|
||||
static void elap_send_all_queued() {
|
||||
while (elap_send_one_queued());
|
||||
}
|
||||
|
||||
static bool elap_receive_one()
|
||||
{
|
||||
if (!pcap_session)
|
||||
return false;
|
||||
static bool elap_receive_one() {
|
||||
if (!pcap_session)
|
||||
return false;
|
||||
|
||||
struct pcap_pkthdr header;
|
||||
const u_char* packet = pcapdelay_next(pcap_session, &header);
|
||||
if (packet)
|
||||
{
|
||||
// Receive and process one packet from the host network interface.
|
||||
////
|
||||
struct pcap_pkthdr header;
|
||||
const u_char* packet = pcapdelay_next(pcap_session, &header);
|
||||
if (packet)
|
||||
{
|
||||
// Receive and process one packet from the host network interface.
|
||||
////
|
||||
|
||||
// Check the Ethernet 802.3 header.
|
||||
const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet;
|
||||
if (header.len > sizeof(struct ethernet_header_t) &&
|
||||
ntohs(ether->length) <= ETHER_MAX_SIZE &&
|
||||
ntohs(ether->length) > sizeof(struct snap_header_t) &&
|
||||
(memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */
|
||||
(memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */
|
||||
memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */)
|
||||
)
|
||||
{
|
||||
// Check the 802.2 SNAP header.
|
||||
const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t));
|
||||
if (snap->dsap == SNAP_DSAP &&
|
||||
snap->ssap == SNAP_SSAP &&
|
||||
snap->control == SNAP_CONTROL)
|
||||
{
|
||||
if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0)
|
||||
{
|
||||
// Handle an AppleTalk packet.
|
||||
const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t);
|
||||
const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t);
|
||||
// Check the Ethernet 802.3 header.
|
||||
const struct ethernet_header_t* ether = (struct ethernet_header_t*)packet;
|
||||
if (header.len > sizeof(struct ethernet_header_t) &&
|
||||
ntohs(ether->length) <= ETHER_MAX_SIZE &&
|
||||
ntohs(ether->length) > sizeof(struct snap_header_t) &&
|
||||
(memcmp(ðer->source, &HW_LOCAL, sizeof(ether->source)) != 0) && /* Ignore packets sent from our node. */
|
||||
(memcmp(ðer->dest, &HW_LOCAL, sizeof(ether->dest)) == 0 || /* Accept packets destined for our node ... */
|
||||
memcmp(ðer->dest, &HW_APPLETALK_BROADCAST, sizeof(ether->dest)) == 0 /* ... or for broadcast. */)
|
||||
)
|
||||
{
|
||||
// Check the 802.2 SNAP header.
|
||||
const struct snap_header_t* snap = (struct snap_header_t*)(packet + sizeof(struct ethernet_header_t));
|
||||
if (snap->dsap == SNAP_DSAP &&
|
||||
snap->ssap == SNAP_SSAP &&
|
||||
snap->control == SNAP_CONTROL)
|
||||
{
|
||||
if (memcmp(&snap->discriminator, &SNAP_APPLETALK, sizeof(snap->discriminator)) == 0)
|
||||
{
|
||||
// Handle an AppleTalk packet.
|
||||
const size_t payload_size = ntohs(ether->length) - sizeof(struct snap_header_t);
|
||||
const u_char* payload = packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t);
|
||||
|
||||
byte* copy = (byte*)malloc(payload_size);
|
||||
memcpy(copy, payload, payload_size);
|
||||
byte* copy = (byte*)malloc(payload_size);
|
||||
memcpy(copy, payload, payload_size);
|
||||
|
||||
// ELAP does not support short-form DDP, so this must be a long-form DDP packet.
|
||||
struct at_addr_t source, dest;
|
||||
if (payload_size >= sizeof(struct DDP_LONG))
|
||||
{
|
||||
// Extract the protocol address from the header.
|
||||
//
|
||||
// ELAP really shouldn't be looking at the header for the next level of the protocol stack,
|
||||
// but this is a convenient place to glean addresses for the AMT, a process that needs both
|
||||
// hardware and protocol addresses.
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)copy;
|
||||
dest.network = (at_network_t)ntohs(header->dest_net);
|
||||
source.network = (at_network_t)ntohs(header->source_net);
|
||||
dest.node = header->dest_node;
|
||||
source.node = header->source_node;
|
||||
// ELAP does not support short-form DDP, so this must be a long-form DDP packet.
|
||||
struct at_addr_t source, dest;
|
||||
if (payload_size >= sizeof(struct DDP_LONG))
|
||||
{
|
||||
// Extract the protocol address from the header.
|
||||
//
|
||||
// ELAP really shouldn't be looking at the header for the next level of the protocol stack,
|
||||
// but this is a convenient place to glean addresses for the AMT, a process that needs both
|
||||
// hardware and protocol addresses.
|
||||
struct DDP_LONG* header = (struct DDP_LONG*)copy;
|
||||
dest.network = (at_network_t)ntohs(header->dest_net);
|
||||
source.network = (at_network_t)ntohs(header->source_net);
|
||||
dest.node = header->dest_node;
|
||||
source.node = header->source_node;
|
||||
|
||||
enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy);
|
||||
enqueue(&elap_port.in, dest, source, LAP_DDP_LONG, payload_size, copy);
|
||||
|
||||
aarp_glean(&source, ðer->source);
|
||||
}
|
||||
else
|
||||
atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n");
|
||||
}
|
||||
else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0)
|
||||
{
|
||||
// Handle an AARP packet.
|
||||
struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
|
||||
aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network);
|
||||
aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network);
|
||||
aarp->function = ntohs(aarp->function);
|
||||
aarp->hardware_type = ntohs(aarp->hardware_type);
|
||||
aarp->protocol_type = ntohs(aarp->protocol_type);
|
||||
aarp_handle_packet(aarp);
|
||||
}
|
||||
}
|
||||
}
|
||||
aarp_glean(&source, ðer->source);
|
||||
}
|
||||
else
|
||||
atbridge_printf("ATBridge: Dropping invalid short ELAP frame.\n");
|
||||
}
|
||||
else if (memcmp(&snap->discriminator, &SNAP_AARP, sizeof(snap->discriminator)) == 0)
|
||||
{
|
||||
// Handle an AARP packet.
|
||||
struct aarp_header_t* aarp = (struct aarp_header_t*)(packet + sizeof(struct ethernet_header_t) + sizeof(struct snap_header_t));
|
||||
aarp->dest_proto_addr.addr.network = ntohs(aarp->dest_proto_addr.addr.network);
|
||||
aarp->source_proto_addr.addr.network = ntohs(aarp->source_proto_addr.addr.network);
|
||||
aarp->function = ntohs(aarp->function);
|
||||
aarp->hardware_type = ntohs(aarp->hardware_type);
|
||||
aarp->protocol_type = ntohs(aarp->protocol_type);
|
||||
aarp_handle_packet(aarp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void elap_receive_all()
|
||||
{
|
||||
while (elap_receive_one());
|
||||
static void elap_receive_all() {
|
||||
while (elap_receive_one());
|
||||
}
|
||||
|
||||
void elap_process()
|
||||
{
|
||||
elap_receive_all();
|
||||
elap_send_all_queued();
|
||||
void elap_process() {
|
||||
elap_receive_all();
|
||||
elap_send_all_queued();
|
||||
}
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** ELAP port of the AppleTalk Bridge **/
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/* Ethernet addresses are 6 bytes */
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** This module implements the LLAP port of the bridge. **/
|
||||
|
||||
@ -28,12 +14,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "llap.h"
|
||||
|
||||
typedef enum {
|
||||
LLAP_DDP_SHORT = 0x01,
|
||||
LLAP_DDP_LONG = 0x02,
|
||||
LLAP_ENQ = 0x81,
|
||||
LLAP_ACK = 0x82,
|
||||
LLAP_RTS = 0x84,
|
||||
LLAP_CTS = 0x85
|
||||
LLAP_DDP_SHORT = 0x01,
|
||||
LLAP_DDP_LONG = 0x02,
|
||||
LLAP_ENQ = 0x81,
|
||||
LLAP_ACK = 0x82,
|
||||
LLAP_RTS = 0x84,
|
||||
LLAP_CTS = 0x85
|
||||
} LLAP_TYPES;
|
||||
|
||||
const unsigned int LLAP_PACKET_MAX = 603 /* bytes */;
|
||||
@ -45,290 +31,279 @@ const double GAP_TOLERANCE = 4.0;
|
||||
static struct packet_port_t llap_port;
|
||||
|
||||
typedef enum {
|
||||
DIALOG_READY,
|
||||
DIALOG_GOT_CTS,
|
||||
DIALOG_WAIT_IDG
|
||||
DIALOG_READY,
|
||||
DIALOG_GOT_CTS,
|
||||
DIALOG_WAIT_IDG
|
||||
} DIALOG_STATE;
|
||||
static DIALOG_STATE dialog_state;
|
||||
static double dialog_end_dcycs;
|
||||
static double last_frame_dcycs;
|
||||
|
||||
void llap_init()
|
||||
{
|
||||
dialog_state = DIALOG_READY;
|
||||
last_frame_dcycs = 0;
|
||||
port_init(&llap_port);
|
||||
void llap_init() {
|
||||
dialog_state = DIALOG_READY;
|
||||
last_frame_dcycs = 0;
|
||||
port_init(&llap_port);
|
||||
}
|
||||
|
||||
void llap_shutdown()
|
||||
{
|
||||
port_shutdown(&llap_port);
|
||||
void llap_shutdown() {
|
||||
port_shutdown(&llap_port);
|
||||
}
|
||||
|
||||
|
||||
/** Queue one data packet out from the bridge's LLAP port and into the guest. **/
|
||||
void llap_enqueue_out(struct packet_t* packet)
|
||||
{
|
||||
// Generate the RTS.
|
||||
struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
rts->source.network = packet->source.network;
|
||||
rts->source.node = packet->source.node;
|
||||
rts->dest.network = packet->dest.network;
|
||||
rts->dest.node = packet->dest.node;
|
||||
rts->size = 0;
|
||||
rts->data = 0;
|
||||
rts->type = LLAP_RTS;
|
||||
enqueue_packet(&llap_port.out, rts);
|
||||
void llap_enqueue_out(struct packet_t* packet) {
|
||||
// Generate the RTS.
|
||||
struct packet_t* rts = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
rts->source.network = packet->source.network;
|
||||
rts->source.node = packet->source.node;
|
||||
rts->dest.network = packet->dest.network;
|
||||
rts->dest.node = packet->dest.node;
|
||||
rts->size = 0;
|
||||
rts->data = 0;
|
||||
rts->type = LLAP_RTS;
|
||||
enqueue_packet(&llap_port.out, rts);
|
||||
|
||||
// Enqueue the data.
|
||||
enqueue_packet(&llap_port.out, packet);
|
||||
// Enqueue the data.
|
||||
enqueue_packet(&llap_port.out, packet);
|
||||
}
|
||||
|
||||
struct packet_t* llap_dequeue_in()
|
||||
{
|
||||
return dequeue(&llap_port.in);
|
||||
struct packet_t* llap_dequeue_in() {
|
||||
return dequeue(&llap_port.in);
|
||||
}
|
||||
|
||||
static void llap_dump_packet(size_t size, byte data[])
|
||||
{
|
||||
if (size < LLAP_PACKET_MIN)
|
||||
atbridge_printf("LLAP short packet.\n");
|
||||
else if (size > LLAP_PACKET_MAX)
|
||||
atbridge_printf("LLAP long packet.\n");
|
||||
else
|
||||
{
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
|
||||
const char* typeName = 0;
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_DDP_SHORT:
|
||||
typeName = "DDP (short)";
|
||||
break;
|
||||
case LLAP_DDP_LONG:
|
||||
typeName = "DDP (long)";
|
||||
break;
|
||||
case LLAP_ENQ:
|
||||
typeName = "lapENQ";
|
||||
break;
|
||||
case LLAP_ACK:
|
||||
typeName = "lapACK";
|
||||
break;
|
||||
case LLAP_RTS:
|
||||
typeName = "lapRTS";
|
||||
break;
|
||||
case LLAP_CTS:
|
||||
typeName = "lapCTS";
|
||||
break;
|
||||
}
|
||||
static void llap_dump_packet(size_t size, byte data[]) {
|
||||
if (size < LLAP_PACKET_MIN)
|
||||
atbridge_printf("LLAP short packet.\n");
|
||||
else if (size > LLAP_PACKET_MAX)
|
||||
atbridge_printf("LLAP long packet.\n");
|
||||
else
|
||||
{
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
|
||||
if (typeName)
|
||||
atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size);
|
||||
else
|
||||
atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size);
|
||||
|
||||
/*for (size_t i = 0; i < size; i++)
|
||||
atbridge_printf("%02x ", data[i]);
|
||||
atbridge_printf("\n");*/
|
||||
}
|
||||
const char* typeName = 0;
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_DDP_SHORT:
|
||||
typeName = "DDP (short)";
|
||||
break;
|
||||
case LLAP_DDP_LONG:
|
||||
typeName = "DDP (long)";
|
||||
break;
|
||||
case LLAP_ENQ:
|
||||
typeName = "lapENQ";
|
||||
break;
|
||||
case LLAP_ACK:
|
||||
typeName = "lapACK";
|
||||
break;
|
||||
case LLAP_RTS:
|
||||
typeName = "lapRTS";
|
||||
break;
|
||||
case LLAP_CTS:
|
||||
typeName = "lapCTS";
|
||||
break;
|
||||
}
|
||||
|
||||
if (typeName)
|
||||
atbridge_printf("LLAP[%d->%d] %s: %d bytes.\n", source, dest, typeName, size);
|
||||
else
|
||||
atbridge_printf("LLAP[%d->%d] %x: %d bytes.\n", source, dest, type, size);
|
||||
|
||||
/*for (size_t i = 0; i < size; i++)
|
||||
atbridge_printf("%02x ", data[i]);
|
||||
atbridge_printf("\n");*/
|
||||
}
|
||||
}
|
||||
|
||||
/** Reply to a control packet from the GS **/
|
||||
static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type)
|
||||
{
|
||||
struct at_addr_t dest_addr = { 0, dest };
|
||||
struct at_addr_t source_addr = { 0, source };
|
||||
static void llap_reply_control(at_node_t dest, at_node_t source, LLAP_TYPES type) {
|
||||
struct at_addr_t dest_addr = { 0, dest };
|
||||
struct at_addr_t source_addr = { 0, source };
|
||||
|
||||
// Insert control packets at the head of the queue contrary to normal FIFO queue operation
|
||||
// to ensure that control frames arrive in the intended order.
|
||||
insert(&llap_port.out, dest_addr, source_addr, type, 0, 0);
|
||||
// Insert control packets at the head of the queue contrary to normal FIFO queue operation
|
||||
// to ensure that control frames arrive in the intended order.
|
||||
insert(&llap_port.out, dest_addr, source_addr, type, 0, 0);
|
||||
}
|
||||
|
||||
/** Accept a data packet from the GS. **/
|
||||
static void llap_handle_data(size_t size, byte data[])
|
||||
{
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
static void llap_handle_data(size_t size, byte data[]) {
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
|
||||
const size_t data_size = size - 3;
|
||||
byte* data_copy = (byte*)malloc(data_size);
|
||||
memcpy(data_copy, data + 3, data_size);
|
||||
const size_t data_size = size - 3;
|
||||
byte* data_copy = (byte*)malloc(data_size);
|
||||
memcpy(data_copy, data + 3, data_size);
|
||||
|
||||
struct at_addr_t dest_addr = { 0, dest };
|
||||
struct at_addr_t source_addr = { 0, source };
|
||||
enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy);
|
||||
struct at_addr_t dest_addr = { 0, dest };
|
||||
struct at_addr_t source_addr = { 0, source };
|
||||
enqueue(&llap_port.in, dest_addr, source_addr, type, data_size, data_copy);
|
||||
}
|
||||
|
||||
/** Accept a control packet from the GS. **/
|
||||
static void llap_handle_control(size_t size, byte data[])
|
||||
{
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
static void llap_handle_control(size_t size, byte data[]) {
|
||||
at_node_t dest = data[0];
|
||||
at_node_t source = data[1];
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
|
||||
struct at_addr_t addr = { atbridge_get_net(), dest };
|
||||
struct at_addr_t addr = { atbridge_get_net(), dest };
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_ENQ:
|
||||
// Require the GS to take a valid "client" address not known to be in use.
|
||||
if (dest > 127 || dest == 0 || atbridge_address_used(&addr))
|
||||
llap_reply_control(source, dest, LLAP_ACK);
|
||||
break;
|
||||
case LLAP_ACK:
|
||||
break;
|
||||
case LLAP_RTS:
|
||||
if (dest != at_broadcast_node)
|
||||
// The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake.
|
||||
// Note that broadcast packets do not require a CTS.
|
||||
llap_reply_control(source, dest, LLAP_CTS);
|
||||
break;
|
||||
case LLAP_CTS:
|
||||
// The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet.
|
||||
dialog_state = DIALOG_GOT_CTS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_ENQ:
|
||||
// Require the GS to take a valid "client" address not known to be in use.
|
||||
if (dest > 127 || dest == 0 || atbridge_address_used(&addr))
|
||||
llap_reply_control(source, dest, LLAP_ACK);
|
||||
break;
|
||||
case LLAP_ACK:
|
||||
break;
|
||||
case LLAP_RTS:
|
||||
if (dest != at_broadcast_node)
|
||||
// The GS is trying to make a directed transmission. Provide the required RTS/CTS handshake.
|
||||
// Note that broadcast packets do not require a CTS.
|
||||
llap_reply_control(source, dest, LLAP_CTS);
|
||||
break;
|
||||
case LLAP_CTS:
|
||||
// The GS sent a CTS. If the bridge has pending data, prepare to deliver the packet.
|
||||
dialog_state = DIALOG_GOT_CTS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Occassionally, we receive an invalid packet from the GS. I'm unsure if this is due to a bug in GS/OS
|
||||
or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the
|
||||
current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover.
|
||||
**/
|
||||
static void llap_reset_dialog()
|
||||
{
|
||||
dialog_state = DIALOG_READY;
|
||||
last_frame_dcycs = 0;
|
||||
or, more likely, a bug in the SCC emulation. Regardless, when such a thing does occur, discard the
|
||||
current, corrupted dialog. Link errors are routine in real LocalTalk networks, and LocalTalk will recover.
|
||||
**/
|
||||
static void llap_reset_dialog() {
|
||||
dialog_state = DIALOG_READY;
|
||||
last_frame_dcycs = 0;
|
||||
|
||||
// Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS).
|
||||
while (true)
|
||||
{
|
||||
struct packet_t* packet = queue_peek(&llap_port.out);
|
||||
|
||||
if (packet && (packet->type != LLAP_RTS))
|
||||
{
|
||||
packet = dequeue(&llap_port.out);
|
||||
if (packet->data)
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
// Discard packets until the queue is either empty or the next dialog starts (and dialogs begin with an RTS).
|
||||
while (true)
|
||||
{
|
||||
struct packet_t* packet = queue_peek(&llap_port.out);
|
||||
|
||||
if (packet && (packet->type != LLAP_RTS))
|
||||
{
|
||||
packet = dequeue(&llap_port.out);
|
||||
if (packet->data)
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Transfer (send) one LLAP packet from the GS. **/
|
||||
void llap_enqueue_in(double dcycs, size_t size, byte data[])
|
||||
{
|
||||
atbridge_printf("<%0.0f> TX: ", dcycs);
|
||||
llap_dump_packet(size, data);
|
||||
void llap_enqueue_in(double dcycs, size_t size, byte data[]) {
|
||||
atbridge_printf("<%0.0f> TX: ", dcycs);
|
||||
llap_dump_packet(size, data);
|
||||
|
||||
if (size < LLAP_PACKET_MIN)
|
||||
atbridge_printf("ATBridge: Dropping LLAP short packet.\n");
|
||||
else if (size > LLAP_PACKET_MAX)
|
||||
atbridge_printf("ATBridge: Dropping LLAP long packet.\n");
|
||||
else
|
||||
{
|
||||
last_frame_dcycs = dcycs;
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
if (size < LLAP_PACKET_MIN)
|
||||
atbridge_printf("ATBridge: Dropping LLAP short packet.\n");
|
||||
else if (size > LLAP_PACKET_MAX)
|
||||
atbridge_printf("ATBridge: Dropping LLAP long packet.\n");
|
||||
else
|
||||
{
|
||||
last_frame_dcycs = dcycs;
|
||||
LLAP_TYPES type = (LLAP_TYPES)(data[2]);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_DDP_SHORT:
|
||||
case LLAP_DDP_LONG:
|
||||
llap_handle_data(size, data);
|
||||
break;
|
||||
case LLAP_ENQ:
|
||||
case LLAP_ACK:
|
||||
case LLAP_RTS:
|
||||
case LLAP_CTS:
|
||||
llap_handle_control(size, data);
|
||||
break;
|
||||
default:
|
||||
// Intentionally check for valid types and ingore packets with invalid types.
|
||||
// Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge.
|
||||
atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n");
|
||||
llap_reset_dialog();
|
||||
}
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case LLAP_DDP_SHORT:
|
||||
case LLAP_DDP_LONG:
|
||||
llap_handle_data(size, data);
|
||||
break;
|
||||
case LLAP_ENQ:
|
||||
case LLAP_ACK:
|
||||
case LLAP_RTS:
|
||||
case LLAP_CTS:
|
||||
llap_handle_control(size, data);
|
||||
break;
|
||||
default:
|
||||
// Intentionally check for valid types and ingore packets with invalid types.
|
||||
// Sometimes, the bridge gets invalid packets from the GS, which tends to break the bridge.
|
||||
atbridge_printf("ATBridge: Dropping LLAP packet with invalid type.\n");
|
||||
llap_reset_dialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Transfer (receive) one LLAP packet to the GS. **/
|
||||
void llap_dequeue_out(double dcycs, size_t* size, byte* data[])
|
||||
{
|
||||
*size = 0;
|
||||
void llap_dequeue_out(double dcycs, size_t* size, byte* data[]) {
|
||||
*size = 0;
|
||||
|
||||
// The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG).
|
||||
// If necessary, wait for the IDG.
|
||||
if (dialog_state == DIALOG_WAIT_IDG)
|
||||
// The LocalTalk protocol requires a minimum 400us gap between dialogs (called the IDG).
|
||||
// If necessary, wait for the IDG.
|
||||
if (dialog_state == DIALOG_WAIT_IDG)
|
||||
{
|
||||
if ((dcycs - dialog_end_dcycs) >= LLAP_IDG)
|
||||
// The IDG is done.
|
||||
dialog_state = DIALOG_READY;
|
||||
else
|
||||
// Continue waiting for the IDG.
|
||||
return;
|
||||
}
|
||||
// The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG).
|
||||
// If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case,
|
||||
// discard the current dialog and try again.
|
||||
if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG)))
|
||||
{
|
||||
llap_reset_dialog();
|
||||
atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n");
|
||||
}
|
||||
|
||||
struct packet_t* packet = queue_peek(&llap_port.out);
|
||||
|
||||
if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG)))
|
||||
{
|
||||
llap_reset_dialog();
|
||||
packet = queue_peek(&llap_port.out);
|
||||
atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n");
|
||||
}
|
||||
|
||||
if (packet &&
|
||||
((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */
|
||||
(!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */
|
||||
(!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */
|
||||
{
|
||||
dequeue(&llap_port.out);
|
||||
|
||||
// Prepend the LLAP header.
|
||||
*size = packet->size + 3 + 2;
|
||||
*data = (byte*)malloc(*size);
|
||||
(*data)[0] = packet->dest.node;
|
||||
(*data)[1] = packet->source.node;
|
||||
(*data)[2] = packet->type;
|
||||
|
||||
// Insert the data into the new LLAP packet.
|
||||
if (*size)
|
||||
memcpy((*data) + 3, packet->data, packet->size);
|
||||
|
||||
// Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually
|
||||
// check the FCS, the value of the FCS doesn't matter.
|
||||
(*data)[packet->size + 3 + 0] = 0xff;
|
||||
(*data)[packet->size + 3 + 1] = 0xff;
|
||||
|
||||
atbridge_printf("<%0.0f> RX: ", dcycs);
|
||||
llap_dump_packet(*size, *data);
|
||||
|
||||
if (packet->type & 0x80)
|
||||
dialog_state = DIALOG_READY;
|
||||
else
|
||||
{
|
||||
if ((dcycs - dialog_end_dcycs) >= LLAP_IDG)
|
||||
// The IDG is done.
|
||||
dialog_state = DIALOG_READY;
|
||||
else
|
||||
// Continue waiting for the IDG.
|
||||
return;
|
||||
// This was the last packet in the dialog.
|
||||
dialog_state = DIALOG_WAIT_IDG;
|
||||
dialog_end_dcycs = dcycs;
|
||||
}
|
||||
// The LocalTalk protocols requires a maximum 200us gap between frames within a dialog (called the IFG).
|
||||
// If we exceed the IFG, the bridge must be stuck in an incomplete or corrupt dialog. In this case,
|
||||
// discard the current dialog and try again.
|
||||
if ((dialog_state != DIALOG_READY) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IFG)))
|
||||
{
|
||||
llap_reset_dialog();
|
||||
atbridge_printf("ATBridge: Dialog reset due to IFG violation.\n");
|
||||
}
|
||||
|
||||
struct packet_t* packet = queue_peek(&llap_port.out);
|
||||
last_frame_dcycs = dcycs;
|
||||
|
||||
if ((dialog_state == DIALOG_READY) && (packet) && !(packet->type & 0x80) && (last_frame_dcycs != 0) && ((dcycs - last_frame_dcycs) >= (GAP_TOLERANCE*LLAP_IDG)))
|
||||
{
|
||||
llap_reset_dialog();
|
||||
packet = queue_peek(&llap_port.out);
|
||||
atbridge_printf("ATBridge: Dialog reset due to IDG violation.\n");
|
||||
}
|
||||
|
||||
if (packet &&
|
||||
((packet->type & 0x80) || /* Pass along control frames without waiting for a CTS. */
|
||||
(!(packet->type & 0x80) && (packet->dest.node == at_broadcast_node) && (dialog_state == DIALOG_READY)) || /* Pass along broadcast frames, which don't wait for CTS frames. */
|
||||
(!(packet->type & 0x80) && (packet->dest.node != at_broadcast_node) && (dialog_state == DIALOG_GOT_CTS)))) /* Pass along directed frames only after receiving a CTS handshake. */
|
||||
{
|
||||
dequeue(&llap_port.out);
|
||||
|
||||
// Prepend the LLAP header.
|
||||
*size = packet->size + 3 + 2;
|
||||
*data = (byte*)malloc(*size);
|
||||
(*data)[0] = packet->dest.node;
|
||||
(*data)[1] = packet->source.node;
|
||||
(*data)[2] = packet->type;
|
||||
|
||||
// Insert the data into the new LLAP packet.
|
||||
if (*size)
|
||||
memcpy((*data) + 3, packet->data, packet->size);
|
||||
|
||||
// Fake a frame check sequence (FCS). Since our SCC emulation doesn't actually
|
||||
// check the FCS, the value of the FCS doesn't matter.
|
||||
(*data)[packet->size + 3 + 0] = 0xff;
|
||||
(*data)[packet->size + 3 + 1] = 0xff;
|
||||
|
||||
atbridge_printf("<%0.0f> RX: ", dcycs);
|
||||
llap_dump_packet(*size, *data);
|
||||
|
||||
if (packet->type & 0x80)
|
||||
dialog_state = DIALOG_READY;
|
||||
else
|
||||
{
|
||||
// This was the last packet in the dialog.
|
||||
dialog_state = DIALOG_WAIT_IDG;
|
||||
dialog_end_dcycs = dcycs;
|
||||
}
|
||||
|
||||
last_frame_dcycs = dcycs;
|
||||
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
struct packet_t;
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "pcap_delay.h"
|
||||
@ -31,143 +17,130 @@ static void* module = 0;
|
||||
#endif
|
||||
|
||||
|
||||
bool pcapdelay_load()
|
||||
{
|
||||
if (!pcapdelay_is_loaded())
|
||||
{
|
||||
bool pcapdelay_load() {
|
||||
if (!pcapdelay_is_loaded())
|
||||
{
|
||||
#ifdef WIN32
|
||||
module = LoadLibrary("wpcap.dll");
|
||||
module = LoadLibrary("wpcap.dll");
|
||||
#elif __linux__
|
||||
module = dlopen("libpcap.so", RTLD_LAZY);
|
||||
module = dlopen("libpcap.so", RTLD_LAZY);
|
||||
#endif
|
||||
}
|
||||
return pcapdelay_is_loaded();
|
||||
}
|
||||
return pcapdelay_is_loaded();
|
||||
}
|
||||
|
||||
bool pcapdelay_is_loaded()
|
||||
{
|
||||
bool pcapdelay_is_loaded() {
|
||||
#ifdef WIN32
|
||||
return module != NULL;
|
||||
return module != NULL;
|
||||
#elif __linux__
|
||||
return module != 0;
|
||||
return module != 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pcapdelay_unload()
|
||||
{
|
||||
if (pcapdelay_is_loaded())
|
||||
{
|
||||
void pcapdelay_unload() {
|
||||
if (pcapdelay_is_loaded())
|
||||
{
|
||||
#ifdef WIN32
|
||||
FreeLibrary(module);
|
||||
module = NULL;
|
||||
FreeLibrary(module);
|
||||
module = NULL;
|
||||
#elif __linux__
|
||||
dlclose(module);
|
||||
module = 0;
|
||||
dlclose(module);
|
||||
module = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*PFNVOID)();
|
||||
|
||||
static PFNVOID delay_load(const char* proc, PFNVOID* ppfn)
|
||||
{
|
||||
if (pcapdelay_load() && proc && ppfn && !*ppfn)
|
||||
{
|
||||
static PFNVOID delay_load(const char* proc, PFNVOID* ppfn) {
|
||||
if (pcapdelay_load() && proc && ppfn && !*ppfn)
|
||||
{
|
||||
#ifdef WIN32
|
||||
*ppfn = (PFNVOID)GetProcAddress(module, proc);
|
||||
*ppfn = (PFNVOID)GetProcAddress(module, proc);
|
||||
#elif __linux__
|
||||
*ppfn = (PFNVOID)dlsym(module, proc);
|
||||
*ppfn = (PFNVOID)dlsym(module, proc);
|
||||
#endif
|
||||
}
|
||||
if (ppfn)
|
||||
return *ppfn;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (ppfn)
|
||||
return *ppfn;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pcapdelay_freealldevs(pcap_if_t* a0)
|
||||
{
|
||||
typedef void (*PFN)(pcap_if_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn)))
|
||||
(*pfn)(a0);
|
||||
void pcapdelay_freealldevs(pcap_if_t* a0) {
|
||||
typedef void (*PFN)(pcap_if_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_freealldevs", (PFNVOID*)&pfn)))
|
||||
(*pfn)(a0);
|
||||
}
|
||||
|
||||
pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4)
|
||||
{
|
||||
typedef pcap_t* (*PFN)(const char*, int, int, int, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2, a3, a4);
|
||||
else
|
||||
return 0;
|
||||
pcap_t* pcapdelay_open_live(const char* a0, int a1, int a2, int a3, char* a4) {
|
||||
typedef pcap_t* (*PFN)(const char*, int, int, int, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_open_live", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2, a3, a4);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pcapdelay_close(pcap_t* a0)
|
||||
{
|
||||
typedef void (*PFN)(pcap_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn)))
|
||||
(*pfn)(a0);
|
||||
void pcapdelay_close(pcap_t* a0) {
|
||||
typedef void (*PFN)(pcap_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_close", (PFNVOID*)&pfn)))
|
||||
(*pfn)(a0);
|
||||
}
|
||||
|
||||
int pcapdelay_findalldevs(pcap_if_t** a0, char* a1)
|
||||
{
|
||||
typedef int (*PFN)(pcap_if_t**, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1);
|
||||
else
|
||||
return 0;
|
||||
int pcapdelay_findalldevs(pcap_if_t** a0, char* a1) {
|
||||
typedef int (*PFN)(pcap_if_t**, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_findalldevs", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcapdelay_datalink(pcap_t* a0)
|
||||
{
|
||||
typedef int(*PFN)(pcap_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0);
|
||||
else
|
||||
return 0;
|
||||
int pcapdelay_datalink(pcap_t* a0) {
|
||||
typedef int (*PFN)(pcap_t*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_datalink", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2)
|
||||
{
|
||||
typedef int(*PFN)(pcap_t*, int, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2);
|
||||
else
|
||||
return 0;
|
||||
int pcapdelay_setnonblock(pcap_t* a0, int a1, char* a2) {
|
||||
typedef int (*PFN)(pcap_t*, int, char*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_setnonblock", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2)
|
||||
{
|
||||
typedef int(*PFN)(pcap_t*, u_char*, int);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2);
|
||||
else
|
||||
return 0;
|
||||
int pcapdelay_sendpacket(pcap_t* a0, u_char* a1, int a2) {
|
||||
typedef int (*PFN)(pcap_t*, u_char*, int);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_sendpacket", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1)
|
||||
{
|
||||
typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1);
|
||||
else
|
||||
return 0;
|
||||
const u_char* pcapdelay_next(pcap_t* a0, struct pcap_pkthdr* a1) {
|
||||
typedef const u_char*(*PFN)(pcap_t*, struct pcap_pkthdr*);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_next", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3)
|
||||
{
|
||||
typedef const int(*PFN)(pcap_t *, int, pcap_handler, u_char *);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2, a3);
|
||||
else
|
||||
return 0;
|
||||
int pcapdelay_dispatch(pcap_t* a0, int a1, pcap_handler a2, u_char* a3) {
|
||||
typedef const int (*PFN)(pcap_t *, int, pcap_handler, u_char *);
|
||||
static PFN pfn = 0;
|
||||
if ((pfn = (PFN)delay_load("pcap_dispatch", (PFNVOID*)&pfn)))
|
||||
return (*pfn)(a0, a1, a2, a3);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,23 +1,10 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/*
|
||||
This interface provides a thin, delay-loaded wrapper around the PCAP library so that
|
||||
you may start GSport without intalling PCAP. Of course, some features that require
|
||||
|
@ -1,23 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/** This module implements queues for storing and transferring packets within the bridge. **/
|
||||
|
||||
@ -25,117 +11,107 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "atalk.h"
|
||||
#include "port.h"
|
||||
|
||||
void port_init(struct packet_port_t* port)
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
queue_init(&port->in);
|
||||
queue_init(&port->out);
|
||||
}
|
||||
void port_init(struct packet_port_t* port) {
|
||||
if (port)
|
||||
{
|
||||
queue_init(&port->in);
|
||||
queue_init(&port->out);
|
||||
}
|
||||
}
|
||||
|
||||
void port_shutdown(struct packet_port_t* port)
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
queue_shutdown(&port->in);
|
||||
queue_shutdown(&port->out);
|
||||
}
|
||||
void port_shutdown(struct packet_port_t* port) {
|
||||
if (port)
|
||||
{
|
||||
queue_shutdown(&port->in);
|
||||
queue_shutdown(&port->out);
|
||||
}
|
||||
}
|
||||
|
||||
void queue_init(struct packet_queue_t* queue)
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
void queue_init(struct packet_queue_t* queue) {
|
||||
if (queue)
|
||||
{
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void queue_shutdown(struct packet_queue_t* queue)
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
struct packet_t* packet = dequeue(queue);
|
||||
while (packet)
|
||||
{
|
||||
if (packet->data)
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
packet = dequeue(queue);
|
||||
}
|
||||
}
|
||||
void queue_shutdown(struct packet_queue_t* queue) {
|
||||
if (queue)
|
||||
{
|
||||
struct packet_t* packet = dequeue(queue);
|
||||
while (packet)
|
||||
{
|
||||
if (packet->data)
|
||||
free(packet->data);
|
||||
free(packet);
|
||||
packet = dequeue(queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[])
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
void enqueue(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) {
|
||||
if (!queue)
|
||||
return;
|
||||
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
packet->dest.network = dest.network;
|
||||
packet->dest.node = dest.node;
|
||||
packet->source.network = source.network;
|
||||
packet->source.node = source.node;
|
||||
packet->type = type;
|
||||
packet->size = size;
|
||||
packet->data = data;
|
||||
enqueue_packet(queue, packet);
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
packet->dest.network = dest.network;
|
||||
packet->dest.node = dest.node;
|
||||
packet->source.network = source.network;
|
||||
packet->source.node = source.node;
|
||||
packet->type = type;
|
||||
packet->size = size;
|
||||
packet->data = data;
|
||||
enqueue_packet(queue, packet);
|
||||
}
|
||||
|
||||
void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet)
|
||||
{
|
||||
packet->next = 0;
|
||||
void enqueue_packet(struct packet_queue_t* queue, struct packet_t* packet) {
|
||||
packet->next = 0;
|
||||
|
||||
if (queue->tail)
|
||||
queue->tail->next = packet;
|
||||
else
|
||||
queue->head = packet;
|
||||
queue->tail = packet;
|
||||
if (queue->tail)
|
||||
queue->tail->next = packet;
|
||||
else
|
||||
queue->head = packet;
|
||||
queue->tail = packet;
|
||||
}
|
||||
|
||||
void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[])
|
||||
{
|
||||
if (!queue)
|
||||
return;
|
||||
void insert(struct packet_queue_t* queue, struct at_addr_t dest, struct at_addr_t source, byte type, size_t size, byte data[]) {
|
||||
if (!queue)
|
||||
return;
|
||||
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
packet->dest.network = dest.network;
|
||||
packet->dest.node = dest.node;
|
||||
packet->source.network = source.network;
|
||||
packet->source.node = source.node;
|
||||
packet->type = type;
|
||||
packet->size = size;
|
||||
packet->data = data;
|
||||
insert_packet(queue, packet);
|
||||
struct packet_t* packet = (struct packet_t*)malloc(sizeof(struct packet_t));
|
||||
packet->dest.network = dest.network;
|
||||
packet->dest.node = dest.node;
|
||||
packet->source.network = source.network;
|
||||
packet->source.node = source.node;
|
||||
packet->type = type;
|
||||
packet->size = size;
|
||||
packet->data = data;
|
||||
insert_packet(queue, packet);
|
||||
}
|
||||
|
||||
void insert_packet(struct packet_queue_t* queue, struct packet_t* packet)
|
||||
{
|
||||
packet->next = queue->head;
|
||||
queue->head = packet;
|
||||
if (!queue->tail)
|
||||
queue->tail = queue->head;
|
||||
void insert_packet(struct packet_queue_t* queue, struct packet_t* packet) {
|
||||
packet->next = queue->head;
|
||||
queue->head = packet;
|
||||
if (!queue->tail)
|
||||
queue->tail = queue->head;
|
||||
}
|
||||
|
||||
struct packet_t* dequeue(struct packet_queue_t* queue)
|
||||
{
|
||||
if (queue && queue->head)
|
||||
{
|
||||
struct packet_t* packet = queue->head;
|
||||
if (queue->tail == queue->head)
|
||||
queue->tail = queue->head = 0;
|
||||
else
|
||||
queue->head = packet->next;
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
struct packet_t* dequeue(struct packet_queue_t* queue) {
|
||||
if (queue && queue->head)
|
||||
{
|
||||
struct packet_t* packet = queue->head;
|
||||
if (queue->tail == queue->head)
|
||||
queue->tail = queue->head = 0;
|
||||
else
|
||||
queue->head = packet->next;
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct packet_t* queue_peek(struct packet_queue_t* queue)
|
||||
{
|
||||
if (queue)
|
||||
return queue->head;
|
||||
else
|
||||
return 0;
|
||||
struct packet_t* queue_peek(struct packet_queue_t* queue) {
|
||||
if (queue)
|
||||
return queue->head;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013-2014 by Peter Neubauer
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
struct packet_t
|
||||
|
668
src/clock.c
@ -1,28 +1,13 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 - 2012 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "defc.h"
|
||||
#include <time.h>
|
||||
#include "glog.h"
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <mmsystem.h>
|
||||
@ -31,421 +16,396 @@
|
||||
#endif
|
||||
|
||||
extern int Verbose;
|
||||
extern word32 g_vbl_count; // OG change int to word32
|
||||
extern word32 g_vbl_count; // OG change int to word32
|
||||
extern int g_rom_version;
|
||||
extern int g_config_gsplus_update_needed;
|
||||
|
||||
#define CLK_IDLE 1
|
||||
#define CLK_TIME 2
|
||||
#define CLK_INTERNAL 3
|
||||
#define CLK_BRAM1 4
|
||||
#define CLK_BRAM2 5
|
||||
#define CLK_IDLE 1
|
||||
#define CLK_TIME 2
|
||||
#define CLK_INTERNAL 3
|
||||
#define CLK_BRAM1 4
|
||||
#define CLK_BRAM2 5
|
||||
|
||||
int g_clk_mode = CLK_IDLE;
|
||||
int g_clk_read = 0;
|
||||
int g_clk_reg1 = 0;
|
||||
int g_clk_mode = CLK_IDLE;
|
||||
int g_clk_read = 0;
|
||||
int g_clk_reg1 = 0;
|
||||
|
||||
extern int g_c033_data;
|
||||
extern int g_c034_val;
|
||||
|
||||
byte g_bram[2][256];
|
||||
byte *g_bram_ptr = &(g_bram[0][0]);
|
||||
byte g_temp_boot_slot = 254;
|
||||
byte g_orig_boot_slot = 0;
|
||||
byte g_bram[2][256];
|
||||
byte *g_bram_ptr = &(g_bram[0][0]);
|
||||
byte g_temp_boot_slot = 254;
|
||||
byte g_orig_boot_slot = 0;
|
||||
|
||||
word32 g_clk_cur_time = 0xa0000000;
|
||||
int g_clk_next_vbl_update = 0;
|
||||
word32 g_clk_cur_time = 0xa0000000;
|
||||
int g_clk_next_vbl_update = 0;
|
||||
|
||||
double
|
||||
get_dtime()
|
||||
{
|
||||
double get_dtime() {
|
||||
#ifndef _WIN32
|
||||
struct timeval tp1;
|
||||
double dsec;
|
||||
double dusec;
|
||||
struct timeval tp1;
|
||||
double dsec;
|
||||
double dusec;
|
||||
#endif
|
||||
double dtime;
|
||||
double dtime;
|
||||
|
||||
/* Routine used to return actual system time as a double */
|
||||
/* No routine cares about the absolute value, only deltas--maybe */
|
||||
/* take advantage of that in future to increase usec accuracy */
|
||||
/* Routine used to return actual system time as a double */
|
||||
/* No routine cares about the absolute value, only deltas--maybe */
|
||||
/* take advantage of that in future to increase usec accuracy */
|
||||
|
||||
#ifdef _WIN32
|
||||
dtime = timeGetTime() / 1000.0;
|
||||
dtime = timeGetTime() / 1000.0;
|
||||
#else
|
||||
|
||||
# ifdef SOLARIS
|
||||
gettimeofday(&tp1, (void *)0);
|
||||
gettimeofday(&tp1, (void *)0);
|
||||
# else
|
||||
gettimeofday(&tp1, (struct timezone *)0);
|
||||
gettimeofday(&tp1, (struct timezone *)0);
|
||||
# endif
|
||||
|
||||
dsec = (double)tp1.tv_sec;
|
||||
dusec = (double)tp1.tv_usec;
|
||||
dsec = (double)tp1.tv_sec;
|
||||
dusec = (double)tp1.tv_usec;
|
||||
|
||||
dtime = dsec + (dusec / (1000.0 * 1000.0));
|
||||
dtime = dsec + (dusec / (1000.0 * 1000.0));
|
||||
#endif
|
||||
|
||||
return dtime;
|
||||
return dtime;
|
||||
}
|
||||
|
||||
int
|
||||
micro_sleep(double dtime)
|
||||
{
|
||||
int micro_sleep(double dtime) {
|
||||
#ifndef _WIN32
|
||||
struct timeval Timer;
|
||||
int ret;
|
||||
struct timeval Timer;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
if(dtime <= 0.0) {
|
||||
return 0;
|
||||
}
|
||||
if(dtime >= 1.0) {
|
||||
halt_printf("micro_sleep called with %f!!\n", dtime);
|
||||
return -1;
|
||||
}
|
||||
if(dtime <= 0.0) {
|
||||
return 0;
|
||||
}
|
||||
if(dtime >= 1.0) {
|
||||
halt_printf("micro_sleep called with %f!!\n", dtime);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("usleep: %f\n", dtime);
|
||||
printf("usleep: %f\n", dtime);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
Sleep((DWORD)(dtime * 1000));
|
||||
Sleep((DWORD)(dtime * 1000));
|
||||
#else
|
||||
Timer.tv_sec = 0;
|
||||
Timer.tv_usec = (dtime * 1000000.0);
|
||||
if( (ret = select(0, 0, 0, 0, &Timer)) < 0) {
|
||||
fprintf(stderr, "micro_sleep (select) ret: %d, errno: %d\n",
|
||||
ret, errno);
|
||||
return -1;
|
||||
}
|
||||
Timer.tv_sec = 0;
|
||||
Timer.tv_usec = (dtime * 1000000.0);
|
||||
if( (ret = select(0, 0, 0, 0, &Timer)) < 0) {
|
||||
glogf("micro_sleep (select) ret: %d, errno: %d", ret, errno);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clk_bram_zero()
|
||||
{
|
||||
int i, j;
|
||||
void clk_bram_zero() {
|
||||
int i, j;
|
||||
|
||||
/* zero out all bram */
|
||||
for(i = 0; i < 2; i++) {
|
||||
for(j = 0; j < 256; j++) {
|
||||
g_bram[i][j] = 0;
|
||||
}
|
||||
}
|
||||
g_bram_ptr = &(g_bram[0][0]);
|
||||
/* zero out all bram */
|
||||
for(i = 0; i < 2; i++) {
|
||||
for(j = 0; j < 256; j++) {
|
||||
g_bram[i][j] = 0;
|
||||
}
|
||||
}
|
||||
g_bram_ptr = &(g_bram[0][0]);
|
||||
}
|
||||
|
||||
void
|
||||
clk_bram_set(int bram_num, int offset, int val)
|
||||
{
|
||||
g_bram[bram_num][offset] = val;
|
||||
void clk_bram_set(int bram_num, int offset, int val) {
|
||||
g_bram[bram_num][offset] = val;
|
||||
}
|
||||
|
||||
|
||||
extern void x_clk_setup_bram_version();
|
||||
|
||||
void
|
||||
clk_setup_bram_version()
|
||||
{
|
||||
x_clk_setup_bram_version();
|
||||
void clk_setup_bram_version() {
|
||||
x_clk_setup_bram_version();
|
||||
}
|
||||
|
||||
void
|
||||
clk_write_bram(FILE *fconf)
|
||||
{
|
||||
int i, j, k;
|
||||
void clk_write_bram(FILE *fconf) {
|
||||
int i, j, k;
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
fprintf(fconf, "\n");
|
||||
for(j = 0; j < 256; j += 16) {
|
||||
fprintf(fconf, "bram%d[%02x] =", 2*i + 1, j);
|
||||
for(k = 0; k < 16; k++) {
|
||||
fprintf(fconf, " %02x", g_bram[i][j+k]);
|
||||
}
|
||||
fprintf(fconf, "\n");
|
||||
}
|
||||
}
|
||||
for(i = 0; i < 2; i++) {
|
||||
fprintf(fconf, "\n");
|
||||
for(j = 0; j < 256; j += 16) {
|
||||
fprintf(fconf, "bram%d[%02x] =", 2*i + 1, j);
|
||||
for(k = 0; k < 16; k++) {
|
||||
fprintf(fconf, " %02x", g_bram[i][j+k]);
|
||||
}
|
||||
fprintf(fconf, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clk_calculate_bram_checksum(void) {
|
||||
int checksum = 0;
|
||||
int i;
|
||||
if (g_bram_ptr[251] == 0xff) {
|
||||
// Only make the checksum valid if we have non-zeron data!
|
||||
// Otherwise you have very valid zeroes, which confuses the GS firmware mightily.
|
||||
for (i = 250; i >= 0; i--) {
|
||||
checksum = (checksum & 0xFFFF) << 1;
|
||||
checksum = (checksum & 0xFFFF)
|
||||
+ g_bram_ptr[i]
|
||||
+ ((int)g_bram_ptr[i + 1] << 8)
|
||||
+ (checksum >> 16);
|
||||
}
|
||||
checksum &= 0xFFFF;
|
||||
checksum += ((checksum ^ 0xAAAA) << 16);
|
||||
void clk_calculate_bram_checksum(void) {
|
||||
int checksum = 0;
|
||||
int i;
|
||||
if (g_bram_ptr[251] == 0xff) {
|
||||
// Only make the checksum valid if we have non-zeron data!
|
||||
// Otherwise you have very valid zeroes, which confuses the GS firmware mightily.
|
||||
for (i = 250; i >= 0; i--) {
|
||||
checksum = (checksum & 0xFFFF) << 1;
|
||||
checksum = (checksum & 0xFFFF)
|
||||
+ g_bram_ptr[i]
|
||||
+ ((int)g_bram_ptr[i + 1] << 8)
|
||||
+ (checksum >> 16);
|
||||
}
|
||||
checksum &= 0xFFFF;
|
||||
checksum += ((checksum ^ 0xAAAA) << 16);
|
||||
#if defined(GSPLUS_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__) // OSX needs to calculate endianness mid-compilation, can't be passed on compile command
|
||||
g_bram_ptr[252] = (checksum & 0xFF);
|
||||
g_bram_ptr[253] = (checksum >> 8);
|
||||
g_bram_ptr[254] = (checksum >> 16);
|
||||
g_bram_ptr[255] = (checksum >> 24);
|
||||
g_bram_ptr[252] = (checksum & 0xFF);
|
||||
g_bram_ptr[253] = (checksum >> 8);
|
||||
g_bram_ptr[254] = (checksum >> 16);
|
||||
g_bram_ptr[255] = (checksum >> 24);
|
||||
#else
|
||||
g_bram_ptr[255] = (checksum & 0xFF);
|
||||
g_bram_ptr[254] = (checksum >> 8);
|
||||
g_bram_ptr[253] = (checksum >> 16);
|
||||
g_bram_ptr[252] = (checksum >> 24);
|
||||
g_bram_ptr[255] = (checksum & 0xFF);
|
||||
g_bram_ptr[254] = (checksum >> 8);
|
||||
g_bram_ptr[253] = (checksum >> 16);
|
||||
g_bram_ptr[252] = (checksum >> 24);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_cur_time()
|
||||
{
|
||||
struct tm *tm_ptr;
|
||||
time_t cur_time;
|
||||
unsigned int secs, secs2;
|
||||
void update_cur_time() {
|
||||
struct tm *tm_ptr;
|
||||
time_t cur_time;
|
||||
unsigned int secs, secs2;
|
||||
|
||||
|
||||
#ifdef UNDER_CE // OG Not supported on WIndows CE
|
||||
/*
|
||||
SYSTEMTIME stime;
|
||||
FILETIME ftime;
|
||||
GetLocalTime(&stime);
|
||||
SystemTimeToFileTime(&stime,&ftime);
|
||||
cur_time = ftime.dwLowDateTime;
|
||||
*/
|
||||
cur_time = time(0);
|
||||
#ifdef UNDER_CE // OG Not supported on WIndows CE
|
||||
/*
|
||||
SYSTEMTIME stime;
|
||||
FILETIME ftime;
|
||||
GetLocalTime(&stime);
|
||||
SystemTimeToFileTime(&stime,&ftime);
|
||||
cur_time = ftime.dwLowDateTime;
|
||||
*/
|
||||
cur_time = time(0);
|
||||
|
||||
secs=0;
|
||||
secs2=0;
|
||||
secs=0;
|
||||
secs2=0;
|
||||
|
||||
#else
|
||||
cur_time = time(0);
|
||||
cur_time = time(0);
|
||||
|
||||
/* Figure out the timezone (effectively) by diffing two times. */
|
||||
/* this is probably not right for a few hours around daylight savings*/
|
||||
/* time transition */
|
||||
secs2 = (unsigned int)mktime(gmtime(&cur_time));
|
||||
tm_ptr = localtime(&cur_time);
|
||||
secs = (unsigned int)mktime(tm_ptr);
|
||||
/* Figure out the timezone (effectively) by diffing two times. */
|
||||
/* this is probably not right for a few hours around daylight savings*/
|
||||
/* time transition */
|
||||
secs2 = (unsigned int)mktime(gmtime(&cur_time));
|
||||
tm_ptr = localtime(&cur_time);
|
||||
secs = (unsigned int)mktime(tm_ptr);
|
||||
|
||||
#ifdef MAC
|
||||
/* Mac OS X's mktime function modifies the tm_ptr passed in for */
|
||||
/* the CDT timezone and breaks this algorithm. So on a Mac, we */
|
||||
/* will use the tm_ptr->gmtoff member to correct the time */
|
||||
secs = secs + tm_ptr->tm_gmtoff;
|
||||
/* Mac OS X's mktime function modifies the tm_ptr passed in for */
|
||||
/* the CDT timezone and breaks this algorithm. So on a Mac, we */
|
||||
/* will use the tm_ptr->gmtoff member to correct the time */
|
||||
secs = secs + tm_ptr->tm_gmtoff;
|
||||
#else
|
||||
secs = (unsigned int)cur_time - (secs2 - secs);
|
||||
secs = (unsigned int)cur_time - (secs2 - secs);
|
||||
|
||||
if(tm_ptr->tm_isdst) {
|
||||
/* adjust for daylight savings time */
|
||||
secs += 3600;
|
||||
}
|
||||
if(tm_ptr->tm_isdst) {
|
||||
/* adjust for daylight savings time */
|
||||
secs += 3600;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* add in secs to make date based on Apple Jan 1, 1904 instead of */
|
||||
/* Unix's Jan 1, 1970 */
|
||||
/* So add in 66 years and 17 leap year days (1904 is a leap year) */
|
||||
secs += ((66*365) + 17) * (24*3600);
|
||||
/* add in secs to make date based on Apple Jan 1, 1904 instead of */
|
||||
/* Unix's Jan 1, 1970 */
|
||||
/* So add in 66 years and 17 leap year days (1904 is a leap year) */
|
||||
secs += ((66*365) + 17) * (24*3600);
|
||||
|
||||
g_clk_cur_time = secs;
|
||||
g_clk_cur_time = secs;
|
||||
|
||||
clk_printf("Update g_clk_cur_time to %08x\n", g_clk_cur_time);
|
||||
g_clk_next_vbl_update = g_vbl_count + 5;
|
||||
clk_printf("Update g_clk_cur_time to %08x\n", g_clk_cur_time);
|
||||
g_clk_next_vbl_update = g_vbl_count + 5;
|
||||
}
|
||||
|
||||
/* clock_update called by sim65816 every VBL */
|
||||
void
|
||||
clock_update()
|
||||
{
|
||||
/* Nothing to do */
|
||||
void clock_update() {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
void
|
||||
clock_update_if_needed()
|
||||
{
|
||||
int diff;
|
||||
void clock_update_if_needed() {
|
||||
int diff;
|
||||
|
||||
diff = g_clk_next_vbl_update - g_vbl_count;
|
||||
if(diff < 0 || diff > 60) {
|
||||
/* Been a while, re-read the clock */
|
||||
update_cur_time();
|
||||
}
|
||||
diff = g_clk_next_vbl_update - g_vbl_count;
|
||||
if(diff < 0 || diff > 60) {
|
||||
/* Been a while, re-read the clock */
|
||||
update_cur_time();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clock_write_c034(word32 val)
|
||||
{
|
||||
g_c034_val = val & 0x7f;
|
||||
if((val & 0x80) != 0) {
|
||||
if((val & 0x20) == 0) {
|
||||
printf("c034 write not last = 1\n");
|
||||
/* set_halt(1); */
|
||||
}
|
||||
do_clock_data();
|
||||
}
|
||||
void clock_write_c034(word32 val) {
|
||||
g_c034_val = val & 0x7f;
|
||||
if((val & 0x80) != 0) {
|
||||
if((val & 0x20) == 0) {
|
||||
printf("c034 write not last = 1\n");
|
||||
/* set_halt(1); */
|
||||
}
|
||||
do_clock_data();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
do_clock_data()
|
||||
{
|
||||
word32 mask;
|
||||
int read;
|
||||
int op;
|
||||
void do_clock_data() {
|
||||
word32 mask;
|
||||
int read;
|
||||
int op;
|
||||
|
||||
clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode);
|
||||
clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode);
|
||||
|
||||
read = g_c034_val & 0x40;
|
||||
switch(g_clk_mode) {
|
||||
case CLK_IDLE:
|
||||
g_clk_read = (g_c033_data >> 7) & 1;
|
||||
g_clk_reg1 = (g_c033_data >> 2) & 3;
|
||||
op = (g_c033_data >> 4) & 7;
|
||||
if(!read) {
|
||||
/* write */
|
||||
switch(op) {
|
||||
case 0x0: /* Read/write seconds register */
|
||||
g_clk_mode = CLK_TIME;
|
||||
clock_update_if_needed();
|
||||
break;
|
||||
case 0x3: /* internal registers */
|
||||
g_clk_mode = CLK_INTERNAL;
|
||||
if(g_clk_reg1 & 0x2) {
|
||||
/* extend BRAM read */
|
||||
g_clk_mode = CLK_BRAM2;
|
||||
g_clk_reg1 = (g_c033_data & 7) << 5;
|
||||
}
|
||||
break;
|
||||
case 0x2: /* read/write ram 0x10-0x13 */
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
g_clk_reg1 += 0x10;
|
||||
break;
|
||||
case 0x4: /* read/write ram 0x00-0x0f */
|
||||
case 0x5: case 0x6: case 0x7:
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
g_clk_reg1 = (g_c033_data >> 2) & 0xf;
|
||||
break;
|
||||
default:
|
||||
halt_printf("Bad c033_data in CLK_IDLE: %02x\n",
|
||||
g_c033_data);
|
||||
}
|
||||
} else {
|
||||
printf("clk read from IDLE mode!\n");
|
||||
/* set_halt(1); */
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
break;
|
||||
case CLK_BRAM2:
|
||||
if(!read) {
|
||||
/* get more bits of bram addr */
|
||||
if((g_c033_data & 0x83) == 0x00) {
|
||||
/* more address bits */
|
||||
g_clk_reg1 |= ((g_c033_data >> 2) & 0x1f);
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
} else {
|
||||
halt_printf("CLK_BRAM2: c033_data: %02x!\n",
|
||||
g_c033_data);
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
} else {
|
||||
halt_printf("CLK_BRAM2: clock read!\n");
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
break;
|
||||
case CLK_BRAM1:
|
||||
/* access battery ram addr g_clk_reg1 */
|
||||
if(read) {
|
||||
if(g_clk_read) {
|
||||
/* Yup, read */
|
||||
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)){
|
||||
// Modify boot slot
|
||||
g_c033_data = g_temp_boot_slot;
|
||||
clk_calculate_bram_checksum();
|
||||
} else {
|
||||
g_c033_data = g_bram_ptr[g_clk_reg1];
|
||||
}
|
||||
clk_printf("Reading BRAM loc %02x: %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
} else {
|
||||
halt_printf("CLK_BRAM1: said wr, now read\n");
|
||||
}
|
||||
} else {
|
||||
if(g_clk_read) {
|
||||
halt_printf("CLK_BRAM1: said rd, now write\n");
|
||||
} else {
|
||||
/* Yup, write */
|
||||
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
|
||||
// Modify boot slot
|
||||
g_bram_ptr[g_clk_reg1] = g_temp_boot_slot;
|
||||
clk_calculate_bram_checksum();
|
||||
} else {
|
||||
g_bram_ptr[g_clk_reg1] = g_c033_data;
|
||||
}
|
||||
clk_printf("Writing BRAM loc %02x with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
g_config_gsplus_update_needed = 1;
|
||||
}
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
case CLK_TIME:
|
||||
if(read) {
|
||||
if(g_clk_read == 0) {
|
||||
halt_printf("Reading time, but in set mode!\n");
|
||||
}
|
||||
g_c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) &
|
||||
0xff;
|
||||
clk_printf("Returning time byte %d: %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
} else {
|
||||
/* Write */
|
||||
if(g_clk_read) {
|
||||
halt_printf("Write time, but in read mode!\n");
|
||||
}
|
||||
clk_printf("Writing TIME loc %d with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
mask = 0xff << (8 * g_clk_reg1);
|
||||
read = g_c034_val & 0x40;
|
||||
switch(g_clk_mode) {
|
||||
case CLK_IDLE:
|
||||
g_clk_read = (g_c033_data >> 7) & 1;
|
||||
g_clk_reg1 = (g_c033_data >> 2) & 3;
|
||||
op = (g_c033_data >> 4) & 7;
|
||||
if(!read) {
|
||||
/* write */
|
||||
switch(op) {
|
||||
case 0x0: /* Read/write seconds register */
|
||||
g_clk_mode = CLK_TIME;
|
||||
clock_update_if_needed();
|
||||
break;
|
||||
case 0x3: /* internal registers */
|
||||
g_clk_mode = CLK_INTERNAL;
|
||||
if(g_clk_reg1 & 0x2) {
|
||||
/* extend BRAM read */
|
||||
g_clk_mode = CLK_BRAM2;
|
||||
g_clk_reg1 = (g_c033_data & 7) << 5;
|
||||
}
|
||||
break;
|
||||
case 0x2: /* read/write ram 0x10-0x13 */
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
g_clk_reg1 += 0x10;
|
||||
break;
|
||||
case 0x4: /* read/write ram 0x00-0x0f */
|
||||
case 0x5: case 0x6: case 0x7:
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
g_clk_reg1 = (g_c033_data >> 2) & 0xf;
|
||||
break;
|
||||
default:
|
||||
halt_printf("Bad c033_data in CLK_IDLE: %02x\n",
|
||||
g_c033_data);
|
||||
}
|
||||
} else {
|
||||
printf("clk read from IDLE mode!\n");
|
||||
/* set_halt(1); */
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
break;
|
||||
case CLK_BRAM2:
|
||||
if(!read) {
|
||||
/* get more bits of bram addr */
|
||||
if((g_c033_data & 0x83) == 0x00) {
|
||||
/* more address bits */
|
||||
g_clk_reg1 |= ((g_c033_data >> 2) & 0x1f);
|
||||
g_clk_mode = CLK_BRAM1;
|
||||
} else {
|
||||
halt_printf("CLK_BRAM2: c033_data: %02x!\n",
|
||||
g_c033_data);
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
} else {
|
||||
halt_printf("CLK_BRAM2: clock read!\n");
|
||||
g_clk_mode = CLK_IDLE;
|
||||
}
|
||||
break;
|
||||
case CLK_BRAM1:
|
||||
/* access battery ram addr g_clk_reg1 */
|
||||
if(read) {
|
||||
if(g_clk_read) {
|
||||
/* Yup, read */
|
||||
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
|
||||
// Modify boot slot
|
||||
g_c033_data = g_temp_boot_slot;
|
||||
clk_calculate_bram_checksum();
|
||||
} else {
|
||||
g_c033_data = g_bram_ptr[g_clk_reg1];
|
||||
}
|
||||
clk_printf("Reading BRAM loc %02x: %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
} else {
|
||||
halt_printf("CLK_BRAM1: said wr, now read\n");
|
||||
}
|
||||
} else {
|
||||
if(g_clk_read) {
|
||||
halt_printf("CLK_BRAM1: said rd, now write\n");
|
||||
} else {
|
||||
/* Yup, write */
|
||||
if ((g_clk_reg1 == 0x28) && (g_temp_boot_slot != 254)) {
|
||||
// Modify boot slot
|
||||
g_bram_ptr[g_clk_reg1] = g_temp_boot_slot;
|
||||
clk_calculate_bram_checksum();
|
||||
} else {
|
||||
g_bram_ptr[g_clk_reg1] = g_c033_data;
|
||||
}
|
||||
clk_printf("Writing BRAM loc %02x with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
g_config_gsplus_update_needed = 1;
|
||||
}
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
case CLK_TIME:
|
||||
if(read) {
|
||||
if(g_clk_read == 0) {
|
||||
halt_printf("Reading time, but in set mode!\n");
|
||||
}
|
||||
g_c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) &
|
||||
0xff;
|
||||
clk_printf("Returning time byte %d: %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
} else {
|
||||
/* Write */
|
||||
if(g_clk_read) {
|
||||
halt_printf("Write time, but in read mode!\n");
|
||||
}
|
||||
clk_printf("Writing TIME loc %d with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
mask = 0xff << (8 * g_clk_reg1);
|
||||
|
||||
g_clk_cur_time = (g_clk_cur_time & (~mask)) |
|
||||
((g_c033_data & 0xff) << (8 * g_clk_reg1));
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
case CLK_INTERNAL:
|
||||
if(read) {
|
||||
printf("Attempting to read internal reg %02x!\n",
|
||||
g_clk_reg1);
|
||||
} else {
|
||||
switch(g_clk_reg1) {
|
||||
case 0x0: /* test register */
|
||||
if(g_c033_data & 0xc0) {
|
||||
printf("Writing test reg: %02x!\n",
|
||||
g_c033_data);
|
||||
/* set_halt(1); */
|
||||
}
|
||||
break;
|
||||
case 0x1: /* write protect reg */
|
||||
clk_printf("Writing clk wr_protect: %02x\n",
|
||||
g_c033_data);
|
||||
if(g_c033_data & 0x80) {
|
||||
printf("Stop, wr clk wr_prot: %02x\n",
|
||||
g_c033_data);
|
||||
/* set_halt(1); */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
halt_printf("Writing int reg: %02x with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
}
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
default:
|
||||
halt_printf("clk mode: %d unknown!\n", g_clk_mode);
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
}
|
||||
g_clk_cur_time = (g_clk_cur_time & (~mask)) |
|
||||
((g_c033_data & 0xff) << (8 * g_clk_reg1));
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
case CLK_INTERNAL:
|
||||
if(read) {
|
||||
printf("Attempting to read internal reg %02x!\n",
|
||||
g_clk_reg1);
|
||||
} else {
|
||||
switch(g_clk_reg1) {
|
||||
case 0x0: /* test register */
|
||||
if(g_c033_data & 0xc0) {
|
||||
printf("Writing test reg: %02x!\n",
|
||||
g_c033_data);
|
||||
/* set_halt(1); */
|
||||
}
|
||||
break;
|
||||
case 0x1: /* write protect reg */
|
||||
clk_printf("Writing clk wr_protect: %02x\n",
|
||||
g_c033_data);
|
||||
if(g_c033_data & 0x80) {
|
||||
printf("Stop, wr clk wr_prot: %02x\n",
|
||||
g_c033_data);
|
||||
/* set_halt(1); */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
halt_printf("Writing int reg: %02x with %02x\n",
|
||||
g_clk_reg1, g_c033_data);
|
||||
}
|
||||
}
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
default:
|
||||
halt_printf("clk mode: %d unknown!\n", g_clk_mode);
|
||||
g_clk_mode = CLK_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__ ;
|
||||
char g_compile_time[] = "Compiled: " __DATE__ " " __TIME__;
|
||||
|
5720
src/config.c
67
src/config.h
@ -1,40 +1,23 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#define CONF_BUF_LEN 1024
|
||||
#define COPY_BUF_SIZE 4096
|
||||
#define CONF_BUF_LEN 1024
|
||||
#define COPY_BUF_SIZE 4096
|
||||
#define CFG_PRINTF_BUFSIZE 2048
|
||||
|
||||
#define CFG_PATH_MAX 1024
|
||||
|
||||
#define CFG_NUM_SHOWENTS 16
|
||||
#define CFG_PATH_MAX 1024
|
||||
#define CFG_NUM_SHOWENTS 16
|
||||
|
||||
#define CFGTYPE_MENU 1
|
||||
#define CFGTYPE_INT 2
|
||||
#define CFGTYPE_INT 2
|
||||
#define CFGTYPE_DISK 3
|
||||
#define CFGTYPE_FUNC 4
|
||||
#define CFGTYPE_FILE 5
|
||||
#define CFGTYPE_STR 6
|
||||
#define CFGTYPE_DIR 7
|
||||
/* CFGTYPE limited to just 4 bits: 0-15 */
|
||||
|
||||
/* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */
|
||||
@ -44,3 +27,33 @@ STRUCT(Cfg_defval) {
|
||||
int intval;
|
||||
char *strval;
|
||||
};
|
||||
|
||||
|
||||
int cfg_get_fd_size(char *filename);
|
||||
int cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size);
|
||||
int cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, Disk *dsk);
|
||||
int cfg_maybe_insert_disk(int slot, int drive, const char *namestr);
|
||||
int cfg_stat(char *path, struct stat *sb);
|
||||
int cfg_partition_make_list(char *filename, FILE *file);
|
||||
void cfg_htab_vtab(int x, int y);
|
||||
void cfg_home(void);
|
||||
void cfg_cleol(void);
|
||||
void cfg_putchar(int c);
|
||||
void cfg_printf(const char *fmt, ...);
|
||||
void cfg_print_num(int num, int max_len);
|
||||
void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras);
|
||||
void cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change);
|
||||
void cfg_get_base_path(char *pathptr, const char *inptr, int go_up);
|
||||
void cfg_file_init(void);
|
||||
void cfg_free_alldirents(Cfg_listhdr *listhdrptr);
|
||||
void cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, int size, int image_start, int part_num);
|
||||
int cfg_dirent_sortfn(const void *obj1, const void *obj2);
|
||||
int cfg_str_match(const char *str1, const char *str2, int len);
|
||||
void cfg_file_readdir(const char *pathptr);
|
||||
char *cfg_shorten_filename(const char *in_ptr, int maxlen);
|
||||
void cfg_fix_topent(Cfg_listhdr *listhdrptr);
|
||||
void cfg_file_draw(void);
|
||||
void cfg_partition_selected(void);
|
||||
void cfg_file_update_ptr(char *str);
|
||||
void cfg_file_selected(int);
|
||||
void cfg_file_handle_key(int key);
|
||||
|
45
src/config.txt
Normal file
@ -0,0 +1,45 @@
|
||||
# GSplus configuration file version 0.10a
|
||||
|
||||
s5d1 =
|
||||
s5d2 =
|
||||
|
||||
s6d1 =
|
||||
s6d2 =
|
||||
|
||||
s7d1 =
|
||||
|
||||
|
||||
|
||||
bram1[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram1[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
|
||||
bram3[00] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[10] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[20] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[30] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[40] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[50] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[60] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[70] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[80] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[90] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[a0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[b0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[c0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[d0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[e0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
bram3[f0] = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
1505
src/debug.c
Normal file
8
src/debug.h
Normal file
@ -0,0 +1,8 @@
|
||||
extern void debug_init();
|
||||
extern void debug_poll_only();
|
||||
extern void debug_cpu_test();
|
||||
|
||||
// used in sim65816.c
|
||||
void debug_server_poll();
|
||||
int debug_events_waiting();
|
||||
void debug_handle_event();
|
370
src/defc.h
@ -1,25 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "defcomm.h"
|
||||
|
||||
@ -28,8 +12,8 @@
|
||||
#include <stdio.h>
|
||||
extern "C" int outputInfo(const char* format,...);
|
||||
extern "C" int fOutputInfo(FILE*,const char* format,...);
|
||||
#define printf outputInfo
|
||||
#define fprintf fOutputInfo
|
||||
#define printf outputInfo
|
||||
#define fprintf fOutputInfo
|
||||
#endif
|
||||
|
||||
#define STRUCT(a) typedef struct _ ## a a; struct _ ## a
|
||||
@ -46,30 +30,31 @@ typedef unsigned long long word64;
|
||||
void U_STACK_TRACE();
|
||||
|
||||
/* 28MHz crystal, plus every 65th 1MHz cycle is stretched 140ns */
|
||||
#define CYCS_28_MHZ (28636360)
|
||||
#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ)
|
||||
#define CYCS_3_5_MHZ (CYCS_28_MHZ/8)
|
||||
#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0)))
|
||||
#define CYCS_1_MHZ ((int)DCYCS_1_MHZ)
|
||||
#define CYCS_28_MHZ (28636360)
|
||||
#define DCYCS_28_MHZ (1.0*CYCS_28_MHZ)
|
||||
#define CYCS_3_5_MHZ (CYCS_28_MHZ/8)
|
||||
#define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0)))
|
||||
#define CYCS_1_MHZ ((int)DCYCS_1_MHZ)
|
||||
|
||||
/* #define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0) */
|
||||
#define DCYCS_IN_16MS_RAW (262.0 * 65.0)
|
||||
#define DCYCS_IN_16MS_RAW (262.0 * 65.0)
|
||||
/* Use precisely 17030 instead of forcing 60 Hz since this is the number of */
|
||||
/* 1MHz cycles per screen */
|
||||
#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW))
|
||||
#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS))
|
||||
#define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW))
|
||||
#define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS))
|
||||
|
||||
#ifdef GSPLUS_LITTLE_ENDIAN
|
||||
# define BIGEND(a) ((((a) >> 24) & 0xff) + \
|
||||
(((a) >> 8) & 0xff00) + \
|
||||
(((a) << 8) & 0xff0000) + \
|
||||
(((a) << 24) & 0xff000000))
|
||||
# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00))
|
||||
# define GET_BE_WORD32(a) (BIGEND(a))
|
||||
// @todo: look at using <byteswap.h> for fastest platform implementations
|
||||
# define BIGEND(a) ((((a) >> 24) & 0xff) + \
|
||||
(((a) >> 8) & 0xff00) + \
|
||||
(((a) << 8) & 0xff0000) + \
|
||||
(((a) << 24) & 0xff000000))
|
||||
# define GET_BE_WORD16(a) ((((a) >> 8) & 0xff) + (((a) << 8) & 0xff00))
|
||||
# define GET_BE_WORD32(a) (BIGEND(a))
|
||||
#else
|
||||
# define BIGEND(a) (a)
|
||||
# define GET_BE_WORD16(a) (a)
|
||||
# define GET_BE_WORD32(a) (a)
|
||||
# define BIGEND(a) (a)
|
||||
# define GET_BE_WORD16(a) (a)
|
||||
# define GET_BE_WORD32(a) (a)
|
||||
#endif
|
||||
|
||||
#define MAXNUM_HEX_PER_LINE 32
|
||||
@ -78,7 +63,7 @@ void U_STACK_TRACE();
|
||||
# include <libc.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined (__OS2__) && !defined(UNDER_CE) // OG
|
||||
#if !defined(_WIN32) && !defined(UNDER_CE) // OG
|
||||
# include <unistd.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/wait.h>
|
||||
@ -92,7 +77,7 @@ void U_STACK_TRACE();
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef UNDER_CE // OG CE SPecific
|
||||
#ifndef UNDER_CE // OG CE SPecific
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@ -108,24 +93,24 @@ extern int open(const char* name,int,...);
|
||||
extern int read(int,char*,int);
|
||||
extern int close(int);
|
||||
extern int write( int fd, const void *buffer, unsigned int count );
|
||||
extern int lseek(int,int,int);
|
||||
extern int lseek(int,int,int);
|
||||
struct stat { int st_size; };
|
||||
extern int stat(const char* name, struct stat*);
|
||||
extern int fstat(int, struct stat*);
|
||||
#define O_RDWR 1
|
||||
#define O_BINARY 2
|
||||
#define O_RDONLY 4
|
||||
#define O_WRONLY 8
|
||||
#define O_CREAT 16
|
||||
#define O_TRUNC 32
|
||||
#define EAGAIN 11
|
||||
#define EINTR 4
|
||||
#define O_RDWR 1
|
||||
#define O_BINARY 2
|
||||
#define O_RDONLY 4
|
||||
#define O_WRONLY 8
|
||||
#define O_CREAT 16
|
||||
#define O_TRUNC 32
|
||||
#define EAGAIN 11
|
||||
#define EINTR 4
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HPUX
|
||||
# include <machine/inline.h> /* for GET_ITIMER */
|
||||
# include <machine/inline.h> /* for GET_ITIMER */
|
||||
#endif
|
||||
|
||||
#ifdef SOLARIS
|
||||
@ -134,232 +119,232 @@ extern int fstat(int, struct stat*);
|
||||
|
||||
#ifndef O_BINARY
|
||||
/* work around some Windows junk */
|
||||
# define O_BINARY 0
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
STRUCT(Pc_log) {
|
||||
double dcycs;
|
||||
word32 dbank_kpc;
|
||||
word32 instr;
|
||||
word32 psr_acc;
|
||||
word32 xreg_yreg;
|
||||
word32 stack_direct;
|
||||
word32 pad;
|
||||
double dcycs;
|
||||
word32 dbank_kpc;
|
||||
word32 instr;
|
||||
word32 psr_acc;
|
||||
word32 xreg_yreg;
|
||||
word32 stack_direct;
|
||||
word32 pad;
|
||||
};
|
||||
|
||||
STRUCT(Data_log) {
|
||||
double dcycs;
|
||||
word32 addr;
|
||||
word32 val;
|
||||
word32 size;
|
||||
double dcycs;
|
||||
word32 addr;
|
||||
word32 val;
|
||||
word32 size;
|
||||
};
|
||||
|
||||
STRUCT(Event) {
|
||||
double dcycs;
|
||||
int type;
|
||||
Event *next;
|
||||
double dcycs;
|
||||
int type;
|
||||
Event *next;
|
||||
};
|
||||
|
||||
STRUCT(Fplus) {
|
||||
double plus_1;
|
||||
double plus_2;
|
||||
double plus_3;
|
||||
double plus_x_minus_1;
|
||||
double plus_1;
|
||||
double plus_2;
|
||||
double plus_3;
|
||||
double plus_x_minus_1;
|
||||
};
|
||||
|
||||
STRUCT(Engine_reg) {
|
||||
double fcycles;
|
||||
word32 kpc;
|
||||
word32 acc;
|
||||
double fcycles;
|
||||
word32 kpc;
|
||||
word32 acc;
|
||||
|
||||
word32 xreg;
|
||||
word32 yreg;
|
||||
word32 xreg;
|
||||
word32 yreg;
|
||||
|
||||
word32 stack;
|
||||
word32 dbank;
|
||||
word32 stack;
|
||||
word32 dbank;
|
||||
|
||||
word32 direct;
|
||||
word32 psr;
|
||||
Fplus *fplus_ptr;
|
||||
word32 direct;
|
||||
word32 psr;
|
||||
Fplus *fplus_ptr;
|
||||
};
|
||||
|
||||
STRUCT(Kimage) {
|
||||
void *dev_handle;
|
||||
void *dev_handle2;
|
||||
byte *data_ptr;
|
||||
int width_req;
|
||||
int width_act;
|
||||
int height;
|
||||
int depth;
|
||||
int mdepth;
|
||||
int aux_info;
|
||||
void *dev_handle;
|
||||
void *dev_handle2;
|
||||
byte *data_ptr;
|
||||
int width_req;
|
||||
int width_act;
|
||||
int height;
|
||||
int depth;
|
||||
int mdepth;
|
||||
int aux_info;
|
||||
};
|
||||
|
||||
typedef byte *Pg_info;
|
||||
STRUCT(Page_info) {
|
||||
Pg_info rd_wr;
|
||||
Pg_info rd_wr;
|
||||
};
|
||||
|
||||
STRUCT(Cfg_menu) {
|
||||
const char *str;
|
||||
void *ptr;
|
||||
const char *name_str;
|
||||
void *defptr;
|
||||
int cfgtype;
|
||||
const char *str;
|
||||
void *ptr;
|
||||
const char *name_str;
|
||||
void *defptr;
|
||||
int cfgtype;
|
||||
};
|
||||
|
||||
STRUCT(Cfg_dirent) {
|
||||
char *name;
|
||||
int is_dir;
|
||||
int size;
|
||||
int image_start;
|
||||
int part_num;
|
||||
char *name;
|
||||
int is_dir;
|
||||
int size;
|
||||
int image_start;
|
||||
int part_num;
|
||||
};
|
||||
|
||||
STRUCT(Cfg_listhdr) {
|
||||
Cfg_dirent *direntptr;
|
||||
int max;
|
||||
int last;
|
||||
int invalid;
|
||||
Cfg_dirent *direntptr;
|
||||
int max;
|
||||
int last;
|
||||
int invalid;
|
||||
|
||||
int curent;
|
||||
int topent;
|
||||
int curent;
|
||||
int topent;
|
||||
|
||||
int num_to_show;
|
||||
int num_to_show;
|
||||
};
|
||||
|
||||
STRUCT(Emustate_intlist) {
|
||||
const char *str;
|
||||
int *iptr;
|
||||
const char *str;
|
||||
int *iptr;
|
||||
};
|
||||
|
||||
STRUCT(Emustate_dbllist) {
|
||||
const char *str;
|
||||
double *dptr;
|
||||
const char *str;
|
||||
double *dptr;
|
||||
};
|
||||
|
||||
STRUCT(Emustate_word32list) {
|
||||
const char *str;
|
||||
word32 *wptr;
|
||||
const char *str;
|
||||
word32 *wptr;
|
||||
};
|
||||
|
||||
#ifdef __LP64__
|
||||
# define PTR2WORD(a) ((unsigned long)(a))
|
||||
# define PTR2WORD(a) ((unsigned long)(a))
|
||||
#else
|
||||
# define PTR2WORD(a) ((unsigned int)(a))
|
||||
# define PTR2WORD(a) ((unsigned int)(a))
|
||||
#endif
|
||||
|
||||
|
||||
#define ALTZP (g_c068_statereg & 0x80)
|
||||
#define ALTZP (g_c068_statereg & 0x80)
|
||||
/* #define PAGE2 (g_c068_statereg & 0x40) */
|
||||
#define RAMRD (g_c068_statereg & 0x20)
|
||||
#define RAMWRT (g_c068_statereg & 0x10)
|
||||
#define RDROM (g_c068_statereg & 0x08)
|
||||
#define LCBANK2 (g_c068_statereg & 0x04)
|
||||
#define ROMB (g_c068_statereg & 0x02)
|
||||
#define INTCX (g_c068_statereg & 0x01)
|
||||
#define RAMRD (g_c068_statereg & 0x20)
|
||||
#define RAMWRT (g_c068_statereg & 0x10)
|
||||
#define RDROM (g_c068_statereg & 0x08)
|
||||
#define LCBANK2 (g_c068_statereg & 0x04)
|
||||
#define ROMB (g_c068_statereg & 0x02)
|
||||
#define INTCX (g_c068_statereg & 0x01)
|
||||
|
||||
#define C041_EN_25SEC_INTS 0x10
|
||||
#define C041_EN_VBL_INTS 0x08
|
||||
#define C041_EN_SWITCH_INTS 0x04
|
||||
#define C041_EN_MOVE_INTS 0x02
|
||||
#define C041_EN_MOUSE 0x01
|
||||
#define C041_EN_25SEC_INTS 0x10
|
||||
#define C041_EN_VBL_INTS 0x08
|
||||
#define C041_EN_SWITCH_INTS 0x04
|
||||
#define C041_EN_MOVE_INTS 0x02
|
||||
#define C041_EN_MOUSE 0x01
|
||||
|
||||
/* WARNING: SCC1 and SCC0 interrupts must be in this order for scc.c */
|
||||
/* This order matches the SCC hardware */
|
||||
#define IRQ_PENDING_SCC1_ZEROCNT 0x00001
|
||||
#define IRQ_PENDING_SCC1_TX 0x00002
|
||||
#define IRQ_PENDING_SCC1_RX 0x00004
|
||||
#define IRQ_PENDING_SCC0_ZEROCNT 0x00008
|
||||
#define IRQ_PENDING_SCC0_TX 0x00010
|
||||
#define IRQ_PENDING_SCC0_RX 0x00020
|
||||
#define IRQ_PENDING_C023_SCAN 0x00100
|
||||
#define IRQ_PENDING_C023_1SEC 0x00200
|
||||
#define IRQ_PENDING_C046_25SEC 0x00400
|
||||
#define IRQ_PENDING_C046_VBL 0x00800
|
||||
#define IRQ_PENDING_ADB_KBD_SRQ 0x01000
|
||||
#define IRQ_PENDING_ADB_DATA 0x02000
|
||||
#define IRQ_PENDING_ADB_MOUSE 0x04000
|
||||
#define IRQ_PENDING_DOC 0x08000
|
||||
#define IRQ_PENDING_SCC1_ZEROCNT 0x00001
|
||||
#define IRQ_PENDING_SCC1_TX 0x00002
|
||||
#define IRQ_PENDING_SCC1_RX 0x00004
|
||||
#define IRQ_PENDING_SCC0_ZEROCNT 0x00008
|
||||
#define IRQ_PENDING_SCC0_TX 0x00010
|
||||
#define IRQ_PENDING_SCC0_RX 0x00020
|
||||
#define IRQ_PENDING_C023_SCAN 0x00100
|
||||
#define IRQ_PENDING_C023_1SEC 0x00200
|
||||
#define IRQ_PENDING_C046_25SEC 0x00400
|
||||
#define IRQ_PENDING_C046_VBL 0x00800
|
||||
#define IRQ_PENDING_ADB_KBD_SRQ 0x01000
|
||||
#define IRQ_PENDING_ADB_DATA 0x02000
|
||||
#define IRQ_PENDING_ADB_MOUSE 0x04000
|
||||
#define IRQ_PENDING_DOC 0x08000
|
||||
|
||||
|
||||
#define EXTRU(val, pos, len) \
|
||||
( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \
|
||||
(((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) )
|
||||
#define EXTRU(val, pos, len) \
|
||||
( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \
|
||||
(((val) >> (31-(pos)) ) & ( (1<<(len) ) - 1) ) )
|
||||
|
||||
#define DEP1(val, pos, old_val) \
|
||||
(((old_val) & ~(1 << (31 - (pos))) ) | \
|
||||
( ((val) & 1) << (31 - (pos))) )
|
||||
#define DEP1(val, pos, old_val) \
|
||||
(((old_val) & ~(1 << (31 - (pos))) ) | \
|
||||
( ((val) & 1) << (31 - (pos))) )
|
||||
|
||||
#define set_halt(val) \
|
||||
if(val) { set_halt_act(val); }
|
||||
if(val) { set_halt_act(val); }
|
||||
|
||||
#define clear_halt() \
|
||||
clr_halt_act()
|
||||
clr_halt_act()
|
||||
|
||||
#define GET_PAGE_INFO_RD(page) \
|
||||
(page_info_rd_wr[page].rd_wr)
|
||||
(page_info_rd_wr[page].rd_wr)
|
||||
|
||||
#define GET_PAGE_INFO_WR(page) \
|
||||
(page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr)
|
||||
(page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr)
|
||||
|
||||
#define SET_PAGE_INFO_RD(page,val) \
|
||||
;page_info_rd_wr[page].rd_wr = (Pg_info)val;
|
||||
; page_info_rd_wr[page].rd_wr = (Pg_info)val;
|
||||
|
||||
#define SET_PAGE_INFO_WR(page,val) \
|
||||
;page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \
|
||||
(Pg_info)val;
|
||||
; page_info_rd_wr[0x10000 + PAGE_INFO_PAD_SIZE + (page)].rd_wr = \
|
||||
(Pg_info)val;
|
||||
|
||||
#define VERBOSE_DISK 0x001
|
||||
#define VERBOSE_IRQ 0x002
|
||||
#define VERBOSE_CLK 0x004
|
||||
#define VERBOSE_SHADOW 0x008
|
||||
#define VERBOSE_IWM 0x010
|
||||
#define VERBOSE_DOC 0x020
|
||||
#define VERBOSE_ADB 0x040
|
||||
#define VERBOSE_SCC 0x080
|
||||
#define VERBOSE_TEST 0x100
|
||||
#define VERBOSE_VIDEO 0x200
|
||||
#define VERBOSE_MAC 0x400
|
||||
#define VERBOSE_DISK 0x001
|
||||
#define VERBOSE_IRQ 0x002
|
||||
#define VERBOSE_CLK 0x004
|
||||
#define VERBOSE_SHADOW 0x008
|
||||
#define VERBOSE_IWM 0x010
|
||||
#define VERBOSE_DOC 0x020
|
||||
#define VERBOSE_ADB 0x040
|
||||
#define VERBOSE_SCC 0x080
|
||||
#define VERBOSE_TEST 0x100
|
||||
#define VERBOSE_VIDEO 0x200
|
||||
#define VERBOSE_MAC 0x400
|
||||
|
||||
#ifdef NO_VERB
|
||||
# define DO_VERBOSE 0
|
||||
# define DO_VERBOSE 0
|
||||
#else
|
||||
# define DO_VERBOSE 1
|
||||
# define DO_VERBOSE 1
|
||||
#endif
|
||||
|
||||
#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf
|
||||
#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf
|
||||
#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf
|
||||
#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf
|
||||
#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf
|
||||
#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf
|
||||
#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf
|
||||
#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf
|
||||
#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf
|
||||
#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf
|
||||
#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf
|
||||
#define disk_printf if(DO_VERBOSE && (Verbose & VERBOSE_DISK)) printf
|
||||
#define irq_printf if(DO_VERBOSE && (Verbose & VERBOSE_IRQ)) printf
|
||||
#define clk_printf if(DO_VERBOSE && (Verbose & VERBOSE_CLK)) printf
|
||||
#define shadow_printf if(DO_VERBOSE && (Verbose & VERBOSE_SHADOW)) printf
|
||||
#define iwm_printf if(DO_VERBOSE && (Verbose & VERBOSE_IWM)) printf
|
||||
#define doc_printf if(DO_VERBOSE && (Verbose & VERBOSE_DOC)) printf
|
||||
#define adb_printf if(DO_VERBOSE && (Verbose & VERBOSE_ADB)) printf
|
||||
#define scc_printf if(DO_VERBOSE && (Verbose & VERBOSE_SCC)) printf
|
||||
#define test_printf if(DO_VERBOSE && (Verbose & VERBOSE_TEST)) printf
|
||||
#define vid_printf if(DO_VERBOSE && (Verbose & VERBOSE_VIDEO)) printf
|
||||
#define mac_printf if(DO_VERBOSE && (Verbose & VERBOSE_MAC)) printf
|
||||
|
||||
|
||||
#define HALT_ON_SCAN_INT 0x001
|
||||
#define HALT_ON_IRQ 0x002
|
||||
#define HALT_ON_SHADOW_REG 0x004
|
||||
#define HALT_ON_C70D_WRITES 0x008
|
||||
#define HALT_ON_SCAN_INT 0x001
|
||||
#define HALT_ON_IRQ 0x002
|
||||
#define HALT_ON_SHADOW_REG 0x004
|
||||
#define HALT_ON_C70D_WRITES 0x008
|
||||
|
||||
#define HALT_ON(a, msg) \
|
||||
if(Halt_on & a) { \
|
||||
halt_printf(msg); \
|
||||
}
|
||||
#define HALT_ON(a, msg) \
|
||||
if(Halt_on & a) { \
|
||||
halt_printf(msg); \
|
||||
}
|
||||
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) (((a) < (b)) ? (b) : (a))
|
||||
# define MAX(a,b) (((a) < (b)) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
#define GET_ITIMER(dest) dest = get_itimer();
|
||||
#define GET_ITIMER(dest) dest = get_itimer();
|
||||
|
||||
#include "iwm.h"
|
||||
#include "protos.h"
|
||||
@ -368,5 +353,8 @@ STRUCT(Emustate_word32list) {
|
||||
#define JOYSTICK_TYPE_MOUSE 1
|
||||
#define JOYSTICK_TYPE_NATIVE_1 2
|
||||
#define JOYSTICK_TYPE_NATIVE_2 3
|
||||
#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None
|
||||
#define JOYSTICK_TYPE_NONE 4 // OG Added Joystick None
|
||||
#define NB_JOYSTICK_TYPE 5
|
||||
|
||||
// starting window x/y position if Undefined
|
||||
#define WINDOWPOS_UNDEFINED 0xFFFFFFFF
|
||||
|
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#define SHIFT_PER_CHANGE 3
|
||||
|
25
src/defs.h
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "defcomm.h"
|
||||
@ -65,4 +49,3 @@ ftmp2 .reg %fr5
|
||||
fscr1 .reg %fr6
|
||||
|
||||
#define LDC(val,reg) ldil L%val,reg ! ldo R%val(reg),reg
|
||||
|
||||
|
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#ifdef ASM
|
||||
|
24
src/disas.h
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
enum {
|
||||
|
1671
src/engine_c.c
@ -1,22 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
.code
|
||||
|
868
src/fbdriver.c
@ -1,25 +1,9 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2013 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/*
|
||||
* fbdriver - Linux fullscreen framebuffer graphics driver
|
||||
@ -43,11 +27,11 @@ extern word32 g_palette_8to1624[256];
|
||||
extern word32 g_a2palette_8to1624[256];
|
||||
extern word32 g_a2_screen_buffer_changed;
|
||||
extern word32 g_c025_val;
|
||||
#define SHIFT_DOWN ( (g_c025_val & 0x01) )
|
||||
#define CTRL_DOWN ( (g_c025_val & 0x02) )
|
||||
#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) )
|
||||
#define OPTION_DOWN ( (g_c025_val & 0x40) )
|
||||
#define CMD_DOWN ( (g_c025_val & 0x80) )
|
||||
#define SHIFT_DOWN ( (g_c025_val & 0x01) )
|
||||
#define CTRL_DOWN ( (g_c025_val & 0x02) )
|
||||
#define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) )
|
||||
#define OPTION_DOWN ( (g_c025_val & 0x40) )
|
||||
#define CMD_DOWN ( (g_c025_val & 0x80) )
|
||||
extern int g_video_act_margin_left;
|
||||
extern int g_video_act_margin_right;
|
||||
extern int g_video_act_margin_top;
|
||||
@ -69,491 +53,469 @@ extern int g_green_right_shift;
|
||||
extern int g_blue_right_shift;
|
||||
extern Kimage g_mainwin_kimage;
|
||||
|
||||
int keycode_to_a2code[128] =
|
||||
int keycode_to_a2code[128] =
|
||||
{
|
||||
-1, // KEY_RESERVED
|
||||
0x35, // KEY_ESC
|
||||
0x12, // KEY_1
|
||||
0x13, // KEY_2
|
||||
0x14, // KEY_3
|
||||
0x15, // KEY_4
|
||||
0x17, // KEY_5
|
||||
0x16, // KEY_6
|
||||
0x1A, // KEY_7
|
||||
0x1C, // KEY_8
|
||||
0x19, // KEY_9
|
||||
0x1D, // KEY_0
|
||||
0x1B, // KEY_MINUS
|
||||
0x18, // KEY_EQUAL
|
||||
0x3B, // KEY_BACKSPACE0
|
||||
0x30, // KEY_TAB
|
||||
0x0C, // KEY_Q
|
||||
0x0D, // KEY_W
|
||||
0x0E, // KEY_E
|
||||
0x0F, // KEY_R
|
||||
0x11, // KEY_T
|
||||
0x10, // KEY_Y
|
||||
0x20, // KEY_U
|
||||
0x22, // KEY_I
|
||||
0x1F, // KEY_O
|
||||
0x23, // KEY_P
|
||||
0x21, // KEY_LEFTBRACE
|
||||
0x1E, // KEY_RIGHTBRACE
|
||||
0x24, // KEY_ENTER
|
||||
0x36, // KEY_LEFTCTRL
|
||||
0x00, // KEY_A
|
||||
0x01, // KEY_S
|
||||
0x02, // KEY_D
|
||||
0x03, // KEY_F
|
||||
0x05, // KEY_G
|
||||
0x04, // KEY_H
|
||||
0x26, // KEY_J
|
||||
0x28, // KEY_K
|
||||
0x25, // KEY_L
|
||||
0x29, // KEY_SEMICOLON
|
||||
0x27, // KEY_APOSTROPHE
|
||||
0x32, // KEY_GRAVE
|
||||
0x38, // KEY_LEFTSHIFT
|
||||
0x2A, // KEY_BACKSLASH
|
||||
0x06, // KEY_Z
|
||||
0x07, // KEY_X
|
||||
0x08, // KEY_C
|
||||
0x09, // KEY_V
|
||||
0x0B, // KEY_B
|
||||
0x2D, // KEY_N
|
||||
0x2E, // KEY_M
|
||||
0x2B, // KEY_COMMA
|
||||
0x2F, // KEY_DOT
|
||||
0x2C, // KEY_SLASH
|
||||
0x38, // KEY_RIGHTSHIFT
|
||||
0x43, // KEY_KPASTERISK
|
||||
0x37, // KEY_LEFTALT
|
||||
0x31, // KEY_SPACE
|
||||
0x39, // KEY_CAPSLOCK
|
||||
0x7A, // KEY_F1
|
||||
0x78, // KEY_F2
|
||||
0x63, // KEY_F3
|
||||
0x76, // KEY_F4
|
||||
0x60, // KEY_F5
|
||||
0x61, // KEY_F6
|
||||
0x62, // KEY_F7
|
||||
0x64, // KEY_F8
|
||||
0x65, // KEY_F9
|
||||
0x6D, // KEY_F10
|
||||
0x47, // KEY_NUMLOCK
|
||||
0x37, // KEY_SCROLLLOCK
|
||||
0x59, // KEY_KP7
|
||||
0x5B, // KEY_KP8
|
||||
0x5C, // KEY_KP9
|
||||
0x4E, // KEY_KPMINUS
|
||||
0x56, // KEY_KP4
|
||||
0x57, // KEY_KP5
|
||||
0x58, // KEY_KP6
|
||||
0x45, // KEY_KPPLUS
|
||||
0x53, // KEY_KP1
|
||||
0x54, // KEY_KP2
|
||||
0x55, // KEY_KP3
|
||||
0x52, // KEY_KP0
|
||||
0x41, // KEY_KPDOT
|
||||
-1,
|
||||
-1, // KEY_ZENKAKUHANKAKU
|
||||
-1, // KEY_102ND
|
||||
0x67, // KEY_F11
|
||||
0x6F, // KEY_F12
|
||||
-1, // KEY_RO
|
||||
-1, // KEY_KATAKANA
|
||||
-1, // KEY_HIRAGANA
|
||||
-1, // KEY_HENKAN
|
||||
-1, // KEY_KATAKANAHIRAGANA
|
||||
-1, // KEY_MUHENKAN
|
||||
-1, // KEY_KPJPCOMMA
|
||||
0x4C, // KEY_KPENTER
|
||||
0x36, // KEY_RIGHTCTRL
|
||||
0x4B, // KEY_KPSLASH
|
||||
0x7F, // KEY_SYSRQ
|
||||
0x37, // KEY_RIGHTALT
|
||||
0x6E, // KEY_LINEFEED
|
||||
0x73, // KEY_HOME
|
||||
0x3E, // KEY_UP
|
||||
0x74, // KEY_PAGEUP
|
||||
0x3B, // KEY_LEFT
|
||||
0x3C, // KEY_RIGHT
|
||||
0x77, // KEY_END
|
||||
0x3D, // KEY_DOWN
|
||||
0x79, // KEY_PAGEDOWN
|
||||
0x72, // KEY_INSERT
|
||||
0x33, // KEY_DELETE
|
||||
-1, // KEY_MACRO
|
||||
-1, // KEY_MUTE
|
||||
-1, // KEY_VOLUMEDOWN
|
||||
-1, // KEY_VOLUMEUP
|
||||
0x7F, // KEY_POWER /* SC System Power Down */
|
||||
0x51, // KEY_KPEQUAL
|
||||
0x4E, // KEY_KPPLUSMINUS
|
||||
-1, // KEY_PAUSE
|
||||
-1, // KEY_SCALE /* AL Compiz Scale (Expose) */
|
||||
0x2B, // KEY_KPCOMMA
|
||||
-1, // KEY_HANGEUL
|
||||
-1, // KEY_HANJA
|
||||
-1, // KEY_YEN
|
||||
0x3A, // KEY_LEFTMETA
|
||||
0x3A, // KEY_RIGHTMETA
|
||||
-1 // KEY_COMPOSE
|
||||
-1, // KEY_RESERVED
|
||||
0x35, // KEY_ESC
|
||||
0x12, // KEY_1
|
||||
0x13, // KEY_2
|
||||
0x14, // KEY_3
|
||||
0x15, // KEY_4
|
||||
0x17, // KEY_5
|
||||
0x16, // KEY_6
|
||||
0x1A, // KEY_7
|
||||
0x1C, // KEY_8
|
||||
0x19, // KEY_9
|
||||
0x1D, // KEY_0
|
||||
0x1B, // KEY_MINUS
|
||||
0x18, // KEY_EQUAL
|
||||
0x3B, // KEY_BACKSPACE0
|
||||
0x30, // KEY_TAB
|
||||
0x0C, // KEY_Q
|
||||
0x0D, // KEY_W
|
||||
0x0E, // KEY_E
|
||||
0x0F, // KEY_R
|
||||
0x11, // KEY_T
|
||||
0x10, // KEY_Y
|
||||
0x20, // KEY_U
|
||||
0x22, // KEY_I
|
||||
0x1F, // KEY_O
|
||||
0x23, // KEY_P
|
||||
0x21, // KEY_LEFTBRACE
|
||||
0x1E, // KEY_RIGHTBRACE
|
||||
0x24, // KEY_ENTER
|
||||
0x36, // KEY_LEFTCTRL
|
||||
0x00, // KEY_A
|
||||
0x01, // KEY_S
|
||||
0x02, // KEY_D
|
||||
0x03, // KEY_F
|
||||
0x05, // KEY_G
|
||||
0x04, // KEY_H
|
||||
0x26, // KEY_J
|
||||
0x28, // KEY_K
|
||||
0x25, // KEY_L
|
||||
0x29, // KEY_SEMICOLON
|
||||
0x27, // KEY_APOSTROPHE
|
||||
0x32, // KEY_GRAVE
|
||||
0x38, // KEY_LEFTSHIFT
|
||||
0x2A, // KEY_BACKSLASH
|
||||
0x06, // KEY_Z
|
||||
0x07, // KEY_X
|
||||
0x08, // KEY_C
|
||||
0x09, // KEY_V
|
||||
0x0B, // KEY_B
|
||||
0x2D, // KEY_N
|
||||
0x2E, // KEY_M
|
||||
0x2B, // KEY_COMMA
|
||||
0x2F, // KEY_DOT
|
||||
0x2C, // KEY_SLASH
|
||||
0x38, // KEY_RIGHTSHIFT
|
||||
0x43, // KEY_KPASTERISK
|
||||
0x37, // KEY_LEFTALT
|
||||
0x31, // KEY_SPACE
|
||||
0x39, // KEY_CAPSLOCK
|
||||
0x7A, // KEY_F1
|
||||
0x78, // KEY_F2
|
||||
0x63, // KEY_F3
|
||||
0x76, // KEY_F4
|
||||
0x60, // KEY_F5
|
||||
0x61, // KEY_F6
|
||||
0x62, // KEY_F7
|
||||
0x64, // KEY_F8
|
||||
0x65, // KEY_F9
|
||||
0x6D, // KEY_F10
|
||||
0x47, // KEY_NUMLOCK
|
||||
0x37, // KEY_SCROLLLOCK
|
||||
0x59, // KEY_KP7
|
||||
0x5B, // KEY_KP8
|
||||
0x5C, // KEY_KP9
|
||||
0x4E, // KEY_KPMINUS
|
||||
0x56, // KEY_KP4
|
||||
0x57, // KEY_KP5
|
||||
0x58, // KEY_KP6
|
||||
0x45, // KEY_KPPLUS
|
||||
0x53, // KEY_KP1
|
||||
0x54, // KEY_KP2
|
||||
0x55, // KEY_KP3
|
||||
0x52, // KEY_KP0
|
||||
0x41, // KEY_KPDOT
|
||||
-1,
|
||||
-1, // KEY_ZENKAKUHANKAKU
|
||||
-1, // KEY_102ND
|
||||
0x67, // KEY_F11
|
||||
0x6F, // KEY_F12
|
||||
-1, // KEY_RO
|
||||
-1, // KEY_KATAKANA
|
||||
-1, // KEY_HIRAGANA
|
||||
-1, // KEY_HENKAN
|
||||
-1, // KEY_KATAKANAHIRAGANA
|
||||
-1, // KEY_MUHENKAN
|
||||
-1, // KEY_KPJPCOMMA
|
||||
0x4C, // KEY_KPENTER
|
||||
0x36, // KEY_RIGHTCTRL
|
||||
0x4B, // KEY_KPSLASH
|
||||
0x7F, // KEY_SYSRQ
|
||||
0x37, // KEY_RIGHTALT
|
||||
0x6E, // KEY_LINEFEED
|
||||
0x73, // KEY_HOME
|
||||
0x3E, // KEY_UP
|
||||
0x74, // KEY_PAGEUP
|
||||
0x3B, // KEY_LEFT
|
||||
0x3C, // KEY_RIGHT
|
||||
0x77, // KEY_END
|
||||
0x3D, // KEY_DOWN
|
||||
0x79, // KEY_PAGEDOWN
|
||||
0x72, // KEY_INSERT
|
||||
0x33, // KEY_DELETE
|
||||
-1, // KEY_MACRO
|
||||
-1, // KEY_MUTE
|
||||
-1, // KEY_VOLUMEDOWN
|
||||
-1, // KEY_VOLUMEUP
|
||||
0x7F, // KEY_POWER /* SC System Power Down */
|
||||
0x51, // KEY_KPEQUAL
|
||||
0x4E, // KEY_KPPLUSMINUS
|
||||
-1, // KEY_PAUSE
|
||||
-1, // KEY_SCALE /* AL Compiz Scale (Expose) */
|
||||
0x2B, // KEY_KPCOMMA
|
||||
-1, // KEY_HANGEUL
|
||||
-1, // KEY_HANJA
|
||||
-1, // KEY_YEN
|
||||
0x3A, // KEY_LEFTMETA
|
||||
0x3A, // KEY_RIGHTMETA
|
||||
-1 // KEY_COMPOSE
|
||||
};
|
||||
struct termios org_tio;
|
||||
struct fb_var_screeninfo orig_vinfo;
|
||||
struct fb_var_screeninfo vinfo;
|
||||
struct fb_fix_screeninfo finfo;
|
||||
int pix_size, g_screen_mdepth, g_use_shmem = 1;
|
||||
#define MOUSE_LBTN_DOWN 0x01
|
||||
#define MOUSE_MBTN_DOWN 0x02
|
||||
#define MOUSE_RBTN_DOWN 0x04
|
||||
#define MOUSE_LBTN_UP 0x00
|
||||
#define MOUSE_MBTN_UP 0x00
|
||||
#define MOUSE_RBTN_UP 0x00
|
||||
#define MOUSE_BTN_ACTIVE 0x07
|
||||
#define UPDATE_INPUT_MOUSE 0x10
|
||||
int pix_size, g_screen_mdepth, g_use_shmem = 1;
|
||||
#define MOUSE_LBTN_DOWN 0x01
|
||||
#define MOUSE_MBTN_DOWN 0x02
|
||||
#define MOUSE_RBTN_DOWN 0x04
|
||||
#define MOUSE_LBTN_UP 0x00
|
||||
#define MOUSE_MBTN_UP 0x00
|
||||
#define MOUSE_RBTN_UP 0x00
|
||||
#define MOUSE_BTN_ACTIVE 0x07
|
||||
#define UPDATE_INPUT_MOUSE 0x10
|
||||
#define MAX_EVDEV 8
|
||||
char *fb_ptr, g_inputstate = 0;
|
||||
int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0;
|
||||
int evfd[MAX_EVDEV], evdevs, termfd, fbfd = 0;
|
||||
/*
|
||||
* Clean up
|
||||
*/
|
||||
void xdriver_end(void)
|
||||
{
|
||||
char c;
|
||||
static char xexit = 0;
|
||||
if (!xexit)
|
||||
void xdriver_end(void) {
|
||||
char c;
|
||||
static char xexit = 0;
|
||||
if (!xexit)
|
||||
{
|
||||
// cleanup
|
||||
munmap(fb_ptr, finfo.smem_len);
|
||||
ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo);
|
||||
close(fbfd);
|
||||
if (termfd > 0)
|
||||
{
|
||||
// cleanup
|
||||
munmap(fb_ptr, finfo.smem_len);
|
||||
ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo);
|
||||
close(fbfd);
|
||||
if (termfd > 0)
|
||||
{
|
||||
// Flush input
|
||||
while (read(termfd, &c, 1) == 1);
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
tcsetattr(termfd, TCSANOW, &org_tio);
|
||||
close(termfd);
|
||||
}
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
while (evdevs--)
|
||||
close(evfd[evdevs]);
|
||||
xexit = 1;
|
||||
// Flush input
|
||||
while (read(termfd, &c, 1) == 1);
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
tcsetattr(termfd, TCSANOW, &org_tio);
|
||||
close(termfd);
|
||||
}
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
while (evdevs--)
|
||||
close(evfd[evdevs]);
|
||||
xexit = 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Init framebuffer and input
|
||||
*/
|
||||
void dev_video_init(void)
|
||||
{
|
||||
int i;
|
||||
char evdevname[20];
|
||||
struct termios termio;
|
||||
void dev_video_init(void) {
|
||||
int i;
|
||||
char evdevname[20];
|
||||
struct termios termio;
|
||||
|
||||
// Set graphics mode on console
|
||||
if ((termfd = open("/dev/tty", O_RDWR)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error opening tty device.\n");
|
||||
exit(-1);
|
||||
}
|
||||
// Save input settings.
|
||||
tcgetattr(termfd, &termio); /* save current port settings */
|
||||
memcpy(&org_tio, &termio, sizeof(struct termios));
|
||||
ioctl(termfd, KDSETMODE, KD_GRAPHICS);
|
||||
// Open the file for reading and writing
|
||||
if ((fbfd = open("/dev/fb0", O_RDWR)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error opening framebuffer device.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Get variable screen information
|
||||
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
|
||||
{
|
||||
fprintf(stderr, "Error reading variable screen information.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Store for reset(copy vinfo to vinfo_orig)
|
||||
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
|
||||
// Change variable info
|
||||
//vinfo.bits_per_pixel = 8;
|
||||
// Change resolution
|
||||
vinfo.xres = 640;
|
||||
vinfo.yres = 400;
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
|
||||
{
|
||||
fprintf(stderr, "Error setting variable screen information (640x400x8).\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Get fixed screen information
|
||||
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
|
||||
{
|
||||
fprintf(stderr, "Error reading fixed screen information.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// map fb to user mem
|
||||
fb_ptr = (char*)mmap(0,
|
||||
finfo.smem_len,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fbfd,
|
||||
0);
|
||||
if ((int)fb_ptr == -1)
|
||||
{
|
||||
printf("Failed to mmap framebuffer.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit (-1);
|
||||
}
|
||||
g_screen_depth = vinfo.bits_per_pixel;
|
||||
g_screen_mdepth = g_screen_depth;
|
||||
if (g_screen_depth > 8)
|
||||
g_screen_mdepth = 16;
|
||||
if (g_screen_depth > 16)
|
||||
g_screen_mdepth = 32;
|
||||
pix_size = g_screen_mdepth / 8;
|
||||
if (vinfo.bits_per_pixel > 8)
|
||||
{
|
||||
g_red_mask = (1 << vinfo.red.length) - 1;
|
||||
g_green_mask = (1 << vinfo.green.length) - 1;
|
||||
g_blue_mask = (1 << vinfo.blue.length) - 1;
|
||||
g_red_left_shift = vinfo.red.offset;
|
||||
g_green_left_shift = vinfo.green.offset;
|
||||
g_blue_left_shift = vinfo.blue.offset;
|
||||
g_red_right_shift = 8 - vinfo.red.length;
|
||||
g_green_right_shift = 8 - vinfo.green.length;
|
||||
g_blue_right_shift = 8 - vinfo.blue.length;
|
||||
}
|
||||
video_get_kimages();
|
||||
if (g_screen_depth > 8)
|
||||
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
video_update_color_raw(i, g_lores_colors[i & 0xf]);
|
||||
g_a2palette_8to1624[i] = g_palette_8to1624[i];
|
||||
}
|
||||
fclose(stdin);
|
||||
freopen("gsport.log", "w+", stdout);
|
||||
freopen("gsport.err", "w+", stderr);
|
||||
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
|
||||
termio.c_iflag = IGNPAR;
|
||||
termio.c_oflag = 0;
|
||||
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
|
||||
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
|
||||
termio.c_cc[VMIN] = 0; /* non-blocking read */
|
||||
tcsetattr(termfd, TCSANOW, &termio);
|
||||
// Open input event devices
|
||||
for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++)
|
||||
{
|
||||
sprintf(evdevname, "/dev/input/event%c", evdevs + '0');
|
||||
if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0)
|
||||
break;
|
||||
}
|
||||
g_video_act_margin_left = 0;
|
||||
g_video_act_margin_right = 1;
|
||||
g_video_act_margin_top = 0;
|
||||
g_video_act_margin_bottom = 0;
|
||||
// Set graphics mode on console
|
||||
if ((termfd = open("/dev/tty", O_RDWR)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error opening tty device.\n");
|
||||
exit(-1);
|
||||
}
|
||||
// Save input settings.
|
||||
tcgetattr(termfd, &termio); /* save current port settings */
|
||||
memcpy(&org_tio, &termio, sizeof(struct termios));
|
||||
ioctl(termfd, KDSETMODE, KD_GRAPHICS);
|
||||
// Open the file for reading and writing
|
||||
if ((fbfd = open("/dev/fb0", O_RDWR)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error opening framebuffer device.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Get variable screen information
|
||||
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
|
||||
{
|
||||
fprintf(stderr, "Error reading variable screen information.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Store for reset(copy vinfo to vinfo_orig)
|
||||
memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
|
||||
// Change variable info
|
||||
//vinfo.bits_per_pixel = 8;
|
||||
// Change resolution
|
||||
vinfo.xres = 640;
|
||||
vinfo.yres = 400;
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
|
||||
{
|
||||
fprintf(stderr, "Error setting variable screen information (640x400x8).\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// Get fixed screen information
|
||||
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
|
||||
{
|
||||
fprintf(stderr, "Error reading fixed screen information.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit(-1);
|
||||
}
|
||||
// map fb to user mem
|
||||
fb_ptr = (char*)mmap(0,
|
||||
finfo.smem_len,
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED,
|
||||
fbfd,
|
||||
0);
|
||||
if ((int)fb_ptr == -1)
|
||||
{
|
||||
printf("Failed to mmap framebuffer.\n");
|
||||
ioctl(termfd, KDSETMODE, KD_TEXT);
|
||||
exit (-1);
|
||||
}
|
||||
g_screen_depth = vinfo.bits_per_pixel;
|
||||
g_screen_mdepth = g_screen_depth;
|
||||
if (g_screen_depth > 8)
|
||||
g_screen_mdepth = 16;
|
||||
if (g_screen_depth > 16)
|
||||
g_screen_mdepth = 32;
|
||||
pix_size = g_screen_mdepth / 8;
|
||||
if (vinfo.bits_per_pixel > 8)
|
||||
{
|
||||
g_red_mask = (1 << vinfo.red.length) - 1;
|
||||
g_green_mask = (1 << vinfo.green.length) - 1;
|
||||
g_blue_mask = (1 << vinfo.blue.length) - 1;
|
||||
g_red_left_shift = vinfo.red.offset;
|
||||
g_green_left_shift = vinfo.green.offset;
|
||||
g_blue_left_shift = vinfo.blue.offset;
|
||||
g_red_right_shift = 8 - vinfo.red.length;
|
||||
g_green_right_shift = 8 - vinfo.green.length;
|
||||
g_blue_right_shift = 8 - vinfo.blue.length;
|
||||
}
|
||||
video_get_kimages();
|
||||
if (g_screen_depth > 8)
|
||||
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
video_update_color_raw(i, g_lores_colors[i & 0xf]);
|
||||
g_a2palette_8to1624[i] = g_palette_8to1624[i];
|
||||
}
|
||||
fclose(stdin);
|
||||
freopen("gsport.log", "w+", stdout);
|
||||
freopen("gsport.err", "w+", stderr);
|
||||
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
|
||||
termio.c_iflag = IGNPAR;
|
||||
termio.c_oflag = 0;
|
||||
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
|
||||
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
|
||||
termio.c_cc[VMIN] = 0; /* non-blocking read */
|
||||
tcsetattr(termfd, TCSANOW, &termio);
|
||||
// Open input event devices
|
||||
for (evdevs = 0; evdevs < MAX_EVDEV; evdevs++)
|
||||
{
|
||||
sprintf(evdevname, "/dev/input/event%c", evdevs + '0');
|
||||
if ((evfd[evdevs] = open(evdevname, O_RDONLY|O_NONBLOCK)) < 0)
|
||||
break;
|
||||
}
|
||||
g_video_act_margin_left = 0;
|
||||
g_video_act_margin_right = 1;
|
||||
g_video_act_margin_top = 0;
|
||||
g_video_act_margin_bottom = 0;
|
||||
}
|
||||
/*
|
||||
* Colormap
|
||||
*/
|
||||
__u16 cmapred[256], cmapgreen[256], cmapblue[256];
|
||||
int cmapstart, cmaplen, cmapdirty = 0;
|
||||
void x_update_color(int col_num, int red, int green, int blue, word32 rgb)
|
||||
{
|
||||
cmapred[col_num] = red | (red << 8);
|
||||
cmapgreen[col_num] = green | (green << 8);
|
||||
cmapblue[col_num] = blue | (blue << 8);
|
||||
if (cmapdirty == 0)
|
||||
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) {
|
||||
cmapred[col_num] = red | (red << 8);
|
||||
cmapgreen[col_num] = green | (green << 8);
|
||||
cmapblue[col_num] = blue | (blue << 8);
|
||||
if (cmapdirty == 0)
|
||||
{
|
||||
cmapstart = col_num;
|
||||
cmaplen = 1;
|
||||
cmapdirty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col_num < cmapstart)
|
||||
{
|
||||
cmapstart = col_num;
|
||||
cmaplen = 1;
|
||||
cmapdirty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (col_num < cmapstart)
|
||||
{
|
||||
cmaplen += cmapstart - col_num;
|
||||
cmapstart = col_num;
|
||||
}
|
||||
else if (col_num > cmapstart + cmaplen)
|
||||
cmaplen = col_num - cmapstart + 1;
|
||||
cmaplen += cmapstart - col_num;
|
||||
cmapstart = col_num;
|
||||
}
|
||||
else if (col_num > cmapstart + cmaplen)
|
||||
cmaplen = col_num - cmapstart + 1;
|
||||
}
|
||||
}
|
||||
void x_update_physical_colormap(void)
|
||||
{
|
||||
struct fb_cmap fbcol;
|
||||
if (cmapdirty)
|
||||
{
|
||||
cmapdirty = 0;
|
||||
fbcol.start = cmapstart;
|
||||
fbcol.len = cmaplen;
|
||||
fbcol.red = cmapred;
|
||||
fbcol.green = cmapgreen;
|
||||
fbcol.blue = cmapblue;
|
||||
fbcol.transp = NULL;
|
||||
ioctl(fbfd, FBIOPUTCMAP, &fbcol);
|
||||
}
|
||||
void x_update_physical_colormap(void) {
|
||||
struct fb_cmap fbcol;
|
||||
if (cmapdirty)
|
||||
{
|
||||
cmapdirty = 0;
|
||||
fbcol.start = cmapstart;
|
||||
fbcol.len = cmaplen;
|
||||
fbcol.red = cmapred;
|
||||
fbcol.green = cmapgreen;
|
||||
fbcol.blue = cmapblue;
|
||||
fbcol.transp = NULL;
|
||||
ioctl(fbfd, FBIOPUTCMAP, &fbcol);
|
||||
}
|
||||
}
|
||||
void show_xcolor_array(void)
|
||||
{
|
||||
void show_xcolor_array(void) {
|
||||
}
|
||||
/*
|
||||
* Screen update
|
||||
*/
|
||||
void x_get_kimage(Kimage *kimage_ptr)
|
||||
{
|
||||
kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8);
|
||||
void x_get_kimage(Kimage *kimage_ptr) {
|
||||
kimage_ptr->data_ptr = (byte *)malloc(kimage_ptr->width_req * kimage_ptr->height * kimage_ptr->mdepth / 8);
|
||||
}
|
||||
void x_release_kimage(Kimage* kimage_ptr)
|
||||
{
|
||||
if (kimage_ptr->data_ptr)
|
||||
if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400)
|
||||
free(kimage_ptr->data_ptr);
|
||||
kimage_ptr->data_ptr = NULL;
|
||||
void x_release_kimage(Kimage* kimage_ptr) {
|
||||
if (kimage_ptr->data_ptr)
|
||||
if (kimage_ptr->width_req != 640 || kimage_ptr->height != 400)
|
||||
free(kimage_ptr->data_ptr);
|
||||
kimage_ptr->data_ptr = NULL;
|
||||
}
|
||||
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height)
|
||||
{
|
||||
byte *src_ptr, *dst_ptr;
|
||||
void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height) {
|
||||
byte *src_ptr, *dst_ptr;
|
||||
|
||||
// Copy sub-image to framebuffer
|
||||
dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size;
|
||||
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size;
|
||||
width *= pix_size;
|
||||
while (height--)
|
||||
{
|
||||
memcpy(dst_ptr, src_ptr, width);
|
||||
dst_ptr += finfo.line_length;
|
||||
src_ptr += kimage_ptr->width_act * pix_size;
|
||||
}
|
||||
// Copy sub-image to framebuffer
|
||||
dst_ptr = (byte *)fb_ptr + desty * finfo.line_length + destx * pix_size;
|
||||
src_ptr = kimage_ptr->data_ptr + (srcy * kimage_ptr->width_act + srcx) * pix_size;
|
||||
width *= pix_size;
|
||||
while (height--)
|
||||
{
|
||||
memcpy(dst_ptr, src_ptr, width);
|
||||
dst_ptr += finfo.line_length;
|
||||
src_ptr += kimage_ptr->width_act * pix_size;
|
||||
}
|
||||
}
|
||||
void x_push_done(void)
|
||||
{
|
||||
void x_push_done(void) {
|
||||
}
|
||||
/*
|
||||
* NOP routines
|
||||
*/
|
||||
void x_dialog_create_gsport_conf(const char *str)
|
||||
{
|
||||
// Just write the config file already...
|
||||
config_write_config_gsplus_file();
|
||||
void x_dialog_create_gsport_conf(const char *str) {
|
||||
// Just write the config file already...
|
||||
config_write_config_gsplus_file();
|
||||
}
|
||||
int x_show_alert(int is_fatal, const char *str)
|
||||
{
|
||||
// Not implemented yet
|
||||
adb_all_keys_up();
|
||||
clear_fatal_logs();
|
||||
return 0;
|
||||
int x_show_alert(int is_fatal, const char *str) {
|
||||
// Not implemented yet
|
||||
adb_all_keys_up();
|
||||
clear_fatal_logs();
|
||||
return 0;
|
||||
}
|
||||
void x_toggle_status_lines(void)
|
||||
{
|
||||
void x_toggle_status_lines(void) {
|
||||
}
|
||||
void x_redraw_status_lines(void)
|
||||
{
|
||||
void x_redraw_status_lines(void) {
|
||||
}
|
||||
void x_hide_pointer(int do_hide)
|
||||
{
|
||||
void x_hide_pointer(int do_hide) {
|
||||
}
|
||||
void x_auto_repeat_on(int must)
|
||||
{
|
||||
void x_auto_repeat_on(int must) {
|
||||
}
|
||||
void x_full_screen(int do_full)
|
||||
{
|
||||
void x_full_screen(int do_full) {
|
||||
}
|
||||
int x_calc_ratio(float x, float y)
|
||||
{
|
||||
return 1;
|
||||
int x_calc_ratio(float x, float y) {
|
||||
return 1;
|
||||
}
|
||||
void clipboard_paste(void)
|
||||
{
|
||||
void clipboard_paste(void) {
|
||||
}
|
||||
int clipboard_get_char(void)
|
||||
{
|
||||
return 0;
|
||||
int clipboard_get_char(void) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Input handling
|
||||
*/
|
||||
void check_input_events(void)
|
||||
{
|
||||
struct input_event ev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < evdevs; i++)
|
||||
// Check input events
|
||||
while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event))
|
||||
{
|
||||
if (ev.type == EV_REL)
|
||||
{
|
||||
if (ev.code == REL_X)
|
||||
{
|
||||
g_mouse_raw_x += ev.value;
|
||||
if (g_mouse_raw_x < 0)
|
||||
g_mouse_raw_x = 0;
|
||||
if (g_mouse_raw_x > 639)
|
||||
g_mouse_raw_x = 639;
|
||||
}
|
||||
else // REL_Y
|
||||
{
|
||||
g_mouse_raw_y += ev.value;
|
||||
if (g_mouse_raw_y < 0)
|
||||
g_mouse_raw_y = 0;
|
||||
if (g_mouse_raw_y > 399)
|
||||
g_mouse_raw_y = 399;
|
||||
}
|
||||
g_inputstate |= UPDATE_INPUT_MOUSE;
|
||||
}
|
||||
else if (ev.type == EV_KEY)
|
||||
{
|
||||
if (ev.code < 128)
|
||||
{
|
||||
void check_input_events(void) {
|
||||
struct input_event ev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < evdevs; i++)
|
||||
// Check input events
|
||||
while (read(evfd[i], &ev, sizeof(struct input_event)) == sizeof(struct input_event))
|
||||
{
|
||||
if (ev.type == EV_REL)
|
||||
{
|
||||
if (ev.code == REL_X)
|
||||
{
|
||||
g_mouse_raw_x += ev.value;
|
||||
if (g_mouse_raw_x < 0)
|
||||
g_mouse_raw_x = 0;
|
||||
if (g_mouse_raw_x > 639)
|
||||
g_mouse_raw_x = 639;
|
||||
}
|
||||
else // REL_Y
|
||||
{
|
||||
g_mouse_raw_y += ev.value;
|
||||
if (g_mouse_raw_y < 0)
|
||||
g_mouse_raw_y = 0;
|
||||
if (g_mouse_raw_y > 399)
|
||||
g_mouse_raw_y = 399;
|
||||
}
|
||||
g_inputstate |= UPDATE_INPUT_MOUSE;
|
||||
}
|
||||
else if (ev.type == EV_KEY)
|
||||
{
|
||||
if (ev.code < 128)
|
||||
{
|
||||
#if 0
|
||||
if ((ev.code == KEY_F10) && SHIFT_DOWN)
|
||||
{
|
||||
//quitEmulator();
|
||||
iwm_shut();
|
||||
xdriver_end();
|
||||
my_exit(1);
|
||||
}
|
||||
if ((ev.code == KEY_F10) && SHIFT_DOWN)
|
||||
{
|
||||
//quitEmulator();
|
||||
iwm_shut();
|
||||
xdriver_end();
|
||||
my_exit(1);
|
||||
}
|
||||
#endif
|
||||
if (keycode_to_a2code[ev.code] >= 0)
|
||||
adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value);
|
||||
}
|
||||
else if (ev.code == BTN_LEFT)
|
||||
{
|
||||
g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN
|
||||
: UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP;
|
||||
}
|
||||
}
|
||||
else if (ev.type == EV_SYN)
|
||||
{
|
||||
if (g_inputstate & UPDATE_INPUT_MOUSE)
|
||||
update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE);
|
||||
g_inputstate &= ~UPDATE_INPUT_MOUSE;
|
||||
}
|
||||
}
|
||||
if (keycode_to_a2code[ev.code] >= 0)
|
||||
adb_physical_key_update(keycode_to_a2code[ev.code], !ev.value);
|
||||
}
|
||||
else if (ev.code == BTN_LEFT)
|
||||
{
|
||||
g_inputstate = ev.value ? UPDATE_INPUT_MOUSE | MOUSE_LBTN_DOWN
|
||||
: UPDATE_INPUT_MOUSE | MOUSE_LBTN_UP;
|
||||
}
|
||||
}
|
||||
else if (ev.type == EV_SYN)
|
||||
{
|
||||
if (g_inputstate & UPDATE_INPUT_MOUSE)
|
||||
update_mouse(g_mouse_raw_x, g_mouse_raw_y, g_inputstate & MOUSE_BTN_ACTIVE, MOUSE_BTN_ACTIVE);
|
||||
g_inputstate &= ~UPDATE_INPUT_MOUSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void sig_bye(int signo)
|
||||
{
|
||||
xdriver_end();
|
||||
exit (-1);
|
||||
static void sig_bye(int signo) {
|
||||
xdriver_end();
|
||||
exit (-1);
|
||||
}
|
||||
/*
|
||||
* Application entrypoint
|
||||
*/
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if (signal(SIGINT, sig_bye) == SIG_ERR)
|
||||
exit(-1);
|
||||
if (signal(SIGHUP, sig_bye) == SIG_ERR)
|
||||
exit(-1);
|
||||
gsplusmain(argc, argv);
|
||||
xdriver_end();
|
||||
return 0;
|
||||
int main(int argc,char *argv[]) {
|
||||
if (signal(SIGINT, sig_bye) == SIG_ERR)
|
||||
exit(-1);
|
||||
if (signal(SIGHUP, sig_bye) == SIG_ERR)
|
||||
exit(-1);
|
||||
gsplusmain(argc, argv);
|
||||
xdriver_end();
|
||||
return 0;
|
||||
}
|
||||
|
26
src/fix_mac_menu.m
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
void fix_mac_menu(void) {
|
||||
|
||||
/*
|
||||
* add an option-key modifier to all menu shortcuts
|
||||
* eg, command-Q -> option+command-Q
|
||||
*/
|
||||
|
||||
@autoreleasepool {
|
||||
if (NSApp) {
|
||||
NSMenu *menu = [NSApp mainMenu];
|
||||
|
||||
for (NSMenuItem *a in [menu itemArray]) {
|
||||
for (NSMenuItem *b in [[a submenu] itemArray]) {
|
||||
unsigned m = [b keyEquivalentModifierMask];
|
||||
if (m & NSEventModifierFlagCommand)
|
||||
[b setKeyEquivalentModifierMask: m | NSEventModifierFlagOption];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
182
src/fst.h
Normal file
@ -0,0 +1,182 @@
|
||||
/* generated on Tue Oct 18 20:54:09 2016 */
|
||||
|
||||
#define GSString255_length 0
|
||||
#define GSString255_text 2
|
||||
|
||||
#define GSString32_length 0
|
||||
#define GSString32_text 2
|
||||
|
||||
#define ResultBuf255_bufSize 0
|
||||
#define ResultBuf255_bufString 2
|
||||
|
||||
#define ResultBuf32_bufSize 0
|
||||
#define ResultBuf32_bufString 2
|
||||
|
||||
#define TimeRec_second 0
|
||||
#define TimeRec_minute 1
|
||||
#define TimeRec_hour 2
|
||||
#define TimeRec_year 3
|
||||
#define TimeRec_day 4
|
||||
#define TimeRec_month 5
|
||||
#define TimeRec_extra 6
|
||||
#define TimeRec_weekDay 7
|
||||
|
||||
#define CreateRecGS_pCount 0
|
||||
#define CreateRecGS_pathname 2
|
||||
#define CreateRecGS_access 6
|
||||
#define CreateRecGS_fileType 8
|
||||
#define CreateRecGS_auxType 10
|
||||
#define CreateRecGS_storageType 14
|
||||
#define CreateRecGS_eof 16
|
||||
#define CreateRecGS_resourceEOF 20
|
||||
|
||||
#define CreateRec_pathname 0
|
||||
#define CreateRec_fAccess 4
|
||||
#define CreateRec_fileType 6
|
||||
#define CreateRec_auxType 8
|
||||
#define CreateRec_storageType 12
|
||||
#define CreateRec_createDate 14
|
||||
#define CreateRec_createTime 16
|
||||
|
||||
#define DirEntryRecGS_pCount 0
|
||||
#define DirEntryRecGS_refNum 2
|
||||
#define DirEntryRecGS_flags 4
|
||||
#define DirEntryRecGS_base 6
|
||||
#define DirEntryRecGS_displacement 8
|
||||
#define DirEntryRecGS_name 10
|
||||
#define DirEntryRecGS_entryNum 14
|
||||
#define DirEntryRecGS_fileType 16
|
||||
#define DirEntryRecGS_eof 18
|
||||
#define DirEntryRecGS_blockCount 22
|
||||
#define DirEntryRecGS_createDateTime 26
|
||||
#define DirEntryRecGS_modDateTime 34
|
||||
#define DirEntryRecGS_access 42
|
||||
#define DirEntryRecGS_auxType 44
|
||||
#define DirEntryRecGS_fileSysID 48
|
||||
#define DirEntryRecGS_optionList 50
|
||||
#define DirEntryRecGS_resourceEOF 54
|
||||
#define DirEntryRecGS_resourceBlocks 58
|
||||
|
||||
#define DirEntryRec_refNum 0
|
||||
#define DirEntryRec_flags 2
|
||||
#define DirEntryRec_base 4
|
||||
#define DirEntryRec_displacement 6
|
||||
#define DirEntryRec_nameBuffer 8
|
||||
#define DirEntryRec_entryNum 12
|
||||
#define DirEntryRec_fileType 14
|
||||
#define DirEntryRec_endOfFile 16
|
||||
#define DirEntryRec_blockCount 20
|
||||
#define DirEntryRec_createTime 24
|
||||
#define DirEntryRec_modTime 32
|
||||
#define DirEntryRec_access 40
|
||||
#define DirEntryRec_auxType 42
|
||||
#define DirEntryRec_fileSysID 46
|
||||
|
||||
#define FileInfoRecGS_pCount 0
|
||||
#define FileInfoRecGS_pathname 2
|
||||
#define FileInfoRecGS_access 6
|
||||
#define FileInfoRecGS_fileType 8
|
||||
#define FileInfoRecGS_auxType 10
|
||||
#define FileInfoRecGS_storageType 14
|
||||
#define FileInfoRecGS_createDateTime 16
|
||||
#define FileInfoRecGS_modDateTime 24
|
||||
#define FileInfoRecGS_optionList 32
|
||||
#define FileInfoRecGS_eof 36
|
||||
#define FileInfoRecGS_blocksUsed 40
|
||||
#define FileInfoRecGS_resourceEOF 44
|
||||
#define FileInfoRecGS_resourceBlocks 48
|
||||
|
||||
#define FileRec_pathname 0
|
||||
#define FileRec_fAccess 4
|
||||
#define FileRec_fileType 6
|
||||
#define FileRec_auxType 8
|
||||
#define FileRec_storageType 12
|
||||
#define FileRec_createDate 14
|
||||
#define FileRec_createTime 16
|
||||
#define FileRec_modDate 18
|
||||
#define FileRec_modTime 20
|
||||
#define FileRec_blocksUsed 22
|
||||
|
||||
#define OpenRecGS_pCount 0
|
||||
#define OpenRecGS_refNum 2
|
||||
#define OpenRecGS_pathname 4
|
||||
#define OpenRecGS_requestAccess 8
|
||||
#define OpenRecGS_resourceNumber 10
|
||||
#define OpenRecGS_access 12
|
||||
#define OpenRecGS_fileType 14
|
||||
#define OpenRecGS_auxType 16
|
||||
#define OpenRecGS_storageType 20
|
||||
#define OpenRecGS_createDateTime 22
|
||||
#define OpenRecGS_modDateTime 30
|
||||
#define OpenRecGS_optionList 38
|
||||
#define OpenRecGS_eof 42
|
||||
#define OpenRecGS_blocksUsed 46
|
||||
#define OpenRecGS_resourceEOF 50
|
||||
#define OpenRecGS_resourceBlocks 54
|
||||
|
||||
#define OpenRec_openRefNum 0
|
||||
#define OpenRec_openPathname 2
|
||||
#define OpenRec_ioBuffer 6
|
||||
|
||||
#define VolumeRecGS_pCount 0
|
||||
#define VolumeRecGS_devName 2
|
||||
#define VolumeRecGS_volName 6
|
||||
#define VolumeRecGS_totalBlocks 10
|
||||
#define VolumeRecGS_freeBlocks 14
|
||||
#define VolumeRecGS_fileSysID 18
|
||||
#define VolumeRecGS_blockSize 20
|
||||
#define VolumeRecGS_characteristics 22
|
||||
#define VolumeRecGS_deviceID 24
|
||||
|
||||
#define VolumeRec_deviceName 0
|
||||
#define VolumeRec_volName 4
|
||||
#define VolumeRec_totalBlocks 8
|
||||
#define VolumeRec_freeBlocks 12
|
||||
#define VolumeRec_fileSysID 16
|
||||
|
||||
#define JudgeNameRecGS_pCount 0
|
||||
#define JudgeNameRecGS_fileSysID 2
|
||||
#define JudgeNameRecGS_nameType 4
|
||||
#define JudgeNameRecGS_syntax 6
|
||||
#define JudgeNameRecGS_maxLen 10
|
||||
#define JudgeNameRecGS_name 12
|
||||
#define JudgeNameRecGS_nameFlags 16
|
||||
|
||||
#define PositionRecGS_pCount 0
|
||||
#define PositionRecGS_refNum 2
|
||||
#define PositionRecGS_position 4
|
||||
|
||||
#define MarkRec_markRefNum 0
|
||||
#define MarkRec_position 2
|
||||
|
||||
#define EOFRecGS_pCount 0
|
||||
#define EOFRecGS_refNum 2
|
||||
#define EOFRecGS_eof 4
|
||||
|
||||
#define EOFRec_eofRefNum 0
|
||||
#define EOFRec_eofPosition 2
|
||||
|
||||
#define IORecGS_pCount 0
|
||||
#define IORecGS_refNum 2
|
||||
#define IORecGS_dataBuffer 4
|
||||
#define IORecGS_requestCount 8
|
||||
#define IORecGS_transferCount 12
|
||||
#define IORecGS_cachePriority 16
|
||||
|
||||
#define FileIORec_fileRefNum 0
|
||||
#define FileIORec_dataBuffer 2
|
||||
#define FileIORec_requestCount 6
|
||||
#define FileIORec_transferCount 10
|
||||
|
||||
#define SetPositionRecGS_pCount 0
|
||||
#define SetPositionRecGS_refNum 2
|
||||
#define SetPositionRecGS_base 4
|
||||
#define SetPositionRecGS_displacement 6
|
||||
|
||||
#define DevNumRecGS_pCount 0
|
||||
#define DevNumRecGS_devName 2
|
||||
#define DevNumRecGS_devNum 6
|
||||
|
||||
#define DevNumRec_devName 0
|
||||
#define DevNumRec_devNum 4
|
||||
|
47
src/glog.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "glog.h"
|
||||
|
||||
int glog(const char *s) {
|
||||
time_t timer;
|
||||
char buffer[26];
|
||||
struct tm* tm_info;
|
||||
|
||||
time(&timer);
|
||||
tm_info = localtime(&timer);
|
||||
|
||||
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
printf("%s - %s\n", buffer, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int glogf(const char *fmt, ...) {
|
||||
|
||||
time_t timer;
|
||||
char buffer[26];
|
||||
struct tm* tm_info;
|
||||
|
||||
time(&timer);
|
||||
tm_info = localtime(&timer);
|
||||
|
||||
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
printf("%s - ", buffer);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stdout);
|
||||
return 0;
|
||||
}
|
8
src/glog.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int glog(const char *s);
|
||||
int glogf(const char *s, ...);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
164
src/gsos.h
Normal file
@ -0,0 +1,164 @@
|
||||
#define readEnableAllowWrite 0x0000
|
||||
#define readEnable 0x0001
|
||||
#define writeEnable 0x0002
|
||||
#define readWriteEnable 0x0003
|
||||
#define fileInvisible 0x0004 /* Invisible bit */
|
||||
#define backupNeeded 0x0020 /* backup needed bit: CreateRec/ OpenRec access field. (Must be 0 in requestAccess field ) */
|
||||
#define renameEnable 0x0040 /* rename enable bit: CreateRec/ OpenRec access and requestAccess fields */
|
||||
#define destroyEnable 0x0080 /* destroy enable bit: CreateRec/ OpenRec access and requestAccess fields */
|
||||
#define startPlus 0x0000 /* base -> setMark = displacement */
|
||||
#define eofMinus 0x0001 /* base -> setMark = eof - displacement */
|
||||
#define markPlus 0x0002 /* base -> setMark = mark + displacement */
|
||||
#define markMinus 0x0003 /* base -> setMark = mark - displacement */
|
||||
|
||||
/* cachePriority Codes */
|
||||
#define cacheOff 0x0000 /* do not cache blocks invloved in this read */
|
||||
#define cacheOn 0x0001 /* cache blocks invloved in this read if possible */
|
||||
|
||||
/* Error Codes */
|
||||
#define badSystemCall 0x0001 /* bad system call number */
|
||||
#define invalidPcount 0x0004 /* invalid parameter count */
|
||||
#define gsosActive 0x0007 /* GS/OS already active */
|
||||
|
||||
#ifndef devNotFound /* device not found */
|
||||
#define devNotFound 0x0010
|
||||
#endif
|
||||
|
||||
#define invalidDevNum 0x0011 /* invalid device number */
|
||||
#define drvrBadReq 0x0020 /* bad request or command */
|
||||
#define drvrBadCode 0x0021 /* bad control or status code */
|
||||
#define drvrBadParm 0x0022 /* bad call parameter */
|
||||
#define drvrNotOpen 0x0023 /* character device not open */
|
||||
#define drvrPriorOpen 0x0024 /* character device already open */
|
||||
#define irqTableFull 0x0025 /* interrupt table full */
|
||||
#define drvrNoResrc 0x0026 /* resources not available */
|
||||
#define drvrIOError 0x0027 /* I/O error */
|
||||
#define drvrNoDevice 0x0028 /* device not connected */
|
||||
#define drvrBusy 0x0029 /* call aborted; driver is busy */
|
||||
#define drvrWrtProt 0x002B /* device is write protected */
|
||||
#define drvrBadCount 0x002C /* invalid byte count */
|
||||
#define drvrBadBlock 0x002D /* invalid block address */
|
||||
#define drvrDiskSwitch 0x002E /* disk has been switched */
|
||||
#define drvrOffLine 0x002F /* device off line/ no media present */
|
||||
#define badPathSyntax 0x0040 /* invalid pathname syntax */
|
||||
#define tooManyFilesOpen 0x0042 /* too many files open on server volume */
|
||||
#define invalidRefNum 0x0043 /* invalid reference number */
|
||||
|
||||
#ifndef pathNotFound /* subdirectory does not exist */
|
||||
#define pathNotFound 0x0044
|
||||
#endif
|
||||
|
||||
#define volNotFound 0x0045 /* volume not found */
|
||||
|
||||
#ifndef fileNotFound /* file not found */
|
||||
#define fileNotFound 0x0046
|
||||
#endif
|
||||
|
||||
#define dupPathname 0x0047 /* create or rename with existing name */
|
||||
#define volumeFull 0x0048 /* volume full error */
|
||||
#define volDirFull 0x0049 /* volume directory full */
|
||||
#define badFileFormat 0x004A /* version error (incompatible file format) */
|
||||
|
||||
#ifndef badStoreType /* unsupported (or incorrect) storage type */
|
||||
#define badStoreType 0x004B
|
||||
#endif
|
||||
|
||||
#ifndef eofEncountered /* end-of-file encountered */
|
||||
#define eofEncountered 0x004C
|
||||
#endif
|
||||
|
||||
#define outOfRange 0x004D /* position out of range */
|
||||
#define invalidAccess 0x004E /* access not allowed */
|
||||
#define buffTooSmall 0x004F /* buffer too small */
|
||||
#define fileBusy 0x0050 /* file is already open */
|
||||
#define dirError 0x0051 /* directory error */
|
||||
#define unknownVol 0x0052 /* unknown volume type */
|
||||
|
||||
#ifndef paramRangeErr /* parameter out of range */
|
||||
#define paramRangeErr 0x0053
|
||||
#endif
|
||||
|
||||
#define outOfMem 0x0054 /* out of memory */
|
||||
#define dupVolume 0x0057 /* duplicate volume name */
|
||||
#define notBlockDev 0x0058 /* not a block device */
|
||||
|
||||
#ifndef invalidLevel /* specifield level outside legal range */
|
||||
#define invalidLevel 0x0059
|
||||
#endif
|
||||
|
||||
#define damagedBitMap 0x005A /* block number too large */
|
||||
#define badPathNames 0x005B /* invalid pathnames for ChangePath */
|
||||
#define notSystemFile 0x005C /* not an executable file */
|
||||
#define osUnsupported 0x005D /* Operating System not supported */
|
||||
|
||||
#ifndef stackOverflow /* too many applications on stack */
|
||||
#define stackOverflow 0x005F
|
||||
#endif
|
||||
|
||||
#define dataUnavail 0x0060 /* Data unavailable */
|
||||
#define endOfDir 0x0061 /* end of directory has been reached */
|
||||
#define invalidClass 0x0062 /* invalid FST call class */
|
||||
#define resForkNotFound 0x0063 /* file does not contain required resource */
|
||||
#define invalidFSTID 0x0064 /* error - FST ID is invalid */
|
||||
#define invalidFSTop 0x0065 /* invalid FST operation */
|
||||
#define fstCaution 0x0066 /* FST handled call, but result is weird */
|
||||
#define devNameErr 0x0067 /* device exists with same name as replacement name */
|
||||
#define defListFull 0x0068 /* device list is full */
|
||||
#define supListFull 0x0069 /* supervisor list is full */
|
||||
#define fstError 0x006a /* generic FST error */
|
||||
#define resExistsErr 0x0070 /* cannot expand file, resource already exists */
|
||||
#define resAddErr 0x0071 /* cannot add resource fork to this type file */
|
||||
#define networkError 0x0088 /* generic network error */
|
||||
|
||||
/* fileSys IDs */
|
||||
#define proDOSFSID 0x0001 /* ProDOS/SOS */
|
||||
#define dos33FSID 0x0002 /* DOS 3.3 */
|
||||
#define dos32FSID 0x0003 /* DOS 3.2 */
|
||||
#define dos31FSID 0x0003 /* DOS 3.1 */
|
||||
#define appleIIPascalFSID 0x0004 /* Apple II Pascal */
|
||||
#define mfsFSID 0x0005 /* Macintosh (flat file system) */
|
||||
#define hfsFSID 0x0006 /* Macintosh (hierarchical file system) */
|
||||
#define lisaFSID 0x0007 /* Lisa file system */
|
||||
#define appleCPMFSID 0x0008 /* Apple CP/M */
|
||||
#define charFSTFSID 0x0009 /* Character FST */
|
||||
#define msDOSFSID 0x000A /* MS/DOS */
|
||||
#define highSierraFSID 0x000B /* High Sierra */
|
||||
#define iso9660FSID 0x000C /* ISO 9660 */
|
||||
#define appleShareFSID 0x000D /* ISO 9660 */
|
||||
|
||||
/* FSTInfo.attributes Codes */
|
||||
#define characterFST 0x4000 /* character FST */
|
||||
#define ucFST 0x8000 /* SCM should upper case pathnames before passing them to the FST */
|
||||
|
||||
/* QuitRec.flags Codes */
|
||||
#define onStack 0x8000 /* place state information about quitting program on the quit return stack */
|
||||
#define restartable 0x4000 /* the quitting program is capable of being restarted from its dormant memory */
|
||||
|
||||
/* storageType Codes */
|
||||
#define seedling 0x0001 /* standard file with seedling structure */
|
||||
#define standardFile 0x0001 /* standard file type (no resource fork) */
|
||||
#define sapling 0x0002 /* standard file with sapling structure */
|
||||
#define tree 0x0003 /* standard file with tree structure */
|
||||
#define pascalRegion 0x0004 /* UCSD Pascal region on a partitioned disk */
|
||||
#define extendedFile 0x0005 /* extended file type (with resource fork) */
|
||||
#define directoryFile 0x000D /* volume directory or subdirectory file */
|
||||
|
||||
/* version Codes */
|
||||
#define minorRelNumMask 0x00FF /* minor release number */
|
||||
#define majorRelNumMask 0x7F00 /* major release number */
|
||||
#define finalRelNumMask 0x8000 /* final release number */
|
||||
|
||||
/* Other Constants */
|
||||
#define isFileExtended 0x8000 /* GetDirEntryGS */
|
||||
|
||||
/* DControl Codes */
|
||||
#define resetDevice 0x0000
|
||||
#define formatDevice 0x0001
|
||||
#define eject 0x0002
|
||||
#define setConfigParameters 0x0003
|
||||
#define setWaitStatus 0x0004
|
||||
#define setFormatOptions 0x0005
|
||||
#define assignPartitionOwner 0x0006
|
||||
#define armSignal 0x0007
|
||||
#define disarmSignal 0x0008
|
||||
#define setPartitionMap 0x0009
|
BIN
src/gsp_icon.ico
Normal file
After Width: | Height: | Size: 70 KiB |
@ -1,24 +1,8 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Copyright (C) 2016 - Dagen Brock
|
||||
|
||||
Copyright (C) 2010 by GSport contributors
|
||||
|
||||
Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
/* char 0x00 (raw 0x40) */
|
||||
|
90
src/headless_driver.c
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
GSPLUS - Advanced Apple IIGS Emulator Environment
|
||||
Based on the KEGS emulator written by Kent Dickey
|
||||
See COPYRIGHT.txt for Copyright information
|
||||
See LICENSE.txt for license (GPL v2)
|
||||
*/
|
||||
|
||||
#include "defc.h"
|
||||
#include "glog.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
return gsplusmain(argc, argv);
|
||||
}
|
||||
|
||||
int g_screen_mdepth = 0;
|
||||
int g_screenshot_requested = 0;
|
||||
int g_use_shmem = 0;
|
||||
|
||||
extern int g_screen_depth;
|
||||
extern word32 g_palette_8to1624[256];
|
||||
extern word32 g_a2palette_8to1624[256];
|
||||
extern Kimage g_mainwin_kimage;
|
||||
extern int g_lores_colors[];
|
||||
|
||||
void check_input_events() {}
|
||||
|
||||
int clipboard_get_char() { return 0; }
|
||||
|
||||
void clipboard_paste(void) { }
|
||||
|
||||
void dev_video_init() {
|
||||
|
||||
g_screen_depth = 24;
|
||||
g_screen_mdepth = 32;
|
||||
video_get_kimages();
|
||||
video_get_kimage(&g_mainwin_kimage, 0, g_screen_depth, g_screen_mdepth);
|
||||
|
||||
for(int i = 0; i < 256; i++) {
|
||||
word32 lores_col = g_lores_colors[i & 0xf];
|
||||
video_update_color_raw(i, lores_col);
|
||||
g_a2palette_8to1624[i] = g_palette_8to1624[i];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void x_dialog_create_gsport_conf(const char *str) { }
|
||||
|
||||
|
||||
int x_show_alert(int is_fatal, const char *str) { return 0; }
|
||||
|
||||
void get_ximage(Kimage *kimage_ptr) { }
|
||||
void x_toggle_status_lines() { }
|
||||
void x_redraw_status_lines() { }
|
||||
void x_hide_pointer(int do_hide) { }
|
||||
void x_auto_repeat_on(int must) { }
|
||||
void x_auto_repeat_off(int must) { }
|
||||
void x_release_kimage(Kimage* kimage_ptr) { }
|
||||
int x_calc_ratio(float x,float y) { return 1; }
|
||||
|
||||
|
||||
void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr) { }
|
||||
void x_update_color(int col_num, int red, int green, int blue, word32 rgb) { }
|
||||
void x_update_physical_colormap() { }
|
||||
void show_xcolor_array() { }
|
||||
void xdriver_end() { }
|
||||
void x_push_done() { }
|
||||
|
||||
void x_full_screen(int do_full) { }
|
||||
|
||||
void
|
||||
x_get_kimage(Kimage *kimage_ptr) {
|
||||
byte *data;
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
|
||||
width = kimage_ptr->width_req;
|
||||
height = kimage_ptr->height;
|
||||
depth = kimage_ptr->depth;
|
||||
data = malloc(width*height*(depth/4));
|
||||
kimage_ptr->data_ptr = data;
|
||||
}
|
||||
|
||||
void
|
||||
x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height)
|
||||
{
|
||||
}
|
1030
src/host_common.c
Normal file
105
src/host_common.h
Normal file
@ -0,0 +1,105 @@
|
||||
enum {
|
||||
file_non,
|
||||
file_regular,
|
||||
file_resource,
|
||||
file_directory,
|
||||
};
|
||||
|
||||
enum {
|
||||
translate_none,
|
||||
translate_crlf,
|
||||
translate_merlin,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct file_info {
|
||||
|
||||
time_t create_date;
|
||||
time_t modified_date;
|
||||
word16 access;
|
||||
word16 storage_type;
|
||||
word16 file_type;
|
||||
word32 aux_type;
|
||||
word32 eof;
|
||||
word32 blocks;
|
||||
word32 resource_eof;
|
||||
word32 resource_blocks;
|
||||
mode_t st_mode;
|
||||
int has_fi;
|
||||
byte finder_info[32];
|
||||
};
|
||||
|
||||
|
||||
extern Engine_reg engine;
|
||||
|
||||
#define SEC() engine.psr |= 0x01
|
||||
#define CLC() engine.psr &= ~0x01
|
||||
#define SEV() engine.psr |= 0x40
|
||||
#define CLV() engine.psr &= ~0x40
|
||||
#define SEZ() engine.psr |= 0x02
|
||||
#define CLZ() engine.psr &= ~0x02
|
||||
#define SEI() engine.psr |= 0x04
|
||||
#define CLI() engine.psr &= ~0x04
|
||||
|
||||
enum {
|
||||
C = 0x01,
|
||||
Z = 0x02,
|
||||
I = 0x04,
|
||||
D = 0x08,
|
||||
X = 0x10,
|
||||
M = 0x20,
|
||||
V = 0x40,
|
||||
N = 0x80
|
||||
};
|
||||
|
||||
extern int g_cfg_host_read_only;
|
||||
extern int g_cfg_host_crlf;
|
||||
extern int g_cfg_host_merlin;
|
||||
extern char *host_root;
|
||||
|
||||
unsigned host_startup(void);
|
||||
void host_shutdown(void);
|
||||
|
||||
int host_is_root(struct stat *);
|
||||
|
||||
/* garbage collected string routines */
|
||||
|
||||
void *host_gc_malloc(size_t size);
|
||||
void host_gc_free(void);
|
||||
char *host_gc_strdup(const char *src);
|
||||
char *host_gc_append_path(const char *a, const char *b);
|
||||
char *host_gc_append_string(const char *a, const char *b);
|
||||
|
||||
/* text conversion */
|
||||
void host_cr_to_lf(byte *buffer, size_t size);
|
||||
void host_lf_to_cr(byte *buffer, size_t size);
|
||||
void host_merlin_to_text(byte *buffer, size_t size);
|
||||
void host_text_to_merlin(byte *buffer, size_t size);
|
||||
|
||||
/* errno -> IIgs/mli error */
|
||||
word32 host_map_errno(int xerrno);
|
||||
word32 host_map_errno_path(int xerrno, const char *path);
|
||||
const char *host_error_name(word16 error);
|
||||
|
||||
/* file info */
|
||||
|
||||
int host_file_type_to_finder_info(byte *buffer, word16 file_type, word32 aux_type);
|
||||
void host_get_file_xinfo(const char *path, struct file_info *fi);
|
||||
word32 host_get_file_info(const char *path, struct file_info *fi);
|
||||
word32 host_set_file_info(const char *path, struct file_info *fi);
|
||||
|
||||
|
||||
void host_set_date_time_rec(word32 ptr, time_t time);
|
||||
void host_set_date_time(word32 ptr, time_t time);
|
||||
|
||||
time_t host_get_date_time(word32 ptr);
|
||||
time_t host_get_date_time_rec(word32 ptr);
|
||||
|
||||
/* convert to prodos date/time */
|
||||
word32 host_convert_date_time(time_t time);
|
||||
|
||||
|
||||
void host_hexdump(word32 address, int size);
|
||||
void host_hexdump_native(void *data, unsigned address, int size);
|
||||
|