#!/bin/bash -ex
# Cross-compilation instructions
# See at the end of the file for human-readable documentation

# Copyright (C) 2009  Sylvain Beucler

# This file is part of GNU FreeDink

# GNU FreeDink 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 3 of the License, or
# (at your option) any later version.

# GNU FreeDink 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, see
# <http://www.gnu.org/licenses/>.


# Time: < 90mn
# Space: < 1.2GB final + temporary ?MB during compilation
#        /usr/local/pspdev = ~180MB

# Super-user commands can be disabled using 'SUDO=: ./cross.sh'
# Idem for wget if you already downloaded the tarballs
SUDO=${SUDO=sudo}
WGET=${WGET=wget}

# The reference material is at pspdev.org
# List of available tools and libraries:
# svn ls svn://svn.pspdev.org/psp/trunk/

mkdir psp
cd psp

# Grab the source from SVN, because the last releases are old
# (2007). It's likely that they don't make proper releases anymore.
svn co svn://svn.pspdev.org/psp/trunk/psptoolchain
pushd psptoolchain

# Create the install directory
$SUDO mkdir /usr/local/pspdev
$SUDO chown `id`: /usr/local/pspdev

# Follow readme-ubuntu.txt:
if ! grep -q PSPDEV ~/.bashrc; then
    cat <<'EOF' >> ~/.bashrc
export PSPDEV="/usr/local/pspdev"
export PSPSDK="$PSPDEV/psp/sdk"
export PATH="$PATH:$PSPDEV/bin:$PSPSDK/bin"
EOF
    # Reload .bashrc:
    .  ~/.bashrc
fi

$SUDO apt-get install build-essential autoconf automake bison flex \
  libncurses5-dev libreadline5-dev libusb-dev texinfo libgmp3-dev   \
  libmpfr-dev subversion gcc-4.2

# add
#export CC=/usr/bin/gcc-4.2
# in toolchain-sudo.sh

./toolchain-sudo.sh

# Fix-up a couple errors:
# - getopt.h is non-standard (different names for constants)
rm /usr/local/pspdev/psp/include/getopt.h
# - readlink isn't available and prototype is lacking 'unsigned'
sed -i -e 's/.*_EXFUN(readlink.*//' /usr/local/pspdev/psp/include/sys/unistd.h
# - strings.h is missing
echo '#include <string.h>' > /usr/local/pspdev/psp/include/strings.h

popd


# Now compile libraries
# SDL
svn co svn://svn.pspdev.org/psp/trunk/SDL
pushd SDL
# Follow README.PSP:
./autogen.sh
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host psp --prefix=$(psp-config --psp-prefix)
make
make install
popd

# Tremor (SDL_mixer dependency)
svn co svn://svn.pspdev.org/psp/trunk/libTremor
pushd libTremor
# Follow README.PSP:
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" ./autogen.sh \
     --host psp --prefix=$(psp-config --psp-prefix)
make
make install
popd

# SDL_mixer
svn co svn://svn.pspdev.org/psp/trunk/SDL_mixer
pushd SDL_mixer
# Follow README.PSP:
./autogen.sh
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host psp --with-sdl-prefix=$(psp-config --psp-prefix) \
  --disable-music-mp3 --prefix=$(psp-config --psp-prefix) \
  --disable-music-libmikmod --enable-music-mod
make
make install
popd

# libjpeg (SDL_image dependency)
svn co svn://svn.pspdev.org/psp/trunk/jpeg
pushd jpeg
# Follow README.PSP:
make
make install
popd

# zlib (libpng dependency)
svn co svn://svn.pspdev.org/psp/trunk/zlib
pushd zlib
# Follow README.PSP:
make
make install
popd

# libpng (SDL_image dependency)
svn co svn://svn.pspdev.org/psp/trunk/libpng
pushd libpng
# Follow README.PSP:
# (note the presence of example PSP source code)
make
make install
popd

# SDL_image
svn co svn://svn.pspdev.org/psp/trunk/SDL_image
pushd SDL_image
# Follow README.PSP:
./autogen.sh
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host psp --with-sdl-prefix=$(psp-config --psp-prefix) \
  --prefix=$(psp-config --psp-prefix)
make
make install
popd


# FreeType (SDL_ttf dependency)
svn co svn://svn.pspdev.org/psp/trunk/freetype
pushd freetype
# Follow README.PSP:
sh autogen.sh
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
   ./configure --host psp --prefix=$(psp-config --psp-prefix)
make
make install
popd

# SDL_ttf
svn co svn://svn.pspdev.org/psp/trunk/SDL_ttf
pushd SDL_ttf
# Update to 2.0.9 (2.0.7 has a bug with strong style)
# Cf. http://www.libsdl.org/cgi/viewvc.cgi/trunk/SDL_ttf/CHANGES?view=log
$SUDO apt-get --assume-yes install patchutils
svn diff -r 1454:3284 http://svn.libsdl.org/trunk/SDL_ttf/ > 2.0.7-2.0.9.patch
filterdiff -x mkinstalldirs -x missing -x .cvsignore -x install-sh \
  -x config.guess -x config.sub 2.0.7-2.0.9.patch \
  | patch -p0
# Follow README.PSP:
# Note: there's an error with libtool 2, use libtool 1.5
./autogen.sh
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host psp --with-sdl-prefix=$(psp-config --psp-prefix) \
  --with-freetype-prefix=$(psp-config --psp-prefix) \
  --without-x --prefix=$(psp-config --psp-prefix)
make
make install
popd

# SDL_gfx
svn co svn://svn.pspdev.org/psp/trunk/SDL_gfx
pushd SDL_gfx
# Follow README.PSP:
./autogen.sh
AR=psp-ar \
  LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host psp --with-sdl-prefix=$(psp-config --psp-prefix) \
  --prefix=$(psp-config --psp-prefix) --disable-mmx --disable-shared
make
make install
popd


# pkgconfig (used to detect ziplib and zzip in the build system)
VERSION=0.23
cd /usr/src/
$WGET -P depsources/ http://pkgconfig.freedesktop.org/releases/pkg-config-$VERSION.tar.gz
tar xzf depsources/pkg-config-$VERSION.tar.gz
cd pkg-config-$VERSION
./configure --prefix=$(psp-config --psp-prefix)
make
make install-strip
$SUDO ln -nfs $(psp-config --psp-prefix)/bin/pkg-config \
  /usr/local/bin/psp-pkg-config
# or set
# PKG_CONFIG="$PREFIX/bin/pkg-config"

# zziplib
# Currently it crashes at run time, there a 32bit-alignment issue to
# patch:
# http://forums.ps2dev.org/viewtopic.php?p=80775
svn co svn://svn.pspdev.org/psp/trunk/zziplib
pushd zziplib
# Follow README.PSP:
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
   ./configure --host psp --prefix=$(psp-config --psp-prefix) \
     --disable-mmap
make
make install
popd

# libzip
# It doesn't link as there are missing POSIX functions
#VERSION=0.9
#cd /usr/src/
#$WGET -P depsources/ http://www.nih.at/libzip/libzip-$VERSION.tar.gz
#tar xzf depsources/libzip-$VERSION.tar.gz
#cd libzip-$VERSION/
#cp ../SDL_ttf/config.sub ./config.sub  # to support host='psp'
#CPPFLAGS="-I$(psp-config --pspsdk-path)/include" \
#  LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
#  ./configure --host=psp \
#    --prefix=$(psp-config --psp-prefix)
#make
#make install

exit


# FreeDink
mkdir cross-psp && cd cross-psp
# - remove /usr/local/pspdev/psp/include/getopt.h which defines non-standard constants
# - fix /usr/local/pspdev/psp/include/sys/unistd.h: readlink, 3rd argument is "unsigned int" rather then "int"
# '-G0' (up to '-G3', but not '-G4') is needed to avoid errors such as:
#   relocation truncated to fit: R_MIPS_GPREL16 against `__ctype_ptr'
# '-O2' works but '-O0' is the easier to debug; '-O3' works but the executable is bigger than '-O2'
# '--disable-embedded-resources' is optional, but it avoids bundling zziplib
# - use HAVE_PATHCONF in pathmax.h
# - trim fchdir so it doesn't reference dup and dup2
# - alter getcwd so it doesn't use rewinddir
SDL_CONFIG=$(psp-config --psp-prefix)/bin/sdl-config \
  LDFLAGS="-L$(psp-config --pspsdk-path)/lib" \
  LIBS="-lc -lpspuser" \
  CPPFLAGS="-I$(psp-config --pspsdk-path)/include" \
  CFLAGS="-g -O2 -G3" \
  ../configure --host psp \
    --disable-embedded-resources --enable-static --disable-nls
# - edit gnulib/lib/strings.h and get rid of #include_next
make
cd src/
# Cf. /usr/local/pspdev/psp/sdk/lib/build.mak
psp-fixup-imports freedink -o freedink.elf
#mksfo freedink PARAM.SFO
mksfoex -d MEMSIZE=1 $(PSP_EBOOT_TITLE) PARAM.SFO
psp-strip freedink.elf -o freedink_strip.elf
pack-pbp EBOOT.PBP PARAM.SFO NULL  \
		NULL NULL NULL  \
		NULL  freedink_strip.elf NULL
rm -f freedink_strip.elf
# or:
#make && make -f ~/freedink/psp/Makefile.PSP.EBOOT clean all install

# Variant for building a .prx (relocatable, compatible with PSPLink OE):
# (LDFLAGS += -specs=... -Wl-q,-T.../linkfile.prx)
# Optional: CPPFLAGS += "-DPSPFW3X -D_PSP_FW_VERSION=303"
SDL_CONFIG=$(psp-config --psp-prefix)/bin/sdl-config \
  LDFLAGS="-L$(psp-config --pspsdk-path)/lib -specs=/usr/local/pspdev/psp/sdk/lib/prxspecs -Wl,-q,-T/usr/local/pspdev/psp/sdk/lib/linkfile.prx" \
  LIBS="-lc -lpspuser" \
  CPPFLAGS="-I$(psp-config --pspsdk-path)/include -DPSPFW3X -D_PSP_FW_VERSION=303" \
  CFLAGS="-g -O2 -G3" \
  ../configure --host psp \
    --disable-embedded-resources --enable-static --disable-nls
make
cd src/
psp-fixup-imports freedink -o freedink.elf
psp-prxgen freedink.elf freedink.prx  # also strips
pack-pbp ...


# Misc:

# libffi?
VERSION=3.0.8
$WGET ftp://sourceware.org/pub/libffi/libffi-$VERSION.tar.gz
tar xzf libffi-$VERSION.tar.gz
cp .../psp/SDL_ttf/config.sub ./config.sub
mkdir cross-psp && cd cross-psp
LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" CFLAGS="-I$(psp-config --pspsdk-path)/include" \
  ../configure --host psp --prefix=$(psp-config --psp-prefix)
# Patch configure:
#  mipsallegrexel-psp-elf)
#        TARGET=MIPS; TARGETDIR=mips
#        ;;
make
# => doesn't detect architecture properly

# dyncall has PSP binaries, and it mentions it's using "32bit MIPS" +
# a special "eabi" calling convention...
# http://sources.redhat.com/ml/libffi-discuss/2009/msg00014.html

# ...


# log4c
VERSION=1.2.1
$WGET http://prdownloads.sourceforge.net/log4c/log4c-$VERSION.tar.gz
tar xzf log4c-$VERSION.tar.gz
cd log4c-$VERSION
cp ../SDL_ttf/config.sub config/config.sub
CPPFLAGS="-I$(psp-config --pspsdk-path)/include" \
  CFLAGS="-G0" \
  LDFLAGS="-L$(psp-config --pspsdk-path)/lib -lc -lpspuser" \
  ./configure --host=psp \
    --prefix=$(psp-config --psp-prefix) --without-expat
make
# -> error related to missing mmap, I think it just needs to be
#    excluded from the compilation in src/log4c/Makefile.am, as this
#    case is handled in init.c.
#    AM_CONDITIONAL(HAVE_MMAP, test $HAVE_MMAP = 1)
#    + ifdef HAVE_MMAP in src/log4c/Makefile.am
# -> also add a missing #ifdef WITH_ROLLINGFILE in init.c
# -> also remove examples/ from Makefile.am:SUBDIRS, otherwise
#    there're issues with missing rpl_malloc and rpl_realloc
make install

#####

Then you have a classic cross-compilation environment. There's a
PSP-specific post-compilation operation to convert the executable to a
PSP EBOOT.PBP file, as implemented in
/usr/local/pspdev/psp/sdk/lib/build.mak

The SDL version from pspdev can hide all PSP-specific code. Remember
to use -Dmain=SDL_main (or use its `sdl-config --cflags`).

Emulation: you can try "Sam", "Potemkin" (note that it requires "VC++
2005 SP1") and "PSPE". Only "Sam" worked for me, but not fully
(e.g. SDL_GetTicks() was erratic). To run a program, open EBOOT.BPB,
with external media files in the same directory. Beware: Sam allows
the game to remove files from your computer!


Links:
http://ps2dev.org/psp/Tools/Toolchain
- download the latest from their repository

http://gueux-forum.net/index.php?showtopic=77275
- complete tutorial to compile and run an homebrew, from start to finish

http://zx81.zx81.free.fr/serendipity/index.php?/categories/51-Development
- pre-compiled SDKs and GNU/Linux disk images to run in VirtualBox


Docs:

- How to detect PSP firmware version
  Parameters > System Settings > System Information
  e.g.
    3.80 M33-5 -> custom firmware
    3.80 -> official firmware

- Access recovery menu
  * long press on power / suspend (button on the right side)
  * keep R pressed (index finger button on the right)
  * press power button

- How to plug:
  * plug with a standard USB cable, outlet on the top of the PSP
  * go to Parameters -> USB Connection, press X
  * wait a few seconds
  * you can mount /dev/sdb1 like a normal USB reader
  * if this isn't done automatically, use 'pmount /dev/sdb1'
  * pumount /dev/sdb1
  * press [O] on the PSP (don't do that before umounting, there's no
    safety check!!)

- Where to install games:
  * original fat firmware 1.50: 2 directories to install:
    /media/sdb1/PSP/GAME/__SCE__yourgame/EBOOT.PBP
    /media/sdb1/PSP/GAME/%__SCE__yourgame/EBOOT.PBP
  * newer firmware:
    /media/sdb1/PSP/GAME/yourgame/EBOOT.PBP

- Install ScummVM:
  http://wiki.scummvm.org/index.php/PlayStation_Portable
  * cp -a scummvm-0.12.0-psp/single-eboot/scummvm-0.12.0-psp /media/sdb1/PSP/GAME/
  * cp -a bass /media/sdb1/
  * mv /media/sdb1/PSP/GAME/scummvm-0.12.0-psp/sky.cpt /media/sdb1/bass/
  => trouble with v0.13 in some situations, try v0.12 or a snapshot in
  that case http://forums.scummvm.org/viewtopic.php?t=6975

- All releases from Dark_Alex: http://alek.dark-alex.org/filez/dax/
  (the link isn't available from the homepage)

- Create a Pandora Battery - http://www.freedink.org/doc/psp/
  http://www.pspgen.com/despertar-del-cementerio-debricker-downgrade-custom-firmware-article-184615-4.html
  * Install HellCat's Pandora Installer R4b (GPL)
    http://forums.qj.net/showthread.php?t=122449
    cp -a hellcat-pandora-installer-4rb/PSP/GAME/pan3xx /media/sdb1/PSP/GAME/
  * MemStick and MS-IPL Options > Repartition and format MemStick (DESTRUCTIVE!) (give more space to boot sector)
    PSP S&L (all models) can boot on a JigKick, however version TA-085-v2 and later can't _create_ one anymore.
  * Battery Options > make battery Pandora
  * Install Despertar del cementerio v8 to PSP/GAME/pc8
  * Install 500.PBP (link from http://alek.dark-alex.org/pspwiki/index.php/Official_Firmware) to /
    Another download location: http://www.psp-hacks.com/category/36

- Install screenshot-taking utility
  http://www.pspgen.com/divers/telecharger-185222.html?secours

  unzip -d /media/sdb1 pct-prx-v2_1233312675.zip
  echo "ms0:/seplugins/PCT2.PRX" >> /media/sdb1/VSH.TXT
  echo "ms0:/seplugins/PCT2.PRX" >> /media/sdb1/GAME.TXT
  echo "ms0:/seplugins/PCT2.PRX" >> /media/sdb1/GAME150.TXT
  echo "ms0:/seplugins/PCT2.PRX" >> /media/sdb1/POPS.TXT
  
  Stop the console and boot while pressing R to go to the recovery
  menu (see above) and enable the plugins.

  Press the "Notes" key to take a screenshots. I takes between 10 and
  30 seconds depending on hardware, as far as I could see on the
  forums.

  PSPLink has a lightning-fast 'scrshot' command, if you manage to run
  the application from it.

- To get standard output and standart error output, in C:
  freopen("stdout.txt", "w", stdout);
  freopen("stderr.txt", "w", stderr);
  setlinebuf(stdout);
  setlinebuf(stderr);

  Or run it from PSPLink :)

- Downgrading: HellCat's CFW RecoveryFlasher
  http://forums.qj.net/showthread.php?t=143300

  It can revert to versions 3.71-M33-4 or 4.01-M33-2.  3.71-M33 is the
  first firmware that works both on Fat and Slim (3.60-M33 is the
  first firmware that works on Slim but it doesn't work on Fat).
  4.01-M33 was the latest version at the time of the release.

- Downgrading: 1.50 kernel for Slim: using TimeMachine
  http://downloads.exophase.com/pub/440
  http://rapidshare.com/files/148928450/timemachine_0.1.rar

  TimeMachine is essentially the combination of a dual-boot and a set
  of LiveCD's (or LiveMemoryStick's) for PSP.

  Grab firmware 150.PBP, 340.PBP (see locations above).  Also grab
  360.PSAR, which is the result of running 360DUMPER on a verbatim PSP
  S&L - I found a copy from
  http://www.pspgen.com/installer-time-machine-article-2172-1.html in
  the RTU ("Ready To Use") pack.

  Run TIMEMACHINE on the PSP. Choose option 1 "Install iplloader on
  PSP MS boot sector".  The TM installs a GRUB-like boot loader that
  runs a ipl.bin according to a key pressed before turning the PSP on
  and the content of TM/config.txt.  You may need to reinstall
  Despertar del Cementerio to assign a TM key so you can still run it.

  To run 1.50, shutdown the PSP, press and maintain 'circle', plug the
  JigKick battery (keep 'circle' pressed), wait while it access the
  memory card, until the SCE logo appears on screen (then you can
  release 'circle').  You're now temporarily running 1.50 from the
  memory card.

- Downgrading: 1.50 kernel
  addon. http://www.dark-alex.org/forum/viewtopic.php?f=44&t=1612

  It adds support for homebrews that only work with a 1.50 kernel.
  I'm not sure how exactly later kernels break those homebrews.  It
  refuses to work on Slim ("This program only for the standard psp.").
  I'm not sure how easily you can switch back and forth between the
  normal and the 1.50 kernel.  It works by adding new files from 1.50
  firmware in the flash, and if using a default partitionning for the
  flash drives, it needs to remove some applications from the current
  firmware to make room.

- LEDA - Legacy Software Loader
  http://www.dark-alex.org/forum/viewtopic.php?f=44&t=8942
  http://www.dark-alex.org/forum/viewtopic.php?f=44&t=9153

  It's a tool to run old homebrews meant for kernels 1.00 and 1.50.
  Unlike "1.50 kernel addon", it works on S&L.  However, it's not
  compatible with all homebrews, in particular it doesn't seem
  compatible with old versions of PSPLink (those with ELF support).

- Debugging: http://forums.ps2dev.org/viewtopic.php?p=63165
  Using PSPLink
  
  svn co svn://svn.ps2dev.org/psp/trunk/psplinkusb
  pushd psplinkusb
  # Check psplink_manual.pdf
  make -f Makefile.oe release
  (cd release_oe/pc/usbhostfs_pc/ && $SUDO ./mod.sh )

  pmount /dev/sdb1
  cp -a release_oe/psplink /media/sdb1/PSP/GAME/
  pumount /dev/sdb1
  # Run PSPLink from the XBM
  release_oe/pc/usbhostfs_pc/usbhostfs_pc
  release_oe/pc/pspsh/pspsh

  http://forums.ps2dev.org/viewtopic.php?t=11193 : Apparently there
  are issues when running classic .elf (non-relocatable) with a recent
  firmware (i.e. > 1.00/1.50). Recompiling the homebrew as .prx
  (relocatable) works.  Running on firmware 1.50(+3.40hw) works.  Note
  that when compiling a .prx, the default heap size is only 64kB, so
  you need to modify it (e.g. using PSP_HEAP_SIZE_MAX()).

  host0:/> debug freedink.prx
  ~> psp-gdb freedink.elf  # not stripped
  gdb> target remote localhost:10001
  gdb> break SDL_main
  gdb> c
  ...
  gdb> kill
  gdb> detach
  ...
  host0:/> reset
  host0:/> exit

  If you get " Reply contains invalid hex digit 59", you probably ran
  'gdb' instead of 'psp-gdb' :)

  Note that there's no source for the initial break point (_start) nor
  for the initial (SDL's) main - that's not an error.

- Remote display:
  http://www.ngine.de/index.jsp?pageid=4292
  http://www.metagames-eu.com/forums/psp/tuto-remotejoy-psplink-ou-comment-afficher-lecran-de-votre-psp-sur-le-pc-linux-87533.html
  http://forums.ps2dev.org/viewtopic.php?p=80792 (my own notes :))

  Replace Makefile (TODO: needed? It adds -pthreads and actually uses $(CFLAGS))
  cat <<EOF > tools/remotejoy/pcsdl/Makefile
OUTPUT=remotejoy
OBJS=remotejoy.o font.o

CFLAGS=-O2 -pthread -Wall -g $(shell sdl-config --cflags)

all: remotejoy

$(OUTPUT): $(OBJS)
	$(CC) -o $@ $^ $(CFLAGS) $(shell sdl-config --libs)

clean:
	rm -f $(OUTPUT) *.o
EOF
  make -C tools/remotejoy/
  make -C tools/remotejoy/pcsdl/

  pmount /dev/sdb1
  mkdir /media/sdb1/joy
  cp tools/remotejoy/remotejoy.prx /media/sdb1/joy
  pumount /dev/sdb1
  host0:/> ldstart ms0:/joy/remotejoy.prx
  host0:/> ./myapp.prx

  The documentation asks to run vshmain.prx in order to start the XMB
  (the main PSP interface), but this doesn't work for me - so the app
  needs to be run manually.

  Going further:

  pmount /dev/sdb1
  pushd /media/sdb1/SEPLUGINS
  cp ../PSP/GAME/psplink/usbhostfs.prx .
  cp ../PSP/GAME/psplink/psplink.prx .
  cp ../PSP/GAME/psplink/psplink_user.prx .
  cp ../PSP/GAME/psplink/remotejoy.prx  .
  cat <<EOF >> vsh.txt
ms0:/seplugins/usbhostfs.prx
ms0:/seplugins/psplink.prx
ms0:/seplugins/psplink_user.prx
ms0:/seplugins/remotejoy.prx"
EOF
  cat <<EOF >> game.txt
ms0:/seplugins/usbhostfs.prx
ms0:/seplugins/psplink.prx
ms0:/seplugins/psplink_user.prx
ms0:/seplugins/remotejoy.prx"
EOF
  popd
  pumount /dev/sdb1

  Enable the following plugin in the on-boot recovery menu:
  psplink.prx [GAME]
  psplink_user.prx [GAME]
  remotejoy.prx [GAME]

  $ pc/usbhostfs_pc/usbhostfs_pc
  $ ./remotejoy -d -c

  At this point the remote display should be activated when running a
  game. It doesn't work for me..


Hardware:

- By default the screen is a hardware surface, which means you're
  writing to the video video directly - and this also means you'll get
  a flicker effects if you don't do it properly.

- There's hardware double-buffer mode available
  (SDL_HWSURFACE|SDL_DOUBLEBUF), that is, it swaps the buffer's video
  memory on SDL_Flip(screen). Thus you need to redraw your screen
  after each flip(), unless you're not using double-buffer mode.

- Apparently there are issues to set the video mode if there were some
  printf(...) earlier in the code. In doubt, don't print anything when
  testing video modes (or redirect the output to files).

- Requesting an hardware surface (SDL_HWSURFACE) fails unless it's
  480x272.

  Hardware video memory (direct or double-buffer):
  Mode	   Pitch 	272*pitch  272*480*mode/8
  32bit	   2048		544kB	   510kB
  16bit	   1024		272kB	   255kB

  8bit mode doesn't seem to work (it runs, pitch=512B, but screen
  stays black, with or without SDL_HWPALETTE, with or without
  SDL_SetPalette).

- Requesting a fullscreen software surface
  (SDL_SWSURFACE|SDL_FULLSCREEN) succeeds in a number of situations,
  in which case the screen can be auto-resized (e.g. 640x480), or it
  can just be messed (overlaps). 640x480 supports 32/16/8bit modes (I
  didn't test 15bit).

- Results of testvidinfo.c from the SDL examples. Notes:
  - it doesn't list available video modes
  - 'info->current_w' and 'info->current_h' are not present in the
    SDL_VideoInfo structure
  - while hardware video modes are available, there's no hardware
    video memory ("0K")

Video driver: psp
Current display: ?x?, 32 bits-per-pixel
	Red Mask = 0x00ff0000
	Green Mask = 0x0000ff00
	Blue Mask = 0x000000ff
No special fullscreen video modes
Hardware surfaces are available (0K video memory)
Copy blits between hardware surfaces are accelerated
Colorkey blits between hardware surfaces are accelerated
===================================
Setting video mode: 640x480 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 640x480 at 8 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 11.85 seconds, 64.84 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 17.50 seconds, 28.57 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 18.50 seconds, 27.02 FPS
Running display format blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 11.91 seconds, 41.97 FPS
Running display format cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 10.66 seconds, 46.91 FPS
===================================
Setting video mode: 640x480 at 8 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 640x480 at 8 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 640x480 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 640x480 at 16 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 7.59 seconds, 101.13 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 16.14 seconds, 30.98 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 16.45 seconds, 30.40 FPS
Running display format blit test: 408x167 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 12.62 seconds, 39.62 FPS
Running display format cc blit test: 408x167 at 16 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 10.05 seconds, 49.78 FPS
Running display format alpha blit test: 408x167 at 16 bpp, flags: 0x00010000 SDL_SWSURFACE | SDL_SRCALPHA
5000 alpha blits / 500 updates in 30.58 seconds, 16.35 FPS
Running display format cc+alpha blit test: 408x167 at 16 bpp, flags: 0x00013000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK
5000 cc+alpha blits / 500 updates in 22.79 seconds, 21.94 FPS
===================================
Setting video mode: 640x480 at 16 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 640x480 at 16 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 640x480 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 640x480 at 32 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 15.74 seconds, 48.80 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 21.93 seconds, 22.80 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 21.44 seconds, 23.32 FPS
Running display format blit test: 408x167 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 21.77 seconds, 22.97 FPS
Running display format cc blit test: 408x167 at 32 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 17.29 seconds, 28.93 FPS
Running display format alpha blit test: 408x167 at 32 bpp, flags: 0x00010000 SDL_SWSURFACE | SDL_SRCALPHA
5000 alpha blits / 500 updates in 45.06 seconds, 11.10 FPS
Running display format cc+alpha blit test: 408x167 at 32 bpp, flags: 0x00013000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK
5000 cc+alpha blits / 500 updates in 32.47 seconds, 15.40 FPS
===================================
Setting video mode: 640x480 at 32 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 640x480 at 32 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 640x480
===================================
Setting video mode: 800x600 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 800x600 at 8 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 18.14 seconds, 42.34 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 21.11 seconds, 23.68 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 22.10 seconds, 22.63 FPS
Running display format blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 15.51 seconds, 32.24 FPS
Running display format cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 14.24 seconds, 35.12 FPS
===================================
Setting video mode: 800x600 at 8 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 800x600 at 8 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 800x600 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 800x600 at 16 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 11.97 seconds, 64.15 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 17.75 seconds, 28.18 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 18.04 seconds, 27.72 FPS
Running display format blit test: 408x167 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 13.84 seconds, 36.14 FPS
Running display format cc blit test: 408x167 at 16 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 11.52 seconds, 43.40 FPS
Running display format alpha blit test: 408x167 at 16 bpp, flags: 0x00010000 SDL_SWSURFACE | SDL_SRCALPHA
5000 alpha blits / 500 updates in 31.94 seconds, 15.66 FPS
Running display format cc+alpha blit test: 408x167 at 16 bpp, flags: 0x00013000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK
5000 cc+alpha blits / 500 updates in 24.35 seconds, 20.53 FPS
===================================
Setting video mode: 800x600 at 16 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 800x600 at 16 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 800x600 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 800x600 at 32 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 24.33 seconds, 31.56 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 25.48 seconds, 19.63 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 24.95 seconds, 20.04 FPS
Running display format blit test: 408x167 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 25.32 seconds, 19.75 FPS
Running display format cc blit test: 408x167 at 32 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 20.84 seconds, 24.00 FPS
Running display format alpha blit test: 408x167 at 32 bpp, flags: 0x00010000 SDL_SWSURFACE | SDL_SRCALPHA
5000 alpha blits / 500 updates in 48.53 seconds, 10.30 FPS
Running display format cc+alpha blit test: 408x167 at 32 bpp, flags: 0x00013000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK
5000 cc+alpha blits / 500 updates in 36.02 seconds, 13.88 FPS
===================================
Setting video mode: 800x600 at 32 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 800x600 at 32 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 800x600
===================================
Setting video mode: 1024x768 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 1024x768 at 8 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 29.42 seconds, 26.10 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 27.37 seconds, 18.27 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 28.37 seconds, 17.63 FPS
Running display format blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 21.79 seconds, 22.95 FPS
Running display format cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 20.54 seconds, 24.34 FPS
===================================
Setting video mode: 1024x768 at 8 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 1024x768
===================================
Setting video mode: 1024x768 at 8 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 1024x768
===================================
Setting video mode: 1024x768 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 1024x768 at 16 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 20.10 seconds, 38.21 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 21.40 seconds, 23.37 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 21.70 seconds, 23.04 FPS
Running display format blit test: 408x167 at 16 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 17.87 seconds, 27.98 FPS
Running display format cc blit test: 408x167 at 16 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 15.29 seconds, 32.71 FPS
Running display format alpha blit test: 408x167 at 16 bpp, flags: 0x00010000 SDL_SWSURFACE | SDL_SRCALPHA
5000 alpha blits / 500 updates in 35.80 seconds, 13.97 FPS
Running display format cc+alpha blit test: 408x167 at 16 bpp, flags: 0x00013000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK
5000 cc+alpha blits / 500 updates in 28.03 seconds, 17.84 FPS
===================================
Setting video mode: 1024x768 at 16 bpp, flags: 0x80000001 SDL_HWSURFACE | SDL_FULLSCREEN
Setting video mode failed: No video mode large enough for 1024x768
===================================
Setting video mode: 1024x768 at 16 bpp, flags: 0xc0000001 SDL_HWSURFACE | SDL_FULLSCREEN | SDL_DOUBLEBUF
Setting video mode failed: No video mode large enough for 1024x768
===================================
Setting video mode: 1024x768 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
Flags didn't match: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
===================================
Setting video mode: 1024x768 at 32 bpp, flags: 0x80000000 SDL_SWSURFACE | SDL_FULLSCREEN
Running color fill and fullscreen update test
768 fills and flips in 39.65 seconds, 19.37 FPS
Running freshly loaded blit test: 408x167 at 8 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 31.83 seconds, 15.71 FPS
Running freshly loaded cc blit test: 408x167 at 8 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 31.31 seconds, 15.97 FPS
Running display format blit test: 408x167 at 32 bpp, flags: 0x00000000 SDL_SWSURFACE
5000 blits / 500 updates in 31.65 seconds, 15.80 FPS
Running display format cc blit test: 408x167 at 32 bpp, flags: 0x00003000 SDL_SWSURFACE | SDL_SRCCOLORKEY | SDL_RLEACCELOK
5000 cc blits / 500 updates in 27.16 secon
<<output truncated here - either crash or missing stdout flush>>

- The memory stick's path is "ms0:/" (e.g. "ms0:/PSP/GAME/yourgame")

- Accessing "/" goes to "ms0:/", at least when running homebrew from
  the memory stick. This is similar to woe's "/" -> "C:\" (replacing C
  with the current drive's letter).

- By default heap size is around 21-22MB. When using PSP_LARGE_MEM=1
  in a pspdev Makefile, or using "mksfoex -d MEMSIZE=1 'mymodule'
  PARAM.SFO" instead of plain "mksfo", it goes up to around 48-49MB
  (for a text-only SDL app). This was tested by malloc()ing in a loop.

  On a PC, the original game takes 12MB when you start playing, and
  Pilgrim Quest takes 22MB. On truecolor mode this goes to 18 and 30MB
  (though both don't have truecolor graphics).

- Buttons: the numbering is defined in SDL/src/joystick/psp/SDL_sysjoystick.c:

  static const enum PspCtrlButtons button_map[] = {
  	PSP_CTRL_TRIANGLE, PSP_CTRL_CIRCLE, PSP_CTRL_CROSS, PSP_CTRL_SQUARE,
  	PSP_CTRL_LTRIGGER, PSP_CTRL_RTRIGGER,
  	PSP_CTRL_DOWN, PSP_CTRL_LEFT, PSP_CTRL_UP, PSP_CTRL_RIGHT,
  	PSP_CTRL_SELECT, PSP_CTRL_START, PSP_CTRL_HOME, PSP_CTRL_HOLD };

  (starting from zero)

  Note that down/left/up/right are considered buttons (not joystick
  events). In addition, "home" and "hold" are apparently not usable
  directly (I read that it needs kernel mode?), nor are
  note/screen/vol+/vol-.

- Memory: it's actually partitionned, with 2 partitions:
  - partition #1 kernel: 8MB
  - partition #2 user: the rest (24MB PSP1, 56MB PSP2)
  Apparently it's not possible to resize the kernel partitiion and
  claim the memory back :/ Bottom-line: you substract 8MB for your
  your actual max available RAM.

- Kernel modules

  Those are easy to mess and there are lots of details to be aware of.

  Introductory docs:
  http://ps2dev.org/psp/Tutorials/
  http://ps2dev.org/psp/Tutorials/PSP_Modules,_Exports,_Imports_and_Patches.download

  http://forums.ps2dev.org/viewtopic.php?p=58653
  "Okay, let's review the high points of the nanddumper example app..."

  In kernel mode some user-mode functions cannot be used or have
  limitations.  To overcome this there's something called 'kubridge',
  which is hidden^Wincluded in firmware 3.71 M33, 3.80 M33-3 or 4.01
  M33.  From the looks of it it's non-free (only .h and .a).  There
  seem to have been some work in recent firmware to do without.

  The module needs to be declared as kernel mode:
  PSP_MODULE_INFO("mymodule", PSP_MODULE_KERNEL, <major>, <minor>);

  PSP_MODULE_KERNEL is 0x1000, but there are variants. In particular
  0x1007 cannot be stopped and unloaded
  (http://forums.ps2dev.org/viewtopic.php?t=12007).


Links:

- Interview with a PSP Developper
  http://www.hanselman.com/blog/InterviewWithAPSPDeveloperDougBeck.aspx
  Mentions a couple things about the commercial dev environment and memory management
