2008-04-16 Matthieu Bucchianeri <mbucchia@gmail.com>

* ChangeLog, Makefile.am, README, bsp_specs, configure.ac,
	mk_libnds.sh, patch.libnds, preinstall.am, block/block.c,
	clock/clock.c, console/console.c, coproc/coproc.S, coproc/coproc.c,
	coproc/coproc.ld, dswifi/dswifi_license.txt, dswifi/makefile,
	dswifi/arm7/makefile, dswifi/arm7/source/wifi_arm7.c,
	dswifi/arm7/source/wifi_arm7.h, dswifi/arm9/makefile,
	dswifi/arm9/source/sgIP.c, dswifi/arm9/source/sgIP.h,
	dswifi/arm9/source/sgIP_ARP.c, dswifi/arm9/source/sgIP_ARP.h,
	dswifi/arm9/source/sgIP_Config.h, dswifi/arm9/source/sgIP_DHCP.c,
	dswifi/arm9/source/sgIP_DHCP.h, dswifi/arm9/source/sgIP_DNS.c,
	dswifi/arm9/source/sgIP_DNS.h, dswifi/arm9/source/sgIP_Hub.c,
	dswifi/arm9/source/sgIP_Hub.h, dswifi/arm9/source/sgIP_ICMP.c,
	dswifi/arm9/source/sgIP_ICMP.h, dswifi/arm9/source/sgIP_IP.c,
	dswifi/arm9/source/sgIP_IP.h, dswifi/arm9/source/sgIP_TCP.c,
	dswifi/arm9/source/sgIP_TCP.h, dswifi/arm9/source/sgIP_UDP.c,
	dswifi/arm9/source/sgIP_UDP.h, dswifi/arm9/source/sgIP_memblock.c,
	dswifi/arm9/source/sgIP_memblock.h,
	dswifi/arm9/source/sgIP_sockets.c, dswifi/arm9/source/sgIP_sockets.h,
	dswifi/arm9/source/wifi_arm9.c, dswifi/arm9/source/wifi_arm9.h,
	dswifi/common/source/dsregs.h, dswifi/common/source/spinlock.h,
	dswifi/common/source/spinlock.s, dswifi/common/source/wifi_shared.h,
	dswifi/include/dswifi7.h, dswifi/include/dswifi9.h,
	dswifi/include/dswifi_version.h, dswifi/include/netdb.h,
	dswifi/include/sgIP_errno.h, dswifi/include/netinet/in.h, fb/fb.c,
	fb/fb.h, include/bsp.h, include/my_ipc.h, include/tm27.h,
	include/types.h, include/sys/iosupport.h, irq/irq.c, irq/irq.h,
	libfat/gba/include/fat.h, libfat/include/fat.h,
	libfat/nds/include/fat.h, libfat/source/bit_ops.h,
	libfat/source/cache.c, libfat/source/cache.h, libfat/source/common.h,
	libfat/source/directory.c, libfat/source/directory.h,
	libfat/source/fatdir.c, libfat/source/fatdir.h,
	libfat/source/fatfile.c, libfat/source/fatfile.h,
	libfat/source/file_allocation_table.c,
	libfat/source/file_allocation_table.h, libfat/source/filetime.c,
	libfat/source/filetime.h, libfat/source/libfat.c,
	libfat/source/mem_allocate.h, libfat/source/partition.c,
	libfat/source/partition.h, libfat/source/disc_io/disc.c,
	libfat/source/disc_io/disc.h, libfat/source/disc_io/disc_io.h,
	libfat/source/disc_io/io_cf_common.c,
	libfat/source/disc_io/io_cf_common.h,
	libfat/source/disc_io/io_dldi.h, libfat/source/disc_io/io_dldi.s,
	libfat/source/disc_io/io_efa2.c, libfat/source/disc_io/io_efa2.h,
	libfat/source/disc_io/io_fcsr.c, libfat/source/disc_io/io_fcsr.h,
	libfat/source/disc_io/io_m3_common.c,
	libfat/source/disc_io/io_m3_common.h,
	libfat/source/disc_io/io_m3cf.c, libfat/source/disc_io/io_m3cf.h,
	libfat/source/disc_io/io_m3sd.c, libfat/source/disc_io/io_m3sd.h,
	libfat/source/disc_io/io_mpcf.c, libfat/source/disc_io/io_mpcf.h,
	libfat/source/disc_io/io_njsd.c, libfat/source/disc_io/io_njsd.h,
	libfat/source/disc_io/io_nmmc.c, libfat/source/disc_io/io_nmmc.h,
	libfat/source/disc_io/io_sc_common.c,
	libfat/source/disc_io/io_sc_common.h,
	libfat/source/disc_io/io_sccf.c, libfat/source/disc_io/io_sccf.h,
	libfat/source/disc_io/io_scsd.c, libfat/source/disc_io/io_scsd.h,
	libfat/source/disc_io/io_scsd_s.s,
	libfat/source/disc_io/io_sd_common.c,
	libfat/source/disc_io/io_sd_common.h, libnds/Makefile.arm7,
	libnds/Makefile.arm9, libnds/libnds_license.txt,
	libnds/basicARM7/source/defaultARM7.c,
	libnds/include/default_font_bin.h, libnds/include/gbfs.h,
	libnds/include/nds.h, libnds/include/nds/bios.h,
	libnds/include/nds/card.h, libnds/include/nds/dma.h,
	libnds/include/nds/interrupts.h, libnds/include/nds/ipc.h,
	libnds/include/nds/jtypes.h, libnds/include/nds/memory.h,
	libnds/include/nds/registers_alt.h, libnds/include/nds/reload.h,
	libnds/include/nds/system.h, libnds/include/nds/timers.h,
	libnds/include/nds/arm7/audio.h, libnds/include/nds/arm7/clock.h,
	libnds/include/nds/arm7/serial.h, libnds/include/nds/arm7/touch.h,
	libnds/include/nds/arm9/background.h,
	libnds/include/nds/arm9/boxtest.h, libnds/include/nds/arm9/cache.h,
	libnds/include/nds/arm9/console.h,
	libnds/include/nds/arm9/exceptions.h,
	libnds/include/nds/arm9/image.h, libnds/include/nds/arm9/input.h,
	libnds/include/nds/arm9/math.h, libnds/include/nds/arm9/ndsmotion.h,
	libnds/include/nds/arm9/pcx.h, libnds/include/nds/arm9/postest.h,
	libnds/include/nds/arm9/rumble.h, libnds/include/nds/arm9/sound.h,
	libnds/include/nds/arm9/sprite.h, libnds/include/nds/arm9/trig_lut.h,
	libnds/include/nds/arm9/video.h, libnds/include/nds/arm9/videoGL.h,
	libnds/source/arm7/audio.c, libnds/source/arm7/clock.c,
	libnds/source/arm7/microphone.c, libnds/source/arm7/spi.c,
	libnds/source/arm7/touch.c, libnds/source/arm7/userSettings.c,
	libnds/source/arm9/COS.bin, libnds/source/arm9/COS.s,
	libnds/source/arm9/SIN.bin, libnds/source/arm9/SIN.s,
	libnds/source/arm9/TAN.bin, libnds/source/arm9/TAN.s,
	libnds/source/arm9/boxtest.c, libnds/source/arm9/console.c,
	libnds/source/arm9/dcache.s, libnds/source/arm9/default_font.bin,
	libnds/source/arm9/default_font.s,
	libnds/source/arm9/exceptionHandler.S,
	libnds/source/arm9/exceptionHandler.s,
	libnds/source/arm9/exceptions.c, libnds/source/arm9/gurumeditation.c,
	libnds/source/arm9/icache.s, libnds/source/arm9/image.c,
	libnds/source/arm9/initSystem.c, libnds/source/arm9/keys.c,
	libnds/source/arm9/ndsmotion.c, libnds/source/arm9/pcx.c,
	libnds/source/arm9/rumble.c, libnds/source/arm9/sound.c,
	libnds/source/arm9/system.c, libnds/source/arm9/touch.c,
	libnds/source/arm9/video.c, libnds/source/arm9/videoGL.c,
	libnds/source/common/biosCalls.s, libnds/source/common/card.c,
	libnds/source/common/gbfs.c,
	libnds/source/common/interruptDispatcher.s,
	libnds/source/common/interrupts.c, rtc/rtc.c, sound/sound.c,
	sound/sound.h, start/start.S, startup/linkcmds, startup/start.c,
	timer/timer.c, tools/Makefile.am, tools/bin2s, tools/bin2s.c,
	tools/configure.ac, tools/runtest,
	tools/ndstool/include/arm7_sha1_homebrew.h,
	tools/ndstool/include/arm7_sha1_nintendo.h,
	tools/ndstool/include/banner.h, tools/ndstool/include/bigint.h,
	tools/ndstool/include/crc.h, tools/ndstool/include/default_icon.h,
	tools/ndstool/include/encryption.h, tools/ndstool/include/header.h,
	tools/ndstool/include/hook.h, tools/ndstool/include/little.h,
	tools/ndstool/include/loadme.h, tools/ndstool/include/logo.h,
	tools/ndstool/include/ndscreate.h,
	tools/ndstool/include/ndsextract.h, tools/ndstool/include/ndstool.h,
	tools/ndstool/include/ndstree.h, tools/ndstool/include/overlay.h,
	tools/ndstool/include/passme.h, tools/ndstool/include/passme_sram.h,
	tools/ndstool/include/passme_vhd1.h,
	tools/ndstool/include/passme_vhd2.h, tools/ndstool/include/raster.h,
	tools/ndstool/include/sha1.h, tools/ndstool/include/types.h,
	tools/ndstool/source/arm7_sha1_homebrew.c,
	tools/ndstool/source/arm7_sha1_nintendo.c,
	tools/ndstool/source/banner.cpp, tools/ndstool/source/bigint.cpp,
	tools/ndstool/source/compile_date.c, tools/ndstool/source/crc.cpp,
	tools/ndstool/source/default_icon.c,
	tools/ndstool/source/encryption.cpp, tools/ndstool/source/header.cpp,
	tools/ndstool/source/hook.cpp, tools/ndstool/source/loadme.c,
	tools/ndstool/source/logo.cpp, tools/ndstool/source/ndscodes.cpp,
	tools/ndstool/source/ndscreate.cpp,
	tools/ndstool/source/ndsextract.cpp,
	tools/ndstool/source/ndstool.cpp, tools/ndstool/source/ndstree.cpp,
	tools/ndstool/source/passme.cpp, tools/ndstool/source/passme_sram.c,
	tools/ndstool/source/raster.cpp, tools/ndstool/source/sha1.cpp,
	touchscreen/README.reco, touchscreen/parser.c, touchscreen/reco.c,
	touchscreen/reco.h, touchscreen/touchscreen.c,
	touchscreen/touchscreen.h, wifi/compat.c, wifi/compat.h, wifi/wifi.c:
	New files.
This commit is contained in:
Joel Sherrill
2008-04-16 18:37:33 +00:00
parent ed1a900460
commit 311dfa65d8
260 changed files with 44068 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
2008-04-16 Matthieu Bucchianeri <mbucchia@gmail.com>
* ChangeLog, Makefile.am, README, bsp_specs, configure.ac,
mk_libnds.sh, patch.libnds, preinstall.am, block/block.c,
clock/clock.c, console/console.c, coproc/coproc.S, coproc/coproc.c,
coproc/coproc.ld, dswifi/dswifi_license.txt, dswifi/makefile,
dswifi/arm7/makefile, dswifi/arm7/source/wifi_arm7.c,
dswifi/arm7/source/wifi_arm7.h, dswifi/arm9/makefile,
dswifi/arm9/source/sgIP.c, dswifi/arm9/source/sgIP.h,
dswifi/arm9/source/sgIP_ARP.c, dswifi/arm9/source/sgIP_ARP.h,
dswifi/arm9/source/sgIP_Config.h, dswifi/arm9/source/sgIP_DHCP.c,
dswifi/arm9/source/sgIP_DHCP.h, dswifi/arm9/source/sgIP_DNS.c,
dswifi/arm9/source/sgIP_DNS.h, dswifi/arm9/source/sgIP_Hub.c,
dswifi/arm9/source/sgIP_Hub.h, dswifi/arm9/source/sgIP_ICMP.c,
dswifi/arm9/source/sgIP_ICMP.h, dswifi/arm9/source/sgIP_IP.c,
dswifi/arm9/source/sgIP_IP.h, dswifi/arm9/source/sgIP_TCP.c,
dswifi/arm9/source/sgIP_TCP.h, dswifi/arm9/source/sgIP_UDP.c,
dswifi/arm9/source/sgIP_UDP.h, dswifi/arm9/source/sgIP_memblock.c,
dswifi/arm9/source/sgIP_memblock.h,
dswifi/arm9/source/sgIP_sockets.c, dswifi/arm9/source/sgIP_sockets.h,
dswifi/arm9/source/wifi_arm9.c, dswifi/arm9/source/wifi_arm9.h,
dswifi/common/source/dsregs.h, dswifi/common/source/spinlock.h,
dswifi/common/source/spinlock.s, dswifi/common/source/wifi_shared.h,
dswifi/include/dswifi7.h, dswifi/include/dswifi9.h,
dswifi/include/dswifi_version.h, dswifi/include/netdb.h,
dswifi/include/sgIP_errno.h, dswifi/include/netinet/in.h, fb/fb.c,
fb/fb.h, include/bsp.h, include/my_ipc.h, include/tm27.h,
include/types.h, include/sys/iosupport.h, irq/irq.c, irq/irq.h,
libfat/gba/include/fat.h, libfat/include/fat.h,
libfat/nds/include/fat.h, libfat/source/bit_ops.h,
libfat/source/cache.c, libfat/source/cache.h, libfat/source/common.h,
libfat/source/directory.c, libfat/source/directory.h,
libfat/source/fatdir.c, libfat/source/fatdir.h,
libfat/source/fatfile.c, libfat/source/fatfile.h,
libfat/source/file_allocation_table.c,
libfat/source/file_allocation_table.h, libfat/source/filetime.c,
libfat/source/filetime.h, libfat/source/libfat.c,
libfat/source/mem_allocate.h, libfat/source/partition.c,
libfat/source/partition.h, libfat/source/disc_io/disc.c,
libfat/source/disc_io/disc.h, libfat/source/disc_io/disc_io.h,
libfat/source/disc_io/io_cf_common.c,
libfat/source/disc_io/io_cf_common.h,
libfat/source/disc_io/io_dldi.h, libfat/source/disc_io/io_dldi.s,
libfat/source/disc_io/io_efa2.c, libfat/source/disc_io/io_efa2.h,
libfat/source/disc_io/io_fcsr.c, libfat/source/disc_io/io_fcsr.h,
libfat/source/disc_io/io_m3_common.c,
libfat/source/disc_io/io_m3_common.h,
libfat/source/disc_io/io_m3cf.c, libfat/source/disc_io/io_m3cf.h,
libfat/source/disc_io/io_m3sd.c, libfat/source/disc_io/io_m3sd.h,
libfat/source/disc_io/io_mpcf.c, libfat/source/disc_io/io_mpcf.h,
libfat/source/disc_io/io_njsd.c, libfat/source/disc_io/io_njsd.h,
libfat/source/disc_io/io_nmmc.c, libfat/source/disc_io/io_nmmc.h,
libfat/source/disc_io/io_sc_common.c,
libfat/source/disc_io/io_sc_common.h,
libfat/source/disc_io/io_sccf.c, libfat/source/disc_io/io_sccf.h,
libfat/source/disc_io/io_scsd.c, libfat/source/disc_io/io_scsd.h,
libfat/source/disc_io/io_scsd_s.s,
libfat/source/disc_io/io_sd_common.c,
libfat/source/disc_io/io_sd_common.h, libnds/Makefile.arm7,
libnds/Makefile.arm9, libnds/libnds_license.txt,
libnds/basicARM7/source/defaultARM7.c,
libnds/include/default_font_bin.h, libnds/include/gbfs.h,
libnds/include/nds.h, libnds/include/nds/bios.h,
libnds/include/nds/card.h, libnds/include/nds/dma.h,
libnds/include/nds/interrupts.h, libnds/include/nds/ipc.h,
libnds/include/nds/jtypes.h, libnds/include/nds/memory.h,
libnds/include/nds/registers_alt.h, libnds/include/nds/reload.h,
libnds/include/nds/system.h, libnds/include/nds/timers.h,
libnds/include/nds/arm7/audio.h, libnds/include/nds/arm7/clock.h,
libnds/include/nds/arm7/serial.h, libnds/include/nds/arm7/touch.h,
libnds/include/nds/arm9/background.h,
libnds/include/nds/arm9/boxtest.h, libnds/include/nds/arm9/cache.h,
libnds/include/nds/arm9/console.h,
libnds/include/nds/arm9/exceptions.h,
libnds/include/nds/arm9/image.h, libnds/include/nds/arm9/input.h,
libnds/include/nds/arm9/math.h, libnds/include/nds/arm9/ndsmotion.h,
libnds/include/nds/arm9/pcx.h, libnds/include/nds/arm9/postest.h,
libnds/include/nds/arm9/rumble.h, libnds/include/nds/arm9/sound.h,
libnds/include/nds/arm9/sprite.h, libnds/include/nds/arm9/trig_lut.h,
libnds/include/nds/arm9/video.h, libnds/include/nds/arm9/videoGL.h,
libnds/source/arm7/audio.c, libnds/source/arm7/clock.c,
libnds/source/arm7/microphone.c, libnds/source/arm7/spi.c,
libnds/source/arm7/touch.c, libnds/source/arm7/userSettings.c,
libnds/source/arm9/COS.bin, libnds/source/arm9/COS.s,
libnds/source/arm9/SIN.bin, libnds/source/arm9/SIN.s,
libnds/source/arm9/TAN.bin, libnds/source/arm9/TAN.s,
libnds/source/arm9/boxtest.c, libnds/source/arm9/console.c,
libnds/source/arm9/dcache.s, libnds/source/arm9/default_font.bin,
libnds/source/arm9/default_font.s,
libnds/source/arm9/exceptionHandler.S,
libnds/source/arm9/exceptionHandler.s,
libnds/source/arm9/exceptions.c, libnds/source/arm9/gurumeditation.c,
libnds/source/arm9/icache.s, libnds/source/arm9/image.c,
libnds/source/arm9/initSystem.c, libnds/source/arm9/keys.c,
libnds/source/arm9/ndsmotion.c, libnds/source/arm9/pcx.c,
libnds/source/arm9/rumble.c, libnds/source/arm9/sound.c,
libnds/source/arm9/system.c, libnds/source/arm9/touch.c,
libnds/source/arm9/video.c, libnds/source/arm9/videoGL.c,
libnds/source/common/biosCalls.s, libnds/source/common/card.c,
libnds/source/common/gbfs.c,
libnds/source/common/interruptDispatcher.s,
libnds/source/common/interrupts.c, rtc/rtc.c, sound/sound.c,
sound/sound.h, start/start.S, startup/linkcmds, startup/start.c,
timer/timer.c, tools/Makefile.am, tools/bin2s, tools/bin2s.c,
tools/configure.ac, tools/runtest,
tools/ndstool/include/arm7_sha1_homebrew.h,
tools/ndstool/include/arm7_sha1_nintendo.h,
tools/ndstool/include/banner.h, tools/ndstool/include/bigint.h,
tools/ndstool/include/crc.h, tools/ndstool/include/default_icon.h,
tools/ndstool/include/encryption.h, tools/ndstool/include/header.h,
tools/ndstool/include/hook.h, tools/ndstool/include/little.h,
tools/ndstool/include/loadme.h, tools/ndstool/include/logo.h,
tools/ndstool/include/ndscreate.h,
tools/ndstool/include/ndsextract.h, tools/ndstool/include/ndstool.h,
tools/ndstool/include/ndstree.h, tools/ndstool/include/overlay.h,
tools/ndstool/include/passme.h, tools/ndstool/include/passme_sram.h,
tools/ndstool/include/passme_vhd1.h,
tools/ndstool/include/passme_vhd2.h, tools/ndstool/include/raster.h,
tools/ndstool/include/sha1.h, tools/ndstool/include/types.h,
tools/ndstool/source/arm7_sha1_homebrew.c,
tools/ndstool/source/arm7_sha1_nintendo.c,
tools/ndstool/source/banner.cpp, tools/ndstool/source/bigint.cpp,
tools/ndstool/source/compile_date.c, tools/ndstool/source/crc.cpp,
tools/ndstool/source/default_icon.c,
tools/ndstool/source/encryption.cpp, tools/ndstool/source/header.cpp,
tools/ndstool/source/hook.cpp, tools/ndstool/source/loadme.c,
tools/ndstool/source/logo.cpp, tools/ndstool/source/ndscodes.cpp,
tools/ndstool/source/ndscreate.cpp,
tools/ndstool/source/ndsextract.cpp,
tools/ndstool/source/ndstool.cpp, tools/ndstool/source/ndstree.cpp,
tools/ndstool/source/passme.cpp, tools/ndstool/source/passme_sram.c,
tools/ndstool/source/raster.cpp, tools/ndstool/source/sha1.cpp,
touchscreen/README.reco, touchscreen/parser.c, touchscreen/reco.c,
touchscreen/reco.h, touchscreen/touchscreen.c,
touchscreen/touchscreen.h, wifi/compat.c, wifi/compat.h, wifi/wifi.c:
New files.
2008-03-09 Matthieu Bucchianeri <mbucchia@gmail.com>
* ...: original import of the BSP

View File

@@ -0,0 +1,260 @@
##
## $Id$
##
ACLOCAL_AMFLAGS = -I ../../../../aclocal
SUBDIRS = . tools
include $(top_srcdir)/../../../../automake/compile.am
include $(top_srcdir)/../../bsp.am
dist_project_lib_DATA = bsp_specs
include_HEADERS = include/bsp.h
include_HEADERS += include/tm27.h
nodist_include_HEADERS = include/bspopts.h
nodist_include_HEADERS += ../../shared/include/coverhd.h
DISTCLEANFILES = include/bspopts.h
noinst_PROGRAMS =
EXTRA_DIST = start/start.S
start.$(OBJEXT): start/start.S
$(CPPASCOMPILE) -o $@ -c $<
project_lib_DATA = start.$(OBJEXT)
dist_project_lib_DATA += startup/linkcmds
include_rtemsdir = $(includedir)/rtems
include_rtems_HEADERS = fb/fb.h touchscreen/touchscreen.h sound/sound.h
noinst_PROGRAMS += startup.rel
startup_rel_SOURCES = ../../shared/bsplibc.c ../../shared/bsppost.c \
startup/start.c ../../shared/bsppredriverhook.c \
../../shared/bootcard.c ../../shared/sbrk.c \
../../shared/gnatinstallhandler.c
startup_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += clock.rel
clock_rel_SOURCES = clock/clock.c
clock_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
clock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += rtc.rel
rtc_rel_SOURCES = rtc/rtc.c ../../shared/tod.c
rtc_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
rtc_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += console.rel
console_rel_SOURCES = console/console.c
console_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include -I$(srcdir)/include
console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += fb.rel
fb_rel_SOURCES = fb/fb.c
fb_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
fb_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += touchscreen.rel
touchscreen_rel_SOURCES = touchscreen/touchscreen.c touchscreen/parser.c \
touchscreen/reco.c
touchscreen_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
touchscreen_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += timer.rel
timer_rel_SOURCES = timer/timer.c
timer_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
timer_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += sound.rel
sound_rel_SOURCES = sound/sound.c
sound_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
sound_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
noinst_PROGRAMS += block.rel
block_rel_SOURCES = block/block.c
block_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include -DNDS -I$(srcdir)/libfat/source/disc_io
block_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
include_HEADERS += irq/irq.h
noinst_PROGRAMS += irq.rel
irq_rel_SOURCES = irq/irq.c
irq_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include
irq_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
if HAS_NETWORKING
noinst_PROGRAMS += wifi.rel
wifi_rel_SOURCES = wifi/wifi.c \
wifi/compat.c
wifi_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/dswifi/include -I$(srcdir)/libnds/include -I$(srcdir)/dswifi/include -D_KERNEL
wifi_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
# libnds, ARM9 side
noinst_PROGRAMS += libnds9.rel
bin2s: $(srcdir)/tools/bin2s.c
cc -o $(srcdir)/tools/bin2s $(srcdir)/tools/bin2s.c
SUFFIXES = .bin
%.s: %.bin bin2s
$(srcdir)/tools/bin2s $< > $(srcdir)/$@
libnds9_rel_SOURCES = libnds/source/common/biosCalls.S \
libnds/source/common/card.c \
libnds/source/common/gbfs.c \
libnds/source/common/interruptDispatcher.S \
libnds/source/common/interrupts.c \
libnds/source/arm9/boxtest.c \
libnds/source/arm9/default_font.s \
libnds/source/arm9/console.c \
libnds/source/arm9/COS.s \
libnds/source/arm9/dcache.S \
libnds/source/arm9/exceptionHandler.S \
libnds/source/arm9/exceptions.c \
libnds/source/arm9/gurumeditation.c \
libnds/source/arm9/icache.S \
libnds/source/arm9/image.c \
libnds/source/arm9/initSystem.c \
libnds/source/arm9/keys.c \
libnds/source/arm9/ndsmotion.c \
libnds/source/arm9/pcx.c \
libnds/source/arm9/rumble.c \
libnds/source/arm9/SIN.s \
libnds/source/arm9/sound.c \
libnds/source/arm9/system.c \
libnds/source/arm9/TAN.s \
libnds/source/arm9/touch.c \
libnds/source/arm9/video.c \
libnds/source/arm9/videoGL.c
libnds9_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include -I$(srcdir)/include
libnds9_rel_CCASFLAGS = $(AM_CCASFLAGS) -DARM9 -I$(srcdir)/libnds/include
libnds9_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
if HAS_NETWORKING
# dswifi, ARM9 side
noinst_PROGRAMS += dswifi9.rel
dswifi9_rel_SOURCES = dswifi/arm9/source/wifi_arm9.c \
dswifi/common/source/spinlock.s
dswifi9_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/dswifi/include -I$(srcdir)/libnds/include -I$(srcdir)/dswifi/common/source -I$(srcdir)/wifi -D_KERNEL -Dcaddr_t=uint32_t
dswifi9_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
# dldi
noinst_PROGRAMS += libdldi.rel
libdldi_rel_SOURCES = libfat/source/disc_io/disc.c \
libfat/source/disc_io/io_cf_common.c \
libfat/source/disc_io/io_efa2.c \
libfat/source/disc_io/io_fcsr.c \
libfat/source/disc_io/io_m3cf.c \
libfat/source/disc_io/io_m3_common.c \
libfat/source/disc_io/io_m3sd.c \
libfat/source/disc_io/io_mpcf.c \
libfat/source/disc_io/io_njsd.c \
libfat/source/disc_io/io_nmmc.c \
libfat/source/disc_io/io_sccf.c \
libfat/source/disc_io/io_sc_common.c \
libfat/source/disc_io/io_scsd.c \
libfat/source/disc_io/io_sd_common.c \
libfat/source/disc_io/io_dldi.s \
libfat/source/disc_io/io_scsd_s.s
libdldi_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM9 -I$(srcdir)/libnds/include -I$(srcdir)/libfat/source/disc_io
libdldi_rel_CCASFLAGS = $(AM_CCASFLAGS) -DARM9 -I$(srcdir)/libnds/include -I$(srcdir)/libfat/source/disc_io
libdldi_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
# libnds, ARM7 side
noinst_PROGRAMS += libnds7.rel
libnds7_rel_SOURCES = libnds/source/common/biosCalls.S \
libnds/source/common/card.c \
libnds/source/common/gbfs.c \
libnds/source/common/interruptDispatcher.S \
libnds/source/common/interrupts.c \
libnds/source/arm7/audio.c \
libnds/source/arm7/clock.c \
libnds/source/arm7/microphone.c \
libnds/source/arm7/spi.c \
libnds/source/arm7/touch.c \
libnds/source/arm7/userSettings.c
libnds7_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM7 -I$(srcdir)/libnds/include
libnds7_rel_CFLAGS = -mcpu=arm7tdmi -msoft-float
libnds7_rel_CCASFLAGS = -mcpu=arm7tdmi -msoft-float
libnds7_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
if HAS_NETWORKING
# dswifi, ARM7 side
noinst_PROGRAMS += dswifi7.rel
dswifi7_rel_SOURCES = dswifi/arm7/source/wifi_arm7.c \
dswifi/common/source/spinlock.s
dswifi7_rel_CPPFLAGS = $(AM_CPPFLAGS) -DARM7 -I$(srcdir)/dswifi/include -I$(srcdir)/libnds/include -I$(srcdir)/dswifi/common/source
dswifi7_rel_CFLAGS = -mcpu=arm7tdmi -msoft-float
dswifi7_rel_CCASFLAGS = -mcpu=arm7tdmi -msoft-float
dswifi7_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
endif
# include libnds to dist so the user program can include it
include_libndsdir = $(includedir)/libnds
include_libnds_HEADERS = libnds/include/gbfs.h \
libnds/include/nds.h
include_libndsndsdir = $(includedir)/libnds/nds
include_libndsnds_HEADERS = libnds/include/nds/memory.h \
libnds/include/nds/system.h \
libnds/include/nds/bios.h \
libnds/include/nds/registers_alt.h \
libnds/include/nds/interrupts.h \
libnds/include/nds/card.h \
libnds/include/nds/ipc.h \
libnds/include/nds/timers.h \
libnds/include/nds/dma.h \
libnds/include/nds/reload.h \
libnds/include/nds/jtypes.h
include_libndsnds9dir = $(includedir)/libnds/nds/arm9
include_libndsnds9_HEADERS = libnds/include/nds/arm9/ndsmotion.h \
libnds/include/nds/arm9/pcx.h \
libnds/include/nds/arm9/input.h \
libnds/include/nds/arm9/math.h \
libnds/include/nds/arm9/console.h \
libnds/include/nds/arm9/sprite.h \
libnds/include/nds/arm9/videoGL.h \
libnds/include/nds/arm9/cache.h \
libnds/include/nds/arm9/image.h \
libnds/include/nds/arm9/trig_lut.h \
libnds/include/nds/arm9/video.h \
libnds/include/nds/arm9/exceptions.h \
libnds/include/nds/arm9/rumble.h \
libnds/include/nds/arm9/background.h \
libnds/include/nds/arm9/boxtest.h \
libnds/include/nds/arm9/postest.h \
libnds/include/nds/arm9/sound.h
include_libndsnds7dir = $(includedir)/libnds/nds/arm7
include_libndsnds7_HEADERS = libnds/include/nds/arm7/serial.h \
libnds/include/nds/arm7/audio.h \
libnds/include/nds/arm7/clock.h \
libnds/include/nds/arm7/touch.h
EXTRA_DIST += coproc/coproc.S coproc/coproc.c
if HAS_NETWORKING
coproc.bin: coproc/coproc.S coproc/coproc.c libnds7.rel dswifi7.rel
@CC@ -o coproc.elf -mcpu=arm7tdmi -msoft-float -O2 -DARM7 -I$(srcdir)/libnds/include -I$(srcdir)/dswifi/include -DENABLE_WIFI -T $(srcdir)/coproc/coproc.ld $^ -lc
$(OBJCOPY) -O binary coproc.elf coproc.bin
else
coproc.bin: coproc/coproc.S coproc/coproc.c libnds7.rel
@CC@ -o coproc.elf -mcpu=arm7tdmi -msoft-float -O2 -DARM7 -I$(srcdir)/libnds/include -T $(srcdir)/coproc/coproc.ld $^ -lc
$(OBJCOPY) -O binary coproc.elf coproc.bin
endif
project_lib_DATA += coproc.bin
noinst_LIBRARIES = libbsp.a
libbsp_a_SOURCES =
libbsp_a_LIBADD = clock.rel console.rel startup.rel irq.rel timer.rel libnds9.rel rtc.rel fb.rel touchscreen.rel sound.rel block.rel libdldi.rel
if HAS_NETWORKING
libbsp_a_LIBADD += wifi.rel dswifi9.rel
endif
include $(srcdir)/preinstall.am
include $(top_srcdir)/../../../../automake/local.am

View File

@@ -0,0 +1,12 @@
##
## $Id$
##
This is the BSP for Nintendo DS.
Original authors:
* Matthieu Bucchianeri <mbucchia@gmail.com>
* Benjamin Ratier
* Renaud Voltz
* Cedric Gestes

View File

@@ -0,0 +1,114 @@
/*
* RTEMS for Nintendo DS flash driver.
*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#include <rtems.h>
#include <bsp.h>
#include <libchip/ide_ctrl.h>
#include <libchip/ide_ctrl_cfg.h>
#include <libchip/ide_ctrl_io.h>
#include <disc.h>
boolean
nds_flash_probe (int minor)
{
return TRUE;
}
void
nds_flash_initialize (int minor)
{
const IO_INTERFACE *flash;
printk ("[+] flash started\n");
flash = _FAT_disc_dsSlotFindInterface ();
if (flash == NULL) {
printk ("[!] error getting device\n");
rtems_fatal_error_occurred (0);
}
if (_FAT_disc_isInserted (flash)) {
printk ("[#] flash inserted\n");
} else {
printk ("[!] flash not inserted\n");
}
}
void
nds_flash_read_reg (int minor, int reg, uint16_t * value)
{
printk ("nds_flash_read_reg\n");
}
void
nds_flash_write_reg (int minor, int reg, uint16_t value)
{
printk ("nds_flash_write_reg\n");
}
void
nds_flash_read_block (int minor, uint16_t block_size,
blkdev_sg_buffer * bufs,
uint32_t * cbuf, uint32_t * pos)
{
printk ("nds_flash_read_block\n");
}
void
nds_flash_write_block (int minor, uint16_t block_size,
blkdev_sg_buffer * bufs,
uint32_t * cbuf, uint32_t * pos)
{
printk ("nds_flash_write_block\n");
}
int
nds_flash_control (int minor, uint32_t cmd, void *arg)
{
printk ("nds_flash_control\n");
}
rtems_status_code
nds_flash_io_speed (int minor, uint16_t mode)
{
return RTEMS_SUCCESSFUL;
}
ide_ctrl_fns_t nds_flash_ctrl_fns = {
nds_flash_probe,
nds_flash_initialize,
nds_flash_control,
nds_flash_read_reg,
nds_flash_write_reg,
nds_flash_read_block,
nds_flash_write_block,
nds_flash_io_speed
};
/* IDE controllers Table */
ide_controller_bsp_table_t IDE_Controller_Table[] = {
{
"/dev/flash",
IDE_CUSTOM, /* standard IDE controller */
&nds_flash_ctrl_fns,
NULL, /* probe for IDE standard registers */
FALSE, /* not (yet) initialized */
0x0, /* base I/O address for first IDE controller */
FALSE, 0, /* not (yet) interrupt driven */
NULL
}
};
/* Number of rows in IDE_Controller_Table */
unsigned long IDE_Controller_Count = 1;

View File

@@ -0,0 +1,14 @@
%rename endfile old_endfile
%rename startfile old_startfile
%rename link old_link
*startfile:
%{!qrtems: %(old_startfile)} \
%{!nostdlib: %{qrtems: start.o%s crti.o%s crtbegin.o%s}}
*link:
%{!qrtems: %(old_link)} %{qrtems: -Qy -dc -dp -Bstatic -N -e _start}
*endfile:
%{!qrtems: *(old_endfiles)} %{qrtems: crtend.o%s crtn.o%s }

View File

@@ -0,0 +1,88 @@
/*
* RTEMS for Nintendo DS clock driver.
*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#include <rtems.h>
#include <bsp.h>
#include "../irq/irq.h"
#include <nds.h>
#define CLOCK_VECTOR IRQ_TIMER0
/*
* forward declaration for clock isr in clockdrv_shell.c
*/
rtems_isr Clock_isr (rtems_vector_number vector);
/*
* isr registration variables.
*/
static rtems_irq_connect_data clock_isr_data = {
IRQ_TIMER0,
(rtems_irq_hdl) Clock_isr,
NULL,
NULL,
NULL,
0,
0
};
void update_touchscreen (void);
/*
* function called on every ticks.
* NOTE: replaced by macro to avoid empty function call.
*/
#define Clock_driver_support_at_tick() \
update_touchscreen();
/*
* install isr for clock driver.
*/
void
Clock_driver_support_install_isr (rtems_isr_entry new, rtems_isr_entry old)
{
BSP_install_rtems_irq_handler (&clock_isr_data);
}
/*
* disable clock.
*/
void
Clock_driver_support_shutdown_hardware (void)
{
BSP_remove_rtems_irq_handler (&clock_isr_data);
TIMER_CR (0) &= ~(TIMER_ENABLE);
}
/*
* initialize clock on timer 0.
*/
void
Clock_driver_support_initialize_hardware (void)
{
uint32_t freq =
1000 / (rtems_configuration_get_microseconds_per_tick () / 1000);
printk ("[+] clock started\n");
TIMER_CR (0) = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_DIV_64;
printk ("[#] setting clock to %u hz\n", freq);
TIMER_DATA (0) = TIMER_FREQ_64 ((uint16_t) freq);
}
#include "../../../shared/clockdrv_shell.c"

View File

@@ -0,0 +1,28 @@
##
## $Id$
##
AC_PREREQ(2.60)
AC_INIT([rtems-c-src-lib-libbsp-arm-nds],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla])
AC_CONFIG_SRCDIR([bsp_specs])
RTEMS_TOP(../../../../../..)
RTEMS_CANONICAL_TARGET_CPU
AM_INIT_AUTOMAKE([no-define nostdinc foreign 1.10])
RTEMS_BSP_CONFIGURE
RTEMS_PROG_CC_FOR_TARGET([-fasm])
RTEMS_CANONICALIZE_TOOLS
RTEMS_CHECK_TOOL(OBJCOPY,objcopy,:)
RTEMS_PROG_CCAS
RTEMS_CHECK_NETWORKING
AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
RTEMS_CONFIG_BUILD_SUBDIRS(tools)
## $srcdir/mk_libnds.sh $srcdir
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@@ -0,0 +1,191 @@
/*
* RTEMS for Nintendo DS console driver.
*
* Copyright (c) 2008 by Renaud Voltz <renaud.voltz@gmail.com>
* Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#include <bsp.h>
#include <nds.h>
#include <rtems/libio.h>
#include <nds/arm9/console.h>
#include <sys/iosupport.h>
#include <rtems/mw_uid.h>
/*
* enables testsuite output to desmume. this is used to pass the rtems
* testsuite.
* comment the following line to disable (recommended).
*/
//#define TESTSUITE
/*
* printk support.
*/
void
nds_putch (char c)
{
#ifdef TESTSUITE
asm volatile ("swi $0x1");
#endif
consolePrintChar (c);
}
static volatile char ch = 0;
void
console_push (char c)
{
ch = c;
}
char
nds_getch (void)
{
char c;
while (ch == 0);
c = ch;
ch = 0;
return c;
}
BSP_output_char_function_type BSP_output_char =
(BSP_output_char_function_type) nds_putch;
BSP_polling_getchar_function_type BSP_poll_char =
(BSP_polling_getchar_function_type) nds_getch;
/*
* console write operation.
*/
static int
nds_write (rtems_device_minor_number minor, const char *buf, int len)
{
int count;
for (count = 0; count < len; count++) {
nds_putch (buf[count]);
}
return 0;
}
/*
* console read operation.
*/
static int
nds_read (int minor)
{
return nds_getch ();
}
/*
* from touchscreen/parser.c
*/
void register_kbd_msg_queue (char *q_name);
void unregister_kbd_msg_queue (void);
/*
* Console driver
*/
rtems_device_driver
console_initialize (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_status_code status;
printk ("[+] console started\n");
rtems_termios_initialize ();
status = rtems_io_register_name ("/dev/console", major, 0);
if (status != RTEMS_SUCCESSFUL) {
printk ("[!] error registering console\n");
rtems_fatal_error_occurred (status);
}
return (RTEMS_SUCCESSFUL);
}
rtems_device_driver
console_open (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_status_code status;
static rtems_termios_callbacks cb = {
NULL, /* firstOpen */
NULL, /* lastClose */
nds_read, /* pollRead */
nds_write, /* write */
NULL, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
0 /* 1 = outputUsesInterrupts */
};
status = rtems_termios_open (major, minor, arg, &cb);
if (status != RTEMS_SUCCESSFUL)
printk ("[!] error opening console\n");
return (status);
}
rtems_device_driver
console_close (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_device_driver res = RTEMS_SUCCESSFUL;
res = rtems_termios_close (arg);
return res;
}
rtems_device_driver
console_read (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
return rtems_termios_read (arg);
}
rtems_device_driver
console_write (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
return rtems_termios_write (arg);
}
rtems_device_driver
console_control (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_libio_ioctl_args_t *args = arg;
switch (args->command) {
case MW_UID_REGISTER_DEVICE:
register_kbd_msg_queue (args->buffer);
break;
case MW_UID_UNREGISTER_DEVICE:
unregister_kbd_msg_queue ();
break;
default:
return rtems_termios_ioctl (arg);
}
args->ioctl_return = 0;
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,112 @@
@---------------------------------------------------------------------------------
.section ".init"
.global _start
.global _init
@---------------------------------------------------------------------------------
.align 4
.arm
@---------------------------------------------------------------------------------
_start:
@---------------------------------------------------------------------------------
mov r0, #0x04000000 @ IME = 0;
str r0, [r0, #0x208]
mov r0, #0x12 @ Switch to IRQ Mode
msr cpsr, r0
ldr sp, =__sp_irq @ Set IRQ stack
mov r0, #0x13 @ Switch to SVC Mode
msr cpsr, r0
ldr sp, =__sp_svc @ Set SVC stack
mov r0, #0x1F @ Switch to System Mode
msr cpsr, r0
ldr sp, =__sp_usr @ Set user stack
ldr r0, =__bss_start @ Clear BSS section to 0x00
ldr r1, =__bss_end
sub r1, r1, r0
bl ClearMem
ldr r3, =__libc_init_array @ global constructors
bl _call_via_r3
mov r0, #0 @ int argc
mov r1, #0 @ char *argv[]
ldr r3, =main
bl _call_via_r3 @ jump to user code
@ If the user ever returns, return to flash cartridge
mov r0, #0x08000000
bx r0
@---------------------------------------------------------------------------------
@ Clear memory to 0x00 if length != 0
@ r0 = Start Address
@ r1 = Length
@---------------------------------------------------------------------------------
ClearMem:
@---------------------------------------------------------------------------------
mov r2, #3 @ Round down to nearest word boundary
add r1, r1, r2 @ Shouldn't be needed
bics r1, r1, r2 @ Clear 2 LSB (and set Z)
bxeq lr @ Quit if copy size is 0
mov r2, #0
ClrLoop:
stmia r0!, {r2}
subs r1, r1, #4
bne ClrLoop
bx lr
@---------------------------------------------------------------------------------
@ Copy memory if length != 0
@ r1 = Source Address
@ r2 = Dest Address
@ r4 = Dest Address + Length
@---------------------------------------------------------------------------------
CopyMemCheck:
@---------------------------------------------------------------------------------
sub r3, r4, r2 @ Is there any data to copy?
@---------------------------------------------------------------------------------
@ Copy memory
@ r1 = Source Address
@ r2 = Dest Address
@ r3 = Length
@---------------------------------------------------------------------------------
CopyMem:
@---------------------------------------------------------------------------------
mov r0, #3 @ These commands are used in cases where
add r3, r3, r0 @ the length is not a multiple of 4,
bics r3, r3, r0 @ even though it should be.
bxeq lr @ Length is zero, so exit
CIDLoop:
ldmia r1!, {r0}
stmia r2!, {r0}
subs r3, r3, #4
bne CIDLoop
bx lr
_init:
bx lr
@---------------------------------------------------------------------------------
.align
@ .pool
@ .end
@---------------------------------------------------------------------------------
@---------------------------------------------------------------------------------
.section ".fini"
.global _fini
@---------------------------------------------------------------------------------
.align 4
.arm
@---------------------------------------------------------------------------------
_fini:
bx lr
@---------------------------------------------------------------------------------
.align
.pool
.end
@---------------------------------------------------------------------------------

View File

@@ -0,0 +1,207 @@
/*---------------------------------------------------------------------------------
default ARM7 core
Copyright (C) 2005
Michael Noland (joat)
Jason Rogers (dovoto)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds.h>
#include "../include/my_ipc.h"
#ifdef ENABLE_WIFI
#include <dswifi7.h>
#endif
//---------------------------------------------------------------------------------
void startSound(int sampleRate, const void* data, u32 bytes, u8 channel, u8 vol, u8 pan, u8 format) {
//---------------------------------------------------------------------------------
SCHANNEL_TIMER(channel) = SOUND_FREQ(sampleRate);
SCHANNEL_SOURCE(channel) = (u32)data;
SCHANNEL_LENGTH(channel) = bytes >> 2 ;
SCHANNEL_CR(channel) = SCHANNEL_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | (format==1?SOUND_8BIT:SOUND_16BIT);
}
//---------------------------------------------------------------------------------
s32 getFreeSoundChannel() {
//---------------------------------------------------------------------------------
int i;
for (i=0; i<16; i++) {
if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 ) return i;
}
return -1;
}
touchPosition first,tempPos;
//---------------------------------------------------------------------------------
void VcountHandler() {
//---------------------------------------------------------------------------------
static int lastbut = -1;
uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0;
but = REG_KEYXY;
if (!( (but ^ lastbut) & (1<<6))) {
tempPos = touchReadXY();
if ( tempPos.x == 0 || tempPos.y == 0 ) {
but |= (1 <<6);
lastbut = but;
} else {
x = tempPos.x;
y = tempPos.y;
xpx = tempPos.px;
ypx = tempPos.py;
z1 = tempPos.z1;
z2 = tempPos.z2;
}
} else {
lastbut = but;
but |= (1 <<6);
}
IPC->touchX = x;
IPC->touchY = y;
IPC->touchXpx = xpx;
IPC->touchYpx = ypx;
IPC->touchZ1 = z1;
IPC->touchZ2 = z2;
IPC->buttons = but;
}
//---------------------------------------------------------------------------------
void VblankHandler(void) {
//---------------------------------------------------------------------------------
static u8 is_recording = 0;
u32 i;
//sound code :)
TransferSound *snd = IPC->soundData;
IPC->soundData = 0;
if (0 != snd) {
for (i=0; i<snd->count; i++) {
s32 chan = getFreeSoundChannel();
if (chan >= 0) {
startSound(snd->data[i].rate, snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan, snd->data[i].format);
}
}
}
// microphone code
if (!is_recording && my_IPC->record)
{
StartRecording(my_IPC->record_buffer, my_IPC->record_length_max);
is_recording = 1;
}
if (is_recording && !my_IPC->record)
{
my_IPC->recorded_length = 1 + StopRecording();
is_recording = 0;
}
#ifdef ENABLE_WIFI
Wifi_Update(); // update wireless in vblank
#endif
}
#ifdef ENABLE_WIFI
// callback to allow wifi library to notify arm9
void arm7_synctoarm9() { // send fifo message
REG_IPC_FIFO_TX = 0x87654321;
}
// interrupt handler to allow incoming notifications from arm9
void arm7_fifo() { // check incoming fifo messages
u32 msg = REG_IPC_FIFO_RX;
if(msg==0x87654321) Wifi_Sync();
}
#endif
//---------------------------------------------------------------------------------
int main(int argc, char ** argv) {
//---------------------------------------------------------------------------------
#ifdef ENABLE_WIFI
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_SEND_CLEAR; // enable & prepare
// fifo asap
#endif
// read User Settings from firmware
readUserSettings();
//enable sound
powerON(POWER_SOUND);
writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP );
SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F);
irqInit();
// Start the RTC tracking IRQ
initClockIRQ();
SetYtrigger(80);
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqSet(IRQ_TIMER0, ProcessMicrophoneTimerIRQ);
irqEnable(IRQ_VBLANK | IRQ_VCOUNT | IRQ_TIMER0);
#ifdef ENABLE_WIFI
irqSet(IRQ_WIFI, Wifi_Interrupt); // set up wifi interrupt
irqEnable(IRQ_WIFI);
// sync with arm9 and init wifi
u32 fifo_temp;
while (1)
{ // wait for magic number
while (REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)
swiWaitForVBlank();
fifo_temp = REG_IPC_FIFO_RX;
if (fifo_temp == 0x12345678)
break;
}
while (REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)
swiWaitForVBlank();
fifo_temp = REG_IPC_FIFO_RX;
Wifi_Init(fifo_temp);
irqSet(IRQ_FIFO_NOT_EMPTY,arm7_fifo); // set up fifo irq
irqEnable(IRQ_FIFO_NOT_EMPTY);
REG_IPC_FIFO_CR = IPC_FIFO_ENABLE | IPC_FIFO_RECV_IRQ;
Wifi_SetSyncHandler(arm7_synctoarm9); // allow wifi lib to notify arm9
#endif
// Keep the ARM7 mostly idle
while (1) {
swiWaitForVBlank();
}
}

View File

@@ -0,0 +1,195 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
MEMORY {
rom : ORIGIN = 0x08000000, LENGTH = 32M
iwram : ORIGIN = 0x037f8000, LENGTH = 96K
}
__iwram_start = ORIGIN(iwram);
__iwram_top = ORIGIN(iwram)+ LENGTH(iwram);
__sp_irq = __iwram_top - 0x60;
__sp_svc = __sp_irq - 0x100;
__sp_usr = __sp_svc - 0x100;
__irq_flags = __iwram_top - 8;
__irq_vector = __iwram_top - 4;
SECTIONS
{
.init :
{
__text_start = . ;
KEEP (*(.init))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.plt : { *(.plt) } >iwram = 0xff
.text : /* ALIGN (4): */
{
*(.text*)
*(.stub)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.fini :
{
KEEP (*(.fini))
} >iwram =0xff
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >iwram
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >iwram
__exidx_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { KEEP (*(.preinit_array)) } >iwram = 0xff
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { KEEP (*(.init_array)) } >iwram = 0xff
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { KEEP (*(.fini_array)) } >iwram = 0xff
PROVIDE (__fini_array_end = .);
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram = 0xff
.jcr : { KEEP (*(.jcr)) } >iwram = 0
.got : { *(.got.plt) *(.got) } >iwram = 0
.iwram ALIGN(4) :
{
__iwram_start = ABSOLUTE(.) ;
*(.iwram)
*iwram.*(.text)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__iwram_end = ABSOLUTE(.) ;
} >iwram = 0xff
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >iwram = 0xff
.bss ALIGN(4) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >iwram
__bss_end = . ;
__bss_end__ = . ;
_end = . ;
__end__ = . ;
PROVIDE (end = _end);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.stack 0x80000 : { _stack = .; *(.stack) }
/* These must appear regardless of . */
}

View File

@@ -0,0 +1,145 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
endif
include $(DEVKITARM)/ds_rules
TOPDIR ?= $(CURDIR)/..
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD ?= release
SOURCES := source ../common/source
INCLUDES := include build ../common/source ../include
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb-interwork
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM7
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -mno-fpu -Wl,-Map,$(notdir $*).map
ifneq ($(BUILD),debug)
export ARM7BIN := $(TOPDIR)/lib/libdswifi7.a
else
export ARM7BIN := $(TOPDIR)/lib/libdswifi7d.a
CFLAGS += -DSGIP_DEBUG
endif
LIBS :=
#-lnds7
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr debug release
@rm -f $(TOPDIR)/lib/libdswifi7*
all: $(ARM7BIN)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM7BIN) : $(OFILES)
@rm -f "$(ARM7BIN)"
@$(AR) rcs "$(ARM7BIN)" $(OFILES)
@echo built ... $(notdir $@)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
// DS Wifi interface code
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
// wifi_arm7.h - arm7 wifi interface header
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef WIFI_ARM7_H
#define WIFI_ARM7_H
#ifndef ARM7
#error Wifi is only accessible from the ARM7
#endif
// keepalive updated in the update handler, which should be called in vblank
// keepalive set for 2 minutes.
#define WIFI_KEEPALIVE_COUNT (60*60*2)
#define WIFI_REG(ofs) (*((volatile u16 *)(0x04800000+(ofs))))
// Wifi regs
#define W_WEPKEY0 (((volatile u16 *)(0x04805F80)))
#define W_WEPKEY1 (((volatile u16 *)(0x04805FA0)))
#define W_WEPKEY2 (((volatile u16 *)(0x04805FC0)))
#define W_WEPKEY3 (((volatile u16 *)(0x04805FE0)))
#define W_MODE_RST (*((volatile u16 *)(0x04800004)))
#define W_MODE_WEP (*((volatile u16 *)(0x04800006)))
#define W_IF (*((volatile u16 *)(0x04800010)))
#define W_IE (*((volatile u16 *)(0x04800012)))
#define W_MACADDR (((volatile u16 *)(0x04800018)))
#define W_BSSID (((volatile u16 *)(0x04800020)))
#define W_AIDS (*((volatile u16 *)(0x04800028)))
#define W_RETRLIMIT (*((volatile u16 *)(0x0480002C)))
#define W_POWERSTATE (*((volatile u16 *)(0x0480003C)))
#define W_RANDOM (*((volatile u16 *)(0x04800044)))
#define W_BBSIOCNT (*((volatile u16 *)(0x04800158)))
#define W_BBSIOWRITE (*((volatile u16 *)(0x0480015A)))
#define W_BBSIOREAD (*((volatile u16 *)(0x0480015C)))
#define W_BBSIOBUSY (*((volatile u16 *)(0x0480015E)))
#define W_RFSIODATA2 (*((volatile u16 *)(0x0480017C)))
#define W_RFSIODATA1 (*((volatile u16 *)(0x0480017E)))
#define W_RFSIOBUSY (*((volatile u16 *)(0x04800180)))
#include "wifi_shared.h"
extern volatile Wifi_MainStruct * WifiData;
// Wifi Sync Handler function: Callback function that is called when the arm9 needs to be told to synchronize with new fifo data.
// If this callback is used (see Wifi_SetSyncHandler()), it should send a message via the fifo to the arm9, which will call Wifi_Sync() on arm9.
typedef void (*WifiSyncHandler)();
#ifdef __cplusplus
extern "C" {
#endif
extern void Read_Flash(int address, char * destination, int length);
extern void InitFlashData();
extern int ReadFlashByte(int address);
extern int ReadFlashHWord(int address);
extern int ReadFlashBytes(int address, int numbytes);
extern int Wifi_BBRead(int a);
extern int Wifi_BBWrite(int a, int b);
extern void Wifi_RFWrite(int writedata);
extern void Wifi_RFInit();
extern void Wifi_BBInit();
extern void Wifi_WakeUp();
extern void Wifi_Shutdown();
extern void Wifi_MacInit();
extern void Wifi_Interrupt();
extern void Wifi_Update();
extern void Wifi_CopyMacAddr(volatile void * dest, volatile void * src);
extern int Wifi_CmpMacAddr(volatile void * mac1, volatile void * mac2);
extern void Wifi_Init(u32 WifiData);
extern void Wifi_Deinit();
extern void Wifi_Start();
extern void Wifi_Stop();
extern void Wifi_SetChannel(int channel);
extern void Wifi_SetWepKey(void * wepkey);
extern void Wifi_SetWepMode(int wepmode);
extern void Wifi_SetBeaconPeriod(int beacon_period);
extern void Wifi_SetMode(int wifimode);
extern void Wifi_SetPreambleType(int preamble_type);
extern void Wifi_TxSetup();
extern void Wifi_RxSetup();
extern void Wifi_DisableTempPowerSave();
extern int Wifi_SendOpenSystemAuthPacket();
extern int Wifi_SendAssocPacket();
extern int Wifi_SendNullFrame();
extern int Wifi_SendPSPollFrame();
extern int Wifi_ProcessReceivedFrame(int macbase, int framelen);
extern void Wifi_Sync();
extern void Wifi_SetSyncHandler(WifiSyncHandler sh);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,150 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
endif
include $(DEVKITARM)/ds_rules
TOPDIR ?= $(CURDIR)/..
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD ?= release
SOURCES := source ../common/source
INCLUDES := include ../common/source ../include
DATA := data
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
# note: arm9tdmi isn't the correct CPU arch, but anything newer and LD
# *insists* it has a FPU or VFP, and it won't take no for an answer!
CFLAGS := -g -Wall -O2\
-mcpu=arm9tdmi -mtune=arm9tdmi -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS)
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -mno-fpu -Wl,-Map,$(notdir $*.map)
ifneq ($(BUILD),debug)
export ARM9BIN := $(TOPDIR)/lib/libdswifi9.a
else
export ARM9BIN := $(TOPDIR)/lib/libdswifi9d.a
CFLAGS += -DSGIP_DEBUG
endif
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS :=
#-lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export CC := $(PREFIX)gcc
export CXX := $(PREFIX)g++
export AR := $(PREFIX)ar
export OBJCOPY := $(PREFIX)objcopy
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr debug release
@rm -f $(TOPDIR)/lib/libdswifi9*
all: $(ARM9BIN)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM9BIN) : $(OFILES)
@rm -f "$(ARM9BIN)"
@$(AR) rcs "$(ARM9BIN)" $(OFILES)
@echo built ... $(notdir $@)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -0,0 +1,63 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP.h"
unsigned long volatile sgIP_timems;
int sgIP_errno;
// sgIP_Init(): Initializes sgIP hub and sets up a default surrounding interface (ARP and IP)
void sgIP_Init() {
sgIP_timems = 0;
sgIP_memblock_Init();
sgIP_Hub_Init();
sgIP_ARP_Init();
sgIP_TCP_Init();
sgIP_UDP_Init();
sgIP_DNS_Init();
sgIP_DHCP_Init();
sgIP_Hub_AddProtocolInterface(PROTOCOL_ETHER_IP,&sgIP_IP_ReceivePacket,0);
}
unsigned long count_100ms;
unsigned long count_1000ms;
void sgIP_Timer(int num_ms) {
sgIP_timems+=num_ms;
count_100ms+=num_ms;
if(count_100ms>=100) {
count_100ms-=100;
if(count_100ms>=100) count_100ms=0;
sgIP_ARP_Timer100ms();
}
count_1000ms+=num_ms;
if(count_1000ms>=1000) {
count_1000ms-=1000;
if(count_1000ms>=1000) count_1000ms=0;
sgIP_DNS_Timer1000ms();
}
sgIP_TCP_Timer();
}

View File

@@ -0,0 +1,56 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_H
#define SGIP_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
#include "sgIP_Hub.h"
#include "sgIP_IP.h"
#include "sgIP_ARP.h"
#include "sgIP_ICMP.h"
#include "sgIP_TCP.h"
#include "sgIP_UDP.h"
#include "sgIP_DNS.h"
#include "sgIP_DHCP.h"
extern unsigned long volatile sgIP_timems;
#ifdef __cplusplus
extern "C" {
#endif
void sgIP_Init();
void sgIP_Timer(int num_ms);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,304 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_ARP.h"
sgIP_ARP_Record ArpRecords[SGIP_ARP_MAXENTRIES];
int sgIP_FindArpSlot(sgIP_Hub_HWInterface * hw, unsigned long destip) {
int i;
for(i=0;i<SGIP_ARP_MAXENTRIES;i++) {
if(ArpRecords[i].flags&SGIP_ARP_FLAG_ACTIVE) {
if(ArpRecords[i].linked_interface==hw && ArpRecords[i].protocol_address==destip) return i;
}
}
return -1;
}
int sgIP_GetArpSlot() {
int i,m,midle;
m=0;
midle=0;
for(i=0;i<SGIP_ARP_MAXENTRIES;i++) {
if(ArpRecords[i].flags&SGIP_ARP_FLAG_ACTIVE) {
if(ArpRecords[i].idletime>=midle) {
midle=ArpRecords[i].idletime; m=i;
}
} else {
return i;
}
}
// this slot *was* in use, so let's fix that situation.
if(ArpRecords[m].queued_packet) sgIP_memblock_free(ArpRecords[m].queued_packet);
ArpRecords[m].flags=0;
ArpRecords[m].retrycount=0;
ArpRecords[m].idletime=0;
ArpRecords[m].queued_packet=0;
return m;
}
int sgIP_is_broadcast_address(sgIP_Hub_HWInterface * hw, unsigned long ipaddr) {
if((hw->snmask | ipaddr) == 0xFFFFFFFF) return 1;
return 0;
}
// this function will protect against malformed packets that could cause internal problems.
int sgIP_ARP_Check_isok(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb, sgIP_Header_ARP * arp) {
return 1; // doesn't do anything yet ;)
}
void sgIP_ARP_Init() {
int i;
for(i=0;i<SGIP_ARP_MAXENTRIES;i++) {
ArpRecords[i].flags=0;
ArpRecords[i].idletime=0;
ArpRecords[i].queued_packet=0;
}
}
void sgIP_ARP_Timer100ms() {
int i;
for(i=0;i<SGIP_ARP_MAXENTRIES;i++) {
if(ArpRecords[i].flags & SGIP_ARP_FLAG_ACTIVE) {
ArpRecords[i].idletime++;
if(!(ArpRecords[i].flags&SGIP_ARP_FLAG_HAVEHWADDR)) {
ArpRecords[i].retrycount++;
if(ArpRecords[i].retrycount>125) { // it's a lost cause.
if(ArpRecords[i].queued_packet) { // if there is already a queued packet, kill it.
sgIP_memblock_free(ArpRecords[i].queued_packet);
}
ArpRecords[i].flags=0;
continue;
}
if((ArpRecords[i].retrycount&7)==7) { // attempt retransmit of ARP frame.
sgIP_ARP_SendARPRequest(ArpRecords[i].linked_interface, ArpRecords[i].linked_protocol, ArpRecords[i].protocol_address);
}
}
}
}
}
void sgIP_ARP_FlushInterface(sgIP_Hub_HWInterface * hw) {
int i;
for(i=0;i<SGIP_ARP_MAXENTRIES;i++) {
if(ArpRecords[i].linked_interface==hw) ArpRecords[i].flags=0;
if(hw==0) ArpRecords[i].flags=0; // flush all interfaces
}
}
// don't *really* need to process this, but it helps.
int sgIP_ARP_ProcessIPFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb) {
return 0;
}
int sgIP_ARP_ProcessARPFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb) {
int i, j, ip;
if(!hw || !mb) return 0;
sgIP_memblock_exposeheader(mb,-14); // hide 14 bytes at the start temporarily...
// look at arp frame...
sgIP_Header_ARP * arp = (sgIP_Header_ARP *) mb->datastart;
if(!sgIP_ARP_Check_isok(hw,mb,arp)) {
sgIP_memblock_free(mb);
return 0; // error - arp header incorrect somehow.
}
sgIP_memblock_exposeheader(mb,14); // re-expose 14 bytes at the start...
if(htons(arp->opcode)==1) { // request
// requested IP
ip = arp->addresses[arp->hw_addr_len*2+4+0]+(arp->addresses[arp->hw_addr_len*2+4+1]<<8)+(arp->addresses[arp->hw_addr_len*2+4+2]<<16)+(arp->addresses[arp->hw_addr_len*2+4+3]<<24);
SGIP_DEBUG_MESSAGE(("ARP: request IP %08X",ip));
if(ip==hw->ipaddr) {// someone's asking for our info, toss them a reply.
sgIP_ARP_SendARPResponse(hw,mb);
return 0;
}
}
if(htons(arp->opcode)==2) { // response
// sender IP
ip = arp->addresses[arp->hw_addr_len+0]+(arp->addresses[arp->hw_addr_len+1]<<8)+(arp->addresses[arp->hw_addr_len+2]<<16)+(arp->addresses[arp->hw_addr_len+3]<<24);
i=sgIP_FindArpSlot(hw,ip);
if(i!=-1) { // we've been waiting for you...
for(j=0;j<arp->hw_addr_len;j++) ArpRecords[i].hw_address[j]=arp->addresses[j];
ArpRecords[i].flags|=SGIP_ARP_FLAG_HAVEHWADDR;
sgIP_memblock * mb2;
mb2=ArpRecords[i].queued_packet;
ArpRecords[i].queued_packet=0;
if(mb2) sgIP_ARP_SendProtocolFrame(hw,mb2,ArpRecords[i].linked_protocol,ip);
}
}
sgIP_memblock_free(mb);
return 0;
}
int sgIP_ARP_SendProtocolFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb, unsigned short protocol, unsigned long destaddr) {
int i,j;
int m;
sgIP_Header_Ethernet * ether;
if(!hw || !mb) return 0;
sgIP_memblock_exposeheader(mb,14); // add 14 bytes at the start for the header
if(sgIP_is_broadcast_address(hw,destaddr)) {
// construct ethernet header
ether = (sgIP_Header_Ethernet *) mb->datastart;
for(j=0;j<6;j++) {
ether->src_mac[j] = hw->hwaddr[j];
ether->dest_mac[j]= 0xFF; // broadcast destination
}
ether->protocol=protocol;
return sgIP_Hub_SendRawPacket(hw,mb); // this function will free the memory block when it's done.
}
i=sgIP_FindArpSlot(hw,destaddr);
if(i!=-1) {
if(ArpRecords[i].flags & SGIP_ARP_FLAG_HAVEHWADDR) { // we have the adddress
ArpRecords[i].idletime=0;
// construct ethernet header
ether = (sgIP_Header_Ethernet *) mb->datastart;
for(j=0;j<6;j++) {
ether->src_mac[j] = hw->hwaddr[j];
ether->dest_mac[j]= ArpRecords[i].hw_address[j];
}
ether->protocol=protocol;
return sgIP_Hub_SendRawPacket(hw,mb); // this function will free the memory block when it's done.
} else { // we don't have the address, but are looking for it.
if(ArpRecords[i].queued_packet) { // if there is already a queued packet, reject the new one.
sgIP_memblock_free(mb);
return 0; // couldn't send.
} else {
sgIP_memblock_exposeheader(mb,-14); // re-hide ethernet header.
ArpRecords[i].queued_packet=mb; // queue packet.
ArpRecords[i].linked_protocol=protocol; // queue packet.
return 0;
}
}
}
m=sgIP_GetArpSlot(); // gets and cleans out an arp slot for us
// build new record
ArpRecords[m].flags=SGIP_ARP_FLAG_ACTIVE;
ArpRecords[m].idletime=0;
ArpRecords[m].retrycount=0;
ArpRecords[m].linked_interface=hw;
ArpRecords[m].protocol_address=destaddr;
sgIP_memblock_exposeheader(mb,-14); // re-hide ethernet header.
ArpRecords[m].queued_packet=mb;
ArpRecords[m].linked_protocol=protocol;
sgIP_ARP_SendARPRequest(hw,protocol,destaddr);
return 0; // queued, but not sent yet.
}
int sgIP_ARP_SendARPResponse(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb) {
int i;
if(!hw || !mb) return 0;
sgIP_memblock_exposeheader(mb,-14); // hide 14 bytes at the start temporarily...
// Repurpose existing ARP packet
sgIP_Header_ARP * arp = (sgIP_Header_ARP *) mb->datastart;
if(!sgIP_ARP_Check_isok(hw,mb,arp)) {
sgIP_memblock_free(mb);
return 0; // error - arp header incorrect somehow.
}
if(arp->hw_addr_len!=hw->hwaddrlen || arp->protocol_addr_len!=4) {
// eek! can't send it back in this sorry state!
sgIP_memblock_free(mb);
return 0;
}
arp->opcode=htons(2); // response
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i+4+hw->hwaddrlen]=arp->addresses[i]; // copy src hw addr
for(i=0;i<4;i++) arp->addresses[i+(hw->hwaddrlen)*2+4]=arp->addresses[i+hw->hwaddrlen];
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i]=hw->hwaddr[i];
for(i=0;i<4;i++) arp->addresses[i+(hw->hwaddrlen)]=(hw->ipaddr>>(i*8))&255;
// construct ethernet header
sgIP_memblock_exposeheader(mb,14); // add 14 bytes at the start for the header
sgIP_Header_Ethernet * ether = (sgIP_Header_Ethernet *) mb->datastart;
for(i=0;i<6;i++) {
ether->src_mac[i] = hw->hwaddr[i];
ether->dest_mac[i]= arp->addresses[i+4+hw->hwaddrlen]; // requesting party
}
ether->protocol=htons(0x0806); // ARP protocol
// Send ethernet packet
return sgIP_Hub_SendRawPacket(hw,mb); // this function will free the memory block when it's done.
}
int sgIP_ARP_SendGratARP(sgIP_Hub_HWInterface * hw) {
int i;
if(!hw) return 0;
sgIP_memblock * mb = sgIP_memblock_alloc(SGIP_HEADER_ARP_BASESIZE+2*4 + 2*hw->hwaddrlen);
if(!mb) return 0;
// Construct ARP packet
sgIP_Header_ARP * arp = (sgIP_Header_ARP *) mb->datastart;
arp->hwspace=htons(1); // ethernet
arp->protocol=htons(0x0800);
arp->opcode=htons(2); // response
arp->hw_addr_len=hw->hwaddrlen;
arp->protocol_addr_len= 4;
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i]=hw->hwaddr[i];
for(i=0;i<4;i++) arp->addresses[i+hw->hwaddrlen]=(hw->ipaddr>>(i*8))&255;
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i+4+hw->hwaddrlen]=hw->hwaddr[i];
for(i=0;i<4;i++) arp->addresses[i+hw->hwaddrlen*2+4]=(hw->ipaddr>>(i*8))&255;
// construct ethernet header
sgIP_memblock_exposeheader(mb,14); // add 14 bytes at the start for the header
sgIP_Header_Ethernet * ether = (sgIP_Header_Ethernet *) mb->datastart;
for(i=0;i<6;i++) {
ether->src_mac[i] = hw->hwaddr[i];
ether->dest_mac[i]= 0xFF; // broadcast packet
}
ether->protocol=htons(0x0806); // ARP protocol
// Send ethernet packet
return sgIP_Hub_SendRawPacket(hw,mb); // this function will free the memory block when it's done.
}
int sgIP_ARP_SendARPRequest(sgIP_Hub_HWInterface * hw, int protocol, unsigned long protocol_addr) {
int i;
if(!hw) return 0;
sgIP_memblock * mb = sgIP_memblock_alloc(SGIP_HEADER_ARP_BASESIZE+2*4 + 2*hw->hwaddrlen);
if(!mb) return 0;
// Construct ARP packet
sgIP_Header_ARP * arp = (sgIP_Header_ARP *) mb->datastart;
arp->hwspace=htons(1); // 1=ethernet
arp->protocol=(protocol);
arp->opcode=htons(1); // 1=request
arp->hw_addr_len=hw->hwaddrlen;
arp->protocol_addr_len= 4;
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i]=hw->hwaddr[i];
for(i=0;i<4;i++) arp->addresses[i+hw->hwaddrlen]=(hw->ipaddr>>(i*8))&255;
for(i=0;i<hw->hwaddrlen;i++) arp->addresses[i+4+hw->hwaddrlen]=0;
for(i=0;i<4;i++) arp->addresses[i+hw->hwaddrlen*2+4]=(protocol_addr>>(i*8))&255;
// construct ethernet header
sgIP_memblock_exposeheader(mb,14); // add 14 bytes at the start for the header
sgIP_Header_Ethernet * ether = (sgIP_Header_Ethernet *) mb->datastart;
for(i=0;i<6;i++) {
ether->src_mac[i] = hw->hwaddr[i];
ether->dest_mac[i]= 0xFF; // broadcast packet
}
ether->protocol=htons(0x0806); // ARP protocol
// Send ethernet packet
return sgIP_Hub_SendRawPacket(hw,mb); // this function will free the memory block when it's done.
}

View File

@@ -0,0 +1,80 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_ARP_H
#define SGIP_ARP_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
#include "sgIP_Hub.h"
#define SGIP_ARP_FLAG_ACTIVE 0x0001
#define SGIP_ARP_FLAG_HAVEHWADDR 0x0002
typedef struct SGIP_ARP_RECORD {
unsigned short flags, retrycount;
unsigned long idletime;
sgIP_Hub_HWInterface * linked_interface;
sgIP_memblock * queued_packet;
int linked_protocol;
unsigned long protocol_address;
char hw_address[SGIP_MAXHWADDRLEN];
} sgIP_ARP_Record;
typedef struct SGIP_HEADER_ARP {
unsigned short hwspace; // ethernet=1;
unsigned short protocol;
unsigned char hw_addr_len;
unsigned char protocol_addr_len;
unsigned short opcode; // request=1, reply=2
unsigned char addresses[8+12]; // sender HW, sender Protocol, dest HW, dest Protocol
} sgIP_Header_ARP;
#define SGIP_HEADER_ARP_BASESIZE 8
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_ARP_Init();
extern void sgIP_ARP_Timer100ms();
extern void sgIP_ARP_FlushInterface(sgIP_Hub_HWInterface * hw);
extern int sgIP_ARP_ProcessIPFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb);
extern int sgIP_ARP_ProcessARPFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb);
extern int sgIP_ARP_SendProtocolFrame(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb, unsigned short protocol, unsigned long destaddr);
extern int sgIP_ARP_SendARPResponse(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb);
extern int sgIP_ARP_SendGratARP(sgIP_Hub_HWInterface * hw);
extern int sgIP_ARP_SendARPRequest(sgIP_Hub_HWInterface * hw, int protocol, unsigned long protocol_addr);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,274 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_CONFIG_H
#define SGIP_CONFIG_H
#include <errno.h>
//////////////////////////////////////////////////////////////////////////
// General options - these control the core functionality of the stack.
// SGIP_USEDYNAMICMEMORY: Allows the stack to use memory as it needs it, via malloc()/free()
// This option is extremely useful in environments where it can be used, as it prevents the
// overhead of allocating per-connection memory in advance, and allows an unlimited number
// of connections, provided the memory space. This option requires the implementation of
// two C functions, "void * sgIP_malloc(int)" and "void sgIP_free(void *)", which behave
// similarly to the malloc and free functions commonly used in C.
#define SGIP_USEDYNAMICMEMORY
// SGIP_INTERRUPT_THREADING_MODEL: Provides memory protection in a system that can allow
// multiple processing "threads" by way of interrupts. This is not required on single
// threaded systems, and not adequate on multithreaded systems, but provides a way to
// allow protection against contention on interrupt-driven systems. This option requires
// the system to implement two C functions "int sgIP_DisableInterrupts()" and additionally
// "void sgIP_RestoreInterrupts(int)" that takes as a parameter the value returned by
// sgIP_DisableInterrupts(). Interrupts are disabled upon beginning work with sensitive
// memory areas or allocation/deallocation of memory, and are restored afterwards.
#define SGIP_INTERRUPT_THREADING_MODEL
// SGIP_MULTITHREADED_THREADING_MODEL: Standard memory protection for large multithreaded
// systems, such as operating systems and the like. This kind of memory protection is
// useful for true multithreaded systems but useless in a single-threaded system and
// harmful in an interrupt-based multiprocess system.
//#define SGIP_MULTITHREADED_THREADING_MODEL
#define SGIP_LITTLEENDIAN
//////////////////////////////////////////////////////////////////////////
// Temporary memory system settings
// SGIP_MEMBLOCK_DATASIZE: This is the maximum data size contained in a single sgIP_memblock.
// for best performance ensure this value is larger than any packet that is expected to be
// received, however, in a memory-tight situation, much smaller values can be used.
#define SGIP_MEMBLOCK_DATASIZE 1600
// SGIP_MEMBLOCK_BASENUM: The starting number of memblocks that will be allocated. This is
// also the total number of memblocks that will be allocated if sgIP is not configured to use
// dynamic memory allocation.
#define SGIP_MEMBLOCK_BASENUM 12
// SGIP_MEMBLOCK_STEPNUM: In the case that all memblocks are full, and dynamic memory is
// enabled, this many additional memblocks will be allocated in an attempt to satasfy the
// memory usage demands of the stack.
#define SGIP_MEMBLOCK_STEPNUM 6
// SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL: Who cares what the other memblock defines say, let's
// Generate all memblocks by mallocing 'em.
#define SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
//////////////////////////////////////////////////////////////////////////
// Hardware layer settings
// SGIP_MAXHWADDRLEN: The maximum usable hardware address length. Ethernet is 6 bytes.
#define SGIP_MAXHWADDRLEN 8
// SGIP_MAXHWHEADER: The maximum allocated size for hardware headers.
#define SGIP_MAXHWHEADER 16
// SGIP_MTU_OVERRIDE: This is the maximum MTU that will be accepted. By default it is being
// set to 1460 bytes in order to be courteous to Ethernet and it's ridiculously low MTU.
// This value will allow you to prevent fragmentation of IP packets by not using the full
// MTU available to your network interface when the IP packet will just be sliced and diced
// at the next smaller MTU. (the stack will still use HW mtu if it's lower.)
#define SGIP_MTU_OVERRIDE 1460
//////////////////////////////////////////////////////////////////////////
// Connection settings - can be tuned to change memory usage and performance
// SGIP_TCP_STATELESS_LISTEN: Uses a technique to prevent syn-flooding from blocking listen
// ports by using all the connection blocks/memory.
#define SGIP_TCP_STATELESS_LISTEN
// SGIP_TCP_STEALTH: Only sends packets in response to connections to active ports. Doing so
// causes ports to appear not as closed, but as if the deviced does not exist when probing
// ports that are not in use.
//#define SGIP_TCP_STEALTH
// SGIP_TCP_TTL: Time-to-live value given to outgoing packets, in the absence of a reason to
// manually override this value.
#define SGIP_IP_TTL 128
// SGIP_TCPRECEIVEBUFFERLENGTH: The size (in bytes) of the receive FIFO in a TCP connection
#define SGIP_TCP_RECEIVEBUFFERLENGTH 8192
// SGIP_TCPTRANSMITBUFFERLENGTH: The size (in bytes) of the transmit FIFO in a TCP connection
#define SGIP_TCP_TRANSMITBUFFERLENGTH 8192
// SGIP_TCPOOBBUFFERLENGTH: The size (in bytes) of the receive OOB data FIFO in a TCP connection
#define SGIP_TCP_OOBBUFFERLENGTH 256
// SGIP_ARP_MAXENTRIES: The maximum number of cached ARP entries - this is defined staticly
// because it's somewhat impractical to dynamicly allocate memory for such a small structure
// (at least on most smaller systems)
#define SGIP_ARP_MAXENTRIES 32
// SGIP_HUB_MAXHWINTERFACES: The maximum number of hardware interfaces the sgIP hub will
// connect to. A hardware interface being some port (ethernet, wifi, etc) that will relay
// packets to the outside world.
#define SGIP_HUB_MAXHWINTERFACES 1
// SGIP_HUB_MAXPROTOCOLINTERFACES: The maximum number of protocol interfaces the sgIP hub will
// connect to. A protocol interface being a software handler for a certain protocol type
// (such as IP)
#define SGIP_HUB_MAXPROTOCOLINTERFACES 1
#define SGIP_TCP_FIRSTOUTGOINGPORT 40000
#define SGIP_TCP_LASTOUTGOINGPORT 65000
#define SGIP_UDP_FIRSTOUTGOINGPORT 40000
#define SGIP_UDP_LASTOUTGOINGPORT 65000
#define SGIP_TCP_GENTIMEOUTMS 6000
#define SGIP_TCP_TRANSMIT_DELAY 25
#define SGIP_TCP_TRANSMIT_IMMTHRESH 40
#define SGIP_TCP_TIMEMS_2MSL 1000*60*2
#define SGIP_TCP_MAXRETRY 7
#define SGIP_TCP_MAXSYNS 64
#define SGIP_TCP_REACK_THRESH 1000
#define SGIP_TCP_SYNRETRYMS 250
#define SGIP_TCP_GENRETRYMS 500
#define SGIP_TCP_BACKOFFMAX 6000
#define SGIP_SOCKET_MAXSOCKETS 32
//#define SGIP_SOCKET_DEFAULT_NONBLOCK 1
//////////////////////////////////////////////////////////////////////////
// DNS settings
#define SGIP_DNS_MAXRECORDSCACHE 16
#define SGIP_DNS_MAXRECORDADDRS 4
#define SGIP_DNS_MAXALIASES 4
#define SGIP_DNS_TIMEOUTMS 5000
#define SGIP_DNS_MAXRETRY 3
#define SGIP_DNS_MAXSERVERRETRY 4
//////////////////////////////////////////////////////////////////////////
#define SGIP_DHCP_ERRORTIMEOUT 45000
#define SGIP_DHCP_RESENDTIMEOUT 3000
#define SGIP_DHCP_DEFAULTHOSTNAME "NintendoDS"
#define SGIP_DHCP_CLASSNAME "sgIP 0.3"
//////////////////////////////////////////////////////////////////////////
// Static memory settings - only used if SGIP_USEDYNAMICMEMORY is NOT defined.
// SGIP_TCP_MAXCONNECTIONS: In the case dynamic memory is not used, this value gives the max
// number of TCP blocks available for inbound/outbound connections via TCP.
#define SGIP_TCP_MAXCONNECTIONS 10
//////////////////////////////////////////////////////////////////////////
// Debugging options
// SGIP_DEBUG: Enable debug logging.
// requires external function "void sgIP_dbgprint(char *, ...);"
//#define SGIP_DEBUG
#ifdef SGIP_DEBUG
#define SGIP_DEBUG_MESSAGE(param) sgIP_dbgprint param
#define SGIP_DEBUG_ERROR(param) sgIP_dbgprint param; while(1);
#else
#define SGIP_DEBUG_MESSAGE(param)
#define SGIP_DEBUG_ERROR(param)
#endif
//////////////////////////////////////////////////////////////////////////
// Error handling
extern int sgIP_errno;
#define SGIP_ERROR(a) ((errno=(a)), -1)
#define SGIP_ERROR0(a) ((errno=(a)), 0)
//////////////////////////////////////////////////////////////////////////
// Error checking
#ifdef SGIP_MULTITHREADED_THREADING_MODEL
#ifdef SGIP_INTERRUPT_THREADING_MODEL
#error SGIP_INTERRUPT_THREADING_MODEL and SGIP_MULTITHREADED_THREADING_MODEL cannot be used together!
#endif
#endif
//////////////////////////////////////////////////////////////////////////
// External option-based dependencies
#ifdef SGIP_INTERRUPT_THREADING_MODEL
#ifdef __cplusplus
extern "C" {
#endif
extern int sgIP_DisableInterrupts();
extern void sgIP_RestoreInterrupts(int);
extern void sgIP_IntrWaitEvent();
#ifdef __cplusplus
};
#endif
#define SGIP_INTR_PROTECT() \
int tIME; \
tIME=sgIP_DisableInterrupts()
#define SGIP_INTR_REPROTECT() \
tIME=sgIP_DisableInterrupts()
#define SGIP_INTR_UNPROTECT() \
sgIP_RestoreInterrupts(tIME)
#define SGIP_WAITEVENT() \
sgIP_IntrWaitEvent()
#else // !SGIP_INTERRUPT_THREADING_MODEL
#define SGIP_INTR_PROTECT()
#define SGIP_INTR_REPROTECT()
#define SGIP_INTR_UNPROTECT()
#define SGIP_WAITEVENT();
#endif // SGIP_INTERRUPT_THREADING_MODEL
#ifdef SGIP_DEBUG
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_dbgprint(char *, ...);
#ifdef __cplusplus
};
#endif
#endif // SGIP_DEBUG
#ifdef SGIP_USEDYNAMICMEMORY
#ifdef __cplusplus
extern "C" {
#endif
extern void * sgIP_malloc(int);
extern void sgIP_free(void *);
#ifdef __cplusplus
};
#endif
#endif // SGIP_USEDYNAMICMEMORY
#endif

View File

@@ -0,0 +1,375 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_DHCP.h"
#include "sgIP_DNS.h"
#include <string.h>
#include "sys/socket.h"
#include "netinet/in.h"
extern unsigned long volatile sgIP_timems;
int dhcp_socket;
char dhcp_hostname[64];
int dhcp_tid;
unsigned long dhcp_timestart, dhcp_timelastaction;
sgIP_DHCP_Packet * dhcp_p;
sgIP_Hub_HWInterface * dhcp_int;
int dhcp_optionptr;
int dhcp_requestDNS;
int dhcp_status;
int dhcp_state; // 0== send DHCPDISCOVER wait for DHCPOFFER, 1== send DHCPREQUEST wait for DHCPACK
unsigned long dhcp_rcvd_ip, dhcp_rcvd_gateway, dhcp_rcvd_snmask, dhcp_rcvd_dns[3], dhcp_serverip;
void sgIP_DHCP_Init() {
dhcp_socket=0;
dhcp_p=0;
dhcp_int=0;
dhcp_rcvd_ip=0;
strcpy(dhcp_hostname,SGIP_DHCP_DEFAULTHOSTNAME);
dhcp_status=SGIP_DHCP_STATUS_IDLE;
}
void sgIP_DHCP_SetHostName(char * s) {
strncpy(dhcp_hostname,s,63);
dhcp_hostname[63]=0;
}
int sgIP_DHCP_IsDhcpIp(unsigned long ip) { // check if the IP address was assigned via dhcp.
return ip==dhcp_rcvd_ip;
}
void sgIP_DHCP_SendDgram() {
struct sockaddr_in sain;
int len_dhcp;
sain.sin_port=htons(67); // bootp server port
sain.sin_addr.s_addr=0xFFFFFFFF; // broadcast
dhcp_p->options[dhcp_optionptr++]=0xFF; // terminate options list.
//sendto(dhcp_socket,dhcp_p,sizeof(sgIP_DHCP_Packet)-312+dhcp_optionptr,0,(struct sockaddr *)&sain,sizeof(sain));
len_dhcp = sizeof(sgIP_DHCP_Packet)-312+dhcp_optionptr;
if(len_dhcp<300) len_dhcp=300;
sendto(dhcp_socket,dhcp_p,len_dhcp,0,(struct sockaddr *)&sain,sizeof(sain));
sgIP_free(dhcp_p);
dhcp_p=0;
dhcp_timelastaction=sgIP_timems;
}
void sgIP_DHCP_BeginDgram(int dgramtype) {
int i;
if(dhcp_p) sgIP_free(dhcp_p);
dhcp_p = (sgIP_DHCP_Packet *) sgIP_malloc(sizeof(sgIP_DHCP_Packet));
if(!dhcp_p) return;
// ensure packet is zero'd.. seems to pacify some routers. malloc doesn't initialise the memory returned.
memset(dhcp_p,0,sizeof(sgIP_DHCP_Packet));
dhcp_p->op=1; // 1==BOOTREQUEST
dhcp_p->htype=1; // 1== ethernet address type
dhcp_p->hlen=6; // hardware address length
dhcp_p->hops=0; // client sets to zero
dhcp_p->xid=dhcp_tid; // DHCP transaction ID
dhcp_p->secs=(sgIP_timems-dhcp_timestart)/1000; // seconds since DHCP start
dhcp_p->flags=htons(0x0000); // top bit set = request broadcast response
dhcp_p->ciaddr=0;
dhcp_p->yiaddr=0;
dhcp_p->siaddr=0;
dhcp_p->giaddr=0;
memcpy(dhcp_p->chaddr,dhcp_int->hwaddr,6);
dhcp_optionptr=0;
dhcp_p->options[dhcp_optionptr++]=0x63;
dhcp_p->options[dhcp_optionptr++]=0x82;
dhcp_p->options[dhcp_optionptr++]=0x53;
dhcp_p->options[dhcp_optionptr++]=0x63; // 4-byte "magic cookie" (bleh!)
// add some necessary options... - by default add the dhcp message type, host name, class id, and parameter request list
dhcp_p->options[dhcp_optionptr++]=0x35; // DHCP Message type
dhcp_p->options[dhcp_optionptr++]=0x01;
dhcp_p->options[dhcp_optionptr++]=dgramtype;
dhcp_p->options[dhcp_optionptr++]=0x3D; // DHCP client identifier
dhcp_p->options[dhcp_optionptr++]=0x07; // length
dhcp_p->options[dhcp_optionptr++]=0x01; // hw type
for(i=0;i<6;i++) dhcp_p->options[dhcp_optionptr++]=dhcp_int->hwaddr[i];
dhcp_p->options[dhcp_optionptr++]=0x0C; // DHCP host name
dhcp_p->options[dhcp_optionptr++]=strlen(dhcp_hostname);
for(i=0;i<strlen(dhcp_hostname);i++) {
dhcp_p->options[dhcp_optionptr++]=dhcp_hostname[i];
}
dhcp_p->options[dhcp_optionptr++]=0x37; // DHCP Parameter request list
dhcp_p->options[dhcp_optionptr++]=2+dhcp_requestDNS;
dhcp_p->options[dhcp_optionptr++]=1; // subnet mask
dhcp_p->options[dhcp_optionptr++]=3; // router
if(dhcp_requestDNS) dhcp_p->options[dhcp_optionptr++]=6; // dns server
if(dgramtype==DHCP_TYPE_REQUEST) {
dhcp_p->options[dhcp_optionptr++]=0x32; // DHCP Requested IP address
dhcp_p->options[dhcp_optionptr++]=0x04;
dhcp_p->options[dhcp_optionptr++]=(dhcp_rcvd_ip)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_rcvd_ip>>8)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_rcvd_ip>>16)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_rcvd_ip>>24)&255;
dhcp_p->options[dhcp_optionptr++]=0x36; // DHCP Server identifier
dhcp_p->options[dhcp_optionptr++]=0x04;
dhcp_p->options[dhcp_optionptr++]=(dhcp_serverip)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_serverip>>8)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_serverip>>16)&255;
dhcp_p->options[dhcp_optionptr++]=(dhcp_serverip>>24)&255;
}
dhcp_p->options[dhcp_optionptr++]=0x3C; // DHCP Vendor Class ID
dhcp_p->options[dhcp_optionptr++]=strlen(SGIP_DHCP_CLASSNAME);
for(i=0;i<strlen(SGIP_DHCP_CLASSNAME);i++) {
dhcp_p->options[dhcp_optionptr++]=(SGIP_DHCP_CLASSNAME)[i];
}
// reason we don't send it immediately is in case the calling code wants to modify some data or add some options.
}
void sgIP_DHCP_Start(sgIP_Hub_HWInterface * interface, int getDNS) { // begin dhcp transaction to get IP and maybe DNS data.
struct sockaddr_in sain;
int i;
SGIP_DEBUG_MESSAGE(("sgIP_DHCP_Start()"));
sgIP_DHCP_Terminate();
dhcp_requestDNS=getDNS?1:0;
dhcp_int=interface;
dhcp_timestart=sgIP_timems;
dhcp_timelastaction=sgIP_timems;
dhcp_tid=sgIP_timems;
dhcp_status=SGIP_DHCP_STATUS_WORKING;
dhcp_state=0;
dhcp_rcvd_ip = 0;
dhcp_rcvd_gateway=0;
dhcp_rcvd_snmask=0;
dhcp_rcvd_dns[0]=0;
dhcp_rcvd_dns[1]=0;
dhcp_rcvd_dns[2]=0;
dhcp_socket=socket(AF_INET,SOCK_DGRAM,0);
sain.sin_addr.s_addr=0;
sain.sin_port=htons(68); // BOOTP client
bind(dhcp_socket,(struct sockaddr *)&sain,sizeof(sain));
i=1;
ioctl(dhcp_socket,FIONBIO,&i);
sgIP_DHCP_BeginDgram(DHCP_TYPE_DISCOVER);
sgIP_DHCP_SendDgram();
}
void sgIP_DHCP_Release() { // call to dump our DHCP address and leave.
if(dhcp_status==SGIP_DHCP_STATUS_WORKING) {
sgIP_DHCP_Terminate();
} else {
sgIP_DHCP_BeginDgram(DHCP_TYPE_RELEASE);
dhcp_p->ciaddr=dhcp_int->ipaddr;
sgIP_DHCP_SendDgram();
}
}
int sgIP_DHCP_Update() { // MUST be called periodicly; returns status - call until it returns SGIP_DHCP_STATUS_SUCCESS or _FAILED.
sgIP_DHCP_Packet * p;
struct sockaddr_in * sain;
int i,j,n,l;
if(dhcp_status!=SGIP_DHCP_STATUS_WORKING) return dhcp_status;
int send = 0;
p=(sgIP_DHCP_Packet *)sgIP_malloc(sizeof(sgIP_DHCP_Packet));
if(p) {
while(1) {
l=recvfrom(dhcp_socket,p,sizeof(sgIP_DHCP_Packet),0,(struct sockaddr *)&sain,&n);
if(l==-1) break;
if(p->op!=2 || p->htype!=1 || p->hlen!=6 || p->xid!=dhcp_tid ) continue;
// check magic cookie
if(p->options[0]!=0x63 || p->options[1]!=0x82 || p->options[2]!=0x53 || p->options[3]!=0x63) continue;
i=4; // yay, the cookie is valid.
l -= (sizeof(sgIP_DHCP_Packet)-312); // number of bytes remaining in the options
while(i<l) {
n=p->options[i++];
switch(n) {
case 0: // ignore
break;
case 255: // end-of-options marker.
l=0;
break;
case 53: // message type, variable length, 2+n
j=p->options[i++];
if(dhcp_state==0) {
if(p->options[i]!=DHCP_TYPE_OFFER) l=-1;
} else {
if(p->options[i]==DHCP_TYPE_ACK) {
sgIP_free(p);
sgIP_DHCP_Terminate();
dhcp_int->ipaddr=dhcp_rcvd_ip;
dhcp_int->gateway=dhcp_rcvd_gateway;
dhcp_int->snmask=dhcp_rcvd_snmask;
SGIP_DEBUG_MESSAGE(("DHCP Configured!"));
SGIP_DEBUG_MESSAGE(("IP%08X SM%08X GW%08X",dhcp_rcvd_ip,dhcp_rcvd_snmask,dhcp_rcvd_gateway));
if(dhcp_requestDNS) {
dhcp_int->dns[0]=dhcp_rcvd_dns[0];
dhcp_int->dns[1]=dhcp_rcvd_dns[1];
dhcp_int->dns[2]=dhcp_rcvd_dns[2];
SGIP_DEBUG_MESSAGE(("DNS %08X %08X %08X",dhcp_rcvd_dns[0],dhcp_rcvd_dns[1],dhcp_rcvd_dns[2]));
}
dhcp_status=SGIP_DHCP_STATUS_SUCCESS;
return dhcp_status;
} else {
l=-1;
}
}
i+=j;
break;
case 1: // subnet mask field, variable length 2+n
j=p->options[i++];
if(dhcp_state==1 || j<4) {i+=j; break; }
dhcp_rcvd_snmask = (dhcp_rcvd_snmask>>8) | (p->options[i++]<<24);
dhcp_rcvd_snmask = (dhcp_rcvd_snmask>>8) | (p->options[i++]<<24);
dhcp_rcvd_snmask = (dhcp_rcvd_snmask>>8) | (p->options[i++]<<24);
dhcp_rcvd_snmask = (dhcp_rcvd_snmask>>8) | (p->options[i++]<<24);
i+=j-4;
break;
case 3: // gateway, variable length 2+n
j=p->options[i++];
if(dhcp_state==1 || j<4) {i+=j; break; }
dhcp_rcvd_gateway = (dhcp_rcvd_gateway>>8) | (p->options[i++]<<24);
dhcp_rcvd_gateway = (dhcp_rcvd_gateway>>8) | (p->options[i++]<<24);
dhcp_rcvd_gateway = (dhcp_rcvd_gateway>>8) | (p->options[i++]<<24);
dhcp_rcvd_gateway = (dhcp_rcvd_gateway>>8) | (p->options[i++]<<24);
i+=j-4;
break;
case 54: // server ID, variable length 2+n
j=p->options[i++];
if(dhcp_state==1 || j<4) {i+=j; break; }
dhcp_serverip = (dhcp_serverip>>8) | (p->options[i++]<<24);
dhcp_serverip = (dhcp_serverip>>8) | (p->options[i++]<<24);
dhcp_serverip = (dhcp_serverip>>8) | (p->options[i++]<<24);
dhcp_serverip = (dhcp_serverip>>8) | (p->options[i++]<<24);
i+=j-4;
break;
case 6: // dns servers, variable length 2+n
if(dhcp_requestDNS && !dhcp_state) {
j=p->options[i++];
n=0;
while(n<3 && 4*n+3<j) {
dhcp_rcvd_dns[n] = (dhcp_rcvd_dns[n]>>8) | (p->options[i++]<<24);
dhcp_rcvd_dns[n] = (dhcp_rcvd_dns[n]>>8) | (p->options[i++]<<24);
dhcp_rcvd_dns[n] = (dhcp_rcvd_dns[n]>>8) | (p->options[i++]<<24);
dhcp_rcvd_dns[n] = (dhcp_rcvd_dns[n]>>8) | (p->options[i++]<<24);
n++;
}
i+=j-4*n;
break;
}
default:
j=p->options[i++];
i+=j;
}
}
if(l==-1) continue;
dhcp_rcvd_ip=(p->yiaddr);
// discover succeeded. increment transaction id. force sending REQUEST message next.
dhcp_state=1;
dhcp_tid += ( sgIP_timems-dhcp_timestart ) + 1;
send = 1;
break;
}
sgIP_free(p);
// has timeout expired?
if( (sgIP_timems-dhcp_timestart) > SGIP_DHCP_ERRORTIMEOUT) {
SGIP_DEBUG_MESSAGE(("sgIP DHCP error timeout!"));
sgIP_DHCP_Terminate();
dhcp_status=SGIP_DHCP_STATUS_FAILED;
return dhcp_status;
}
if( send || (sgIP_timems-dhcp_timelastaction) > SGIP_DHCP_RESENDTIMEOUT )
{
if(dhcp_state==0) sgIP_DHCP_BeginDgram(DHCP_TYPE_DISCOVER); else sgIP_DHCP_BeginDgram(DHCP_TYPE_REQUEST);
sgIP_DHCP_SendDgram();
}
} else {
SGIP_DEBUG_MESSAGE(("sgIP DHCP alloc failed!"));
sgIP_DHCP_Terminate();
dhcp_status=SGIP_DHCP_STATUS_FAILED;
}
return dhcp_status;
}
void sgIP_DHCP_Terminate() { // kill the process where it stands; deallocate all DHCP resources.
if(dhcp_socket) closesocket(dhcp_socket);
dhcp_socket=0;
if(dhcp_p) sgIP_free(dhcp_p);
dhcp_p=0;
dhcp_status=SGIP_DHCP_STATUS_IDLE;
}
int gethostname(char *name, size_t len)
{
int size = sizeof(dhcp_hostname);
if (name == NULL)
return SGIP_ERROR(EFAULT);
if ( len <= size )
return SGIP_ERROR(EINVAL);
strncpy(name, dhcp_hostname, size);
name[size]=0;
return 0;
}
int sethostname(const char *name, size_t len)
{
sgIP_DNS_Record *rec;
int size = sizeof(dhcp_hostname);
if (name == NULL)
return SGIP_ERROR(EFAULT);
if ( len > size - 1)
return SGIP_ERROR(EINVAL);
rec = sgIP_DNS_FindDNSRecord(dhcp_hostname);
strncpy(dhcp_hostname, name, len);
dhcp_hostname[len]=0;
strncpy(rec->aliases[0], name, len);
rec->aliases[0][len]=0;
strncpy(rec->name, name, len);
rec->name[len]=0;
return 0;
}

View File

@@ -0,0 +1,86 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_DHCP_H
#define SGIP_DHCP_H
#include "sgIP_Config.h"
#include "sgIP_Hub.h"
// "DHCP Server" port is 67, "DHCP Client" port is 68
// DHCP messages broadcast by a client prior to that client obtaining its IP address must have the source address field in the IP header set to 0.
typedef struct SGIP_DHCP_PACKET { // yes, freaking big endian prevails here too.
unsigned char op; // opcode/message type (1=BOOTREQUEST, 2=BOOTREPLY)
unsigned char htype; // hardware address type
unsigned char hlen; // Hardware address length (should be 6, for ethernet/wifi)
unsigned char hops; // set to 0
unsigned long xid; // 4-byte client specified transaction ID
unsigned short secs; // seconds elapsed since client started trying to boot
unsigned short flags; // flags
unsigned long ciaddr; // client IP address, filled in by client if verifying previous params
unsigned long yiaddr; // "your" (client) IP address
unsigned long siaddr; // IP addr of next server to use in bootstrap.
unsigned long giaddr; // Relay agent IP address
unsigned char chaddr[16]; // client hardware address
char sname[64]; // optional server hostname (null terminated string)
char file[128]; // boot file name, null terminated string
char options[312]; // optional parameters
} sgIP_DHCP_Packet;
enum SGIP_DHCP_STATUS {
SGIP_DHCP_STATUS_IDLE,
SGIP_DHCP_STATUS_WORKING,
SGIP_DHCP_STATUS_FAILED,
SGIP_DHCP_STATUS_SUCCESS
};
#define DHCP_TYPE_DISCOVER 1
#define DHCP_TYPE_OFFER 2
#define DHCP_TYPE_REQUEST 3
#define DHCP_TYPE_ACK 5
#define DHCP_TYPE_RELEASE 7
#ifdef __cplusplus
extern "C" {
#endif
void sgIP_DHCP_Init();
void sgIP_DHCP_SetHostName(char * s); // just for the fun of it.
int sgIP_DHCP_IsDhcpIp(unsigned long ip); // check if the IP address was assigned via dhcp.
void sgIP_DHCP_Start(sgIP_Hub_HWInterface * interface, int getDNS); // begin dhcp transaction to get IP and maybe DNS data.
void sgIP_DHCP_Release(); // call to dump our DHCP address and leave.
int sgIP_DHCP_Update(); // MUST be called periodicly after _Start; returns status - call until it returns something other than SGIP_DHCP_STATUS_WORKING
void sgIP_DHCP_Terminate(); // kill the process where it stands; deallocate all DHCP resources.
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,492 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_DNS.h"
#include "sgIP_Hub.h"
#include "netinet/in.h"
#include "sys/socket.h"
int dns_sock;
int time_count;
int last_id;
int query_time_start;
extern unsigned long volatile sgIP_timems;
// cache record data
sgIP_DNS_Record dnsrecords[SGIP_DNS_MAXRECORDSCACHE];
// data to return via hostent
volatile sgIP_DNS_Record dnsrecord_return;
volatile char * alias_list[SGIP_DNS_MAXALIASES+1];
volatile char * addr_list[SGIP_DNS_MAXRECORDADDRS+1];
char ipaddr_alias[256];
unsigned long ipaddr_ip;
volatile sgIP_DNS_Hostent dnsrecord_hostent;
unsigned char querydata[512];
unsigned char responsedata[512];
void sgIP_DNS_Init() {
int i;
for(i=0;i<SGIP_DNS_MAXRECORDSCACHE;i++) dnsrecords[i].flags=0;
dns_sock=-1;
time_count=0;
}
void sgIP_DNS_Timer1000ms() {
int i;
time_count++;
for(i=0;i<SGIP_DNS_MAXRECORDSCACHE;i++) {
if(dnsrecords[i].flags & SGIP_DNS_FLAG_RESOLVED) {
dnsrecords[i].TTL-=1;
if(dnsrecords[i].TTL<=0) {
dnsrecords[i].flags=0;
}
}
}
}
int sgIP_DNS_isipaddress(const char * name, unsigned long * ipdest) {
int i,j,t,ndot;
unsigned long out_addr, g[4];
const char * c;
ndot=0;
c=name;
while(*c) { // scan for invalid characters
if(!((*c>='0' && *c<='9') || (*c>='A' && *c<='F') || (*c>='a' && *c<='f') || *c=='.' || *c=='x' || *c=='X')) return 0;
if(*c=='.') ndot++;
c++;
}
if(ndot>3) return 0;
c=name;
for(i=0;i<=ndot;i++) {
g[i]=0;
t=0;
j=0;
while(*c && *c!='.') {
if(j==0 && *c=='0') { t++; }
else if(j==1 && t==1 && (*c=='x' || *c=='X')) { t++; }
else {
switch(t) {
case 0: // decimal
if(*c=='x' || *c=='X' || (*c>='A' && *c<='F') || (*c>='a' && *c<='f')) return 0;
g[i]=(g[i]*10)+(*c-'0');
break;
case 1: // octal
if(*c=='x' || *c=='X' || (*c>='A' && *c<='F') || (*c>='a' && *c<='f') || *c=='8' || *c=='9') return 0;
g[i]=(g[i]<<3)+(*c-'0');
break;
case 2: // hex
if(*c=='x' || *c=='X') return 0;
if(*c>='0' && *c<='9') {
g[i]=(g[i]<<4)+(*c-'0');
} else {
g[i]=(g[i]<<4)+(*c&0xDF)+9;
}
break;
}
}
j++; c++;
}
if(*c) c++; else break;
}
out_addr=0;
switch(ndot) {
case 0:
out_addr=g[0];
break;
case 1:
if(g[0]>=0x100 || g[1]>=0x1000000) return 0;
out_addr= (g[0]<<24) | g[1];
break;
case 2:
if(g[0]>=0x100 || g[1]>=0x100 || g[2]>=0x10000) return 0;
out_addr= (g[0]<<24) | (g[1]<<16) | g[2];
break;
case 3:
if(g[0]>=0x100 || g[1]>=0x100 || g[2]>=0x100 || g[3]>=0x100) return 0;
out_addr= (g[0]<<24) | (g[1]<<16) | (g[2]<<8) | g[3];
break;
}
*ipdest=htonl(out_addr);
return 1;
}
sgIP_DNS_Record * sgIP_DNS_FindDNSRecord(const char * name) {
int i,j,k,n,c,c2;
SGIP_INTR_PROTECT();
for(i=0;i<SGIP_DNS_MAXRECORDSCACHE;i++) {
if((dnsrecords[i].flags&(SGIP_DNS_FLAG_ACTIVE|SGIP_DNS_FLAG_RESOLVED)) == (SGIP_DNS_FLAG_ACTIVE|SGIP_DNS_FLAG_RESOLVED)) {
for(j=0;j<dnsrecords[i].numalias;j++) {
k=0;
for(n=0;name[n] && dnsrecords[i].aliases[j][n]; n++) { // obscure and complex case-insensitive string compare.
c=name[n];
c2=dnsrecords[i].aliases[j][n];
if(c>='a' && c<='z') c+='A'-'a';
if(c2>='a' && c2<='z') c2+='A'-'a';
if(c==c2) {
k++;
} else {
k=0; break;
}
}
if(name[n] || dnsrecords[i].aliases[j][n]) k=0;
if(k) {
SGIP_INTR_UNPROTECT();
return dnsrecords+i;
}
}
}
}
SGIP_INTR_UNPROTECT();
return 0;
}
sgIP_DNS_Record * sgIP_DNS_GetUnusedRecord() {
int i,j,minttl;
SGIP_INTR_PROTECT();
for(i=0;i<SGIP_DNS_MAXRECORDSCACHE;i++) {
if(!(dnsrecords[i].flags&SGIP_DNS_FLAG_ACTIVE)) {
SGIP_INTR_UNPROTECT();
return dnsrecords+i;
}
}
minttl=dnsrecords[0].TTL; j=0;
for(i=1;i<SGIP_DNS_MAXRECORDSCACHE;i++) {
if(dnsrecords[i].TTL<minttl && !(dnsrecords[i].flags&SGIP_DNS_FLAG_BUSY)) {
j=i;
minttl=dnsrecords[i].TTL;
}
}
dnsrecords[j].flags=0;
SGIP_INTR_UNPROTECT();
return dnsrecords+j;
}
static
void sgIP_ntoa(unsigned long ipaddr) {
int c,i,j,n;
c=0;
for(j=0;j<4;j++) {
if(j) ipaddr_alias[c++]='.';
n=(ipaddr>>(j*8))&255;
i=0;
if(n>=100) { i=n/100; ipaddr_alias[c++]='0'+i; n-=i*100; }
if(n>=10 || i) { i=n/10; ipaddr_alias[c++]='0'+i; n-=i*10; }
ipaddr_alias[c++]='0'+n;
}
ipaddr_alias[c]=0;
}
static
sgIP_DNS_Hostent * sgIP_DNS_GenerateHostentIP(unsigned long ipaddr) {
sgIP_ntoa(ipaddr);
alias_list[0]=ipaddr_alias;
alias_list[1]=0;
ipaddr_ip=ipaddr;
addr_list[0]=(char *)&ipaddr_ip;
addr_list[1]=0;
dnsrecord_hostent.h_addr_list=(char **)addr_list;
dnsrecord_hostent.h_addrtype=1;
dnsrecord_hostent.h_aliases=(char **)alias_list;
dnsrecord_hostent.h_length=4;
dnsrecord_hostent.h_name=ipaddr_alias;
return (sgIP_DNS_Hostent *)&dnsrecord_hostent;
}
sgIP_DNS_Hostent * sgIP_DNS_GenerateHostent(sgIP_DNS_Record * dnsrec) {
volatile int i;
dnsrecord_return = *dnsrec; // copy struct
for(i=0;i<dnsrecord_return.numalias;i++) {
alias_list[i]=dnsrecord_return.aliases[i];
}
alias_list[i]=0;
for(i=0;i<dnsrecord_return.numaddr;i++) {
addr_list[i]=(char *)&(dnsrecord_return.addrdata[i*dnsrecord_return.addrlen]);
}
addr_list[i]=0;
dnsrecord_hostent.h_addr_list=(char **)addr_list;
dnsrecord_hostent.h_addrtype=dnsrecord_return.addrclass;
dnsrecord_hostent.h_aliases=(char **)alias_list;
dnsrecord_hostent.h_length=dnsrecord_return.addrlen;
dnsrecord_hostent.h_name=(char *)dnsrecord_return.name;
return (sgIP_DNS_Hostent *)&dnsrecord_hostent;
}
static
int sgIP_DNS_genquery(const char * name) {
int i,j,c,l;
unsigned short * querydata_s = (unsigned short *) querydata;
unsigned char * querydata_c = querydata;
// header section
querydata_s[0]=htons(time_count&0xFFFF);
last_id=querydata_s[0];
querydata_s[1]=htons(0x0100); // recursion desired, standard query
querydata_s[2]=htons(1); // one QD (question)
querydata_s[3]=0; // no resource records
querydata_s[4]=0; // no nameserver records
querydata_s[5]=0; // no additional records
// question section
querydata_c+=12;
querydata_s+=6;
j=0;
i=0;
while(1) {
l=j;
j++;
c=0;
while(name[i]!=0 && name[i]!='.' && i<255) {
querydata_c[j++]=name[i++]; c++;
}
querydata_c[l]=c;
if(name[i]==0 || i>=255) break;
if(c==0) return 0; // this should never happen (unless there's really invalid input with 2 dots next to each other.)
i++;
}
querydata_c[j++]=0; // terminating zero length
// qtype
querydata_c[j++]=0;
querydata_c[j++]=1; // 00 01 "A" (address)
// qclass
querydata_c[j++]=0;
querydata_c[j++]=1; // 00 01 "IN" (internet)
return j+12; // length
}
void sgIP_DNS_CopyAliasAt(char * deststr,int offset) {
char * c;
int i,j;
i=0;
c=(char *)responsedata+offset;
do {
j=c[0];
if(j>63) {
j=((j&63)<<8) | c[1];
c=(char *)responsedata+j;
continue;
}
if(!j) break;
c++;
for(;j>0;j--) {
deststr[i++]= *(c++);
}
deststr[i++]='.';
} while(1);
if(i>0) i--;
deststr[i]=0;
}
sgIP_DNS_Hostent * sgIP_DNS_gethostbyname(const char * name) {
sgIP_DNS_Record * rec;
sgIP_DNS_Hostent * he;
sgIP_Hub_HWInterface * hw;
int len,i,sainlen;
int retries,dtime;
unsigned long serverip;
struct sockaddr_in sain;
unsigned long IP;
SGIP_INTR_PROTECT();
// is name an IP address?
if(sgIP_DNS_isipaddress(name,&IP)) {
SGIP_INTR_UNPROTECT();
return sgIP_DNS_GenerateHostentIP(IP);
}
// check cache, return if value required is in cache...
rec=sgIP_DNS_FindDNSRecord(name);
if(rec) {
he=sgIP_DNS_GenerateHostent(rec);
SGIP_INTR_UNPROTECT();
return he;
}
// not in cache? generate a query...
len=sgIP_DNS_genquery(name);
// send off the query, handle retransmit and trying other dns servers.
if(dns_sock==-1) {
hw=sgIP_Hub_GetDefaultInterface();
serverip=hw->dns[0];
dns_sock=socket(AF_INET,SOCK_DGRAM,0);
i=1;
i=ioctl(dns_sock,FIONBIO,&i); // set non-blocking
retries=0;
do {
query_time_start=sgIP_timems;
sain.sin_addr.s_addr=serverip;
sain.sin_port=htons(53);
i=sendto(dns_sock,querydata,len,0,(struct sockaddr *)&sain,sizeof(sain));
dns_listenonly:
do {
i=recvfrom(dns_sock,responsedata,512,0,(struct sockaddr *)&sain,&sainlen);
if(i!=-1) break;
dtime=sgIP_timems-query_time_start;
if(dtime>SGIP_DNS_TIMEOUTMS) break;
SGIP_INTR_UNPROTECT();
SGIP_WAITEVENT();
SGIP_INTR_REPROTECT();
} while(1);
if(i==-1) { // no reply, retry
retries++;
if(retries>=SGIP_DNS_MAXRETRY) { // maybe try another server? for now just quit.
closesocket(dns_sock);
dns_sock=-1;
SGIP_INTR_UNPROTECT();
return NULL;
}
continue; // send again
}
// got something, is it what we want?
if(i<12 || sain.sin_addr.s_addr!=serverip || sain.sin_port!=htons(53)) { // suspicious.
goto dns_listenonly; // yay! a goto! - go back and see if we can get a more official response.
}
// parse response.
{
const unsigned short * resdata_s = (unsigned short *) responsedata;
const unsigned char * resdata_c = responsedata;
const char * c;
int j,q,a, nalias,naddr;
if(last_id!=resdata_s[0]) { // bad.
goto dns_listenonly;
}
q=htons(resdata_s[2]);
a=htons(resdata_s[3]);
// no answer.
if (a == 0)
{
closesocket(dns_sock);
dns_sock=-1;
SGIP_INTR_UNPROTECT();
return NULL;
}
resdata_c+=12;
while(q) { // ignore questions
do {
j=resdata_c[0];
if(j>63) { resdata_c+=2; break; }
resdata_c += j+1;
} while(j);
resdata_c+=4;
q--;
}
nalias=0;
naddr=0;
rec=sgIP_DNS_GetUnusedRecord();
rec->flags=SGIP_DNS_FLAG_ACTIVE | SGIP_DNS_FLAG_BUSY;
while(a) {
if(nalias<SGIP_DNS_MAXALIASES) sgIP_DNS_CopyAliasAt(rec->aliases[nalias++],resdata_c-responsedata);
do {
j=resdata_c[0];
if(j>63) { resdata_c+=2; break; }
resdata_c += j+1;
} while(j);
// CNAME=5, A=1
j=resdata_c[1];
rec->addrclass=(resdata_c[2]<<8)|resdata_c[3];
rec->TTL = (resdata_c[4]<<24)|(resdata_c[5]<<16)|(resdata_c[6]<<8)|resdata_c[7];
if(j==1) { // A
if(naddr<SGIP_DNS_MAXRECORDADDRS) {
rec->addrdata[naddr*4] = resdata_c[10];
rec->addrdata[naddr*4+1] = resdata_c[11];
rec->addrdata[naddr*4+2] = resdata_c[12];
rec->addrdata[naddr*4+3] = resdata_c[13];
naddr++;
}
}
j=(resdata_c[8]<<8)|resdata_c[9];
resdata_c+=10+j;
a--;
}
// likely we have all the data we care for now.
rec->addrlen=4;
rec->numaddr=naddr;
rec->numalias=nalias;
for(c=name,i=0;*c;c++,i++) rec->name[i]=*c;
rec->name[i]=0;
rec->flags=SGIP_DNS_FLAG_ACTIVE | SGIP_DNS_FLAG_RESOLVED;
break; // we got our answer, let's get out of here!
}
} while(1);
closesocket(dns_sock);
dns_sock=-1;
} else {
SGIP_INTR_UNPROTECT();
return NULL;
}
// received response, return data
he=sgIP_DNS_GenerateHostent(rec);
SGIP_INTR_UNPROTECT();
return he;
}
unsigned long inet_addr(const char *cp) {
unsigned long IP;
if(sgIP_DNS_isipaddress(cp,&IP)) {
return IP;
}
return 0xFFFFFFFF;
}
int inet_aton(const char *cp, struct in_addr *inp) {
unsigned long IP;
if(sgIP_DNS_isipaddress(cp,&IP)) {
inp->s_addr = IP;
return 1;
}
return 0;
}
char *inet_ntoa(struct in_addr in) {
sgIP_ntoa(in.s_addr);
return (char *)ipaddr_alias;
}

View File

@@ -0,0 +1,69 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_DNS_H
#define SGIP_DNS_H
#include "sgIP_Config.h"
#define SGIP_DNS_FLAG_ACTIVE 1
#define SGIP_DNS_FLAG_RESOLVED 2
#define SGIP_DNS_FLAG_BUSY 4
typedef struct SGIP_DNS_RECORD {
char name [256];
char aliases[SGIP_DNS_MAXALIASES][256];
unsigned char addrdata[SGIP_DNS_MAXRECORDADDRS*4];
short addrlen;
short addrclass;
int numaddr,numalias;
int TTL;
int flags;
} sgIP_DNS_Record;
typedef struct SGIP_DNS_HOSTENT {
char * h_name;
char ** h_aliases;
int h_addrtype; // class - 1=IN (internet)
int h_length;
char ** h_addr_list;
} sgIP_DNS_Hostent;
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_DNS_Init();
extern void sgIP_DNS_Timer1000ms();
extern sgIP_DNS_Hostent * sgIP_DNS_gethostbyname(const char * name);
extern sgIP_DNS_Record * sgIP_DNS_GetUnusedRecord();
extern sgIP_DNS_Record * sgIP_DNS_FindDNSRecord(const char * name);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,211 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_Hub.h"
#include "sgIP_ARP.h"
//////////////////////////////////////////////////////////////////////////
// Global vars
int NumHWInterfaces;
int NumProtocolInterfaces;
sgIP_Hub_Protocol ProtocolInterfaces[SGIP_HUB_MAXPROTOCOLINTERFACES];
sgIP_Hub_HWInterface HWInterfaces[SGIP_HUB_MAXHWINTERFACES];
//////////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////////
// Public functions
void sgIP_Hub_Init() {
NumHWInterfaces=0;
NumProtocolInterfaces=0;
}
sgIP_Hub_Protocol * sgIP_Hub_AddProtocolInterface(int protocolID, int (*ReceivePacket)(sgIP_memblock *), int (*InterfaceInit)(sgIP_Hub_Protocol *)) {
int n;
if(NumProtocolInterfaces>=SGIP_HUB_MAXPROTOCOLINTERFACES) return 0;
for(n=0;n<SGIP_HUB_MAXPROTOCOLINTERFACES;n++) {
if(!(ProtocolInterfaces[n].flags&SGIP_FLAG_PROTOCOL_IN_USE)) break;
}
if(n==SGIP_HUB_MAXPROTOCOLINTERFACES) return 0;
ProtocolInterfaces[n].flags=SGIP_FLAG_PROTOCOL_IN_USE | SGIP_FLAG_PROTOCOL_ENABLED;
ProtocolInterfaces[n].protocol=protocolID;
ProtocolInterfaces[n].ReceivePacket=ReceivePacket;
if(InterfaceInit) InterfaceInit(ProtocolInterfaces+n);
NumProtocolInterfaces++;
return ProtocolInterfaces+n;
}
sgIP_Hub_HWInterface * sgIP_Hub_AddHardwareInterface(int (*TransmitFunction)(sgIP_Hub_HWInterface *, sgIP_memblock *), int (*InterfaceInit)(sgIP_Hub_HWInterface *)) {
int n;
if(NumHWInterfaces>=SGIP_HUB_MAXHWINTERFACES) return 0;
for(n=0;n<SGIP_HUB_MAXHWINTERFACES;n++) {
if(!(HWInterfaces[n].flags&SGIP_FLAG_HWINTERFACE_IN_USE)) break;
}
if(n==SGIP_HUB_MAXHWINTERFACES) return 0;
HWInterfaces[n].flags = SGIP_FLAG_HWINTERFACE_IN_USE | SGIP_FLAG_HWINTERFACE_ENABLED;
HWInterfaces[n].TransmitFunction=TransmitFunction;
if(InterfaceInit) InterfaceInit(HWInterfaces+n);
NumHWInterfaces++;
return HWInterfaces+n;
}
extern void sgIP_Hub_RemoveProtocolInterface(sgIP_Hub_Protocol * protocol) {
int n;
for(n=0;n<SGIP_HUB_MAXPROTOCOLINTERFACES;n++) {
if(ProtocolInterfaces+n ==protocol) break;
}
if(n==SGIP_HUB_MAXPROTOCOLINTERFACES) return;
protocol->flags=0;
NumProtocolInterfaces--;
}
extern void sgIP_Hub_RemoveHardwareInterface(sgIP_Hub_HWInterface * hw) {
int n;
for(n=0;n<SGIP_HUB_MAXHWINTERFACES;n++) {
if(HWInterfaces+n == hw) break;
}
if(n==SGIP_HUB_MAXHWINTERFACES) return;
hw->flags=0;
NumHWInterfaces--;
}
int sgIP_Hub_ReceiveHardwarePacket(sgIP_Hub_HWInterface * hw, sgIP_memblock * packet) {
if(!hw || !packet) return 0;
if(hw->flags & SGIP_FLAG_HWINTERFACE_ENABLED) {
int n;
int protocol;
protocol = ((unsigned short *)packet->datastart)[6];
// SGIP_DEBUG_MESSAGE(("hub: rx packet %04X %X",protocol,packet->totallength));
if(protocol==PROTOCOL_ETHER_ARP) { // arp
sgIP_ARP_ProcessARPFrame(hw,packet);
return 0;
}
if(protocol==PROTOCOL_ETHER_IP) { // IP, forward to the ARP system.
}
// hide ethernet header for higher-level protocols
sgIP_memblock_exposeheader(packet,-14);
for(n=0;n<SGIP_HUB_MAXPROTOCOLINTERFACES;n++) {
if(ProtocolInterfaces[n].flags&SGIP_FLAG_PROTOCOL_ENABLED && ProtocolInterfaces[n].protocol==protocol) { // this protocol handler
return ProtocolInterfaces[n].ReceivePacket(packet);
}
}
}
// hrmm, packet is unhandled. Ignore it for now.
sgIP_memblock_free(packet);
return 0;
}
// send packet from a protocol interface, resolve the requisite hardware interface addresses and send it.
int sgIP_Hub_SendProtocolPacket(int protocol, sgIP_memblock * packet, unsigned long dest_address, unsigned long src_address) {
if(!packet) return 0;
sgIP_Hub_HWInterface * hw;
int i;
hw=0;
// figure out what hardware interface is in use.
for(i=0;i<SGIP_HUB_MAXHWINTERFACES;i++) if(HWInterfaces[i].ipaddr==src_address) {hw=HWInterfaces+i; break;}
if(!hw) {
sgIP_memblock_free(packet);
return 0;
}
// resolve protocol address to hardware address & send packet
if( (src_address & hw->snmask) == (dest_address & hw->snmask) // on same network
|| dest_address == 0xFFFFFFFF ) // or broadcast address, send directly.
{
return sgIP_ARP_SendProtocolFrame(hw,packet,protocol,dest_address);
} else { // eek, on different network. Send to gateway
return sgIP_ARP_SendProtocolFrame(hw,packet,protocol,hw->gateway);
}
}
// send packet on a hardware interface.
int sgIP_Hub_SendRawPacket(sgIP_Hub_HWInterface * hw, sgIP_memblock * packet) {
if(!hw || !packet) return 0;
if(hw->flags&SGIP_FLAG_HWINTERFACE_ENABLED) {
return hw->TransmitFunction(hw,packet);
}
sgIP_memblock_free(packet);
return 0;
}
int sgIP_Hub_IPMaxMessageSize(unsigned long ipaddr) {
return SGIP_MTU_OVERRIDE; // hack - make this more accurate soon!
}
unsigned long sgIP_Hub_GetCompatibleIP(unsigned long destIP) {
int n;
for(n=0;n<SGIP_HUB_MAXHWINTERFACES;n++) {
if((HWInterfaces[n].flags&SGIP_FLAG_HWINTERFACE_IN_USE)) {
if((HWInterfaces[n].ipaddr & HWInterfaces[n].snmask) == (destIP & HWInterfaces[n].snmask)) return HWInterfaces[n].ipaddr;
}
}
for(n=0;n<SGIP_HUB_MAXHWINTERFACES;n++) {
if((HWInterfaces[n].flags&SGIP_FLAG_HWINTERFACE_IN_USE)) {
return HWInterfaces[n].ipaddr;
}
}
return 0;
}
extern sgIP_Hub_HWInterface * sgIP_Hub_GetDefaultInterface() {
int n;
for(n=0;n<SGIP_HUB_MAXHWINTERFACES;n++) {
if((HWInterfaces[n].flags&SGIP_FLAG_HWINTERFACE_IN_USE)) {
return HWInterfaces+n;
}
}
return 0;
}
#ifdef SGIP_LITTLEENDIAN
unsigned short htons(unsigned short num) {
return ((num<<8)&0xFF00) | (num>>8);
}
unsigned long htonl(unsigned long num) {
return (num<<24) | ((num&0xFF00)<<8) | ((num&0xFF0000)>>8) | (num>>24);
}
#else
unsigned short htons(unsigned short num) {
return num;
}
unsigned long htonl(unsigned long num) {
return num;
}
#endif

View File

@@ -0,0 +1,109 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_HUB_H
#define SGIP_HUB_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
#define SGIP_FLAG_PROTOCOL_IN_USE 0x0001
#define SGIP_FLAG_PROTOCOL_ENABLED 0x8000
#define SGIP_FLAG_HWINTERFACE_IN_USE 0x0001
#define SGIP_FLAG_HWINTERFACE_CONNECTED 0x0002
#define SGIP_FLAG_HWINTERFACE_USEDHCP 0x0004
#define SGIP_FLAG_HWINTERFACE_CHANGENETWORK 0x0008
#define SGIP_FLAG_HWINTERFACE_ENABLED 0x8000
#ifdef SGIP_LITTLEENDIAN
#define PROTOCOL_ETHER_ARP 0x0608
#define PROTOCOL_ETHER_IP 0x0008
#else
#define PROTOCOL_ETHER_ARP 0x0806
#define PROTOCOL_ETHER_IP 0x0800
#endif
// structure sgIP_Hub_Protocol: Used to record the interface between the sgIP Hub and a protocol handler
typedef struct SGIP_HUB_PROTOCOL {
unsigned short flags;
unsigned short protocol;
int (*ReceivePacket)(sgIP_memblock *);
} sgIP_Hub_Protocol;
typedef struct SGIP_HUB_HWINTERFACE {
unsigned short flags;
unsigned short hwaddrlen;
int MTU;
int (*TransmitFunction)(struct SGIP_HUB_HWINTERFACE *, sgIP_memblock *);
void * userdata;
unsigned long ipaddr, gateway, snmask, dns[3];
unsigned char hwaddr[SGIP_MAXHWADDRLEN];
} sgIP_Hub_HWInterface;
typedef struct SGIP_HEADER_ETHERNET {
unsigned char dest_mac[6];
unsigned char src_mac[6];
unsigned short protocol;
} sgIP_Header_Ethernet;
#define ntohs(num) htons(num)
#define ntohl(num) htonl(num)
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_Hub_Init();
extern sgIP_Hub_Protocol * sgIP_Hub_AddProtocolInterface(int protocolID, int (*ReceivePacket)(sgIP_memblock *), int (*InterfaceInit)(sgIP_Hub_Protocol *));
extern sgIP_Hub_HWInterface * sgIP_Hub_AddHardwareInterface(int (*TransmitFunction)(sgIP_Hub_HWInterface *, sgIP_memblock *), int (*InterfaceInit)(sgIP_Hub_HWInterface *));
extern void sgIP_Hub_RemoveProtocolInterface(sgIP_Hub_Protocol * protocol);
extern void sgIP_Hub_RemoveHardwareInterface(sgIP_Hub_HWInterface * hw);
extern int sgIP_Hub_ReceiveHardwarePacket(sgIP_Hub_HWInterface * hw, sgIP_memblock * packet);
extern int sgIP_Hub_SendProtocolPacket(int protocol, sgIP_memblock * packet, unsigned long dest_address, unsigned long src_address);
extern int sgIP_Hub_SendRawPacket(sgIP_Hub_HWInterface * hw, sgIP_memblock * packet);
extern int sgIP_Hub_IPMaxMessageSize(unsigned long ipaddr);
unsigned long sgIP_Hub_GetCompatibleIP(unsigned long destIP);
extern sgIP_Hub_HWInterface * sgIP_Hub_GetDefaultInterface();
unsigned short htons(unsigned short num);
unsigned long htonl(unsigned long num);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,56 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_ICMP.h"
#include "sgIP_IP.h"
#include "sgIP_Hub.h"
void sgIP_ICMP_Init() {
}
int sgIP_ICMP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip) {
if(!mb) return 0;
sgIP_Header_ICMP * icmp;
icmp = (sgIP_Header_ICMP *) mb->datastart;
if(icmp->checksum!=0 && sgIP_memblock_IPChecksum(mb,0,mb->totallength)!=0xFFFF) {
SGIP_DEBUG_MESSAGE(("ICMP receive checksum incorrect"));
sgIP_memblock_free(mb);
return 0;
}
switch(icmp->type) {
case 8: // echo request
icmp->type=0; // change to echo reply
// mod checksum
icmp->checksum=0;
icmp->checksum=~sgIP_memblock_IPChecksum(mb,0,mb->totallength);
return sgIP_IP_SendViaIP(mb,PROTOCOL_IP_ICMP,destip,srcip);
case 0: // echo reply (ignore for now)
default: // others (ignore for now)
break;
}
sgIP_memblock_free(mb);
return 0;
}

View File

@@ -0,0 +1,52 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_ICMP_H
#define SGIP_ICMP_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
typedef struct SGIP_HEADER_ICMP {
unsigned char type,code;
unsigned short checksum;
unsigned long xtra;
} sgIP_Header_ICMP;
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_ICMP_Init();
extern int sgIP_ICMP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,124 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_IP.h"
#include "sgIP_TCP.h"
#include "sgIP_UDP.h"
#include "sgIP_ICMP.h"
#include "sgIP_Hub.h"
int idnum_count;
int sgIP_IP_ReceivePacket(sgIP_memblock * mb) {
sgIP_Header_IP * iphdr;
unsigned short * chksum_calc;
int chksum_temp;
int hdrlen;
iphdr=(sgIP_Header_IP *)mb->datastart;
chksum_calc=(unsigned short *)mb->datastart;
// check that header is valid:
hdrlen=iphdr->version_ihl&15;
// check length...
if(mb->totallength<htons(iphdr->tot_length)) {
SGIP_DEBUG_MESSAGE(("IP: bad length!"));
SGIP_DEBUG_MESSAGE(("-%i/%i",mb->totallength,htons(iphdr->tot_length)));
sgIP_memblock_free(mb);
return 0; // bad size.
}
sgIP_memblock_trimsize(mb,htons(iphdr->tot_length));
// check version
if((iphdr->version_ihl>>4)!=4) {
SGIP_DEBUG_MESSAGE(("IP: bad version!"));
sgIP_memblock_free(mb);
return 0; // bad version.
}
// check checksum
chksum_temp=sgIP_memblock_IPChecksum(mb,0,hdrlen*4);
if(chksum_temp!=0xFFFF) { // bad chksum! kill packet.
SGIP_DEBUG_MESSAGE(("IP: bad checksum!"));
sgIP_memblock_free(mb);
return 0; // bad checksum.
}
if(htons(iphdr->fragment_offset)&0x3FFF) { // fragmented! oh noes! We can't deal with this!
SGIP_DEBUG_MESSAGE(("IP: fragmented!"));
sgIP_memblock_free(mb);
return 0; // fragmented.
}
sgIP_memblock_exposeheader(mb,-hdrlen*4);
switch(iphdr->protocol) {
case PROTOCOL_IP_ICMP: // ICMP
sgIP_ICMP_ReceivePacket(mb,iphdr->src_address,iphdr->dest_address);
break;
case PROTOCOL_IP_TCP: // TCP
sgIP_TCP_ReceivePacket(mb,iphdr->src_address,iphdr->dest_address);
break;
case PROTOCOL_IP_UDP: // UDP
sgIP_UDP_ReceivePacket(mb,iphdr->src_address,iphdr->dest_address);
break;
default:
sgIP_memblock_free(mb);
}
return 0;
}
int sgIP_IP_MaxContentsSize(unsigned long destip) {
return sgIP_Hub_IPMaxMessageSize(destip)-sgIP_IP_RequiredHeaderSize();
}
int sgIP_IP_RequiredHeaderSize() {
return 5*4; // we'll not include zeroed options.
}
int sgIP_IP_SendViaIP(sgIP_memblock * mb, int protocol, unsigned long srcip, unsigned long destip) {
sgIP_Header_IP * iphdr;
unsigned short * chksum_calc;
int chksum_temp,i;
sgIP_memblock_exposeheader(mb,20);
iphdr=(sgIP_Header_IP *)mb->datastart;
chksum_calc=(unsigned short *)mb->datastart;
iphdr->dest_address=destip;
iphdr->fragment_offset=0;
iphdr->header_checksum=0;
iphdr->identification=idnum_count++;
iphdr->protocol=protocol;
iphdr->src_address=srcip;
iphdr->tot_length=htons(mb->totallength);
iphdr->TTL=SGIP_IP_TTL;
iphdr->type_of_service=0;
iphdr->version_ihl=0x45;
chksum_temp=0;
for(i=0;i<10;i++) chksum_temp+=chksum_calc[i];
chksum_temp += chksum_temp>>16;
chksum_temp &= 0xFFFF;
chksum_temp = ~chksum_temp;
if(chksum_temp==0) chksum_temp=0xFFFF;
iphdr->header_checksum=chksum_temp;
return sgIP_Hub_SendProtocolPacket(htons(0x0800),mb,destip,srcip);
}
unsigned long sgIP_IP_GetLocalBindAddr(unsigned long srcip, unsigned long destip) {
if(srcip) return srcip;
return sgIP_Hub_GetCompatibleIP(destip);
}

View File

@@ -0,0 +1,64 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_IP_H
#define SGIP_IP_H
#include "sgIP_memblock.h"
#define PROTOCOL_IP_ICMP 1
#define PROTOCOL_IP_TCP 6
#define PROTOCOL_IP_UDP 17
typedef struct SGIP_HEADER_IP {
unsigned char version_ihl; // version = top 4 bits == 4, IHL = header length in 32bit increments = bottom 4 bits
unsigned char type_of_service; // [3bit prescidence][ D ][ T ][ R ][ 0 0 ] - D=low delya, T=high thoroughput, R= high reliability
unsigned short tot_length; // total length of packet including header
unsigned short identification; // value assigned by sender to aid in packet reassembly
unsigned short fragment_offset; // top 3 bits are flags [0][DF][MF] (Don't Fragment / More Fragments Exist) - offset is in 8-byte chunks.
unsigned char TTL; // time to live, measured in hops
unsigned char protocol; // protocols: ICMP=1, TCP=6, UDP=17
unsigned short header_checksum; // checksum:
unsigned long src_address; // src address is 32bit IP address
unsigned long dest_address; // dest address is 32bit IP address
unsigned char options[4]; // optional options come here.
} sgIP_Header_IP;
#ifdef __cplusplus
extern "C" {
#endif
extern int sgIP_IP_ReceivePacket(sgIP_memblock * mb);
extern int sgIP_IP_MaxContentsSize(unsigned long destip);
extern int sgIP_IP_RequiredHeaderSize();
extern int sgIP_IP_SendViaIP(sgIP_memblock * mb, int protocol, unsigned long srcip, unsigned long destip);
extern unsigned long sgIP_IP_GetLocalBindAddr(unsigned long srcip, unsigned long destip);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,915 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_TCP.h"
#include "sgIP_IP.h"
#include "sgIP_Hub.h"
#include "sys/socket.h"
sgIP_Record_TCP * tcprecords;
int port_counter;
unsigned long lasttime;
extern unsigned long volatile sgIP_timems;
sgIP_TCP_SYNCookie synlist[SGIP_TCP_MAXSYNS];
int numsynlist; // number of active entries in synlist (earliest first)
void sgIP_TCP_Init() {
tcprecords=0;
numsynlist=0;
port_counter=SGIP_TCP_FIRSTOUTGOINGPORT;
lasttime=sgIP_timems;
}
void sgIP_TCP_Timer() { // scan through tcp records and resend anything necessary
sgIP_Record_TCP * rec;
int time,i,j;
time=sgIP_timems-lasttime;
lasttime=sgIP_timems;
for(i=0;i<numsynlist;i++) {
if(synlist[i].timenext<=time) {
j=time-synlist[i].timenext;
synlist[i].timebackoff*=2;
if(synlist[i].timebackoff>SGIP_TCP_BACKOFFMAX) synlist[i].timebackoff=SGIP_TCP_BACKOFFMAX;
if(j>synlist[i].timebackoff) synlist[i].timenext=0; else synlist[i].timenext=synlist[i].timebackoff-j;
// resend SYN
sgIP_TCP_SendSynReply(SGIP_TCP_FLAG_SYN|SGIP_TCP_FLAG_ACK,synlist[i].localseq,synlist[i].remoteseq,synlist[i].localip,synlist[i].remoteip,synlist[i].localport,synlist[i].remoteport,-1);
} else {
synlist[i].timenext-=time;
}
}
rec=tcprecords;
while(rec) {
time=sgIP_timems-rec->time_last_action;
switch(rec->tcpstate) {
case SGIP_TCP_STATE_NODATA: // newly allocated [do nothing]
case SGIP_TCP_STATE_UNUSED: // allocated & BINDed [do nothing]
case SGIP_TCP_STATE_CLOSED: // Block is unused. [do nothing]
case SGIP_TCP_STATE_LISTEN: // listening [do nothing]
case SGIP_TCP_STATE_FIN_WAIT_2: // got ACK for our FIN, haven't got FIN yet. [do nothing]
break;
case SGIP_TCP_STATE_SYN_SENT: // connect initiated [resend syn]
if(time>rec->time_backoff) {
rec->retrycount++;
if(rec->retrycount>=SGIP_TCP_MAXRETRY) {
//error
rec->errorcode=ECONNABORTED;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
break;
}
j=rec->time_backoff;
j*=2;
if(j>SGIP_TCP_BACKOFFMAX) j=SGIP_TCP_BACKOFFMAX;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_SYN,0);
rec->time_backoff=j; // preserve backoff
}
break;
case SGIP_TCP_STATE_CLOSE_WAIT: // got FIN, wait for user code to close socket & send FIN [do nothing]
case SGIP_TCP_STATE_ESTABLISHED: // syns have been exchanged [check for data in buffer, send]
if(rec->want_shutdown==1 && rec->buf_tx_out==rec->buf_tx_in) { // oblige & shutdown
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_FIN | SGIP_TCP_FLAG_ACK,0);
if(rec->tcpstate==SGIP_TCP_STATE_CLOSE_WAIT) {
rec->tcpstate=SGIP_TCP_STATE_CLOSING;
} else {
rec->tcpstate=SGIP_TCP_STATE_FIN_WAIT_1;
}
rec->want_shutdown=2;
break;
}
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
j+=(int)(rec->sequence-rec->sequence_next);
if(j>0) {// never-sent bytes
if(time>SGIP_TCP_TRANSMIT_DELAY) { // 1000 is an arbitrary constant.
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
i=(int)(rec->txwindow-rec->sequence);
if(j>i) j=i;
i=sgIP_IP_MaxContentsSize(rec->destip)-20; // max tcp data size
if(j>i) j=i;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,i);
break;
}
}
if(time>rec->time_backoff && rec->buf_tx_out!=rec->buf_tx_in) { // resend last packet
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
i=(int)(rec->txwindow-rec->sequence);
if(j>i) j=i;
i=sgIP_IP_MaxContentsSize(rec->destip)-20; // max tcp data size
if(j>i) j=i;
j=rec->time_backoff;
j*=2;
if(j>SGIP_TCP_BACKOFFMAX) j=SGIP_TCP_BACKOFFMAX;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,i);
rec->time_backoff=j; // preserve backoff
break;
}
break;
case SGIP_TCP_STATE_FIN_WAIT_1: // sent a FIN, haven't got FIN or ACK yet. [resend fin]
if(time>rec->time_backoff) {
rec->retrycount++;
if(rec->retrycount>=SGIP_TCP_MAXRETRY) {
//error
rec->errorcode=ETIMEDOUT;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
break;
}
j=rec->time_backoff;
j*=2;
if(j>SGIP_TCP_BACKOFFMAX) j=SGIP_TCP_BACKOFFMAX;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_FIN,0);
rec->time_backoff=j; // preserve backoff
}
break;
case SGIP_TCP_STATE_CLOSING: // got FIN, waiting for ACK of our FIN [resend FINACK]
if(time>rec->time_backoff) {
rec->retrycount++;
if(rec->retrycount>=SGIP_TCP_MAXRETRY) {
//error
rec->errorcode=ETIMEDOUT;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
break;
}
j=rec->time_backoff;
j*=2;
if(j>SGIP_TCP_BACKOFFMAX) j=SGIP_TCP_BACKOFFMAX;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_FIN | SGIP_TCP_FLAG_ACK,0);
rec->time_backoff=j; // preserve backoff
}
break;
case SGIP_TCP_STATE_LAST_ACK: // wait for ACK of our last FIN [resend FIN]
if(time>rec->time_backoff) {
rec->retrycount++;
if(rec->retrycount>=SGIP_TCP_MAXRETRY) {
//error
rec->errorcode=ETIMEDOUT;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
break;
}
j=rec->time_backoff;
j*=2;
if(j>SGIP_TCP_BACKOFFMAX) j=SGIP_TCP_BACKOFFMAX;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_FIN,0);
rec->time_backoff=j; // preserve backoff
}
break;
case SGIP_TCP_STATE_TIME_WAIT: // wait to ensure remote tcp knows it's been terminated. [reset in 2MSL]
if(time>SGIP_TCP_TIMEMS_2MSL) {
rec->errorcode=ESHUTDOWN;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
}
break;
}
rec=rec->next;
}
}
unsigned long sgIP_TCP_support_seqhash(unsigned long srcip, unsigned long destip, unsigned short srcport, unsigned short destport) {
unsigned long hash;
hash=destip;
hash ^= destport * (0x02041089+sgIP_timems);
hash ^= srcport * (0x080810422+(sgIP_timems<<1));
hash ^= srcip * (0x48841221+(sgIP_timems<<3));
hash ^= destip * (0x04020108+(sgIP_timems<<5));
return hash;
}
int sgIP_TCP_GetUnusedOutgoingPort() {
int myport,clear;
sgIP_Record_TCP * rec;
port_counter+=(sgIP_timems&1023); // semi-random
if(port_counter>SGIP_TCP_LASTOUTGOINGPORT) port_counter=SGIP_TCP_FIRSTOUTGOINGPORT;
while(1) {
rec = tcprecords;
myport=port_counter++;
if(port_counter>SGIP_TCP_LASTOUTGOINGPORT) port_counter=SGIP_TCP_FIRSTOUTGOINGPORT;
clear=1;
while(rec) {
if(rec->srcport==myport && rec->tcpstate!=SGIP_TCP_STATE_CLOSED && rec->tcpstate!=SGIP_TCP_STATE_NODATA) { clear=0; break; }
rec=rec->next;
}
if(clear) return myport;
}
}
int sgIP_TCP_CalcChecksum(sgIP_memblock * mb, unsigned long srcip, unsigned long destip, int totallength) {
int checksum;
if(!mb) return 0;
if(mb->totallength&1) mb->datastart[mb->totallength]=0;
checksum=sgIP_memblock_IPChecksum(mb,0,mb->totallength);
// add in checksum of "faux header"
checksum+=(destip&0xFFFF);
checksum+=(destip>>16);
checksum+=(srcip&0xFFFF);
checksum+=(srcip>>16);
checksum+=htons(totallength);
checksum+=(6)<<8;
checksum= (checksum&0xFFFF) +(checksum>>16);
checksum= (checksum&0xFFFF) +(checksum>>16);
return checksum;
}
int sgIP_TCP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip) {
if(!mb) return 0;
sgIP_Header_TCP * tcp;
int delta1,delta2, delta3,datalen, shouldReply;
unsigned long tcpack,tcpseq;
tcp = (sgIP_Header_TCP *) mb->datastart;
// 01234567890123456789012345678901
// TCPxxxxxxxx-xxxxxxxx,xxxx-xxxx
//SGIP_DEBUG_MESSAGE(("TCP%08X-%08X,%04X-%04X",srcip,destip,tcp->srcport,tcp->destport));
// -Lxxxx,Cxxxx,Fxx,hx,Axxxxxxxx
//SGIP_DEBUG_MESSAGE(("-L%04X,C%04X,F%02X,h%X,A%08X",mb->totallength,tcp->checksum,tcp->tcpflags,tcp->dataofs_>>4,tcp->acknum));
if(tcp->checksum!=0x0000 && sgIP_TCP_CalcChecksum(mb,srcip,destip,mb->totallength)!=0xFFFF) { // checksum is invalid!
SGIP_DEBUG_MESSAGE(("TCP receive checksum incorrect"));
sgIP_memblock_free(mb);
return 0;
}
sgIP_Record_TCP * rec;
rec=tcprecords;
// find associated block.
while(rec) {
if(rec->srcport==tcp->destport && (rec->srcip==destip || rec->srcip==0)) {
if((rec->tcpstate==SGIP_TCP_STATE_LISTEN && (tcp->tcpflags&SGIP_TCP_FLAG_SYN)) || rec->destport==tcp->srcport) break;
}
rec=rec->next;
}
if(!rec) { // could be completion of an incoming connection?
tcpack=htonl(tcp->acknum);
if(tcp->tcpflags&SGIP_TCP_FLAG_ACK) {
int i,j;
for(i=0;i<numsynlist;i++) {
if(synlist[i].localseq+1==tcpack) { // oki! this is probably legit ;)
rec=synlist[i].linked; // we have the data we need.
// remove entry from synlist
numsynlist--;
i*=3;
for(;i<numsynlist;i++) {
synlist[i]=synlist[i+1]; // assume struct copy
}
for(j=0;j<rec->maxlisten;j++) if(!rec->listendata[j]) break; // find last entry in listen queue
if(j==rec->maxlisten) { rec=0; break; } // discard this connection! we have no space in the listen queue.
rec->listendata[j]=sgIP_TCP_AllocRecord();
j++;
if(j!=rec->maxlisten) rec->listendata[j]=0;
rec=rec->listendata[j-1];
// fill in data about the connection.
rec->tcpstate=SGIP_TCP_STATE_ESTABLISHED;
rec->time_last_action=sgIP_timems;
rec->time_backoff=SGIP_TCP_GENRETRYMS; // backoff timer
rec->srcip=destip;
rec->destip=srcip;
rec->srcport=tcp->destport;
rec->destport=tcp->srcport;
rec->sequence=htonl(tcp->acknum);
rec->ack=htonl(tcp->seqnum);
rec->sequence_next=rec->sequence;
rec->rxwindow=rec->ack+1400; // last byte in receive window
rec->txwindow=rec->sequence+htons(tcp->window);
sgIP_memblock_free(mb);
return 0;
}
}
}
}
if(!rec) { // we don't have a clue what this one is.
#ifndef SGIP_TCP_STEALTH
// send a RST
sgIP_TCP_SendSynReply(SGIP_TCP_FLAG_RST,ntohl(tcp->acknum),0,destip,srcip,tcp->destport,tcp->srcport,0);
#endif
sgIP_memblock_free(mb);
return 0;
}
// check sequence and ACK numbers, to ensure they're in range.
tcpack=htonl(tcp->acknum);
tcpseq=htonl(tcp->seqnum);
datalen=mb->totallength-(tcp->dataofs_>>4)*4;
shouldReply=0;
if(tcp->tcpflags&SGIP_TCP_FLAG_RST) { // verify if rst is legit, and act on it.
// check seq against receive window
delta1=(int)(tcpseq-rec->ack);
delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta2<0 || rec->tcpstate==SGIP_TCP_STATE_LISTEN) {
// out of range, ignore
} else {
// in range! reset connection.
rec->errorcode=ECONNRESET;
rec->tcpstate=SGIP_TCP_STATE_CLOSED;
}
sgIP_memblock_free(mb);
return 0;
}
if((tcp->tcpflags&SGIP_TCP_FLAG_ACK) && !(tcp->tcpflags&SGIP_TCP_FLAG_SYN)) { // doesn't work very well with SYN.
// verify ack value (checking ack sequence vs transmit window)
delta1=(int)(tcpack-rec->sequence);
delta2=(int)(rec->txwindow-tcpack);
if(delta1<0 || delta2<0) { // invalid ack range, discard packet
sgIP_memblock_free(mb);
return 0;
}
delta2=tcpack-rec->sequence;
rec->sequence=tcpack;
delta2+=rec->buf_tx_in;
if(delta2>=SGIP_TCP_TRANSMITBUFFERLENGTH) delta2-=SGIP_TCP_TRANSMITBUFFERLENGTH;
rec->buf_tx_in=delta2;
if(delta1>0) shouldReply=1;
}
rec->txwindow=rec->sequence+htons(tcp->window);
// now, decide what to do with our nice new shiny memblock...
// for most states, receive data
switch(rec->tcpstate) {
case SGIP_TCP_STATE_NODATA: // newly allocated
case SGIP_TCP_STATE_UNUSED: // allocated & BINDed
case SGIP_TCP_STATE_CLOSED: // Block is unused.
case SGIP_TCP_STATE_LISTEN: // listening
case SGIP_TCP_STATE_TIME_WAIT: // wait to ensure remote tcp knows it's been terminated.
case SGIP_TCP_STATE_SYN_SENT: // connect initiated
case SGIP_TCP_STATE_CLOSE_WAIT: // got FIN, wait for user code to close socket & send FIN
case SGIP_TCP_STATE_CLOSING: // got FIN, waiting for ACK of our FIN
case SGIP_TCP_STATE_LAST_ACK: // wait for ACK of our last FIN
break;
case SGIP_TCP_STATE_SYN_RECEIVED: // spawned from listen socket; or from syn sent.
case SGIP_TCP_STATE_ESTABLISHED: // syns have been exchanged
case SGIP_TCP_STATE_FIN_WAIT_1: // sent a FIN, haven't got FIN or ACK yet.
case SGIP_TCP_STATE_FIN_WAIT_2: // got ACK for our FIN, haven't got FIN yet.
if(tcp->tcpflags&SGIP_TCP_FLAG_ACK) {
// check end of incoming data against receive window
delta1=(int)(tcpseq+datalen-rec->ack); // check end of data vs start of window (>=0, end of data is equal to or after start of unreceived data)
delta2=(int)(rec->rxwindow-tcpseq-datalen); // check end of data vs end of window (>=0, end of data is equal to or before end of rx window)
delta3=(int)(rec->ack-tcpseq); // check start of data vs start of window (>=0, start of data is equal or before the next expected byte)
if(delta1<0 || delta2<0 || delta3<0) {
if(delta1>-SGIP_TCP_RECEIVEBUFFERLENGTH) { // ack it anyway, they got lost on the retard bus.
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
}
break; // out of range, they should know better.
}
{
int datastart=(tcp->dataofs_>>4)*4;
delta1=(int)(tcpseq-rec->ack);
if(delta1<0) { // data is partly ack'd...just copy what we need.
datastart-=delta1;
datalen+=delta1;
}
// copy data into the fifo
rec->ack+=datalen;
delta1=datalen;
while(datalen>0) { // don't actually need to check the rx buffer length, if the ack check approved it, it will be in range (not overflow) by default
delta2=SGIP_TCP_RECEIVEBUFFERLENGTH-rec->buf_rx_out; // number of bytes til the end of the buffer
if(datalen<delta2) delta2=datalen;
sgIP_memblock_CopyToLinear(mb,rec->buf_rx+rec->buf_rx_out,datastart,delta2);
datalen-=delta2;
datastart+=delta2;
rec->buf_rx_out += delta2;
if(rec->buf_rx_out>=SGIP_TCP_RECEIVEBUFFERLENGTH) rec->buf_rx_out-=SGIP_TCP_RECEIVEBUFFERLENGTH;
}
if(rec->tcpstate==SGIP_TCP_STATE_FIN_WAIT_1 || rec->tcpstate==SGIP_TCP_STATE_FIN_WAIT_2) break;
if(shouldReply || delta1>=0) { // send a packet in reply, ha!
delta1=rec->buf_tx_out-rec->buf_tx_in;
if(delta1<0) delta1+=SGIP_TCP_TRANSMITBUFFERLENGTH;
delta2=(int)(rec->txwindow-rec->sequence);
if(delta1>delta2) delta1=delta2;
delta2=sgIP_IP_MaxContentsSize(rec->destip)-20; // max tcp data size
if(delta1>delta2) delta1=delta2;
if(delta1>=0) { // could be less than 0, but very odd.
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,delta1);
}
}
}
}
}
// decide what to do with the others
switch(rec->tcpstate) {
case SGIP_TCP_STATE_NODATA: // newly allocated
case SGIP_TCP_STATE_UNUSED: // allocated & BINDed
case SGIP_TCP_STATE_CLOSED: // Block is unused.
break; // can't do anything in these states.
case SGIP_TCP_STATE_LISTEN: // listening
if(tcp->tcpflags&SGIP_TCP_FLAG_SYN) { // other end requesting a connection
if(numsynlist==SGIP_TCP_MAXSYNS) {
numsynlist--;
for(delta1=0;delta1<numsynlist;delta1++) {
synlist[delta1]=synlist[delta1+1]; // assume struct copy
}
}
{
unsigned long myseq,myport;
myport=tcp->destport;
myseq=sgIP_TCP_support_seqhash(srcip,destip,tcp->srcport,myport);
// send relevant synack
sgIP_TCP_SendSynReply(SGIP_TCP_FLAG_SYN|SGIP_TCP_FLAG_ACK,myseq,tcpseq+1,destip,srcip,myport,tcp->srcport,-1);
synlist[numsynlist].localseq=myseq;
synlist[numsynlist].timebackoff=SGIP_TCP_SYNRETRYMS;
synlist[numsynlist].timenext=SGIP_TCP_SYNRETRYMS;
synlist[numsynlist].linked=rec;
synlist[numsynlist].remoteseq=tcpseq+1;
synlist[numsynlist].remoteip=srcip;
synlist[numsynlist].localip=destip;
synlist[numsynlist].localport=myport;
synlist[numsynlist].remoteport=tcp->srcport;
numsynlist++;
}
}
break;
case SGIP_TCP_STATE_SYN_SENT: // connect initiated
switch(tcp->tcpflags&(SGIP_TCP_FLAG_SYN|SGIP_TCP_FLAG_ACK)) {
case SGIP_TCP_FLAG_SYN | SGIP_TCP_FLAG_ACK: // both flags set
rec->ack=tcpseq+1;
rec->sequence=tcpack;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
rec->tcpstate=SGIP_TCP_STATE_ESTABLISHED;
rec->retrycount=0;
break;
case SGIP_TCP_FLAG_SYN: // just got a syn...
rec->ack=tcpseq+1;
rec->sequence=tcpack;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
rec->tcpstate=SGIP_TCP_STATE_SYN_RECEIVED;
rec->retrycount=0;
break;
}
break;
case SGIP_TCP_STATE_SYN_RECEIVED: // spawned from listen socket; or from syn sent.
if(tcp->tcpflags&SGIP_TCP_FLAG_ACK) {
rec->tcpstate=SGIP_TCP_STATE_ESTABLISHED;
rec->retrycount=0;
}
break;
case SGIP_TCP_STATE_ESTABLISHED: // syns have been exchanged
if(tcp->tcpflags&SGIP_TCP_FLAG_FIN) {
// check sequence against next ack number
delta1=(int)(tcpseq-rec->ack);
//delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta1>0) break; // out of range, they should know better.
// this is the end...
rec->tcpstate=SGIP_TCP_STATE_CLOSE_WAIT;
rec->ack=tcpseq+datalen+1;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
}
break;
case SGIP_TCP_STATE_FIN_WAIT_1: // sent a FIN, haven't got FIN or ACK yet.
switch(tcp->tcpflags&(SGIP_TCP_FLAG_FIN|SGIP_TCP_FLAG_ACK)) {
case SGIP_TCP_FLAG_FIN:
// check sequence against next ack number
delta1=(int)(tcpseq-rec->ack);
//delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta1>0) break; // out of range, they should know better.
rec->tcpstate=SGIP_TCP_STATE_CLOSING;
rec->ack=tcpseq+datalen+1;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
break;
case SGIP_TCP_FLAG_ACK: // already checked ack against appropriate window
rec->tcpstate=SGIP_TCP_STATE_FIN_WAIT_2;
break;
case (SGIP_TCP_FLAG_FIN | SGIP_TCP_FLAG_ACK): // already checked ack, check sequence though
// check sequence against next ack number
delta1=(int)(tcpseq-rec->ack);
//delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta1>0) break; // out of range, they should know better.
rec->tcpstate=SGIP_TCP_STATE_TIME_WAIT;
rec->ack=tcpseq+datalen+1;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
break;
}
break;
case SGIP_TCP_STATE_FIN_WAIT_2: // got ACK for our FIN, haven't got FIN yet.
if(tcp->tcpflags&SGIP_TCP_FLAG_FIN) {
// check sequence against next ack number
delta1=(int)(tcpseq-rec->ack);
//delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta1>0) break; // out of range, they should know better.
rec->tcpstate=SGIP_TCP_STATE_TIME_WAIT;
rec->ack=tcpseq+datalen+1;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
}
break;
case SGIP_TCP_STATE_CLOSE_WAIT: // got FIN, wait for user code to close socket & send FIN
if(tcp->tcpflags&SGIP_TCP_FLAG_FIN) {
// check sequence against next ack number
delta1=(int)(tcpseq-rec->ack);
//delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<0 || delta1>0) break; // out of range, they should know better.
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0); // they still don't seem to have got our ack, we'll send it again.
}
break;
case SGIP_TCP_STATE_CLOSING: // got FIN, waiting for ACK of our FIN
switch(tcp->tcpflags&(SGIP_TCP_FLAG_FIN|SGIP_TCP_FLAG_ACK)) {
case SGIP_TCP_FLAG_FIN:
// check sequence against receive window
delta1=(int)(tcpseq-rec->ack);
delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<1 || delta2<0) break; // out of range, they should know better.
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0); // resend their ack.
break;
case SGIP_TCP_FLAG_ACK: // already checked ack against appropriate window
rec->tcpstate=SGIP_TCP_STATE_TIME_WAIT;
break;
case (SGIP_TCP_FLAG_FIN | SGIP_TCP_FLAG_ACK): // already checked ack, check sequence though
// check sequence against receive window
delta1=(int)(tcpseq-rec->ack);
delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<1 || delta2<0) break; // out of range, they should know better.
rec->tcpstate=SGIP_TCP_STATE_TIME_WAIT;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
break;
}
break;
case SGIP_TCP_STATE_LAST_ACK: // wait for ACK of our last FIN
if(tcp->tcpflags&SGIP_TCP_FLAG_ACK) {
rec->tcpstate=SGIP_TCP_STATE_TIME_WAIT;
}
break;
case SGIP_TCP_STATE_TIME_WAIT: // wait to ensure remote tcp knows it's been terminated.
if(tcp->tcpflags&SGIP_TCP_FLAG_FIN) {
// check sequence against receive window
delta1=(int)(tcpseq-rec->ack);
delta2=(int)(rec->rxwindow-tcpseq);
if(delta1<1 || delta2<0) break; // out of range, they should know better.
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0); // send 'em a grat ACK
}
break;
}
sgIP_memblock_free(mb);
return 0;
}
sgIP_memblock * sgIP_TCP_GenHeader(sgIP_Record_TCP * rec, int flags, int datalength) {
sgIP_memblock * mb = sgIP_memblock_alloc(datalength+20+sgIP_IP_RequiredHeaderSize());
int windowlen;
if(!mb) return 0;
sgIP_memblock_exposeheader(mb,-sgIP_IP_RequiredHeaderSize()); // hide IP header space for later
sgIP_Header_TCP * tcp = (sgIP_Header_TCP *) mb->datastart;
tcp->srcport=rec->srcport;
tcp->destport=rec->destport;
tcp->seqnum=htonl(rec->sequence);
tcp->acknum=htonl(rec->ack);
tcp->tcpflags=flags;
tcp->urg_ptr=0; // no support for URG data atm.
tcp->checksum=0;
tcp->dataofs_=5<<4; // header length == 20 (5*32bit)
windowlen=rec->buf_rx_out-rec->buf_rx_in;
if(windowlen<0) windowlen+=SGIP_TCP_RECEIVEBUFFERLENGTH; // we now have the amount in the buffer
windowlen = SGIP_TCP_RECEIVEBUFFERLENGTH-windowlen-1;
if(windowlen<0) windowlen=0;
if(flags&SGIP_TCP_FLAG_ACK) rec->want_reack = windowlen<SGIP_TCP_REACK_THRESH; // indicate an additional ack should be sent when we have more space in the buffer.
if(windowlen>65535) windowlen=65535;
if(windowlen>1400) windowlen=1400; // don't want to deal with IP fragmentation.
rec->rxwindow=rec->ack+windowlen; // last byte in receive window
tcp->window=htons(windowlen);
return mb;
}
void sgIP_TCP_FixChecksum(unsigned long srcip, unsigned long destip, sgIP_memblock * mb) {
int checksum;
if(!mb) return;
sgIP_Header_TCP * tcp;
tcp = (sgIP_Header_TCP *) mb->datastart;
tcp->checksum=0;
checksum=sgIP_memblock_IPChecksum(mb,0,mb->totallength);
// add in checksum of "faux header"
checksum+=(destip&0xFFFF);
checksum+=(destip>>16);
checksum+=(srcip&0xFFFF);
checksum+=(srcip>>16);
checksum+=htons(mb->totallength);
checksum+=(6)<<8;
checksum=(checksum&0xFFFF) + (checksum>>16);
checksum=(checksum&0xFFFF) + (checksum>>16);
checksum = ~checksum;
if(checksum==0) checksum=0xFFFF;
tcp->checksum=checksum;
}
int sgIP_TCP_SendPacket(sgIP_Record_TCP * rec, int flags, int datalength) { // data sent is taken directly from the TX fifo.
int i,j,k;
if(!rec) return 0;
SGIP_INTR_PROTECT();
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
if(datalength>j) datalength=j;
sgIP_memblock * mb =sgIP_TCP_GenHeader(rec,flags,datalength);
if(!mb) {
SGIP_INTR_UNPROTECT();
return 0;
}
j=20; // destination offset in memblock for data
rec->sequence_next=rec->sequence+datalength;
k=rec->buf_tx_in;
while(datalength>0) {
i=SGIP_TCP_TRANSMITBUFFERLENGTH-rec->buf_tx_in;
if(i>datalength)i=datalength;
sgIP_memblock_CopyFromLinear(mb,rec->buf_tx+k,j,i);
k+=i;
if(k>=SGIP_TCP_TRANSMITBUFFERLENGTH) k-=SGIP_TCP_TRANSMITBUFFERLENGTH;
j+=i;
datalength-=i;
}
sgIP_TCP_FixChecksum(rec->srcip,rec->destip,mb);
sgIP_IP_SendViaIP(mb,6,rec->srcip,rec->destip);
rec->time_last_action=sgIP_timems; // semi-generic timer.
rec->time_backoff=SGIP_TCP_GENRETRYMS; // backoff timer
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_TCP_SendSynReply(int flags,unsigned long seq, unsigned long ack, unsigned long srcip, unsigned long destip, int srcport, int destport, int windowlen) {
SGIP_INTR_PROTECT();
sgIP_memblock * mb = sgIP_memblock_alloc(20+sgIP_IP_RequiredHeaderSize());
if(!mb) {
SGIP_INTR_UNPROTECT();
return 0;
}
sgIP_memblock_exposeheader(mb,-sgIP_IP_RequiredHeaderSize()); // hide IP header space for later
sgIP_Header_TCP * tcp = (sgIP_Header_TCP *) mb->datastart;
tcp->srcport=srcport;
tcp->destport=destport;
tcp->seqnum=htonl(seq);
tcp->acknum=htonl(ack);
tcp->tcpflags=flags;
tcp->urg_ptr=0; // no support for URG data atm.
tcp->checksum=0;
tcp->dataofs_=5<<4; // header length == 20 (5*32bit)
if(windowlen<0 || windowlen>1400) windowlen=1400; // don't want to deal with IP fragmentation.
tcp->window=htons(windowlen);
sgIP_TCP_FixChecksum(srcip,destip,mb);
sgIP_IP_SendViaIP(mb,6,srcip,destip);
SGIP_INTR_UNPROTECT();
return 0;
}
sgIP_Record_TCP * sgIP_TCP_AllocRecord() {
SGIP_INTR_PROTECT();
sgIP_Record_TCP * rec;
rec = sgIP_malloc(sizeof(sgIP_Record_TCP));
if(rec) {
rec->buf_oob_in=0;
rec->buf_oob_out=0;
rec->buf_rx_in=0;
rec->buf_rx_out=0;
rec->buf_tx_in=0;
rec->buf_tx_out=0;
rec->tcpstate=0;
rec->next=tcprecords;
tcprecords=rec;
rec->maxlisten=0;
rec->srcip=0;
rec->retrycount=0;
rec->errorcode=0;
rec->listendata=0;
rec->want_shutdown=0;
rec->want_reack=0;
}
SGIP_INTR_UNPROTECT();
return rec;
}
void sgIP_TCP_FreeRecord(sgIP_Record_TCP * rec) {
if(!rec) return;
SGIP_INTR_PROTECT();
sgIP_Record_TCP * t;
int i,j;
rec->tcpstate=0;
if(tcprecords==rec) {
tcprecords=rec->next;
} else {
t=tcprecords;
while(t) {
if(t->next==rec) {
t->next=rec->next;
break;
}
t=t->next;
}
}
if(rec->listendata) {
for(i=0;i<rec->maxlisten;i++) {
if(!rec->listendata[i]) break;
sgIP_TCP_FreeRecord(rec->listendata[i]);
}
// kill any possible waiting elements in the SYN chain.
j=0;
for(i=0;i<numsynlist;i++) {
if(j!=i) {
synlist[j]=synlist[i];
}
if(synlist[i].linked==rec) j--;
j++;
}
numsynlist=j;
sgIP_free(rec->listendata);
}
sgIP_free(rec);
SGIP_INTR_UNPROTECT();
}
int sgIP_TCP_Bind(sgIP_Record_TCP * rec, int srcport, unsigned long srcip) {
if(!rec) return 0;
SGIP_INTR_PROTECT();
if(rec->tcpstate==SGIP_TCP_STATE_NODATA) {
rec->srcip=srcip;
rec->srcport=srcport;
rec->tcpstate=SGIP_TCP_STATE_UNUSED;
}
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_TCP_Listen(sgIP_Record_TCP * rec, int maxlisten) {
if(!rec) return SGIP_ERROR(EINVAL);
if(rec->tcpstate!=SGIP_TCP_STATE_UNUSED) return SGIP_ERROR(EINVAL);
int err;
SGIP_INTR_PROTECT();
if(rec->maxlisten!=0) { // we're *already* listening.
err=0;
} else {
err=0;
if(maxlisten<=0) maxlisten=1;
rec->maxlisten=maxlisten;
rec->listendata = (sgIP_Record_TCP **) sgIP_malloc(maxlisten*4); // pointers to TCP records, 0-terminated list.
if(!rec->listendata) { rec->maxlisten=0; err=0; } else {rec->tcpstate=SGIP_TCP_STATE_LISTEN; rec->listendata[0]=0;}
}
SGIP_INTR_UNPROTECT();
return err;
}
sgIP_Record_TCP * sgIP_TCP_Accept(sgIP_Record_TCP * rec) {
if(!rec) return (sgIP_Record_TCP *)SGIP_ERROR0(EINVAL);
if(rec->tcpstate!=SGIP_TCP_STATE_LISTEN) return (sgIP_Record_TCP *)SGIP_ERROR0(EINVAL);
int err,i;
sgIP_Record_TCP * t;
SGIP_INTR_PROTECT();
if(!rec->listendata) err=SGIP_ERROR0(EINVAL);
else {
if(!rec->listendata[0]) {
err=SGIP_ERROR0(EWOULDBLOCK);
} else {
t=rec->listendata[0];
for(i=1;i<rec->maxlisten;i++) {
rec->listendata[i-1]=rec->listendata[i];
}
rec->listendata[i-1]=0;
SGIP_INTR_UNPROTECT();
return t;
}
}
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_TCP_Close(sgIP_Record_TCP * rec) {
if(!rec) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
if(rec->want_shutdown==0) rec->want_shutdown=1;
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_TCP_Connect(sgIP_Record_TCP * rec, unsigned long destip, int destport) {
if(!rec) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
if(rec->tcpstate==SGIP_TCP_STATE_NODATA) { // need to bind a local address
rec->srcip=sgIP_IP_GetLocalBindAddr(0,destip);
rec->srcport=htons(sgIP_TCP_GetUnusedOutgoingPort());
rec->destip=destip;
rec->destport=destport;
} else if(rec->tcpstate==SGIP_TCP_STATE_UNUSED) { // already bound to a local address.
rec->srcip=sgIP_IP_GetLocalBindAddr(rec->srcip,destip);
rec->destip=destip;
rec->destport=destport;
} else {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EINVAL);
}
// send a SYN packet, and advance the state of the connection
rec->sequence=sgIP_TCP_support_seqhash(rec->srcip,rec->destip,rec->srcport,rec->destport);
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_SYN,0);
rec->retrycount=0;
rec->tcpstate=SGIP_TCP_STATE_SYN_SENT;
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_TCP_Send(sgIP_Record_TCP * rec, const char * datatosend, int datalength, int flags) {
if(!rec || !datatosend) return SGIP_ERROR(EINVAL);
if(rec->want_shutdown) return SGIP_ERROR(ESHUTDOWN);
SGIP_INTR_PROTECT();
int bufsize;
bufsize=rec->buf_tx_out-rec->buf_tx_in;
if(bufsize<0) bufsize+=SGIP_TCP_TRANSMITBUFFERLENGTH;
if(bufsize==0) { rec->time_last_action=sgIP_timems; rec->time_backoff=SGIP_TCP_GENRETRYMS; } // first byte sent, set up delay before sending
bufsize=SGIP_TCP_TRANSMITBUFFERLENGTH-bufsize-1; // space left in buffer
if(datalength>bufsize) datalength=bufsize;
int i,j;
j=rec->buf_tx_out;
for(i=0;i<datalength;i++) {
rec->buf_tx[j++]=datatosend[i];
if(j==SGIP_TCP_TRANSMITBUFFERLENGTH) j=0;
}
rec->buf_tx_out = j;
// check for immediate transmit
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
j+=(int)(rec->sequence-rec->sequence_next);
if(j>SGIP_TCP_TRANSMIT_IMMTHRESH && rec->tcpstate==SGIP_TCP_STATE_ESTABLISHED) {
j=(int)(rec->sequence_next-rec->sequence);
if(j<1000) { // arbitrary constant.
j=rec->buf_tx_out-rec->buf_tx_in;
if(j<0) j+=SGIP_TCP_TRANSMITBUFFERLENGTH;
i=(int)(rec->txwindow-rec->sequence);
if(j>i) j=i;
i=sgIP_IP_MaxContentsSize(rec->destip)-20; // max tcp data size
if(j>i) j=i;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,i);
rec->retrycount=0;
}
}
SGIP_INTR_UNPROTECT();
if(datalength==0) return SGIP_ERROR(EWOULDBLOCK);
return datalength;
}
int sgIP_TCP_Recv(sgIP_Record_TCP * rec, char * databuf, int buflength, int flags) {
if(!rec || !databuf) return SGIP_ERROR(EINVAL); //error
if(rec->buf_rx_in==rec->buf_rx_out) {
if(rec->tcpstate==SGIP_TCP_STATE_CLOSED || rec->tcpstate==SGIP_TCP_STATE_CLOSE_WAIT) {
if(rec->errorcode) return SGIP_ERROR(rec->errorcode);
return SGIP_ERROR0(ESHUTDOWN);
}
return SGIP_ERROR(EWOULDBLOCK); //error no data
}
SGIP_INTR_PROTECT();
int rxlen = rec->buf_rx_out - rec->buf_rx_in;
if(rxlen<0) rxlen+=SGIP_TCP_RECEIVEBUFFERLENGTH;
if(buflength>rxlen) buflength=rxlen;
int i,j;
j=rec->buf_rx_in;
for(i=0;i<buflength;i++) {
databuf[i]=rec->buf_rx[j++];
if(j==SGIP_TCP_RECEIVEBUFFERLENGTH) j=0;
}
if(!(flags&MSG_PEEK)) {
rec->buf_rx_in=j;
if(rec->want_reack) {
i=rec->buf_rx_out-rec->buf_rx_in;
if(i<0) i+=SGIP_TCP_RECEIVEBUFFERLENGTH; // we now have the amount in the buffer
i = SGIP_TCP_RECEIVEBUFFERLENGTH-i-1;
if(i<0) i=0;
if(i>SGIP_TCP_REACK_THRESH) {
rec->want_reack=0;
sgIP_TCP_SendPacket(rec,SGIP_TCP_FLAG_ACK,0);
}
}
}
SGIP_INTR_UNPROTECT();
return buflength;
}

View File

@@ -0,0 +1,134 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_TCP_H
#define SGIP_TCP_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
enum SGIP_TCP_STATE {
SGIP_TCP_STATE_NODATA, // newly allocated
SGIP_TCP_STATE_UNUSED, // allocated & BINDed
SGIP_TCP_STATE_LISTEN, // listening
SGIP_TCP_STATE_SYN_SENT, // connect initiated
SGIP_TCP_STATE_SYN_RECEIVED, // spawned from listen socket;
SGIP_TCP_STATE_ESTABLISHED, // syns have been exchanged
SGIP_TCP_STATE_FIN_WAIT_1, // sent a FIN, haven't got FIN or ACK yet.
SGIP_TCP_STATE_FIN_WAIT_2, // got ACK for our FIN, haven't got FIN yet.
SGIP_TCP_STATE_CLOSE_WAIT, // got FIN, wait for user code to close socket & send FIN
SGIP_TCP_STATE_CLOSING, // got FIN, waiting for ACK of our FIN
SGIP_TCP_STATE_LAST_ACK, // wait for ACK of our last FIN
SGIP_TCP_STATE_TIME_WAIT, // wait to ensure remote tcp knows it's been terminated.
SGIP_TCP_STATE_CLOSED, // Block is unused.
};
#define SGIP_TCP_FLAG_FIN 1
#define SGIP_TCP_FLAG_SYN 2
#define SGIP_TCP_FLAG_RST 4
#define SGIP_TCP_FLAG_PSH 8
#define SGIP_TCP_FLAG_ACK 16
#define SGIP_TCP_FLAG_URG 32
typedef struct SGIP_HEADER_TCP {
unsigned short srcport,destport;
unsigned long seqnum;
unsigned long acknum;
unsigned char dataofs_;
unsigned char tcpflags;
unsigned short window;
unsigned short checksum;
unsigned short urg_ptr;
unsigned char options[4];
} sgIP_Header_TCP;
// sgIP_Record_TCP - a TCP record, to store data for an active TCP connection.
typedef struct SGIP_RECORD_TCP {
struct SGIP_RECORD_TCP * next; // operate as a linked list
// TCP state information
int tcpstate;
unsigned long sequence; // sequence number of first byte not acknowledged by remote system
unsigned long ack; // external sequence number of next byte to receive
unsigned long sequence_next; // sequence number of first unsent byte
unsigned long rxwindow; // sequence of last byte in receive window
unsigned long txwindow; // sequence of last byte allowed to send
int time_last_action; // used for retransmission and etc.
int time_backoff;
int retrycount;
unsigned long srcip;
unsigned long destip;
unsigned short srcport,destport;
struct SGIP_RECORD_TCP ** listendata;
int maxlisten;
int errorcode;
int want_shutdown; // 0= don't want shutdown, 1= want shutdown, 2= being shutdown
int want_reack;
// TCP buffer information:
int buf_rx_in, buf_rx_out;
int buf_tx_in, buf_tx_out;
int buf_oob_in, buf_oob_out;
unsigned char buf_rx[SGIP_TCP_RECEIVEBUFFERLENGTH];
unsigned char buf_tx[SGIP_TCP_TRANSMITBUFFERLENGTH];
unsigned char buf_oob[SGIP_TCP_OOBBUFFERLENGTH];
} sgIP_Record_TCP;
typedef struct SGIP_TCP_SYNCOOKIE {
unsigned long localseq, remoteseq;
unsigned long localip, remoteip;
unsigned short localport, remoteport;
unsigned long timenext,timebackoff;
sgIP_Record_TCP * linked; // parent listening connection
} sgIP_TCP_SYNCookie;
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_TCP_Init();
extern void sgIP_TCP_Timer();
extern int sgIP_TCP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip);
extern int sgIP_TCP_SendPacket(sgIP_Record_TCP * rec, int flags, int datalength); // data sent is taken directly from the TX fifo.
extern int sgIP_TCP_SendSynReply(int flags,unsigned long seq, unsigned long ack, unsigned long srcip, unsigned long destip, int srcport, int destport, int windowlen);
extern sgIP_Record_TCP * sgIP_TCP_AllocRecord();
extern void sgIP_TCP_FreeRecord(sgIP_Record_TCP * rec);
extern int sgIP_TCP_Bind(sgIP_Record_TCP * rec, int srcport, unsigned long srcip);
extern int sgIP_TCP_Listen(sgIP_Record_TCP * rec, int maxlisten);
extern sgIP_Record_TCP * sgIP_TCP_Accept(sgIP_Record_TCP * rec);
extern int sgIP_TCP_Close(sgIP_Record_TCP * rec);
extern int sgIP_TCP_Connect(sgIP_Record_TCP * rec, unsigned long destip, int destport);
extern int sgIP_TCP_Send(sgIP_Record_TCP * rec, const char * datatosend, int datalength, int flags);
extern int sgIP_TCP_Recv(sgIP_Record_TCP * rec, char * databuf, int buflength, int flags);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,245 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_Hub.h"
#include "sgIP_UDP.h"
#include "sgIP_IP.h"
sgIP_Record_UDP * udprecords;
int udpport_counter;
extern unsigned long volatile sgIP_timems;
void sgIP_UDP_Init() {
udprecords=0;
udpport_counter=SGIP_UDP_FIRSTOUTGOINGPORT;
}
int sgIP_UDP_GetUnusedOutgoingPort() {
int myport,clear;
sgIP_Record_UDP * rec;
udpport_counter+=(sgIP_timems&1023); // semi-random
if(udpport_counter>SGIP_UDP_LASTOUTGOINGPORT) udpport_counter=SGIP_UDP_FIRSTOUTGOINGPORT;
while(1) {
rec = udprecords;
myport=udpport_counter++;
if(udpport_counter>SGIP_UDP_LASTOUTGOINGPORT) udpport_counter=SGIP_UDP_FIRSTOUTGOINGPORT;
clear=1;
while(rec) {
if(rec->srcport==myport) { clear=0; break; }
rec=rec->next;
}
if(clear) return myport;
}
}
int sgIP_UDP_CalcChecksum(sgIP_memblock * mb, unsigned long srcip, unsigned long destip, int totallength) {
int checksum;
if(!mb) return 0;
if(mb->totallength&1) mb->datastart[mb->totallength]=0;
checksum=sgIP_memblock_IPChecksum(mb,0,mb->totallength);
// add in checksum of "faux header"
checksum+=(destip&0xFFFF);
checksum+=(destip>>16);
checksum+=(srcip&0xFFFF);
checksum+=(srcip>>16);
checksum+=htons(totallength);
checksum+=(17)<<8;
checksum=(checksum&0xFFFF) + (checksum>>16);
checksum=(checksum&0xFFFF) + (checksum>>16);
checksum = (~checksum)&0xFFFF;
if(checksum==0) checksum=0xFFFF;
return checksum;
}
int sgIP_UDP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip) {
if(!mb) return 0;
int chk = sgIP_UDP_CalcChecksum(mb,srcip,destip,mb->totallength);
if(chk!=0xFFFF) {
SGIP_DEBUG_MESSAGE(("UDP receive checksum incorrect"));
sgIP_memblock_free(mb);
return 0; // checksum error
}
sgIP_Header_UDP * udp;
udp=(sgIP_Header_UDP *)mb->datastart;
sgIP_Record_UDP * rec;
sgIP_memblock *tmb;
SGIP_INTR_PROTECT();
rec=udprecords;
while(rec) {
if((rec->srcip==destip || rec->srcip==0) && rec->srcport==udp->destport && rec->state!=SGIP_UDP_STATE_UNUSED) break; // a match!
rec=rec->next;
}
if(!rec) { // no matching records
sgIP_memblock_free(mb);
SGIP_INTR_UNPROTECT();
return 0;
}
// we have a record and a packet for it; add some data to the record and stuff it into the record queue.
sgIP_memblock_exposeheader(mb,4);
*((unsigned long *)mb->datastart)=srcip; // keep srcip around.
if(rec->incoming_queue==0) {
rec->incoming_queue=mb;
} else {
rec->incoming_queue_end->next=mb;
}
tmb=mb;
while(tmb->next) tmb=tmb->next;
rec->incoming_queue_end=tmb;
// ok, data added to queue - yay!
// that means... we're done.
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_UDP_SendPacket(sgIP_Record_UDP * rec, const char * data, int datalen, unsigned long destip, int destport) {
if(!rec || !data) return SGIP_ERROR(EINVAL);
if(rec->state!=SGIP_UDP_STATE_BOUND) {
rec->srcip=0;
rec->srcport=sgIP_UDP_GetUnusedOutgoingPort();
rec->state=SGIP_UDP_STATE_BOUND;
}
sgIP_memblock * mb = sgIP_memblock_alloc(sgIP_IP_RequiredHeaderSize()+8+datalen);
if(!mb) return SGIP_ERROR(ENOMEM);
sgIP_memblock_exposeheader(mb,-sgIP_IP_RequiredHeaderSize()); // hide IP header space for later
SGIP_INTR_PROTECT();
unsigned long srcip = sgIP_IP_GetLocalBindAddr(rec->srcip,destip);
sgIP_Header_UDP * udp = (sgIP_Header_UDP *) mb->datastart;
udp->srcport=rec->srcport;
udp->destport=destport;
udp->length=htons(datalen+8);
udp->checksum=0;
int i;
for(i=0;i<datalen;i++) {
mb->datastart[i+8]=data[i];
}
udp->checksum=sgIP_UDP_CalcChecksum(mb,srcip,destip,mb->totallength);
sgIP_IP_SendViaIP(mb,17,srcip,destip);
SGIP_INTR_UNPROTECT();
return datalen;
}
sgIP_Record_UDP * sgIP_UDP_AllocRecord() {
SGIP_INTR_PROTECT();
sgIP_Record_UDP * rec;
rec = (sgIP_Record_UDP *)sgIP_malloc(sizeof(sgIP_Record_UDP));
if(rec) {
rec->destip=0;
rec->destport=0;
rec->incoming_queue=0;
rec->incoming_queue_end=0;
rec->srcip=0;
rec->srcport=0;
rec->state=0;
rec->next=udprecords;
udprecords=rec;
}
SGIP_INTR_UNPROTECT();
return rec;
}
void sgIP_UDP_FreeRecord(sgIP_Record_UDP * rec) {
if(!rec) return;
SGIP_INTR_PROTECT();
sgIP_Record_UDP * t;
// incoming queue is all clumped together as a single memblock, so, time to free it all in one call :)
if(rec->incoming_queue) sgIP_memblock_free(rec->incoming_queue); // woohoo!
rec->state=0;
if(udprecords==rec) {
udprecords=rec->next;
} else {
t=udprecords;
while(t) {
if(t->next==rec) {
t->next=rec->next;
break;
}
t=t->next;
}
}
sgIP_free(rec);
SGIP_INTR_UNPROTECT();
}
int sgIP_UDP_Bind(sgIP_Record_UDP * rec, int srcport, unsigned long srcip) {
if(!rec) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
if(rec->state!=SGIP_UDP_STATE_UNUSED) {
rec->srcip=srcip;
rec->srcport=srcport;
if(rec->state==SGIP_UDP_STATE_UNBOUND) rec->state=SGIP_UDP_STATE_BOUND;
}
SGIP_INTR_UNPROTECT();
return 0;
}
int sgIP_UDP_RecvFrom(sgIP_Record_UDP * rec, char * destbuf, int buflength, int flags, unsigned long * sender_ip, unsigned short * sender_port) {
if(!rec || !destbuf || !sender_ip || !sender_port || buflength==0) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
if(rec->incoming_queue==0) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EWOULDBLOCK);
}
int packetlen=rec->incoming_queue->totallength-12;
if(packetlen>buflength) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EMSGSIZE);
}
sgIP_memblock * mb;
*sender_ip=*((unsigned long *)rec->incoming_queue->datastart);
*sender_port=((unsigned short *)rec->incoming_queue->datastart)[2];
int totlen,first, buf_start,i;
totlen=rec->incoming_queue->totallength;
first=12;
buf_start=0;
while(totlen>0 && rec->incoming_queue) {
totlen-=rec->incoming_queue->thislength;
for(i=first;i<rec->incoming_queue->thislength;i++) {
destbuf[buf_start+i-first]=rec->incoming_queue->datastart[i];
}
buf_start+=rec->incoming_queue->thislength-first;
first=0;
mb=rec->incoming_queue;
rec->incoming_queue=rec->incoming_queue->next;
mb->next=0;
sgIP_memblock_free(mb);
}
if(!(rec->incoming_queue)) rec->incoming_queue_end=0;
SGIP_INTR_UNPROTECT();
return buf_start;
}
int sgIP_UDP_SendTo(sgIP_Record_UDP * rec, const char * buf, int buflength, int flags, unsigned long dest_ip, int dest_port) {
return sgIP_UDP_SendPacket(rec,buf,buflength,dest_ip,dest_port);
}

View File

@@ -0,0 +1,81 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_UDP_H
#define SGIP_UDP_H
#include "sgIP_Config.h"
#include "sgIP_memblock.h"
enum SGIP_UDP_STATE {
SGIP_UDP_STATE_UNBOUND, // newly allocated
SGIP_UDP_STATE_BOUND, // got a source address/port
SGIP_UDP_STATE_UNUSED, // no longer in use.
};
typedef struct SGIP_HEADER_UDP {
unsigned short srcport,destport;
unsigned short length,checksum;
} sgIP_Header_UDP;
typedef struct SGIP_RECORD_UDP {
struct SGIP_RECORD_UDP * next;
int state;
unsigned long srcip;
unsigned long destip;
unsigned short srcport,destport;
sgIP_memblock * incoming_queue;
sgIP_memblock * incoming_queue_end;
} sgIP_Record_UDP;
#ifdef __cplusplus
extern "C" {
#endif
void sgIP_UDP_Init();
int sgIP_UDP_CalcChecksum(sgIP_memblock * mb, unsigned long srcip, unsigned long destip, int totallength);
int sgIP_UDP_ReceivePacket(sgIP_memblock * mb, unsigned long srcip, unsigned long destip);
int sgIP_UDP_SendPacket(sgIP_Record_UDP * rec, const char * data, int datalen, unsigned long destip, int destport);
sgIP_Record_UDP * sgIP_UDP_AllocRecord();
void sgIP_UDP_FreeRecord(sgIP_Record_UDP * rec);
int sgIP_UDP_Bind(sgIP_Record_UDP * rec, int srcport, unsigned long srcip);
int sgIP_UDP_RecvFrom(sgIP_Record_UDP * rec, char * destbuf, int buflength, int flags, unsigned long * sender_ip, unsigned short * sender_port);
int sgIP_UDP_SendTo(sgIP_Record_UDP * rec, const char * buf, int buflength, int flags, unsigned long dest_ip, int dest_port);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,295 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_memblock.h"
#include <stdlib.h>
#include <string.h>
#ifndef SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
#ifndef SGIP_USEDYNAMICMEMORY
sgIP_memblock memblock_pool[SGIP_MEMBLOCK_BASENUM];
#else
sgIP_memblock * memblock_pool;
#endif
sgIP_memblock * memblock_poolfree;
int numused, numfree;
void * pool_link;
sgIP_memblock * sgIP_memblock_getunused() {
int i;
sgIP_memblock * mb;
SGIP_INTR_PROTECT();
if(memblock_poolfree) { // we still have free memblocks!
mb=memblock_poolfree;
memblock_poolfree=mb->next;
numfree--;
numused++;
} else { // oh noes, we have no more free memblocks.
mb = 0; // eventually alloc new blocks, but for now just stop.
}
SGIP_INTR_UNPROTECT();
return mb;
}
#endif //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
void sgIP_memblock_Init() {
#ifndef SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
int i;
#ifdef SGIP_USEDYNAMICMEMORY
pool_link = sgIP_malloc(sizeof(sgIP_memblock)*SGIP_MEMBLOCK_BASENUM+4);
((long *)pool_link)[0]=0;
memblock_pool = (sgIP_memblock *) (((char *)pool_link)+4);
#endif
numused=numfree=0;
memblock_poolfree=0;
for(i=0;i<SGIP_MEMBLOCK_BASENUM;i++) {
memblock_pool[i].totallength=0;
memblock_pool[i].next=memblock_poolfree;
memblock_poolfree=memblock_pool+i;
numfree++;
}
#endif //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
}
#ifdef SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
sgIP_memblock * sgIP_memblock_allocHW(int headersize, int packetsize) {
sgIP_memblock * mb;
mb = (sgIP_memblock *) sgIP_malloc(SGIP_MEMBLOCK_HEADERSIZE+SGIP_MAXHWHEADER+packetsize);
if(!mb) return 0;
mb->totallength=headersize+packetsize;
mb->thislength=mb->totallength;
mb->datastart=mb->reserved+SGIP_MAXHWHEADER-headersize;
mb->next=0;
return mb;
}
#else //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
sgIP_memblock * sgIP_memblock_allocHW(int headersize, int packetsize) {
sgIP_memblock * mb, * tmb, *t;
int totlen;
mb = sgIP_memblock_getunused();
if(!mb) return 0;
mb->totallength=headersize+packetsize;
mb->datastart=mb->reserved+SGIP_MAXHWHEADER-headersize;
mb->next=0;
mb->thislength=headersize+SGIP_MEMBLOCK_FIRSTINTERNALSIZE;
if(mb->thislength>=mb->totallength) {
mb->thislength = mb->totallength;
// SGIP_DEBUG_MESSAGE(("memblock_alloc: %i free, %i used",numfree,numused));
return mb;
} else { // need more blocks
totlen=mb->thislength;
tmb=mb;
while(totlen<mb->totallength) {
t=sgIP_memblock_getunused();
if(!t) { // we're skrewed.
sgIP_memblock_free(mb);
return 0;
}
tmb->next=t;
t->totallength=mb->totallength;
t->datastart=mb->reserved; // no header on blocks after the first.
t->next=0;
t->thislength=SGIP_MEMBLOCK_INTERNALSIZE;
if(t->thislength+totlen>=mb->totallength) {
t->thislength=mb->totallength-totlen;
// SGIP_DEBUG_MESSAGE(("memblock_alloc: %i free, %i used",numfree,numused));
return mb;
} else { // need YET more blocks.
totlen+=t->thislength;
tmb=t;
} // the cycle contiues.
}
sgIP_memblock_free(mb); // should never get here.
}
return 0;
}
#endif //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
sgIP_memblock * sgIP_memblock_alloc(int packetsize) {
return sgIP_memblock_allocHW(0,packetsize);
}
#ifdef SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
void sgIP_memblock_free(sgIP_memblock * mb) {
sgIP_memblock * f;
SGIP_INTR_PROTECT();
while(mb) {
mb->totallength=0;
mb->thislength=0;
f=mb;
mb = mb->next;
sgIP_free(f);
}
SGIP_INTR_UNPROTECT();
}
#else //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
void sgIP_memblock_free(sgIP_memblock * mb) {
sgIP_memblock * f;
SGIP_INTR_PROTECT();
while(mb) {
mb->totallength=0;
mb->thislength=0;
f=mb;
mb = mb->next;
numfree++; // reinstate memblock into the pool!
numused--;
f->next=memblock_poolfree;
memblock_poolfree=f;
}
// SGIP_DEBUG_MESSAGE(("memblock_free: %i free, %i used",numfree,numused));
SGIP_INTR_UNPROTECT();
}
#endif //SGIP_MEMBLOCK_DYNAMIC_MALLOC_ALL
// positive to expose, negative to hide.
void sgIP_memblock_exposeheader(sgIP_memblock * mb, int change) {
if(mb) {
mb->thislength+=change;
mb->totallength+=change;
mb->datastart-=change;
while(mb->next) {
mb->next->totallength=mb->totallength;
mb=mb->next;
}
}
}
void sgIP_memblock_trimsize(sgIP_memblock * mb, int newsize) {
int lentot;
if(mb) {
mb->totallength=newsize;
lentot=0;
while(mb) {
lentot+=mb->thislength;
if(lentot>newsize) {
mb->thislength-=(lentot-newsize);
if(mb->next) sgIP_memblock_free(mb->next);
mb->next=0;
return;
} else {
mb=mb->next;
}
}
}
}
int sgIP_memblock_IPChecksum(sgIP_memblock * mb, int startbyte, int chksum_length) {
int chksum_temp,offset;
// check checksum
chksum_temp=0;
offset=0;
while(mb && startbyte>mb->thislength) { startbyte-=mb->thislength; mb=mb->next; }
if(!mb) return 0;
while(chksum_length) {
while(startbyte+offset+1<mb->thislength && chksum_length>1) {
chksum_temp+= ((unsigned char *)mb->datastart)[startbyte+offset] + (((unsigned char *)mb->datastart)[startbyte+offset+1]<<8);
offset+=2;
chksum_length-=2;
}
chksum_temp= (chksum_temp&0xFFFF) +(chksum_temp>>16);
if(startbyte+offset<mb->thislength && chksum_length>0) {
chksum_temp+= ((unsigned char *)mb->datastart)[startbyte+offset];
if(chksum_length==1) break;
chksum_length--;
offset=0;
startbyte=0;
mb=mb->next;
if(!mb) break;
if(mb->thislength==0) break;
chksum_temp+= ((unsigned char *)mb->datastart)[startbyte+offset]<<8;
if(chksum_length==1) break;
offset++;
chksum_length--;
}
}
chksum_temp= (chksum_temp&0xFFFF) +(chksum_temp>>16);
chksum_temp= (chksum_temp&0xFFFF) +(chksum_temp>>16);
return chksum_temp;
}
int sgIP_memblock_CopyToLinear(sgIP_memblock * mb, void * dest_buf, int startbyte, int copy_length) {
int copylen,ofs_src, tot_copy;
ofs_src=startbyte;
while(mb && ofs_src>=mb->thislength) { ofs_src-=mb->thislength; mb=mb->next; }
if(!mb) return 0;
if(startbyte+copy_length>mb->totallength) copy_length=mb->totallength-startbyte;
if(copy_length<0) copy_length=0;
tot_copy=0;
while(copy_length>0) {
copylen=copy_length;
if(copylen>mb->thislength-ofs_src) copylen=mb->thislength-ofs_src;
memcpy(((char *)dest_buf)+tot_copy,mb->datastart+ofs_src,copylen);
copy_length-=copylen;
tot_copy+=copylen;
ofs_src=0;
mb=mb->next;
if(!mb) break;
}
return tot_copy;
}
int sgIP_memblock_CopyFromLinear(sgIP_memblock * mb, void * src_buf, int startbyte, int copy_length) {
int copylen,ofs_src, tot_copy;
ofs_src=startbyte;
while(mb && ofs_src>=mb->thislength) { ofs_src-=mb->thislength; mb=mb->next; }
if(!mb) return 0;
if(startbyte+copy_length>mb->totallength) copy_length=mb->totallength-startbyte;
if(copy_length<0) copy_length=0;
tot_copy=0;
while(copy_length>0) {
copylen=copy_length;
if(copylen>mb->thislength-ofs_src) copylen=mb->thislength-ofs_src;
memcpy(mb->datastart+ofs_src,((char *)src_buf)+tot_copy,copylen);
copy_length-=copylen;
tot_copy+=copylen;
ofs_src=0;
mb=mb->next;
if(!mb) break;
}
return tot_copy;
}
int sgIP_memblock_CopyBlock(sgIP_memblock * mb_src, sgIP_memblock * mb_dest, int start_src, int start_dest, int copy_length) {
return 0;
}

View File

@@ -0,0 +1,65 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_MEMBLOCK_H
#define SGIP_MEMBLOCK_H
#include "sgIP_Config.h"
typedef struct SGIP_MEMBLOCK {
int totallength;
int thislength;
struct SGIP_MEMBLOCK * next;
char * datastart;
char reserved[SGIP_MEMBLOCK_DATASIZE-16]; // assume the other 4 values are 16 bytes total in length.
} sgIP_memblock;
#define SGIP_MEMBLOCK_HEADERSIZE 16
#define SGIP_MEMBLOCK_INTERNALSIZE (SGIP_MEMBLOCK_DATASIZE-16)
#define SGIP_MEMBLOCK_FIRSTINTERNALSIZE (SGIP_MEMBLOCK_DATASIZE-16-SGIP_MAXHWHEADER)
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_memblock_Init();
extern sgIP_memblock * sgIP_memblock_alloc(int packetsize);
extern sgIP_memblock * sgIP_memblock_allocHW(int headersize, int packetsize);
extern void sgIP_memblock_free(sgIP_memblock * mb);
extern void sgIP_memblock_exposeheader(sgIP_memblock * mb, int change);
extern void sgIP_memblock_trimsize(sgIP_memblock * mb, int newsize);
extern int sgIP_memblock_IPChecksum(sgIP_memblock * mb, int startbyte, int chksum_length);
extern int sgIP_memblock_CopyToLinear(sgIP_memblock * mb, void * dest_buf, int startbyte, int copy_length);
extern int sgIP_memblock_CopyFromLinear(sgIP_memblock * mb, void * src_buf, int startbyte, int copy_length);
extern int sgIP_memblock_CopyBlock(sgIP_memblock * mb_src, sgIP_memblock * mb_dest, int start_src, int start_dest, int copy_length);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,520 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "sgIP_sockets.h"
#include "sgIP_TCP.h"
#include "sgIP_UDP.h"
#include "sgIP_ICMP.h"
#include "sgIP_DNS.h"
sgIP_socket_data socketlist[SGIP_SOCKET_MAXSOCKETS];
extern unsigned long sgIP_timems;
void sgIP_sockets_Init() {
int i;
for(i=0;i<SGIP_SOCKET_MAXSOCKETS;i++) {
socketlist[i].conn_ptr=0;
socketlist[i].flags = 0;
}
}
// spawn/kill socket for internal use ONLY.
int spawn_socket(int flags) {
int s;
SGIP_INTR_PROTECT();
for(s=0;s<SGIP_SOCKET_MAXSOCKETS;s++) if(!(socketlist[s].flags&SGIP_SOCKET_FLAG_ACTIVE)) break;
if(s==SGIP_SOCKET_MAXSOCKETS) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(ENOMEM);
}
socketlist[s].flags=SGIP_SOCKET_FLAG_ACTIVE | flags;
socketlist[s].conn_ptr=0;
SGIP_INTR_UNPROTECT();
return s+1;
}
int kill_socket(int s) {
if(s<1 || s>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
s--;
socketlist[s].conn_ptr=0;
socketlist[s].flags=0;
SGIP_INTR_UNPROTECT();
return 0;
}
int socket(int domain, int type, int protocol) {
int s;
if(domain!=AF_INET) return SGIP_ERROR(EINVAL);
if(protocol!=0) return SGIP_ERROR(EINVAL);
if(type!=SOCK_DGRAM && type!=SOCK_STREAM) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
for(s=0;s<SGIP_SOCKET_MAXSOCKETS;s++) if(!(socketlist[s].flags&SGIP_SOCKET_FLAG_ACTIVE)) break;
if(s==SGIP_SOCKET_MAXSOCKETS) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(ENOMEM);
}
if(type==SOCK_STREAM) {
socketlist[s].flags=SGIP_SOCKET_FLAG_ACTIVE | SGIP_SOCKET_FLAG_TYPE_TCP;
socketlist[s].conn_ptr=sgIP_TCP_AllocRecord();
} else if(type==SOCK_DGRAM) {
socketlist[s].flags=SGIP_SOCKET_FLAG_ACTIVE | SGIP_SOCKET_FLAG_TYPE_UDP;
socketlist[s].conn_ptr=sgIP_UDP_AllocRecord();
} else {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EINVAL);
}
#ifdef SGIP_SOCKET_DEFAULT_NONBLOCK
socketlist[s].flags|=SGIP_SOCKET_FLAG_NONBLOCKING;
#endif
SGIP_INTR_UNPROTECT();
return s+1;
}
int closesocket(int socket) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
socket--;
if(!(socketlist[socket].flags&SGIP_SOCKET_FLAG_ACTIVE)) { SGIP_INTR_UNPROTECT(); return 0; }
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
sgIP_TCP_FreeRecord((sgIP_Record_TCP *)socketlist[socket].conn_ptr);
} else if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
sgIP_UDP_FreeRecord((sgIP_Record_UDP *)socketlist[socket].conn_ptr);
}
socketlist[socket].conn_ptr=0;
socketlist[socket].flags=0;
SGIP_INTR_UNPROTECT();
return 0;
}
int bind(int socket, const struct sockaddr * addr, int addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
if(addr_len!=sizeof(struct sockaddr_in)) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
retval=sgIP_TCP_Bind((sgIP_Record_TCP *)socketlist[socket].conn_ptr,((struct sockaddr_in *)addr)->sin_port,((struct sockaddr_in *)addr)->sin_addr.s_addr);
} else if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
retval=sgIP_UDP_Bind((sgIP_Record_UDP *)socketlist[socket].conn_ptr,((struct sockaddr_in *)addr)->sin_port,((struct sockaddr_in *)addr)->sin_addr.s_addr);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int connect(int socket, const struct sockaddr * addr, int addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
if(addr_len!=sizeof(struct sockaddr_in)) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
int i;
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
retval=sgIP_TCP_Connect((sgIP_Record_TCP *)socketlist[socket].conn_ptr,((struct sockaddr_in *)addr)->sin_addr.s_addr,((struct sockaddr_in *)addr)->sin_port);
if(retval==0) {
do {
i=((sgIP_Record_TCP *)socketlist[socket].conn_ptr)->tcpstate;
if(i==SGIP_TCP_STATE_ESTABLISHED || i==SGIP_TCP_STATE_CLOSE_WAIT) {retval=0; break;}
if(i==SGIP_TCP_STATE_CLOSED || i==SGIP_TCP_STATE_UNUSED || i==SGIP_TCP_STATE_LISTEN || i==SGIP_TCP_STATE_NODATA)
{ retval=SGIP_ERROR(((sgIP_Record_TCP *)socketlist[socket].conn_ptr)->errorcode); break; }
if(socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) break;
SGIP_INTR_UNPROTECT();
SGIP_WAITEVENT();
SGIP_INTR_REPROTECT();
} while(1);
}
}
SGIP_INTR_UNPROTECT();
return retval;
}
int send(int socket, const void * data, int sendlength, int flags) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return -1;
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
do {
retval=sgIP_TCP_Send((sgIP_Record_TCP *)socketlist[socket].conn_ptr,data,sendlength,flags);
if(retval!=-1) break;
if(errno!=EWOULDBLOCK) break;
if(socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) break;
SGIP_INTR_UNPROTECT();
SGIP_WAITEVENT();
SGIP_INTR_REPROTECT();
} while(1);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int recv(int socket, void * data, int recvlength, int flags) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return -1;
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
do {
retval=sgIP_TCP_Recv((sgIP_Record_TCP *)socketlist[socket].conn_ptr,data,recvlength,flags);
if(retval!=-1) break;
if(errno!=EWOULDBLOCK) break;
if(socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) break;
SGIP_INTR_UNPROTECT();
SGIP_WAITEVENT();
SGIP_INTR_REPROTECT();
} while(1);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int sendto(int socket, const void * data, int sendlength, int flags, const struct sockaddr * addr, int addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return -1;
if(!addr) return -1;
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
} else if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
retval=sgIP_UDP_SendTo((sgIP_Record_UDP *)socketlist[socket].conn_ptr,data,sendlength,flags,((struct sockaddr_in *)addr)->sin_addr.s_addr,((struct sockaddr_in *)addr)->sin_port);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int recvfrom(int socket, void * data, int recvlength, int flags, struct sockaddr * addr, int * addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return -1;
if(!addr) return -1;
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
} else if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
do {
retval=sgIP_UDP_RecvFrom((sgIP_Record_UDP *)socketlist[socket].conn_ptr,data,recvlength,flags,&(((struct sockaddr_in *)addr)->sin_addr.s_addr),&(((struct sockaddr_in *)addr)->sin_port));
if(retval!=-1) break;
if(errno!=EWOULDBLOCK) break;
if(socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) break;
SGIP_INTR_UNPROTECT(); // give interrupts a chance to occur.
SGIP_WAITEVENT(); // don't just try again immediately
SGIP_INTR_REPROTECT();
} while(1);
*addr_len = sizeof(struct sockaddr_in);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int listen(int socket, int max_connections) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
retval=sgIP_TCP_Listen((sgIP_Record_TCP *)socketlist[socket].conn_ptr,max_connections);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int accept(int socket, struct sockaddr * addr, int * addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS || !addr || !addr_len) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
sgIP_Record_TCP * ret;
int retval,s;
retval=SGIP_ERROR0(EINVAL);
ret=0;
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
s=spawn_socket((socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) | SGIP_SOCKET_FLAG_TYPE_TCP);
if(s>0) {
do {
ret=sgIP_TCP_Accept((sgIP_Record_TCP *)socketlist[socket].conn_ptr);
if(ret!=0) break;
if(errno!=EWOULDBLOCK) break;
if(socketlist[socket].flags&SGIP_SOCKET_FLAG_NONBLOCKING) break;
SGIP_INTR_UNPROTECT(); // give interrupts a chance to occur.
SGIP_WAITEVENT(); // don't just try again immediately
SGIP_INTR_REPROTECT();
} while(1);
}
if(ret==0) {
kill_socket(s);
retval=-1;
} else {
*addr_len=sizeof(struct sockaddr_in);
((struct sockaddr_in *)addr)->sin_family=AF_INET;
((struct sockaddr_in *)addr)->sin_port=ret->destport;
((struct sockaddr_in *)addr)->sin_addr.s_addr=ret->destip;
socketlist[s-1].conn_ptr=ret;
retval=s;
}
}
SGIP_INTR_UNPROTECT();
return retval;
}
int shutdown(int socket, int shutdown_type) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EINVAL);
SGIP_INTR_PROTECT();
int retval=SGIP_ERROR(EINVAL);
socket--;
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
retval=sgIP_TCP_Close((sgIP_Record_TCP *)socketlist[socket].conn_ptr);
}
SGIP_INTR_UNPROTECT();
return retval;
}
int ioctl(int socket, long cmd, void * arg) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EBADF);
socket--;
int retval,i;
retval=0;
SGIP_INTR_PROTECT();
switch(cmd) {
case FIONBIO:
if(!arg){
retval=SGIP_ERROR(EINVAL);
} else {
socketlist[socket].flags &= ~SGIP_SOCKET_FLAG_NONBLOCKING;
if(*((unsigned long *)arg)) socketlist[socket].flags |= SGIP_SOCKET_FLAG_NONBLOCKING;
}
break;
case FIONREAD:
if(!arg) {
retval=SGIP_ERROR(EINVAL);
} else {
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
i=((sgIP_Record_TCP *)socketlist[socket].conn_ptr)->buf_rx_out-((sgIP_Record_TCP *)socketlist[socket].conn_ptr)->buf_rx_in;
if(i<0) i+=SGIP_TCP_RECEIVEBUFFERLENGTH;
*((int *)arg)=i;
} else {
retval=SGIP_ERROR(EINVAL);
}
}
}
SGIP_INTR_UNPROTECT();
return retval;
}
int setsockopt(int socket, int level, int option_name, const void * data, int data_len) {
return 0;
}
int getsockopt(int socket, int level, int option_name, void * data, int * data_len) {
return 0;
}
int getpeername(int socket, struct sockaddr *addr, int * addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EBADF);
if(!addr || !addr_len) return SGIP_ERROR(EFAULT);
if(*addr_len<sizeof(struct sockaddr_in)) return SGIP_ERROR(EFAULT);
socket--;
SGIP_INTR_PROTECT();
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
{
struct sockaddr_in * sain = (struct sockaddr_in *)addr;
sgIP_Record_TCP * rec = (sgIP_Record_TCP *)socketlist[socket].conn_ptr;
if(rec->tcpstate!=SGIP_TCP_STATE_ESTABLISHED) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(ENOTCONN);
} else {
sain->sin_addr.s_addr=rec->destip;
sain->sin_family=AF_INET;
sain->sin_port=rec->destport;
*addr_len=sizeof(struct sockaddr_in);
}
}
} else {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EOPNOTSUPP);
}
SGIP_INTR_UNPROTECT();
return 0;
}
int getsockname(int socket, struct sockaddr *addr, int * addr_len) {
if(socket<1 || socket>SGIP_SOCKET_MAXSOCKETS) return SGIP_ERROR(EBADF);
if(!addr || !addr_len) return SGIP_ERROR(EFAULT);
if(*addr_len<sizeof(struct sockaddr_in)) return SGIP_ERROR(EFAULT);
socket--;
SGIP_INTR_PROTECT();
if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
{
struct sockaddr_in * sain = (struct sockaddr_in *)addr;
sgIP_Record_TCP * rec = (sgIP_Record_TCP *)socketlist[socket].conn_ptr;
if(rec->tcpstate==SGIP_TCP_STATE_UNUSED || rec->tcpstate==SGIP_TCP_STATE_CLOSED) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EINVAL);
} else {
sain->sin_addr.s_addr=rec->srcip;
sain->sin_family=AF_INET;
sain->sin_port=rec->srcport;
*addr_len=sizeof(struct sockaddr_in);
}
}
} else if((socketlist[socket].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
{
struct sockaddr_in * sain = (struct sockaddr_in *)addr;
sgIP_Record_UDP * rec = (sgIP_Record_UDP *)socketlist[socket].conn_ptr;
if(rec->state==SGIP_UDP_STATE_UNUSED) {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EINVAL);
} else {
sain->sin_addr.s_addr=rec->srcip;
sain->sin_family=AF_INET;
sain->sin_port=rec->srcport;
*addr_len=sizeof(struct sockaddr_in);
}
}
} else {
SGIP_INTR_UNPROTECT();
return SGIP_ERROR(EOPNOTSUPP);
}
SGIP_INTR_UNPROTECT();
return 0;
}
struct hostent * gethostbyname(const char * name) {
return (struct hostent *)sgIP_DNS_gethostbyname(name);
};
extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) {
// 31 days = 2678400 seconds
unsigned long timeout_ms, lasttime, temp;
sgIP_Record_TCP * rec;
sgIP_Record_UDP * urec;
lasttime=sgIP_timems;
if(!timeout) timeout_ms=2678400000UL;
else {
if(timeout->tv_sec>=2678400) {
timeout_ms=2678400000UL;
} else {
timeout_ms=timeout->tv_sec*1000 + (timeout->tv_usec/1000);
}
}
SGIP_INTR_PROTECT();
nfds=SGIP_SOCKET_MAXSOCKETS;
int i,j,retval;
while(timeout_ms>0) { // check all fd sets
// readfds
if(readfds) {
for(i=0;i<nfds;i++) {
if(FD_ISSET(i+1,readfds)) {
if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
rec = (sgIP_Record_TCP *)socketlist[i].conn_ptr;
if(rec->buf_rx_in!=rec->buf_rx_out) { timeout_ms=0; break; }
} else if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
urec = (sgIP_Record_UDP *)socketlist[i].conn_ptr;
if(urec->incoming_queue) { timeout_ms=0; break; }
}
}
}
if(timeout_ms==0) break;
}
if(writefds) {
// writefds
for(i=0;i<nfds;i++) {
if(FD_ISSET(i+1,writefds)) {
if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
rec = (sgIP_Record_TCP *)socketlist[i].conn_ptr;
j=rec->buf_tx_in-1;
if(j<0) j=SGIP_TCP_TRANSMITBUFFERLENGTH-1;
if(rec->buf_tx_in!=j) { timeout_ms=0; break; }
}
}
}
if(timeout_ms==0) break;
}
// errorfds
// ignore errorfds for now.
temp=sgIP_timems-lasttime;
if(timeout_ms<temp) timeout_ms=0; else timeout_ms -= temp;
lasttime+=temp;
SGIP_INTR_UNPROTECT(); // give interrupts a chance to occur.
SGIP_WAITEVENT(); // don't just try again immediately
SGIP_INTR_REPROTECT();
}
// markup fd sets and return
// readfds
retval=0;
if(readfds) {
for(i=0;i<nfds;i++) {
if(FD_ISSET(i+1,readfds)) {
if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
rec = (sgIP_Record_TCP *)socketlist[i].conn_ptr;
if(rec->buf_rx_in==rec->buf_rx_out) { FD_CLR(i+1,readfds);} else retval++;
} else if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_UDP) {
urec = (sgIP_Record_UDP *)socketlist[i].conn_ptr;
if(!urec->incoming_queue) { FD_CLR(i+1,readfds);} else retval++;
}
}
}
}
// writefds
if(writefds) {
for(i=0;i<nfds;i++) {
if(FD_ISSET(i+1,writefds)) {
if((socketlist[i].flags&SGIP_SOCKET_FLAG_TYPEMASK)==SGIP_SOCKET_FLAG_TYPE_TCP) {
rec = (sgIP_Record_TCP *)socketlist[i].conn_ptr;
j=rec->buf_tx_in-1;
if(j<0) j=SGIP_TCP_TRANSMITBUFFERLENGTH-1;
if(rec->buf_tx_in==j) { FD_CLR(i+1,writefds); } else retval++;
}
}
}
}
if(errorfds) { FD_ZERO(errorfds); }
SGIP_INTR_UNPROTECT();
return retval;
}
/*
extern void FD_CLR(int fd, fd_set * fdset) {
if(fd<1 || fd>FD_SETSIZE || !fdset) return;
fd--;
fdset->fdbits[fd>>5] &= ~(1<<(fd&31));
}
extern int FD_ISSET(int fd, fd_set * fdset) {
if(fd<1 || fd>FD_SETSIZE || !fdset) return 0;
fd--;
return (fdset->fdbits[fd>>5] & 1<<(fd&31))?1:0;
}
extern void FD_SET(int fd, fd_set * fdset) {
if(fd<1 || fd>FD_SETSIZE || !fdset) return;
fd--;
fdset->fdbits[fd>>5] |= 1<<(fd&31);
}
extern void FD_ZERO(fd_set * fdset) {
int i;
if(!fdset) return;
for(i=0;i<(FD_SETSIZE+31)/32;i++) {
fdset->fdbits[i]=0;
}
}
*/

View File

@@ -0,0 +1,83 @@
// DSWifi Project - sgIP Internet Protocol Stack Implementation
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef SGIP_SOCKETS_H
#define SGIP_SOCKETS_H
#include "sgIP_Config.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "netdb.h"
#define SGIP_SOCKET_FLAG_ACTIVE 0x8000
#define SGIP_SOCKET_FLAG_NONBLOCKING 0x4000
#define SGIP_SOCKET_FLAG_TYPEMASK 0x0001
#define SGIP_SOCKET_FLAG_TYPE_TCP 0x0001
#define SGIP_SOCKET_FLAG_TYPE_UDP 0x0000
typedef struct SGIP_SOCKET_DATA {
unsigned int flags;
void * conn_ptr;
} sgIP_socket_data;
#ifdef __cplusplus
extern "C" {
#endif
extern void sgIP_sockets_Init();
// sys/socket.h
extern int socket(int domain, int type, int protocol);
extern int bind(int socket, const struct sockaddr * addr, int addr_len);
extern int connect(int socket, const struct sockaddr * addr, int addr_len);
extern int send(int socket, const void * data, int sendlength, int flags);
extern int recv(int socket, void * data, int recvlength, int flags);
extern int sendto(int socket, const void * data, int sendlength, int flags, const struct sockaddr * addr, int addr_len);
extern int recvfrom(int socket, void * data, int recvlength, int flags, struct sockaddr * addr, int * addr_len);
extern int listen(int socket, int max_connections);
extern int accept(int socket, struct sockaddr * addr, int * addr_len);
extern int shutdown(int socket, int shutdown_type);
extern int closesocket(int socket);
extern int ioctl(int socket, long cmd, void * arg);
extern int setsockopt(int socket, int level, int option_name, const void * data, int data_len);
extern int getsockopt(int socket, int level, int option_name, void * data, int * data_len);
extern int getpeername(int socket, struct sockaddr *addr, int * addr_len);
extern int getsockname(int socket, struct sockaddr *addr, int * addr_len);
// sys/time.h (actually intersects partly with libnds, so I'm letting libnds handle fd_set for the time being)
extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
// arpa/inet.h
extern unsigned long inet_addr(const char *cp);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,995 @@
// DS Wifi interface code
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
// wifi_arm9.c - arm9 wifi support code
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include <nds.h>
#include "dsregs.h"
#include "wifi_arm9.h"
#include <stdarg.h>
#include <stdlib.h>
#include <sys/socket.h>
#ifdef WIFI_USE_TCP_SGIP
#include "sgIP.h"
sgIP_Hub_HWInterface * wifi_hw;
int sgIP_DisableInterrupts() {
int a;
a=REG_IME;
REG_IME=0;
return a;
}
void sgIP_RestoreInterrupts(int old_ime) {
REG_IME=old_ime;
}
void sgIP_IntrWaitEvent() {
// __asm( ".ARM\n swi 0x060000\n" );
int i,j;
j=0;
for(i=0;i<20000;i++) {
j+=i;
}
}
void * sgIP_malloc(int size) __attribute__((weak));
void sgIP_free(void * ptr) __attribute__((weak));
//////////////////////////////////////////////////////////////////////////
// wifi heap allocator system
#define WHEAP_RECORD_FLAG_INUSE 0
#define WHEAP_RECORD_FLAG_UNUSED 1
#define WHEAP_RECORD_FLAG_FREED 2
typedef struct WHEAP_RECORD {
struct WHEAP_RECORD * next;
unsigned short flags, unused;
int size;
} wHeapRecord;
#ifdef SGIP_DEBUG
#define WHEAP_FILL_START 0xAA
#define WHEAP_FILL_END 0xBB
#define WHEAP_PAD_START 4
#define WHEAP_PAD_END 4
#define WHEAP_DO_PAD
#else
#define WHEAP_PAD_START 0
#define WHEAP_PAD_END 0
#undef WHEAP_DO_PAD
#endif
#define WHEAP_RECORD_SIZE (sizeof(wHeapRecord))
#define WHEAP_PAD_SIZE ((WHEAP_PAD_START)+(WHEAP_PAD_END))
#define WHEAP_SIZE_CUTOFF ((WHEAP_RECORD_SIZE)+64)
int wHeapsize;
wHeapRecord * wHeapStart; // start of heap
wHeapRecord * wHeapFirst; // first free block
void wHeapAllocInit(int size) {
wHeapStart=(wHeapRecord *)malloc(size);
wHeapFirst=wHeapStart;
wHeapStart->flags=WHEAP_RECORD_FLAG_UNUSED;
wHeapStart->next=0;
wHeapStart->size=size-sizeof(wHeapRecord);
}
void * wHeapAlloc(int size) {
wHeapRecord * rec = wHeapFirst;
void * voidptr;
int n;
size=(size+3)&(~3);
if(size==0) size=4;
size+=WHEAP_PAD_SIZE;
if(!rec) { SGIP_DEBUG_MESSAGE(("wHeapAlloc: heap full!")); return 0; } // should not happen given normal use.
while(rec->size<size) {
if(!rec->next) { SGIP_DEBUG_MESSAGE(("wHeapAlloc: heap too full!")); return 0; } // cannot alloc
if(rec->next->flags!=WHEAP_RECORD_FLAG_INUSE) { // try to merge with next one
rec->size+=rec->next->size+WHEAP_RECORD_SIZE;
rec->next=rec->next->next;
} else { // skip ahead to more friendly waters
rec=rec->next;
while(rec->next) {
if(rec->flags!=WHEAP_RECORD_FLAG_INUSE) break;
rec=rec->next;
}
if(rec->flags==WHEAP_RECORD_FLAG_INUSE) { SGIP_DEBUG_MESSAGE(("wHeapAlloc: heap too full!")); return 0; } // no empty slots :(
}
}
rec->flags=WHEAP_RECORD_FLAG_INUSE;
n=rec->size-size;
voidptr = ((char *)rec)+WHEAP_RECORD_SIZE+WHEAP_PAD_START;
if(n<WHEAP_SIZE_CUTOFF) { // pad to include unused portion
rec->unused=n;
} else { // chop block into 2
wHeapRecord * rec2;
rec2=(wHeapRecord *)(((char *)rec)+WHEAP_RECORD_SIZE+size);
rec2->flags=WHEAP_RECORD_FLAG_UNUSED;
rec2->size=rec->size-size-WHEAP_RECORD_SIZE;
rec->size=size;
rec2->next=rec->next;
rec->next=rec2;
rec->unused=0;
}
if(rec==wHeapFirst) {
while(wHeapFirst->next && wHeapFirst->flags==WHEAP_RECORD_FLAG_INUSE) wHeapFirst=wHeapFirst->next;
if(wHeapFirst->flags==WHEAP_RECORD_FLAG_INUSE) wHeapFirst=0;
}
#ifdef WHEAP_DO_PAD
{
int i;
for(i=0;i<WHEAP_PAD_START;i++) {
(((unsigned char *)rec)+WHEAP_RECORD_SIZE)[i]=WHEAP_FILL_START;
}
for(i=0;i<WHEAP_PAD_END;i++) {
(((unsigned char *)rec)+WHEAP_RECORD_SIZE+size-WHEAP_PAD_END)[i]=WHEAP_FILL_END;
}
}
#endif
return voidptr;
}
void wHeapFree(void * data) {
wHeapRecord * rec = (wHeapRecord *)(((char *)data)-WHEAP_RECORD_SIZE-WHEAP_PAD_START);
#ifdef WHEAP_DO_PAD
{
int size=rec->size-rec->unused;
int i;
for(i=0;i<WHEAP_PAD_START;i++) {
if((((unsigned char *)rec)+WHEAP_RECORD_SIZE)[i]!=WHEAP_FILL_START) break;
}
if(i!=WHEAP_PAD_START) { // note heap error
SGIP_DEBUG_MESSAGE(("wHeapFree: Corruption found before allocated data! 0x%X",data));
}
for(i=0;i<WHEAP_PAD_END;i++) {
if((((unsigned char *)rec)+WHEAP_RECORD_SIZE+size-WHEAP_PAD_END)[i]!=WHEAP_FILL_END) break;
}
if(i!=WHEAP_PAD_END) { // note heap error
SGIP_DEBUG_MESSAGE(("wHeapFree: Corruption found after allocated data! 0x%x",data));
}
}
#endif
if(rec->flags!=WHEAP_RECORD_FLAG_INUSE) { // note heap error
SGIP_DEBUG_MESSAGE(("wHeapFree: Data already freed! 0x%X",data));
}
rec->flags=WHEAP_RECORD_FLAG_FREED;
if(rec<wHeapFirst || !wHeapFirst) wHeapFirst=rec; // reposition the "starting" pointer.
}
//////////////////////////////////////////////////////////////////////////
void * sgIP_malloc(int size) { return wHeapAlloc(size); }
void sgIP_free(void * ptr) { wHeapFree(ptr); }
#endif
void ethhdr_print(char f, void * d) {
char buffer[33];
int i;
int t,c;
buffer[0]=f;
buffer[1]=':';
buffer[14]=' ';
buffer[27]=' ';
buffer[32]=0;
for(i=0;i<6;i++) {
t=((u8 *)d)[i];
c=t&15;
if(c>9) c+='A'-10; else c+='0';
buffer[3+i*2]=c;
c=(t>>4)&15;
if(c>9) c+='A'-10; else c+='0';
buffer[2+i*2]=c;
t=((u8 *)d)[i+6];
c=t&15;
if(c>9) c+='A'-10; else c+='0';
buffer[16+i*2]=c;
c=(t>>4)&15;
if(c>9) c+='A'-10; else c+='0';
buffer[15+i*2]=c;
}
for(i=0;i<2;i++) {
t=((u8 *)d)[i+12];
c=t&15;
if(c>9) c+='A'-10; else c+='0';
buffer[29+i*2]=c;
c=(t>>4)&15;
if(c>9) c+='A'-10; else c+='0';
buffer[28+i*2]=c;
}
SGIP_DEBUG_MESSAGE((buffer));
}
Wifi_MainStruct Wifi_Data_Struct;
volatile Wifi_MainStruct * WifiData = 0;
WifiPacketHandler packethandler = 0;
WifiSyncHandler synchandler = 0;
void erasemem(void * mem, int length) {
int i;
char * m = (char *)mem;
for(i=0;i<length;i++)
m[i]=0;
}
void Wifi_CopyMacAddr(volatile void * dest, volatile void * src) {
((u16 *)dest)[0]=((u16 *)src)[0];
((u16 *)dest)[1]=((u16 *)src)[1];
((u16 *)dest)[2]=((u16 *)src)[2];
}
int Wifi_CmpMacAddr(volatile void * mac1,volatile void * mac2) {
return (((u16 *)mac1)[0]==((u16 *)mac2)[0]) && (((u16 *)mac1)[1]==((u16 *)mac2)[1]) && (((u16 *)mac1)[2]==((u16 *)mac2)[2]);
}
u32 Wifi_TxBufferWordsAvailable() {
s32 size=WifiData->txbufIn-WifiData->txbufOut-1;
if(size<0) size += WIFI_TXBUFFER_SIZE/2;
return size;
}
void Wifi_TxBufferWrite(s32 start, s32 len, u16 * data) {
int writelen;
while(len>0) {
writelen=len;
if(writelen>(WIFI_TXBUFFER_SIZE/2)-start) writelen=(WIFI_TXBUFFER_SIZE/2)-start;
len-=writelen;
while(writelen) {
WifiData->txbufData[start++]=*(data++);
writelen--;
}
start=0;
}
}
int Wifi_RxRawReadPacket(s32 packetID, s32 readlength, u16 * data) {
int readlen,read_data;
readlength= (readlength+1)/2;
read_data=0;
while(readlength>0) {
readlen=readlength;
if(readlen>(WIFI_RXBUFFER_SIZE/2)-packetID) readlen=(WIFI_RXBUFFER_SIZE/2)-packetID;
readlength-=readlen;
read_data+=readlen;
while(readlen>0) {
*(data++) = WifiData->rxbufData[packetID++];
readlen--;
}
packetID=0;
}
return read_data;
}
u16 Wifi_RxReadOffset(s32 base, s32 offset) {
base+=offset;
if(base>=(WIFI_RXBUFFER_SIZE/2)) base -= (WIFI_RXBUFFER_SIZE/2);
return WifiData->rxbufData[base];
}
// datalen = size of packet from beginning of 802.11 header to end, but not including CRC.
int Wifi_RawTxFrame(u16 datalen, u16 rate, u16 * data) {
Wifi_TxHeader txh;
int sizeneeded;
int base;
sizeneeded=((datalen+12+4+3)/4)*2;
if(sizeneeded>Wifi_TxBufferWordsAvailable()) {WifiData->stats[WSTAT_TXQUEUEDREJECTED]++; return -1; }
txh.tx_rate=rate;
txh.tx_length=datalen+4;
base = WifiData->txbufOut;
Wifi_TxBufferWrite(base,6,(u16 *)&txh);
base += 6;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
Wifi_TxBufferWrite(base,((datalen+3)/4)*2,data);
base += ((datalen+3)/4)*2;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
WifiData->txbufOut=base;
WifiData->stats[WSTAT_TXQUEUEDPACKETS]++;
WifiData->stats[WSTAT_TXQUEUEDBYTES]+=sizeneeded;
if(synchandler) synchandler();
return 0;
}
void Wifi_RawSetPacketHandler(WifiPacketHandler wphfunc) {
packethandler=wphfunc;
}
void Wifi_SetSyncHandler(WifiSyncHandler wshfunc) {
synchandler=wshfunc;
}
void Wifi_DisableWifi() {
WifiData->reqMode=WIFIMODE_DISABLED;
WifiData->reqReqFlags &= ~WFLAG_REQ_APCONNECT;
}
void Wifi_EnableWifi() {
WifiData->reqMode=WIFIMODE_NORMAL;
WifiData->reqReqFlags &= ~WFLAG_REQ_APCONNECT;
}
void Wifi_SetPromiscuousMode(int enable) {
if(enable) WifiData->reqReqFlags |= WFLAG_REQ_PROMISC;
else WifiData->reqReqFlags &= ~WFLAG_REQ_PROMISC;
}
void Wifi_ScanMode() {
WifiData->reqMode=WIFIMODE_SCAN;
WifiData->reqReqFlags &= ~WFLAG_REQ_APCONNECT;
}
void Wifi_SetChannel(int channel) {
if(channel<1 || channel>13) return;
if(WifiData->reqMode==WIFIMODE_NORMAL || WifiData->reqMode==WIFIMODE_SCAN) {
WifiData->reqChannel=channel;
}
}
int Wifi_GetNumAP() {
int i,j;
j=0;
for(i=0;i<WIFI_MAX_AP;i++) if(WifiData->aplist[i].flags&WFLAG_APDATA_ACTIVE) j++;
return j;
}
int Wifi_GetAPData(int apnum, Wifi_AccessPoint * apdata) {
int i,j;
if(!apdata) return WIFI_RETURN_PARAMERROR;
j=0;
for(i=0;i<WIFI_MAX_AP;i++){
if(WifiData->aplist[i].flags&WFLAG_APDATA_ACTIVE) {
if(j==apnum) {
while(Spinlock_Acquire(WifiData->aplist[i])!=SPINLOCK_OK);
{
// additionally calculate average RSSI here
WifiData->aplist[i].rssi=0;
for(j=0;j<8;j++) {
WifiData->aplist[i].rssi+=WifiData->aplist[i].rssi_past[j];
}
WifiData->aplist[i].rssi = WifiData->aplist[i].rssi >> 3;
*apdata = WifiData->aplist[i]; // yay for struct copy!
Spinlock_Release(WifiData->aplist[i]);
return WIFI_RETURN_OK;
}
}
j++;
}
}
return WIFI_RETURN_ERROR;
}
int Wifi_FindMatchingAP(int numaps, Wifi_AccessPoint * apdata, Wifi_AccessPoint * match_dest) {
int ap_match,i,j,n;
Wifi_AccessPoint ap;
u16 macaddrzero[3] = {0,0,0}; // check for empty mac addr
ap_match=-1;
for(i=0;i<Wifi_GetNumAP();i++){
Wifi_GetAPData(i,&ap);
for(j=0;j<numaps;j++) {
if(apdata[j].ssid_len>32 || ((signed char)apdata[j].ssid_len)<0) continue;
if(apdata[j].ssid_len>0) { // compare SSIDs
if(apdata[j].ssid_len!=ap.ssid_len) continue;
for(n=0;n<apdata[j].ssid_len;n++) {
if(apdata[j].ssid[n]!=ap.ssid[n]) break;
}
if(n!=apdata[j].ssid_len) continue;
}
if(!Wifi_CmpMacAddr(apdata[j].macaddr,macaddrzero)) { // compare mac addr
if(!Wifi_CmpMacAddr(apdata[j].macaddr,ap.macaddr)) continue;
}
if(apdata[j].channel!=0) { // compare channels
if(apdata[j].channel!=ap.channel) continue;
}
if(j<ap_match || ap_match==-1) {
ap_match=j;
if(match_dest) *match_dest = ap;
}
if(ap_match==0) return ap_match;
}
}
return ap_match;
}
int wifi_connect_state = 0; // -1==error, 0==searching, 1==associating, 2==dhcp'ing, 3==done, 4=searching wfc data
Wifi_AccessPoint wifi_connect_point;
int Wifi_ConnectAP(Wifi_AccessPoint * apdata, int wepmode, int wepkeyid, u8 * wepkey) {
int i;
Wifi_AccessPoint ap;
wifi_connect_state=-1;
if(!apdata) return -1;
if(((signed char)apdata->ssid_len)<0 || apdata->ssid_len>32) return -1;
Wifi_DisconnectAP();
wifi_connect_state=0;
WifiData->wepmode9=wepmode; // copy data
WifiData->wepkeyid9=wepkeyid;
for(i=0;i<20;i++) {
WifiData->wepkey9[i]=wepkey[i];
}
i=Wifi_FindMatchingAP(1,apdata,&ap);
if(i==0) {
Wifi_CopyMacAddr(WifiData->bssid9, ap.bssid);
Wifi_CopyMacAddr(WifiData->apmac9, ap.bssid);
WifiData->ssid9[0]=ap.ssid_len;
for(i=0;i<32;i++) {
WifiData->ssid9[i+1]=ap.ssid[i];
}
WifiData->apchannel9=ap.channel;
for(i=0;i<16;i++) WifiData->baserates9[i]=ap.base_rates[i];
WifiData->reqMode=WIFIMODE_NORMAL;
WifiData->reqReqFlags |= WFLAG_REQ_APCONNECT | WFLAG_REQ_APCOPYVALUES;
wifi_connect_state=1;
} else {
WifiData->reqMode=WIFIMODE_SCAN;
wifi_connect_point = *apdata;
}
return 0;
}
void Wifi_AutoConnect() {
if(!(WifiData->wfc_enable[0]&0x80)) {
wifi_connect_state=ASSOCSTATUS_CANNOTCONNECT;
} else {
wifi_connect_state=4;
WifiData->reqMode=WIFIMODE_SCAN;
}
}
static
void sgIP_DNS_Record_Localhost()
{
sgIP_DNS_Record *rec;
const unsigned char * resdata_c = (unsigned char *)&(wifi_hw->ipaddr);
rec = sgIP_DNS_GetUnusedRecord();
rec->flags=SGIP_DNS_FLAG_ACTIVE | SGIP_DNS_FLAG_BUSY;
rec->addrlen = 4;
rec->numalias = 1;
gethostname(rec->aliases[0], 256);
gethostname(rec->name, 256);
rec->numaddr = 1;
rec->addrdata[0] = resdata_c[0];
rec->addrdata[1] = resdata_c[1];
rec->addrdata[2] = resdata_c[2];
rec->addrdata[3] = resdata_c[3];
rec->addrclass = AF_INET;
rec->TTL = 0;
rec->flags=SGIP_DNS_FLAG_ACTIVE | SGIP_DNS_FLAG_BUSY|SGIP_DNS_FLAG_RESOLVED;
}
int Wifi_AssocStatus() {
switch(wifi_connect_state) {
case -1: // error
return ASSOCSTATUS_CANNOTCONNECT;
case 0: // searching
{
int i;
Wifi_AccessPoint ap;
i=Wifi_FindMatchingAP(1,&wifi_connect_point,&ap);
if(i==0) {
Wifi_CopyMacAddr(WifiData->bssid9, ap.bssid);
Wifi_CopyMacAddr(WifiData->apmac9, ap.bssid);
WifiData->ssid9[0]=ap.ssid_len;
for(i=0;i<32;i++) {
WifiData->ssid9[i+1]=ap.ssid[i];
}
WifiData->apchannel9=ap.channel;
for(i=0;i<16;i++) WifiData->baserates9[i]=ap.base_rates[i];
WifiData->reqMode=WIFIMODE_NORMAL;
WifiData->reqReqFlags |= WFLAG_REQ_APCONNECT | WFLAG_REQ_APCOPYVALUES;
wifi_connect_state=1;
}
}
return ASSOCSTATUS_SEARCHING;
case 1: // associating
switch(WifiData->curMode) {
case WIFIMODE_DISABLED:
case WIFIMODE_NORMAL:
case WIFIMODE_DISASSOCIATE:
return ASSOCSTATUS_DISCONNECTED;
case WIFIMODE_SCAN:
if(WifiData->reqReqFlags&WFLAG_REQ_APCONNECT) return ASSOCSTATUS_AUTHENTICATING;
return ASSOCSTATUS_DISCONNECTED;
case WIFIMODE_ASSOCIATE:
switch(WifiData->authlevel) {
case WIFI_AUTHLEVEL_DISCONNECTED:
return ASSOCSTATUS_AUTHENTICATING;
case WIFI_AUTHLEVEL_AUTHENTICATED:
case WIFI_AUTHLEVEL_DEASSOCIATED:
return ASSOCSTATUS_ASSOCIATING;
case WIFI_AUTHLEVEL_ASSOCIATED:
#ifdef WIFI_USE_TCP_SGIP
if(wifi_hw) {
if(!(wifi_hw->ipaddr)) {
sgIP_DHCP_Start(wifi_hw,wifi_hw->dns[0]==0);
wifi_connect_state=2;
return ASSOCSTATUS_ACQUIRINGDHCP;
}
}
sgIP_ARP_SendGratARP(wifi_hw);
#endif
wifi_connect_state=3;
WifiData->flags9|=WFLAG_ARM9_NETREADY;
return ASSOCSTATUS_ASSOCIATED;
}
break;
case WIFIMODE_ASSOCIATED:
#ifdef WIFI_USE_TCP_SGIP
if(wifi_hw) {
if(!(wifi_hw->ipaddr)) {
sgIP_DHCP_Start(wifi_hw,wifi_hw->dns[0]==0);
wifi_connect_state=2;
return ASSOCSTATUS_ACQUIRINGDHCP;
}
}
sgIP_ARP_SendGratARP(wifi_hw);
#endif
wifi_connect_state=3;
WifiData->flags9|=WFLAG_ARM9_NETREADY;
return ASSOCSTATUS_ASSOCIATED;
case WIFIMODE_CANNOTASSOCIATE:
return ASSOCSTATUS_CANNOTCONNECT;
}
return ASSOCSTATUS_DISCONNECTED;
case 2: // dhcp'ing
#ifdef WIFI_USE_TCP_SGIP
{
int i;
i=sgIP_DHCP_Update();
if(i!=SGIP_DHCP_STATUS_WORKING) {
switch(i) {
case SGIP_DHCP_STATUS_SUCCESS:
wifi_connect_state=3;
WifiData->flags9|=WFLAG_ARM9_NETREADY;
sgIP_ARP_SendGratARP(wifi_hw);
sgIP_DNS_Record_Localhost();
return ASSOCSTATUS_ASSOCIATED;
default:
case SGIP_DHCP_STATUS_IDLE:
case SGIP_DHCP_STATUS_FAILED:
Wifi_DisconnectAP();
wifi_connect_state=-1;
return ASSOCSTATUS_CANNOTCONNECT;
}
}
}
#else
// should never get here (dhcp state) without sgIP!
Wifi_DisconnectAP();
wifi_connect_state=-1;
return ASSOCSTATUS_CANNOTCONNECT;
#endif
return ASSOCSTATUS_ACQUIRINGDHCP;
case 3: // connected!
return ASSOCSTATUS_ASSOCIATED;
case 4: // search nintendo WFC data for a suitable AP
{
int n,i;
for(n=0;n<3;n++) if(!(WifiData->wfc_enable[n]&0x80)) break;
Wifi_AccessPoint ap;
n=Wifi_FindMatchingAP(n,WifiData->wfc_ap,&ap);
if(n!=-1) {
#ifdef WIFI_USE_TCP_SGIP
Wifi_SetIP(WifiData->wfc_config[n][0],WifiData->wfc_config[n][1],WifiData->wfc_config[n][2],WifiData->wfc_config[n][3],WifiData->wfc_config[n][4]);
#endif
WifiData->wepmode9=WifiData->wfc_enable[n]&0x03; // copy data
WifiData->wepkeyid9=(WifiData->wfc_enable[n]>>4)&7;
for(i=0;i<16;i++) {
WifiData->wepkey9[i]=WifiData->wfc_wepkey[n][i];
}
Wifi_CopyMacAddr(WifiData->bssid9, ap.bssid);
Wifi_CopyMacAddr(WifiData->apmac9, ap.bssid);
WifiData->ssid9[0]=ap.ssid_len;
for(i=0;i<32;i++) {
WifiData->ssid9[i+1]=ap.ssid[i];
}
WifiData->apchannel9=ap.channel;
for(i=0;i<16;i++) WifiData->baserates9[i]=ap.base_rates[i];
WifiData->reqMode=WIFIMODE_NORMAL;
WifiData->reqReqFlags |= WFLAG_REQ_APCONNECT | WFLAG_REQ_APCOPYVALUES;
wifi_connect_state=1;
return ASSOCSTATUS_SEARCHING;
}
}
return ASSOCSTATUS_SEARCHING;
}
return ASSOCSTATUS_CANNOTCONNECT;
}
int Wifi_DisconnectAP() {
WifiData->reqMode=WIFIMODE_NORMAL;
WifiData->reqReqFlags &= ~WFLAG_REQ_APCONNECT;
WifiData->flags9&=~WFLAG_ARM9_NETREADY;
wifi_connect_state=-1;
return 0;
}
#ifdef WIFI_USE_TCP_SGIP
int Wifi_TransmitFunction(sgIP_Hub_HWInterface * hw, sgIP_memblock * mb) {
// convert ethernet frame into wireless frame and output.
// ethernet header: 6byte dest, 6byte src, 2byte protocol_id
// assumes individual pbuf len is >=14 bytes, it's pretty likely ;) - also hopes pbuf len is a multiple of 2 :|
int base,framelen, hdrlen, writelen;
int copytotal, copyexpect;
u16 framehdr[6+12+2];
sgIP_memblock * t;
framelen=mb->totallength-14+8 + (WifiData->wepmode7?4:0);
if(!(WifiData->flags9&WFLAG_ARM9_NETUP)) {
SGIP_DEBUG_MESSAGE(("Transmit:err_netdown"));
sgIP_memblock_free(mb);
return 0; //?
}
if(framelen+40>Wifi_TxBufferWordsAvailable()*2) { // error, can't send this much!
SGIP_DEBUG_MESSAGE(("Transmit:err_space"));
sgIP_memblock_free(mb);
return 0; //?
}
ethhdr_print('T',mb->datastart);
framehdr[0]=0;
framehdr[1]=0;
framehdr[2]=0;
framehdr[3]=0;
framehdr[4]=0; // rate, will be filled in by the arm7.
hdrlen=18;
framehdr[7]=0;
if(WifiData->curReqFlags&WFLAG_REQ_APADHOC) { // adhoc mode
framehdr[6]=0x0008;
Wifi_CopyMacAddr(framehdr+14,WifiData->bssid7);
Wifi_CopyMacAddr(framehdr+11,WifiData->MacAddr);
Wifi_CopyMacAddr(framehdr+8,((u8 *)mb->datastart));
} else {
framehdr[6]=0x0108;
Wifi_CopyMacAddr(framehdr+8,WifiData->bssid7);
Wifi_CopyMacAddr(framehdr+11,WifiData->MacAddr);
Wifi_CopyMacAddr(framehdr+14,((u8 *)mb->datastart));
}
if(WifiData->wepmode7) { framehdr[6] |=0x4000; hdrlen=20; }
framehdr[17] = 0;
framehdr[18] = 0; // wep IV, will be filled in if needed on the arm7 side.
framehdr[19] = 0;
framehdr[5]=framelen+hdrlen*2-12+4;
copyexpect= ((framelen+hdrlen*2-12+4) +12 -4 +1)/2;
copytotal=0;
WifiData->stats[WSTAT_TXQUEUEDPACKETS]++;
WifiData->stats[WSTAT_TXQUEUEDBYTES]+=framelen+hdrlen*2;
base = WifiData->txbufOut;
Wifi_TxBufferWrite(base,hdrlen,framehdr);
base += hdrlen;
copytotal+=hdrlen;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
// add LLC header
framehdr[0]=0xAAAA;
framehdr[1]=0x0003;
framehdr[2]=0x0000;
framehdr[3]=((u16 *)mb->datastart)[6]; // frame type
Wifi_TxBufferWrite(base,4,framehdr);
base += 4;
copytotal+=4;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
t=mb;
writelen=(mb->thislength-14);
if(writelen) {
Wifi_TxBufferWrite(base,(writelen+1)/2,((u16 *)mb->datastart)+7);
base+=(writelen+1)/2;
copytotal+=(writelen+1)/2;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
}
while(mb->next) {
mb=mb->next;
writelen=mb->thislength;
Wifi_TxBufferWrite(base,(writelen+1)/2,((u16 *)mb->datastart));
base+=(writelen+1)/2;
copytotal+=(writelen+1)/2;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
}
if(WifiData->wepmode7) { // add required extra bytes
base+=2;
copytotal+=2;
if(base>=(WIFI_TXBUFFER_SIZE/2)) base -= WIFI_TXBUFFER_SIZE/2;
}
WifiData->txbufOut=base; // update fifo out pos, done sending packet.
sgIP_memblock_free(t); // free packet, as we're the last stop on this chain.
if(copytotal!=copyexpect) {
SGIP_DEBUG_MESSAGE(("Tx exp:%i que:%i",copyexpect,copytotal));
}
if(synchandler) synchandler();
return 0;
}
int Wifi_Interface_Init(sgIP_Hub_HWInterface * hw) {
hw->MTU=2300;
hw->ipaddr=(192)|(168<<8)|(1<<16)|(151<<24);
hw->snmask=0x00FFFFFF;
hw->gateway=(192)|(168<<8)|(1<<16)|(1<<24);
hw->dns[0]=(192)|(168<<8)|(1<<16)|(1<<24);
hw->hwaddrlen=6;
Wifi_CopyMacAddr(hw->hwaddr,WifiData->MacAddr);
hw->userdata=0;
return 0;
}
void Wifi_Timer(int num_ms) {
Wifi_Update();
sgIP_Timer(num_ms);
}
#endif
unsigned long Wifi_Init(int initflags) {
erasemem(&Wifi_Data_Struct,sizeof(Wifi_Data_Struct));
DC_FlushAll();
WifiData = (Wifi_MainStruct *) (((u32)&Wifi_Data_Struct)| 0x00400000); // should prevent the cache from eating us alive.
#ifdef WIFI_USE_TCP_SGIP
switch(initflags & WIFIINIT_OPTION_HEAPMASK) {
case WIFIINIT_OPTION_USEHEAP_128:
wHeapAllocInit(128*1024);
break;
case WIFIINIT_OPTION_USEHEAP_64:
wHeapAllocInit(64*1024);
break;
case WIFIINIT_OPTION_USEHEAP_256:
wHeapAllocInit(256*1024);
break;
case WIFIINIT_OPTION_USEHEAP_512:
wHeapAllocInit(512*1024);
break;
case WIFIINIT_OPTION_USECUSTOMALLOC:
break;
}
sgIP_Init();
#endif
WifiData->flags9 = WFLAG_ARM9_ACTIVE | (initflags & WFLAG_ARM9_INITFLAGMASK) ;
return (u32) &Wifi_Data_Struct;
}
int Wifi_CheckInit() {
if(!WifiData) return 0;
return ((WifiData->flags7 & WFLAG_ARM7_ACTIVE) && (WifiData->flags9 & WFLAG_ARM9_ARM7READY));
}
void Wifi_Update() {
int cnt;
int base, base2, len, fulllen;
if(!WifiData) return;
#ifdef WIFI_USE_TCP_SGIP
if(!(WifiData->flags9&WFLAG_ARM9_ARM7READY)) {
if(WifiData->flags7 & WFLAG_ARM7_ACTIVE) {
WifiData->flags9 |=WFLAG_ARM9_ARM7READY;
// add network interface.
wifi_hw = sgIP_Hub_AddHardwareInterface(&Wifi_TransmitFunction,&Wifi_Interface_Init);
sgIP_timems=WifiData->random; //hacky! but it should work just fine :)
}
}
if(WifiData->authlevel!=WIFI_AUTHLEVEL_ASSOCIATED && WifiData->flags9&WFLAG_ARM9_NETUP) {
WifiData->flags9 &= ~(WFLAG_ARM9_NETUP);
} else if(WifiData->authlevel==WIFI_AUTHLEVEL_ASSOCIATED && !(WifiData->flags9&WFLAG_ARM9_NETUP)) {
WifiData->flags9 |= (WFLAG_ARM9_NETUP);
}
#endif
// check for received packets, forward to whatever wants them.
cnt=0;
while(WifiData->rxbufIn!=WifiData->rxbufOut) {
base = WifiData->rxbufIn;
len=Wifi_RxReadOffset(base,4);
fulllen=((len+3)&(~3))+12;
#ifdef WIFI_USE_TCP_SGIP
// Do lwIP interfacing for rx here
if((Wifi_RxReadOffset(base,6)&0x01CF)==0x0008) // if it is a non-null data packet coming from the AP (toDS==0)
{
u16 framehdr[6+12+2+4];
sgIP_memblock * mb;
int hdrlen;
base2=base;
Wifi_RxRawReadPacket(base,22*2,framehdr);
// ethhdr_print('!',framehdr+8);
if((framehdr[8]==((u16 *)WifiData->MacAddr)[0] && framehdr[9]==((u16 *)WifiData->MacAddr)[1] && framehdr[10]==((u16 *)WifiData->MacAddr)[2]) ||
(framehdr[8]==0xFFFF && framehdr[9]==0xFFFF && framehdr[10]==0xFFFF)) {
// destination matches our mac address, or the broadcast address.
//if(framehdr[6]&0x4000) { // wep enabled (when receiving WEP packets, the IV is stripped for us! how nice :|
// base2+=24; hdrlen=28; // base2+=[wifi hdr 12byte]+[802 header hdrlen]+[slip hdr 8byte]
//} else {
base2+=22; hdrlen=24;
//}
// SGIP_DEBUG_MESSAGE(("%04X %04X %04X %04X %04X",Wifi_RxReadOffset(base2-8,0),Wifi_RxReadOffset(base2-7,0),Wifi_RxReadOffset(base2-6,0),Wifi_RxReadOffset(base2-5,0),Wifi_RxReadOffset(base2-4,0)));
// check for LLC/SLIP header...
if(Wifi_RxReadOffset(base2-4,0)==0xAAAA && Wifi_RxReadOffset(base2-4,1)==0x0003 && Wifi_RxReadOffset(base2-4,2)==0) {
mb = sgIP_memblock_allocHW(14,len-8-hdrlen);
if(mb) {
if(base2>=(WIFI_RXBUFFER_SIZE/2)) base2-=(WIFI_RXBUFFER_SIZE/2);
Wifi_RxRawReadPacket(base2,(len-8-hdrlen)&(~1),((u16 *)mb->datastart)+7);
if(len&1) ((u8 *)mb->datastart)[len+14-1-8-hdrlen]=Wifi_RxReadOffset(base2,((len-8-hdrlen)/2))&255;
Wifi_CopyMacAddr(mb->datastart,framehdr+8); // copy dest
if(Wifi_RxReadOffset(base,6)&0x0200) { // from DS set?
Wifi_CopyMacAddr(((u8 *)mb->datastart)+6,framehdr+14); // copy src from adrs3
} else {
Wifi_CopyMacAddr(((u8 *)mb->datastart)+6,framehdr+11); // copy src from adrs2
}
((u16 *)mb->datastart)[6]=framehdr[(hdrlen/2)+6+3]; // assume LLC exists and is 8 bytes.
ethhdr_print('R',mb->datastart);
// Done generating recieved data packet... now distribute it.
sgIP_Hub_ReceiveHardwarePacket(wifi_hw,mb);
}
}
}
}
#endif
// check if we have a handler
if(packethandler) {
base2=base+6;
if(base2>=(WIFI_RXBUFFER_SIZE/2)) base2-=(WIFI_RXBUFFER_SIZE/2);
(*packethandler)(base2,len);
}
base+=fulllen/2;
if(base>=(WIFI_RXBUFFER_SIZE/2)) base-=(WIFI_RXBUFFER_SIZE/2);
WifiData->rxbufIn=base;
if(cnt++>80) break;
}
}
//////////////////////////////////////////////////////////////////////////
// Ip addr get/set functions
#ifdef WIFI_USE_TCP_SGIP
u32 Wifi_GetIP() {
if(wifi_hw) return wifi_hw->ipaddr;
return 0;
}
unsigned long Wifi_GetIPInfo(unsigned long * pGateway,unsigned long * pSnmask,unsigned long * pDns1,unsigned long * pDns2) {
if(wifi_hw) {
if(pGateway) *pGateway=wifi_hw->gateway;
if(pSnmask) *pSnmask=wifi_hw->snmask;
if(pDns1) *pDns1=wifi_hw->dns[0];
if(pDns2) *pDns2=wifi_hw->dns[1];
return wifi_hw->ipaddr;
}
return 0;
}
void Wifi_SetIP(u32 IPaddr, u32 gateway, u32 subnetmask, u32 dns1, u32 dns2) {
if(wifi_hw) {
SGIP_DEBUG_MESSAGE(("SetIP%08X %08X %08X",IPaddr,gateway,subnetmask));
wifi_hw->ipaddr=IPaddr;
wifi_hw->gateway=gateway;
wifi_hw->snmask=subnetmask;
wifi_hw->dns[0]=dns1;
wifi_hw->dns[1]=dns2;
// reset arp cache...
sgIP_ARP_FlushInterface(wifi_hw);
}
}
void Wifi_SetDHCP() {
}
#endif
int Wifi_GetData(int datatype, int bufferlen, unsigned char * buffer) {
int i;
if(datatype<0 || datatype>=MAX_WIFIGETDATA) return -1;
switch(datatype) {
case WIFIGETDATA_MACADDRESS:
if(bufferlen<6 || !buffer) return -1;
for(i=0;i<6;i++) {
buffer[i]=WifiData->MacAddr[i];
}
return 6;
case WIFIGETDATA_NUMWFCAPS:
for(i=0;i<3;i++) if(!(WifiData->wfc_enable[i]&0x80)) break;
return i;
}
return -1;
}
u32 Wifi_GetStats(int statnum) {
if(statnum<0 || statnum>=NUM_WIFI_STATS) return 0;
return WifiData->stats[statnum];
}
//////////////////////////////////////////////////////////////////////////
// sync functions
void Wifi_Sync() {
Wifi_Update();
}

View File

@@ -0,0 +1,122 @@
// DS Wifi interface code
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
// wifi_arm9.c - arm9 wifi support header
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef WIFI_ARM9_H
#define WIFI_ARM9_H
#include "wifi_shared.h"
// default option is to use 128k heap
#define WIFIINIT_OPTION_USEHEAP_128 0x0000
#define WIFIINIT_OPTION_USEHEAP_64 0x1000
#define WIFIINIT_OPTION_USEHEAP_256 0x2000
#define WIFIINIT_OPTION_USEHEAP_512 0x3000
#define WIFIINIT_OPTION_USECUSTOMALLOC 0x4000
#define WIFIINIT_OPTION_HEAPMASK 0xF000
#ifdef WIFI_USE_TCP_SGIP
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
};
#endif
#endif
extern volatile Wifi_MainStruct * WifiData;
enum WIFIGETDATA {
WIFIGETDATA_MACADDRESS, // MACADDRESS: returns data in the buffer, requires at least 6 bytes
WIFIGETDATA_NUMWFCAPS, // NUM WFC APS: returns number between 0 and 3, doesn't use buffer.
MAX_WIFIGETDATA
};
// Wifi Packet Handler function: (int packetID, int packetlength) - packetID is only valid while the called function is executing.
// call Wifi_RxRawReadPacket while in the packet handler function, to retreive the data to a local buffer.
typedef void (*WifiPacketHandler)(int, int);
// Wifi Sync Handler function: Callback function that is called when the arm7 needs to be told to synchronize with new fifo data.
// If this callback is used (see Wifi_SetSyncHandler()), it should send a message via the fifo to the arm7, which will call Wifi_Sync() on arm7.
typedef void (*WifiSyncHandler)();
#ifdef __cplusplus
extern "C" {
#endif
extern void Wifi_CopyMacAddr(volatile void * dest, volatile void * src);
extern int Wifi_CmpMacAddr(volatile void * mac1, volatile void * mac2);
extern unsigned long Wifi_Init(int initflags);
extern int Wifi_CheckInit();
extern int Wifi_RawTxFrame(u16 datalen, u16 rate, u16 * data);
extern void Wifi_SetSyncHandler(WifiSyncHandler wshfunc);
extern void Wifi_RawSetPacketHandler(WifiPacketHandler wphfunc);
extern int Wifi_RxRawReadPacket(s32 packetID, s32 readlength, u16 * data);
extern void Wifi_DisableWifi();
extern void Wifi_EnableWifi();
extern void Wifi_SetPromiscuousMode(int enable);
extern void Wifi_ScanMode();
extern void Wifi_SetChannel(int channel);
extern int Wifi_GetNumAP();
extern int Wifi_GetAPData(int apnum, Wifi_AccessPoint * apdata);
extern int Wifi_FindMatchingAP(int numaps, Wifi_AccessPoint * apdata, Wifi_AccessPoint * match_dest);
extern int Wifi_ConnectAP(Wifi_AccessPoint * apdata, int wepmode, int wepkeyid, u8 * wepkey);
extern void Wifi_AutoConnect();
extern int Wifi_AssocStatus();
extern int Wifi_DisconnectAP();
extern int Wifi_GetData(int datatype, int bufferlen, unsigned char * buffer);
extern void Wifi_Update();
extern void Wifi_Sync();
#ifdef WIFI_USE_TCP_SGIP
extern void Wifi_Timer(int num_ms);
extern void Wifi_SetIP(u32 IPaddr, u32 gateway, u32 subnetmask, u32 dns1, u32 dns2);
extern u32 Wifi_GetIP();
#endif
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,179 @@
//////////////////////////////////////////////////////////////////////////
// DSRegs.h - (c) 2005-2006 Stephen Stair
// General reference mumbo jumbo to give me easy access to the regs I like.
//////////////////////////////////////////////////////////////////////////
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef DSREGS_H
#define DSREGS_H
#include <nds.h>
//////////////////////////////////////////////////////////////////////////
// General registers
// general memory range defines
#define PAL ((u16 *) 0x05000000)
#define VRAM1 ((u16 *) 0x06000000)
#define VRAM2 ((u16 *) 0x06200000)
//#define OAM ((u16 *) 0x07000000)
#define CART ((u16 *) 0x08000000)
// video registers
#define DISPCNT (*((u32 volatile *) 0x04000000))
#define DISPSTAT (*((u16 volatile *) 0x04000004))
#define VCOUNT (*((u16 volatile *) 0x04000006))
#define BG0CNT (*((u16 volatile *) 0x04000008))
#define BG1CNT (*((u16 volatile *) 0x0400000A))
#define BG2CNT (*((u16 volatile *) 0x0400000C))
#define BG3CNT (*((u16 volatile *) 0x0400000E))
#define BG0HOFS (*((u16 volatile *) 0x04000010))
#define BG0VOFS (*((u16 volatile *) 0x04000012))
#define BG1HOFS (*((u16 volatile *) 0x04000014))
#define BG1VOFS (*((u16 volatile *) 0x04000016))
#define BG2HOFS (*((u16 volatile *) 0x04000018))
#define BG2VOFS (*((u16 volatile *) 0x0400001A))
#define BG3HOFS (*((u16 volatile *) 0x0400001C))
#define BG3VOFS (*((u16 volatile *) 0x0400001E))
#define BG2PA (*((u16 volatile *) 0x04000020))
#define BG2PB (*((u16 volatile *) 0x04000022))
#define BG2PC (*((u16 volatile *) 0x04000024))
#define BG2PD (*((u16 volatile *) 0x04000026))
#define BG2X (*((u32 volatile *) 0x04000028))
#define BG2Y (*((u32 volatile *) 0x0400002C))
#define BG3PA (*((u16 volatile *) 0x04000030))
#define BG3PB (*((u16 volatile *) 0x04000032))
#define BG3PC (*((u16 volatile *) 0x04000034))
#define BG3PD (*((u16 volatile *) 0x04000036))
#define BG3X (*((u32 volatile *) 0x04000038))
#define BG3Y (*((u32 volatile *) 0x0400003C))
#define WIN0H (*((u16 volatile *) 0x04000040))
#define WIN1H (*((u16 volatile *) 0x04000042))
#define WIN0V (*((u16 volatile *) 0x04000044))
#define WIN1V (*((u16 volatile *) 0x04000046))
#define WININ (*((u16 volatile *) 0x04000048))
#define WINOUT (*((u16 volatile *) 0x0400004A))
#define MOSAIC (*((u16 volatile *) 0x0400004C))
#define BLDCNT (*((u16 volatile *) 0x04000050))
#define BLDALPHA (*((u16 volatile *) 0x04000052))
#define BLDY (*((u16 volatile *) 0x04000054))
#define DISPCNT2 (*((u32 volatile *) 0x04001000))
#define DISPSTAT2 (*((u16 volatile *) 0x04001004))
#define VCOUNT2 (*((u16 volatile *) 0x04001006))
#define BG0CNT2 (*((u16 volatile *) 0x04001008))
#define BG1CNT2 (*((u16 volatile *) 0x0400100A))
#define BG2CNT2 (*((u16 volatile *) 0x0400100C))
#define BG3CNT2 (*((u16 volatile *) 0x0400100E))
#define BG0HOFS2 (*((u16 volatile *) 0x04001010))
#define BG0VOFS2 (*((u16 volatile *) 0x04001012))
#define BG1HOFS2 (*((u16 volatile *) 0x04001014))
#define BG1VOFS2 (*((u16 volatile *) 0x04001016))
#define BG2HOFS2 (*((u16 volatile *) 0x04001018))
#define BG2VOFS2 (*((u16 volatile *) 0x0400101A))
#define BG3HOFS2 (*((u16 volatile *) 0x0400101C))
#define BG3VOFS2 (*((u16 volatile *) 0x0400101E))
#define BG2PA2 (*((u16 volatile *) 0x04001020))
#define BG2PB2 (*((u16 volatile *) 0x04001022))
#define BG2PC2 (*((u16 volatile *) 0x04001024))
#define BG2PD2 (*((u16 volatile *) 0x04001026))
#define BG2X2 (*((u32 volatile *) 0x04001028))
#define BG2Y2 (*((u32 volatile *) 0x0400102C))
#define BG3PA2 (*((u16 volatile *) 0x04001030))
#define BG3PB2 (*((u16 volatile *) 0x04001032))
#define BG3PC2 (*((u16 volatile *) 0x04001034))
#define BG3PD2 (*((u16 volatile *) 0x04001036))
#define BG3X2 (*((u32 volatile *) 0x04001038))
#define BG3Y2 (*((u32 volatile *) 0x0400103C))
#define WIN0H2 (*((u16 volatile *) 0x04001040))
#define WIN1H2 (*((u16 volatile *) 0x04001042))
#define WIN0V2 (*((u16 volatile *) 0x04001044))
#define WIN1V2 (*((u16 volatile *) 0x04001046))
#define WININ2 (*((u16 volatile *) 0x04001048))
#define WINOUT2 (*((u16 volatile *) 0x0400104A))
#define MOSAIC2 (*((u16 volatile *) 0x0400104C))
#define BLDCNT2 (*((u16 volatile *) 0x04001050))
#define BLDALPHA2 (*((u16 volatile *) 0x04001052))
#define BLDY2 (*((u16 volatile *) 0x04001054))
// video memory defines
#define PAL_BG1 ((u16 *) 0x05000000)
#define PAL_FG1 ((u16 *) 0x05000200)
#define PAL_BG2 ((u16 *) 0x05000400)
#define PAL_FG2 ((u16 *) 0x05000600)
// other video defines
#define VRAMBANKCNT (((u16 volatile *) 0x04000240))
#define RGB(r,g,b) ( ((r)&31) | (((g)&31)<<5) | (((b)&31)<<10) )
#define VRAM_SETBANK(bank, set) \
if((bank)&1) { VRAMBANKCNT[(bank)>>1] = (VRAMBANKCNT[(bank)>>1]&0x00ff) | (((set)&0xff)<<8); } else \
{ VRAMBANKCNT[(bank)>>1] = (VRAMBANKCNT[(bank)>>1]&0xff00) | ((set)&0xff); }
// joypad input
#define KEYINPUT (*((u16 volatile *) 0x04000130))
#define KEYCNT (*((u16 volatile *) 0x04000132))
// System registers
#define WAITCNT (*((u16 volatile *) 0x04000204))
//#define IME (*((u16 volatile *) 0x04000208))
//#define IE (*((u32 volatile *) 0x04000210))
//#define IF (*((u32 volatile *) 0x04000214))
#define HALTCNT (*((u16 volatile *) 0x04000300))
//////////////////////////////////////////////////////////////////////////
// ARM7 specific registers
#ifdef ARM7
#define POWERCNT7 (*((u16 volatile *) 0x04000304))
#define SPI_CR (*((u16 volatile *) 0x040001C0))
#define SPI_DATA (*((u16 volatile *) 0x040001C2))
#endif
//////////////////////////////////////////////////////////////////////////
// ARM9 specific registers
#ifdef ARM9
#define POWERCNT (*((u16 volatile *) 0x04000308))
#endif
// End of file!
#endif

View File

@@ -0,0 +1,63 @@
// DS Wifi interface code
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
// spinlock.h - code for spinlocking for basic wifi structure memory protection
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
/*
__asm (
".GLOBL SLasm_Acquire, SLasm_Release \n"
".ARM \n"
"SLasm_Acquire: \n"
" ldr r2,[r0] \n"
" cmp r2,#0 \n"
" movne r0,#1 \n"
" bxne lr \n"
" mov r2,r1 \n"
" swp r2,r2,[r0] \n"
" cmp r2,#0 \n"
" cmpne r2,r1 \n"
" moveq r0,#0 \n"
" bxeq lr \n"
" swp r2,r2,[r0] \n"
" mov r0,#1 \n"
" bx lr \n"
"\n\n"
"SLasm_Release: \n"
" ldr r2,[r0] \n"
" cmp r2,r1 \n"
" movne r0,#2 \n"
" bxne lr \n"
" mov r2,#0 \n"
" swp r2,r2,[r0] \n"
" cmp r2,r1 \n"
" moveq r0,#0 \n"
" movne r0,#2 \n"
" bx lr \n"
);
*/

View File

@@ -0,0 +1,42 @@
.text
.code 32
.GLOBL SLasm_Acquire, SLasm_Release
.ARM
SLasm_Acquire:
ldr r2,[r0]
cmp r2,#0
movne r0,#1
bxne lr
mov r2,r1
swp r2,r2,[r0]
cmp r2,#0
cmpne r2,r1
moveq r0,#0
bxeq lr
swp r2,r2,[r0]
mov r0,#1
bx lr
SLasm_Release:
ldr r2,[r0]
cmp r2,r1
movne r0,#2
bxne lr
mov r2,#0
swp r2,r2,[r0]
cmp r2,r1
moveq r0,#0
movne r0,#2
bx lr
.pool
.end

View File

@@ -0,0 +1,284 @@
// DS Wifi interface code
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
// wifi_shared.h - Shared structures to be used by arm9 and arm7
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef WIFI_SHARED_H
#define WIFI_SHARED_H
#include <nds.h>
// on spinlock contention, the side unsuccessfully attempting the lock reverts the lock.
// if the unlocking side sees the lock incorrectly set, the unlocking side will delay until it has reverted to the correct value, then continue unlocking.
// there should be a delay of at least about ~10-20 cycles between a lock and unlock, to prevent contention.
#define SPINLOCK_NOBODY 0x0000
#define SPINLOCK_ARM7 0x0001
#define SPINLOCK_ARM9 0x0002
#define SPINLOCK_OK 0x0000
#define SPINLOCK_INUSE 0x0001
#define SPINLOCK_ERROR 0x0002
#ifdef ARM7
#define SPINLOCK_VALUE SPINLOCK_ARM7
#endif
#ifdef ARM9
#define SPINLOCK_VALUE SPINLOCK_ARM9
#endif
#define Spinlock_Acquire(structtolock) SLasm_Acquire(&((structtolock).spinlock),SPINLOCK_VALUE)
#define Spinlock_Release(structtolock) SLasm_Release(&((structtolock).spinlock),SPINLOCK_VALUE)
#define Spinlock_Check(structtolock) (((structtolock).spinlock)!=SPINLOCK_NOBODY)
#ifdef __cplusplus
extern "C" {
#endif
extern u32 SLasm_Acquire(volatile u32 * lockaddr, u32 lockvalue);
extern u32 SLasm_Release(volatile u32 * lockaddr, u32 lockvalue);
#ifdef __cplusplus
};
#endif
// If for whatever reason you want to ditch SGIP and use your own stack, comment out the following line.
#define WIFI_USE_TCP_SGIP 1
#define WIFI_RXBUFFER_SIZE (1024*12)
#define WIFI_TXBUFFER_SIZE (1024*24)
#define WIFI_MAX_AP 32
#define WIFI_MAX_ASSOC_RETRY 30
#define WIFI_PS_POLL_CONST 2
#define WIFI_MAX_PROBE 4
#define WIFI_AP_TIMEOUT 40
#define WFLAG_PACKET_DATA 0x0001
#define WFLAG_PACKET_MGT 0x0002
#define WFLAG_PACKET_BEACON 0x0004
#define WFLAG_PACKET_CTRL 0x0008
#define WFLAG_PACKET_ALL 0xFFFF
#define WFLAG_ARM7_ACTIVE 0x0001
#define WFLAG_ARM7_RUNNING 0x0002
#define WFLAG_ARM9_ACTIVE 0x0001
#define WFLAG_ARM9_USELED 0x0002
#define WFLAG_ARM9_ARM7READY 0x0004
#define WFLAG_ARM9_NETUP 0x0008
#define WFLAG_ARM9_NETREADY 0x0010
#define WFLAG_ARM9_INITFLAGMASK 0x0002
#define WFLAG_IP_GOTDHCP 0x0001
// request - request flags
#define WFLAG_REQ_APCONNECT 0x0001
#define WFLAG_REQ_APCOPYVALUES 0x0002
#define WFLAG_REQ_APADHOC 0x0008
#define WFLAG_REQ_PROMISC 0x0010
#define WFLAG_REQ_USEWEP 0x0020
// request - informational flags
#define WFLAG_REQ_APCONNECTED 0x8000
#define WFLAG_APDATA_ADHOC 0x0001
#define WFLAG_APDATA_WEP 0x0002
#define WFLAG_APDATA_WPA 0x0004
#define WFLAG_APDATA_COMPATIBLE 0x0008
#define WFLAG_APDATA_EXTCOMPATIBLE 0x0010
#define WFLAG_APDATA_SHORTPREAMBLE 0x0020
#define WFLAG_APDATA_ACTIVE 0x8000
enum WIFI_RETURN {
WIFI_RETURN_OK = 0, // Everything went ok
WIFI_RETURN_LOCKFAILED = 1, // the spinlock attempt failed (it wasn't retried cause that could lock both cpus- retry again after a delay.
WIFI_RETURN_ERROR = 2, // There was an error in attempting to complete the requested task.
WIFI_RETURN_PARAMERROR = 3, // There was an error in the parameters passed to the function.
};
enum WIFI_STATS {
// software stats
WSTAT_RXQUEUEDPACKETS, // number of packets queued into the rx fifo
WSTAT_TXQUEUEDPACKETS, // number of packets queued into the tx fifo
WSTAT_RXQUEUEDBYTES, // number of bytes queued into the rx fifo
WSTAT_TXQUEUEDBYTES, // number of bytes queued into the tx fifo
WSTAT_RXQUEUEDLOST, // number of packets lost due to space limitations in queuing
WSTAT_TXQUEUEDREJECTED, // number of packets rejected due to space limitations in queuing
WSTAT_RXPACKETS,
WSTAT_RXBYTES,
WSTAT_RXDATABYTES,
WSTAT_TXPACKETS,
WSTAT_TXBYTES,
WSTAT_TXDATABYTES,
WSTAT_ARM7_UPDATES,
WSTAT_DEBUG,
// harware stats (function mostly unknown.)
WSTAT_HW_1B0,WSTAT_HW_1B1,WSTAT_HW_1B2,WSTAT_HW_1B3,WSTAT_HW_1B4,WSTAT_HW_1B5,WSTAT_HW_1B6,WSTAT_HW_1B7,
WSTAT_HW_1B8,WSTAT_HW_1B9,WSTAT_HW_1BA,WSTAT_HW_1BB,WSTAT_HW_1BC,WSTAT_HW_1BD,WSTAT_HW_1BE,WSTAT_HW_1BF,
WSTAT_HW_1C0,WSTAT_HW_1C1,WSTAT_HW_1C4,WSTAT_HW_1C5,
WSTAT_HW_1D0,WSTAT_HW_1D1,WSTAT_HW_1D2,WSTAT_HW_1D3,WSTAT_HW_1D4,WSTAT_HW_1D5,WSTAT_HW_1D6,WSTAT_HW_1D7,
WSTAT_HW_1D8,WSTAT_HW_1D9,WSTAT_HW_1DA,WSTAT_HW_1DB,WSTAT_HW_1DC,WSTAT_HW_1DD,WSTAT_HW_1DE,WSTAT_HW_1DF,
NUM_WIFI_STATS
};
enum WIFI_MODE {
WIFIMODE_DISABLED,
WIFIMODE_NORMAL,
WIFIMODE_SCAN,
WIFIMODE_ASSOCIATE,
WIFIMODE_ASSOCIATED,
WIFIMODE_DISASSOCIATE,
WIFIMODE_CANNOTASSOCIATE,
};
enum WIFI_AUTHLEVEL {
WIFI_AUTHLEVEL_DISCONNECTED,
WIFI_AUTHLEVEL_AUTHENTICATED,
WIFI_AUTHLEVEL_ASSOCIATED,
WIFI_AUTHLEVEL_DEASSOCIATED,
};
enum WEPMODES {
WEPMODE_NONE = 0,
WEPMODE_40BIT = 1,
WEPMODE_128BIT = 2
};
enum WIFI_ASSOCSTATUS {
ASSOCSTATUS_DISCONNECTED, // not *trying* to connect
ASSOCSTATUS_SEARCHING, // data given does not completely specify an AP, looking for AP that matches the data.
ASSOCSTATUS_AUTHENTICATING, // connecting...
ASSOCSTATUS_ASSOCIATING, // connecting...
ASSOCSTATUS_ACQUIRINGDHCP, // connected to AP, but getting IP data from DHCP
ASSOCSTATUS_ASSOCIATED, // Connected! (COMPLETE if Wifi_ConnectAP was called to start)
ASSOCSTATUS_CANNOTCONNECT, // error in connecting... (COMPLETE if Wifi_ConnectAP was called to start)
};
typedef struct WIFI_TXHEADER {
u16 enable_flags;
u16 unknown;
u16 countup;
u16 beaconfreq;
u16 tx_rate;
u16 tx_length;
} Wifi_TxHeader;
typedef struct WIFI_RXHEADER {
u16 a;
u16 b;
u16 c;
u16 d;
u16 byteLength;
u16 rssi_;
} Wifi_RxHeader;
typedef struct WIFI_ACCESSPOINT {
char ssid[33]; // 0-32byte data, zero
char ssid_len;
u8 bssid[6];
u8 macaddr[6];
u16 maxrate; // max rate is measured in steps of 1/2Mbit - 5.5Mbit will be represented as 11, or 0x0B
u32 timectr;
u16 rssi;
u16 flags;
u32 spinlock;
u8 channel;
u8 rssi_past[8];
u8 base_rates[16]; // terminated by a 0 entry
} Wifi_AccessPoint;
typedef struct WIFI_MAINSTRUCT {
unsigned long dummy1[8];
// wifi status
u16 curChannel, reqChannel;
u16 curMode, reqMode;
u16 authlevel,authctr;
u32 flags9, flags7, reqPacketFlags;
u16 curReqFlags, reqReqFlags;
u32 counter7,bootcounter7;
char MacAddr[6];
u16 authtype;
u16 iptype,ipflags;
u32 ip,snmask,gateway;
// current AP data
char ssid7[34],ssid9[34];
u8 bssid7[6], bssid9[6];
u8 apmac7[6], apmac9[6];
char wepmode7, wepmode9;
char wepkeyid7, wepkeyid9;
u8 wepkey7[20],wepkey9[20];
u8 baserates7[16], baserates9[16];
u8 apchannel7, apchannel9;
u8 maxrate7;
u16 ap_rssi;
u16 pspoll_period;
// AP data
Wifi_AccessPoint aplist[WIFI_MAX_AP];
// probe stuff
u8 probe9_numprobe;
u8 probe9_ssidlen[WIFI_MAX_PROBE];
char probe9_ssid[WIFI_MAX_PROBE][32];
// WFC data
u8 wfc_enable[4]; // wep mode, or 0x80 for "enabled"
Wifi_AccessPoint wfc_ap[3];
unsigned long wfc_config[3][5]; // ip, snmask, gateway, primarydns, 2nddns
u8 wfc_wepkey[3][16];
// wifi data
u32 rxbufIn, rxbufOut; // bufIn/bufOut have 2-byte granularity.
u16 rxbufData[WIFI_RXBUFFER_SIZE/2]; // send raw 802.11 data through! rxbuffer is for rx'd data, arm7->arm9 transfer
u32 txbufIn, txbufOut;
u16 txbufData[WIFI_TXBUFFER_SIZE/2]; // tx buffer is for data to tx, arm9->arm7 transfer
// stats data
u32 stats[NUM_WIFI_STATS];
u16 debug[30];
u32 random; // semirandom number updated at the convenience of the arm7. use for initial seeds & such.
unsigned long dummy2[8];
} Wifi_MainStruct;
#endif

View File

@@ -0,0 +1,27 @@
DSWifi Project - sgIP Internet Protocol Stack Implementation
Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org
http://www.akkit.org
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,89 @@
// DSWifi Project - Arm7 Library Header file (dswifi7.h)
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef DSWIFI7_H
#define DSWIFI7_H
#include "dswifi_version.h"
// Wifi Sync Handler function: Callback function that is called when the arm9 needs to be told to synchronize with new fifo data.
// If this callback is used (see Wifi_SetSyncHandler()), it should send a message via the fifo to the arm9, which will call Wifi_Sync() on arm9.
typedef void (*WifiSyncHandler)();
#ifdef __cplusplus
extern "C" {
#endif
// Read_Flash: Reads an arbitrary amount of data from the firmware flash chip
// int address: Offset to start reading from in the flash chip
// char * destination: Pointer to a memory buffer to hold incoming data
// int length: The number of bytes to read
extern void Read_Flash(int address, char * destination, int length);
// PowerChip_ReadWrite: Reads or writes a value to the DS's power chip
// int cmp: The byte-long command to send to the chip (top bit 1=read, 0=write - other bits = register ID to read/write)
// int data: The data to write to the chip (if sending a read command, this should be zero)
// Returns: The data read returned by the serial connection; only really useful when reading.
extern int PowerChip_ReadWrite(int cmd, int data);
// Wifi_Interrupt: Handler for the arm7 wifi interrupt. Should be called by the
// interrupt handler on arm7, and should *not* have multiple interrupts enabled.
extern void Wifi_Interrupt();
// Wifi_Update: Sync function to ensure data continues to flow between the two
// CPUs smoothly. Should be called at a periodic interval, such as in vblank.
extern void Wifi_Update();
// Wifi_Init: Requires the data returned by the arm9 wifi init call. The arm9
// init call's returned data must be passed to the arm7 and then given to this
// function. (or else very bad things happen)
// This function also enables power to the wifi system, which will shorten
// battery life.
// unsigned long WifiData: You must pass the 32bit value returned by the call to
// Wifi_Init on the ARM9.
extern void Wifi_Init(unsigned long WifiData);
// Wifi_Deinit: In the case that it is necessary, this function cuts power to
// the wifi system. After this the wifi will be unusable until Wifi_Init is
// called again.
extern void Wifi_Deinit();
// Wifi_Sync: Call this function when requested to sync by the arm9 side of the
// wifi lib
extern void Wifi_Sync();
// Wifi_SetSyncHandler: Call this function to request notification of when the
// ARM9-side Wifi_Sync function should be called.
// WifiSyncHandler sh: Pointer to the function to be called for notification.
extern void Wifi_SetSyncHandler(WifiSyncHandler sh);
#ifdef __cplusplus
};
#endif
#endif // DSWIFI7_H

View File

@@ -0,0 +1,337 @@
// DSWifi Project - Arm9 Library Header File (dswifi9.h)
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef DSWIFI9_H
#define DSWIFI9_H
#include "dswifi_version.h"
// well, some flags and stuff are just stuffed in here and not documented very well yet... Most of the important stuff is documented though.
// Next version should clean up some of this a lot more :)
#define WIFIINIT_OPTION_USELED 0x0002
// default option is to use 128k heap
#define WIFIINIT_OPTION_USEHEAP_128 0x0000
#define WIFIINIT_OPTION_USEHEAP_64 0x1000
#define WIFIINIT_OPTION_USEHEAP_256 0x2000
#define WIFIINIT_OPTION_USEHEAP_512 0x3000
#define WIFIINIT_OPTION_USECUSTOMALLOC 0x4000
#define WIFIINIT_OPTION_HEAPMASK 0xF000
#define WFLAG_PACKET_DATA 0x0001
#define WFLAG_PACKET_MGT 0x0002
#define WFLAG_PACKET_BEACON 0x0004
#define WFLAG_PACKET_CTRL 0x0008
#define WFLAG_PACKET_ALL 0xFFFF
#define WFLAG_APDATA_ADHOC 0x0001
#define WFLAG_APDATA_WEP 0x0002
#define WFLAG_APDATA_WPA 0x0004
#define WFLAG_APDATA_COMPATIBLE 0x0008
#define WFLAG_APDATA_EXTCOMPATIBLE 0x0010
#define WFLAG_APDATA_SHORTPREAMBLE 0x0020
#define WFLAG_APDATA_ACTIVE 0x8000
enum WIFI_RETURN {
WIFI_RETURN_OK = 0, // Everything went ok
WIFI_RETURN_LOCKFAILED = 1, // the spinlock attempt failed (it wasn't retried cause that could lock both cpus- retry again after a delay.
WIFI_RETURN_ERROR = 2, // There was an error in attempting to complete the requested task.
WIFI_RETURN_PARAMERROR = 3, // There was an error in the parameters passed to the function.
};
enum WIFI_STATS {
// software stats
WSTAT_RXQUEUEDPACKETS, // number of packets queued into the rx fifo
WSTAT_TXQUEUEDPACKETS, // number of packets queued into the tx fifo
WSTAT_RXQUEUEDBYTES, // number of bytes queued into the rx fifo
WSTAT_TXQUEUEDBYTES, // number of bytes queued into the tx fifo
WSTAT_RXQUEUEDLOST, // number of packets lost due to space limitations in queuing
WSTAT_TXQUEUEDREJECTED, // number of packets rejected due to space limitations in queuing
WSTAT_RXPACKETS,
WSTAT_RXBYTES,
WSTAT_RXDATABYTES,
WSTAT_TXPACKETS,
WSTAT_TXBYTES,
WSTAT_TXDATABYTES,
// harware stats (function mostly unknown.)
WSTAT_HW_1B0,WSTAT_HW_1B1,WSTAT_HW_1B2,WSTAT_HW_1B3,WSTAT_HW_1B4,WSTAT_HW_1B5,WSTAT_HW_1B6,WSTAT_HW_1B7,
WSTAT_HW_1B8,WSTAT_HW_1B9,WSTAT_HW_1BA,WSTAT_HW_1BB,WSTAT_HW_1BC,WSTAT_HW_1BD,WSTAT_HW_1BE,WSTAT_HW_1BF,
WSTAT_HW_1C0,WSTAT_HW_1C1,WSTAT_HW_1C4,WSTAT_HW_1C5,
WSTAT_HW_1D0,WSTAT_HW_1D1,WSTAT_HW_1D2,WSTAT_HW_1D3,WSTAT_HW_1D4,WSTAT_HW_1D5,WSTAT_HW_1D6,WSTAT_HW_1D7,
WSTAT_HW_1D8,WSTAT_HW_1D9,WSTAT_HW_1DA,WSTAT_HW_1DB,WSTAT_HW_1DC,WSTAT_HW_1DD,WSTAT_HW_1DE,WSTAT_HW_1DF,
NUM_WIFI_STATS
};
// user code should NEVER have to use the WIFI_MODE or WIFI_AUTHLEVEL enums... is here in case I want to have some debug code...
enum WIFI_MODE {
WIFIMODE_DISABLED,
WIFIMODE_NORMAL,
WIFIMODE_SCAN,
WIFIMODE_ASSOCIATE,
WIFIMODE_ASSOCIATED,
WIFIMODE_DISASSOCIATE,
WIFIMODE_CANNOTASSOCIATE,
};
enum WIFI_AUTHLEVEL {
WIFI_AUTHLEVEL_DISCONNECTED,
WIFI_AUTHLEVEL_AUTHENTICATED,
WIFI_AUTHLEVEL_ASSOCIATED,
WIFI_AUTHLEVEL_DEASSOCIATED,
};
// user code uses members of the WIFIGETDATA structure in calling Wifi_GetData to retreive miscellaneous odd information
enum WIFIGETDATA {
WIFIGETDATA_MACADDRESS, // MACADDRESS: returns data in the buffer, requires at least 6 bytes
WIFIGETDATA_NUMWFCAPS, // NUM WFC APS: returns number between 0 and 3, doesn't use buffer.
MAX_WIFIGETDATA
};
enum WEPMODES {
WEPMODE_NONE = 0,
WEPMODE_40BIT = 1,
WEPMODE_128BIT = 2
};
// WIFI_ASSOCSTATUS - returned by Wifi_AssocStatus() after calling Wifi_ConnectAPk
enum WIFI_ASSOCSTATUS {
ASSOCSTATUS_DISCONNECTED, // not *trying* to connect
ASSOCSTATUS_SEARCHING, // data given does not completely specify an AP, looking for AP that matches the data.
ASSOCSTATUS_AUTHENTICATING, // connecting...
ASSOCSTATUS_ASSOCIATING, // connecting...
ASSOCSTATUS_ACQUIRINGDHCP, // connected to AP, but getting IP data from DHCP
ASSOCSTATUS_ASSOCIATED, // Connected! (COMPLETE if Wifi_ConnectAP was called to start)
ASSOCSTATUS_CANNOTCONNECT, // error in connecting... (COMPLETE if Wifi_ConnectAP was called to start)
};
// most user code will never need to know about the WIFI_TXHEADER or WIFI_RXHEADER
typedef struct WIFI_TXHEADER {
u16 enable_flags;
u16 unknown;
u16 countup;
u16 beaconfreq;
u16 tx_rate;
u16 tx_length;
} Wifi_TxHeader;
typedef struct WIFI_RXHEADER {
u16 a;
u16 b;
u16 c;
u16 d;
u16 byteLength;
u16 rssi_;
} Wifi_RxHeader;
// WIFI_ACCESSPOINT is an important structure in that it defines how to connect to an access point.
// listed inline are information about the members and their function
// if a field is not necessary for Wifi_ConnectAP it will be marked as such
// *only* 4 fields are absolutely required to be filled in correctly for the connection to work, they are:
// ssid, ssid_len, bssid, and channel - all others can be ignored (though flags should be set to 0)
typedef struct WIFI_ACCESSPOINT {
char ssid[33]; // the AP's SSID - zero terminated is not necessary.. if ssid[0] is zero, the ssid will be ignored in trying to find an AP to connect to. [REQUIRED]
char ssid_len; // number of valid bytes in the ssid field (0-32) [REQUIRED]
u8 bssid[6]; // BSSID is the AP's SSID - setting it to all 00's indicates this is not known and it will be ignored [REQUIRED]
u8 macaddr[6]; // mac address of the "AP" is only necessary in ad-hoc mode. [generally not required to connect]
u16 maxrate; // max rate is measured in steps of 1/2Mbit - 5.5Mbit will be represented as 11, or 0x0B [not required to connect]
u32 timectr; // internal information about how recently a beacon has been received [not required to connect]
u16 rssi; // running average of the recent RSSI values for this AP, will be set to 0 after not receiving beacons for a while. [not required to connect]
u16 flags; // flags indicating various parameters for the AP [not required, but the WFLAG_APDATA_ADHOC flag will be used]
u32 spinlock; // internal data word used to lock the record to guarantee data coherence [not required to connect]
u8 channel; // valid channels are 1-13, setting the channel to 0 will indicate the system should search. [REQUIRED]
u8 rssi_past[8]; // rssi_past indicates the RSSI values for the last 8 beacons received ([7] is the most recent) [not required to connect]
u8 base_rates[16]; // list of the base rates "required" by the AP (same format as maxrate) - zero-terminated list [not required to connect]
} Wifi_AccessPoint;
// Wifi Packet Handler function: (int packetID, int packetlength) - packetID is only valid while the called function is executing.
// call Wifi_RxRawReadPacket while in the packet handler function, to retreive the data to a local buffer.
typedef void (*WifiPacketHandler)(int, int);
// Wifi Sync Handler function: Callback function that is called when the arm7 needs to be told to synchronize with new fifo data.
// If this callback is used (see Wifi_SetSyncHandler()), it should send a message via the fifo to the arm7, which will call Wifi_Sync() on arm7.
typedef void (*WifiSyncHandler)();
#ifdef __cplusplus
extern "C" {
#endif
//////////////////////////////////////////////////////////////////////////
// Init/update/state management functions
// Wifi_Init: Initializes the wifi library (arm9 side) and the sgIP library.
// int initflags: set up some optional things, like controlling the LED blinking.
// Returns: a 32bit value that *must* be passed to arm7.
extern unsigned long Wifi_Init(int initflags);
// Wifi_CheckInit: Verifies when the ARM7 has been successfully initialized
// Returns: 1 if the arm7 is ready for wifi, 0 otherwise
extern int Wifi_CheckInit();
// Wifi_DisableWifi: Instructs the ARM7 to disengage wireless and stop receiving or
// transmitting.
extern void Wifi_DisableWifi();
// Wifi_EnableWifi: Instructs the ARM7 to go into a basic "active" mode, not actually
// associated to an AP, but actively receiving and potentially transmitting
extern void Wifi_EnableWifi();
// Wifi_SetPromiscuousMode: Allows the DS to enter or leave a "promsicuous" mode, in which
// all data that can be received is forwarded to the arm9 for user processing.
// Best used with Wifi_RawSetPacketHandler, to allow user code to use the data
// (well, the lib won't use 'em, so they're just wasting CPU otherwise.)
// int enable: 0 to disable promiscuous mode, nonzero to engage
extern void Wifi_SetPromiscuousMode(int enable);
// Wifi_ScanMode: Instructs the ARM7 to periodically rotate through the channels to
// pick up and record information from beacons given off by APs
extern void Wifi_ScanMode();
// Wifi_SetChannel: If the wifi system is not connected or connecting to an access point, instruct
// the chipset to change channel
// int channel: the channel to change to, in the range of 1-13
extern void Wifi_SetChannel(int channel);
// Wifi_GetNumAP:
// Returns: the current number of APs that are known about and tracked internally
extern int Wifi_GetNumAP();
// Wifi_GetAPData: Grabs data from internal structures for user code (always succeeds)
// int apnum: the 0-based index of the access point record to fetch
// Wifi_AccessPoint * apdata: Pointer to the location where the retrieved data should be stored
extern int Wifi_GetAPData(int apnum, Wifi_AccessPoint * apdata);
// Wifi_FindMatchingAP: determines whether various APs exist in the local area. You provide a
// list of APs, and it will return the index of the first one in the list that can be found
// in the internal list of APs that are being tracked
// int numaps: number of records in the list
// Wifi_AccessPoint * apdata: pointer to an array of structures with information about the APs to find
// Wifi_AccessPoint * match_dest: OPTIONAL pointer to a record to receive the matching AP record.
// Returns: -1 for none found, or a positive/zero integer index into the array
extern int Wifi_FindMatchingAP(int numaps, Wifi_AccessPoint * apdata, Wifi_AccessPoint * match_dest);
// Wifi_ConnectAP: Connect to an access point
// Wifi_AccessPoint * apdata: basic data on the AP
// int wepmode: indicates whether wep is used, and what kind
// int wepkeyid: indicates which wep key ID to use for transmitting
// unsigned char * wepkey: the wep key, to be used in all 4 key slots (should make this more flexible in the future)
// Returns: 0 for ok, -1 for error with input data
extern int Wifi_ConnectAP(Wifi_AccessPoint * apdata, int wepmode, int wepkeyid, unsigned char * wepkey);
// Wifi_AutoConnect: Connect to an access point specified by the WFC data in the firmware
extern void Wifi_AutoConnect();
// Wifi_AssocStatus: Returns information about the status of connection to an AP
// Returns: a value from the WIFI_ASSOCSTATUS enum, continue polling until you
// receive ASSOCSTATUS_CONNECTED or ASSOCSTATUS_CANNOTCONNECT
extern int Wifi_AssocStatus();
// Wifi_DisconnectAP: Disassociate from the Access Point
extern int Wifi_DisconnectAP();
// Wifi_Timer: This function should be called in a periodic interrupt. It serves as the basis
// for all updating in the sgIP library, all retransmits, timeouts, and etc are based on this
// function being called. It's not timing critical but it is rather essential.
// int num_ms: The number of milliseconds since the last time this function was called.
extern void Wifi_Timer(int num_ms);
// Wifi_GetIP:
// Returns: The current IP address of the DS (may not be valid before connecting to an AP, or setting the IP manually.)
extern unsigned long Wifi_GetIP(); // get local ip
// Wifi_GetIPInfo: (values may not be valid before connecting to an AP, or setting the IP manually.)
// unsigned long * pGateway: pointer to receive the currently configured gateway IP
// unsigned long * pSnmask: pointer to receive the currently configured subnet mask
// unsigned long * pDns1: pointer to receive the currently configured primary DNS server IP
// unsigned long * pDns2: pointer to receive the currently configured secondary DNS server IP
// Returns: The current IP address of the DS
extern unsigned long Wifi_GetIPInfo(unsigned long * pGateway,unsigned long * pSnmask,unsigned long * pDns1,unsigned long * pDns2);
// Wifi_SetIP: Set the DS's IP address and other IP configuration information.
// unsigned long IPaddr: The new IP address (NOTE! if this value is zero, the IP, the gateway, and the subnet mask will be allocated via DHCP)
// unsigned long gateway: The new gateway (example: 192.168.1.1 is 0xC0A80101)
// unsigned long subnetmask: The new subnet mask (example: 255.255.255.0 is 0xFFFFFF00)
// unsigned long dns1: The new primary dns server (NOTE! if this value is zero AND the IPaddr value is zero, dns1 and dns2 will be allocated via DHCP)
// unsigned long dns2: The new secondary dns server
extern void Wifi_SetIP(unsigned long IPaddr, unsigned long gateway, unsigned long subnetmask, unsigned long dns1, unsigned long dns2);
// Wifi_GetData: Retrieve an arbitrary or misc. piece of data from the wifi hardware. see WIFIGETDATA enum.
// int datatype: element from the WIFIGETDATA enum specifing what kind of data to get
// int bufferlen: length of the buffer to copy data to (not always used)
// unsigned char * buffer: buffer to copy element data to (not always used)
// Returns: -1 for failure, the number of bytes written to the buffer, or the value requested if the buffer isn't used.
extern int Wifi_GetData(int datatype, int bufferlen, unsigned char * buffer);
// Wifi_GetStats: Retreive an element of the wifi statistics gathered
// int statnum: Element from the WIFI_STATS enum, indicating what statistic to return
// Returns: the requested stat, or 0 for failure
extern u32 Wifi_GetStats(int statnum);
//////////////////////////////////////////////////////////////////////////
// Raw Send/Receive functions
// Wifi_RawTxFrame: Send a raw 802.11 frame at a specified rate
// unsigned short datalen: The length in bytes of the frame to send
// unsigned short rate: The rate to transmit at (Specified as mbits/10, 1mbit=0x000A, 2mbit=0x0014)
// unsigned short * data: Pointer to the data to send (should be halfword-aligned)
// Returns: Nothing of interest.
extern int Wifi_RawTxFrame(unsigned short datalen, unsigned short rate, unsigned short * data);
// Wifi_RawSetPacketHandler: Set a handler to process all raw incoming packets
// WifiPacketHandler wphfunc: Pointer to packet handler (see WifiPacketHandler definition for more info)
extern void Wifi_RawSetPacketHandler(WifiPacketHandler wphfunc);
// Wifi_RxRawReadPacket: Allows user code to read a packet from within the WifiPacketHandler function
// long packetID: a non-unique identifier which locates the packet specified in the internal buffer
// long readlength: number of bytes to read (actually reads (number+1)&~1 bytes)
// unsigned short * data: location for the data to be read into
extern int Wifi_RxRawReadPacket(long packetID, long readlength, unsigned short * data);
//////////////////////////////////////////////////////////////////////////
// Fast transfer support - update functions
// Wifi_Update: Checks for new data from the arm7 and initiates routing if data
// is available.
extern void Wifi_Update();
// Wifi_Sync: Call this function when requested to sync by the arm7 side of the
// wifi lib
extern void Wifi_Sync();
// Wifi_SetSyncHandler: Call this function to request notification of when the
// ARM7-side Wifi_Sync function should be called.
// WifiSyncHandler sh: Pointer to the function to be called for notification.
extern void Wifi_SetSyncHandler(WifiSyncHandler sh);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,10 @@
#ifndef _dswifi_version_h_
#define _dswifi_version_h_
#define DSWIFI_MAJOR 0
#define DSWIFI_MINOR 3
#define DSWIFI_REVISION 4
#define DSWIFI_VERSION "0.3.4"
#endif // _dswifi_version_h_

View File

@@ -0,0 +1,49 @@
// DSWifi Project - socket emulation layer defines/prototypes (netdb.h)
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef NETDB_H
#define NETDB_H
struct hostent {
char * h_name;
char ** h_aliases;
int h_addrtype;
int h_length;
char ** h_addr_list;
};
#ifdef __cplusplus
extern "C" {
#endif
extern struct hostent * gethostbyname(const char * name);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,61 @@
// DSWifi Project - socket emulation layer defines/prototypes (netinet/in.h)
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef NETINET_IN_H
#define NETINET_IN_H
#include "sys/socket.h"
#define INADDR_ANY 0x00000000
#define INADDR_BROADCAST 0xFFFFFFFF
#define INADDR_NONE 0xFFFFFFFF
struct in_addr {
unsigned long s_addr;
};
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
#ifdef __cplusplus
extern "C" {
#endif
// actually from arpa/inet.h - but is included through netinet/in.h
unsigned long inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
#ifdef __cplusplus
};
#endif
#endif

View File

@@ -0,0 +1,165 @@
// DSWifi Project - socket emulation layer defines/prototypes (sgIP_errno.h)
// Copyright (C) 2005-2006 Stephen Stair - sgstair@akkit.org - http://www.akkit.org
/******************************************************************************
DSWifi Lib and test materials are licenced under the MIT open source licence:
Copyright (c) 2005-2006 Stephen Stair
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
/**** Note: This file is unused unless you need to build in an environment without newlib ****/
#ifndef SGIP_ERRNO_H
#define SGIP_ERRNO_H
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#ifndef errno
extern int sgIP_errno;
#define errno sgIP_errno
#endif
#endif

View File

@@ -0,0 +1,69 @@
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
endif
export TOPDIR := $(CURDIR)
export DSWIFI_MAJOR := 0
export DSWIFI_MINOR := 3
export DSWIFI_REVISION := 4
VERSION := $(DSWIFI_MAJOR).$(DSWIFI_MINOR).$(DSWIFI_REVISION)
.PHONEY: release debug clean all
all: include/dswifi_version.h release debug
include/dswifi_version.h : makefile
@echo "#ifndef _dswifi_version_h_" > $@
@echo "#define _dswifi_version_h_" >> $@
@echo >> $@
@echo "#define DSWIFI_MAJOR $(DSWIFI_MAJOR)" >> $@
@echo "#define DSWIFI_MINOR $(DSWIFI_MINOR)" >> $@
@echo "#define DSWIFI_REVISION $(DSWIFI_REVISION)" >> $@
@echo >> $@
@echo '#define DSWIFI_VERSION "'$(DSWIFI_MAJOR).$(DSWIFI_MINOR).$(DSWIFI_REVISION)'"' >> $@
@echo >> $@
@echo "#endif // _dswifi_version_h_" >> $@
#-------------------------------------------------------------------------------
release: lib
#-------------------------------------------------------------------------------
$(MAKE) -C arm9 BUILD=release
$(MAKE) -C arm7 BUILD=release
#-------------------------------------------------------------------------------
debug: lib
#-------------------------------------------------------------------------------
$(MAKE) -C arm9 BUILD=debug
$(MAKE) -C arm7 BUILD=debug
#-------------------------------------------------------------------------------
lib:
#-------------------------------------------------------------------------------
mkdir lib
#-------------------------------------------------------------------------------
clean:
#-------------------------------------------------------------------------------
@$(MAKE) -C arm9 clean
@$(MAKE) -C arm7 clean
#-------------------------------------------------------------------------------
dist-src: clean
#-------------------------------------------------------------------------------
@tar --exclude=*CVS* -cvjf dswifi-src-$(VERSION).tar.bz2 arm7 arm9 common include makefile dswifi_license.txt
#-------------------------------------------------------------------------------
dist-bin: all
#-------------------------------------------------------------------------------
@tar --exclude=*CVS* -cvjf dswifi-$(VERSION).tar.bz2 include lib dswifi_license.txt
dist: dist-bin dist-src
#-------------------------------------------------------------------------------
install: dist-bin
#-------------------------------------------------------------------------------
bzip2 -cd dswifi-$(VERSION).tar.bz2 | tar -xv -C $(DEVKITPRO)/libnds

View File

@@ -0,0 +1,207 @@
/*
* RTEMS for Nintendo DS framebuffer display driver.
*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <bsp.h>
#include "../irq/irq.h"
#include <rtems/libio.h>
#include <nds.h>
#include <rtems/mw_fb.h>
/*
* screen information for the driver (fb0).
*/
static struct fb_screeninfo fb_info = {
SCREEN_WIDTH, SCREEN_HEIGHT, /* screen size x, y */
16, /* bits per pixel */
SCREEN_WIDTH, /* pixels per line (redundant with xres ?) */
(void *) VRAM_A, /* buffer pointer */
0x18000, /* buffer size */
FB_TYPE_PACKED_PIXELS, /* type of dsplay */
FB_VISUAL_TRUECOLOR /* color scheme used */
};
/*
* screen information for the driver (fb1).
*/
static struct fb_screeninfo fb_info2 = {
SCREEN_WIDTH, SCREEN_HEIGHT, /* screen size x, y */
16, /* bits per pixel */
SCREEN_WIDTH, /* pixels per line (redundant with xres ?) */
(void *) VRAM_B, /* buffer pointer */
0x18000, /* buffer size */
FB_TYPE_PACKED_PIXELS, /* type of dsplay */
FB_VISUAL_TRUECOLOR /* color scheme used */
};
/*
* fbds device driver initialize entry point.
*/
rtems_device_driver
fbds_initialize (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_status_code status;
printk ("[+] framebuffer started\n");
/* register the devices */
status = rtems_io_register_name ("/dev/fb0", major, 0);
if (status != RTEMS_SUCCESSFUL) {
printk ("[!] error registering framebuffer\n");
rtems_fatal_error_occurred (status);
}
status = rtems_io_register_name ("/dev/fb1", major, 1);
if (status != RTEMS_SUCCESSFUL) {
printk ("[!] error registering framebuffer\n");
rtems_fatal_error_occurred (status);
}
return RTEMS_SUCCESSFUL;
}
/*
* fbds device driver open operation.
*/
rtems_device_driver
fbds_open (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
return RTEMS_SUCCESSFUL;
}
/*
* fbds device driver close operation.
*/
rtems_device_driver
fbds_close (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
return RTEMS_SUCCESSFUL;
}
/*
* fbds device driver read operation.
*/
rtems_device_driver
fbds_read (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
rw_args->bytes_moved = 0;
return RTEMS_SUCCESSFUL;
}
/*
* fbds device driver write operation.
*/
rtems_device_driver
fbds_write (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
rw_args->bytes_moved = 0;
return RTEMS_SUCCESSFUL;
}
/*
* ioctl entry point.
*/
rtems_device_driver
fbds_control (rtems_device_major_number major,
rtems_device_minor_number minor, void *arg)
{
rtems_libio_ioctl_args_t *args = arg;
/* XXX check minor */
switch (args->command) {
case FB_SCREENINFO:
memcpy (args->buffer, minor ? &fb_info2 : &fb_info, sizeof (fb_info));
args->ioctl_return = 0;
break;
case FB_GETPALETTE:
args->ioctl_return = 0; /* XXX */
break;
case FB_SETPALETTE:
args->ioctl_return = 0; /* XXX */
break;
/*
* this function would execute one of the routines of the
* interface based on the operation requested.
*/
case FB_EXEC_FUNCTION:
{
struct fb_exec_function *env = args->buffer;
switch (env->func_no) {
case FB_FUNC_ENTER_GRAPHICS:
/* enter graphics mode */
printk ("[#] entering graphic mode on fb%d\n", minor);
if (!minor) {
videoSetMode (MODE_FB0);
vramSetBankA (VRAM_A_LCD);
memset (fb_info.smem_start, 0, fb_info.smem_len);
} else {
videoSetModeSub (MODE_FB0);
vramSetBankB (VRAM_B_LCD);
memset (fb_info2.smem_start, 0, fb_info2.smem_len);
}
break;
case FB_FUNC_EXIT_GRAPHICS:
/* leave graphics mode, in fact we only clear screen */
printk ("[#] leaving graphic mode on fb%d\n", minor);
if (!minor) {
memset (fb_info.smem_start, 0, fb_info.smem_len);
} else {
memset (fb_info2.smem_start, 0, fb_info2.smem_len);
/* back to console */
videoSetModeSub (MODE_0_2D | DISPLAY_BG0_ACTIVE);
vramSetBankC (VRAM_C_SUB_BG);
}
break;
case FB_FUNC_IS_DIRTY:
break;
case FB_FUNC_GET_MODE:
break;
default:
break;
}
}
/* no break on purpose */
default:
args->ioctl_return = 0;
break;
}
return RTEMS_SUCCESSFUL;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#ifndef _FB_H_
#define _FB_H_
#ifdef __cplusplus
extern "C"
{
#endif
/* fbds prototype entry points */
rtems_device_driver fbds_initialize (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_open (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_control (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_close (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_read (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_write (rtems_device_major_number,
rtems_device_minor_number, void *);
rtems_device_driver fbds_control (rtems_device_major_number,
rtems_device_minor_number, void *);
#define FB_DRIVER_TABLE_ENTRY \
{ fbds_initialize, fbds_open, fbds_close, \
fbds_read, fbds_write, fbds_control }
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#ifndef __BSP_H_
#define __BSP_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <bspopts.h>
#include <rtems.h>
#include <rtems/iosupp.h>
#include <rtems/bspIo.h>
#include <rtems/console.h>
#include <rtems/clockdrv.h>
struct rtems_bsdnet_ifconfig;
int
rtems_wifi_driver_attach (struct rtems_bsdnet_ifconfig *config,
int attach);
#define RTEMS_BSP_NETWORK_DRIVER_NAME "dswifi0"
#define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_wifi_driver_attach
void bsp_start (void);
void bsp_cleanup (void);
#define RTC_DRIVER_TABLE_ENTRY \
{ rtc_initialize, NULL, NULL, NULL, NULL, NULL }
extern rtems_device_driver rtc_initialize (rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,36 @@
/*
* RTEMS for Nintendo DS interprocessor communication extensions.
*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#ifndef _MYIPC_H_
#define _MYIPC_H_
#include "types.h"
typedef struct
{
vuint8_t *record_buffer;
vuint32_t record_length_max;
vuint32_t recorded_length;
vuint8_t record;
} my_TransferRegion;
static inline my_TransferRegion volatile *
getmy_IPC ()
{
return (my_TransferRegion volatile *) (0x027FF000 +
sizeof (TransferRegion));
}
#define my_IPC getmy_IPC()
#endif

View File

@@ -0,0 +1,32 @@
#ifndef __iosupp_h__
#define __iosupp_h__
#include <reent.h>
enum {
STD_IN,
STD_OUT,
STD_ERR,
STD_MAX = 16
};
#define _SHIFTL(v, s, w) \
((unsigned int) (((unsigned int)(v) & ((0x01 << (w)) - 1)) << (s)))
#define _SHIFTR(v, s, w) \
((unsigned int)(((unsigned int)(v) >> (s)) & ((0x01 << (w)) - 1)))
typedef struct {
const char *name;
int (*open_r)(struct _reent *r,const char *path,int flags,int mode);
int (*close_r)(struct _reent *r,int fd);
int (*write_r)(struct _reent *r,int fd,const char *ptr,int len);
int (*read_r)(struct _reent *r,int fd,char *ptr,int len);
int (*seek_r)(struct _reent *r,int fd,int pos,int dir);
int (*stat_r)(struct _reent *r,int fd,struct stat *st);
} devoptab_t;
extern const devoptab_t *devoptab_list[];
int AddDevice( const devoptab_t* device);
#endif

View File

@@ -0,0 +1,35 @@
/**
* @file tm27.h
*
* This include file contains definitions related to Time Test 27.
*/
/*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*
* $Id$
*/
#ifndef _RTEMS_TMTEST27
#error "This is an RTEMS internal file you must not include directly."
#endif
#ifndef __tm27_h
#define __tm27_h
/**
* Define the interrupt mechanism for Time Test 27
*/
#define MUST_WAIT_FOR_INTERRUPT 0
#define Install_tm27_vector( handler ) /* empty */
#define Cause_tm27_intr() /* empty */
#define Clear_tm27_intr() /* empty */
#define Lower_tm27_intr() /* empty */
#endif

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#ifndef BSP_NDS_TYPES_H_
#define BSP_NDS_TYPES_H_
#include <stdint.h>
/*
* volatile types for registers.
*/
typedef volatile char vint8_t;
typedef volatile short int vint16_t;
typedef volatile int vint32_t;
typedef volatile unsigned char vuint8_t;
typedef volatile unsigned short int vuint16_t;
typedef volatile unsigned int vuint32_t;
#endif

View File

@@ -0,0 +1,100 @@
/*
* RTEMS for Nintendo DS interrupt manager.
*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#include <bsp.h>
#include "irq.h"
#include <nds.h>
/*
* this function check that the value given for the irq line is valid.
*/
static int
isValidInterrupt (int irq)
{
if (irq < 0 || irq >= MAX_INTERRUPTS)
return 0;
return 1;
}
/*
* initialize the irq management.
*/
void
BSP_rtems_irq_mngt_init (void)
{
printk ("[+] irq manager started\n");
irqInit ();
REG_IME = IME_ENABLE;
}
/*
* install a irq handler.
*/
int
BSP_install_rtems_irq_handler (const rtems_irq_connect_data * irq)
{
rtems_interrupt_level level;
if (!isValidInterrupt (irq->name))
return 0;
rtems_interrupt_disable (level);
irqSet (irq->name, irq->hdl);
if (irq->on != NULL)
irq->on (irq);
rtems_interrupt_enable (level);
return 1;
}
/*
* return the handler hooked to the given irq.
*/
int
BSP_get_current_rtems_irq_handler (rtems_irq_connect_data * irq)
{
return 0; /* FIXME */
}
/*
* remove & disable given irq.
*/
int
BSP_remove_rtems_irq_handler (const rtems_irq_connect_data * irq)
{
rtems_interrupt_level level;
if (!isValidInterrupt (irq->name))
return 0;
rtems_interrupt_disable (level);
if (irq->off != NULL)
irq->off (irq);
irqClear (irq->name);
rtems_interrupt_enable (level);
return 1;
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2008 by Matthieu Bucchianeri <mbucchia@gmail.com>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
*
* http://www.rtems.com/license/LICENSE
*
* $Id$
*/
#ifndef _IRQ_H_
#define _IRQ_H_
#ifdef __cplusplus
extern "C"
{
#endif
/*
* Type definition for RTEMS managed interrupts
*/
typedef unsigned char rtems_irq_name;
typedef unsigned char rtems_irq_level;
typedef unsigned char rtems_irq_trigger;
struct __rtems_irq_connect_data__; /* forward declaratiuon */
typedef void (*rtems_irq_hdl) (void);
typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__
*);
typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__
*);
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__
*);
/** irq connection data structure */
typedef struct __rtems_irq_connect_data__
{
rtems_irq_name name;
rtems_irq_hdl hdl;
rtems_irq_enable on;
rtems_irq_disable off;
rtems_irq_is_enabled isOn;
rtems_irq_level irqLevel;
rtems_irq_trigger irqTrigger;
} rtems_irq_connect_data;
void BSP_rtems_irq_mngt_init (void);
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data *);
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data *);
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data *);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,102 @@
/*
fat.h
Simple functionality for startup, mounting and unmounting of FAT-based devices.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-14
* fatInitialise renamed to fatInit
2006-07-16 - Chishm
* Added fatInitDefault
*/
#ifndef _LIBFAT_H
#define _LIBFAT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "gba_types.h"
typedef enum {PI_CART_SLOT} PARTITION_INTERFACE;
struct IO_INTERFACE_STRUCT ;
/*
Initialise any inserted block-devices.
Add the fat device driver to the devoptab, making it available for standard file functions.
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
/*
Mount a partition on a custom device
*/
bool fatMountCustomInterface (struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
#ifdef __cplusplus
}
#endif
#endif // _LIBFAT_H

View File

@@ -0,0 +1,117 @@
/*
fat.h
Simple functionality for startup, mounting and unmounting of FAT-based devices.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-14
* fatInitialise renamed to fatInit
2006-07-16 - Chishm
* Added fatInitDefault
*/
#ifndef _LIBFAT_H
#define _LIBFAT_H
#ifdef __cplusplus
extern "C" {
#endif
// When compiling for NDS, make sure NDS is defined
#ifndef NDS
#if defined ARM9 || defined ARM7
#define NDS
#endif
#endif
#ifdef NDS
#include <nds/jtypes.h>
#else
#include "gba_types.h"
#endif
#ifdef NDS
typedef enum {PI_DEFAULT, PI_SLOT_1, PI_SLOT_2, PI_CUSTOM} PARTITION_INTERFACE;
#else
typedef enum {PI_CART_SLOT} PARTITION_INTERFACE;
#endif
struct IO_INTERFACE_STRUCT ;
/*
Initialise any inserted block-devices.
Add the fat device driver to the devoptab, making it available for standard file functions.
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
/*
Mount a partition on a custom device
*/
bool fatMountCustomInterface (const struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
#ifdef __cplusplus
}
#endif
#endif // _LIBFAT_H

View File

@@ -0,0 +1,107 @@
/*
fat.h
Simple functionality for startup, mounting and unmounting of FAT-based devices.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-14
* fatInitialise renamed to fatInit
2006-07-16 - Chishm
* Added fatInitDefault
*/
#ifndef _LIBFAT_H
#define _LIBFAT_H
#ifdef __cplusplus
extern "C" {
#endif
// When compiling for NDS, make sure NDS is defined
#ifndef NDS
#define NDS
#endif
#include <nds/jtypes.h>
typedef enum {PI_DEFAULT, PI_SLOT_1, PI_SLOT_2, PI_CUSTOM} PARTITION_INTERFACE;
struct IO_INTERFACE_STRUCT ;
/*
Initialise any inserted block-devices.
Add the fat device driver to the devoptab, making it available for standard file functions.
cacheSize: The number of pages to allocate for each inserted block-device
setAsDefaultDevice: if true, make this the default device driver for file operations
*/
bool fatInit (u32 cacheSize, bool setAsDefaultDevice);
/*
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
*/
bool fatInitDefault (void);
/*
Mount the device specified by partitionNumber
PD_DEFAULT is not allowed, use _FAT_partition_setDefaultDevice
PD_CUSTOM is not allowed, use _FAT_partition_mountCustomDevice
*/
bool fatMountNormalInterface (PARTITION_INTERFACE partitionNumber, u32 cacheSize);
/*
Mount a partition on a custom device
*/
bool fatMountCustomInterface (struct IO_INTERFACE_STRUCT* device, u32 cacheSize);
/*
Unmount the partition specified by partitionNumber
If there are open files, it will fail
*/
bool fatUnmount (PARTITION_INTERFACE partitionNumber);
/*
Forcibly unmount the partition specified by partitionNumber
Any open files on the partition will become invalid
The cache will be invalidated, and any unflushed writes will be lost
*/
bool fatUnsafeUnmount (PARTITION_INTERFACE partitionNumber);
/*
Set the default device for access by fat: and fat0:
PD_DEFAULT is unallowed.
Doesn't do anything useful on GBA, since there is only one device
*/
bool fatSetDefaultInterface (PARTITION_INTERFACE partitionNumber);
#ifdef __cplusplus
}
#endif
#endif // _LIBFAT_H

View File

@@ -0,0 +1,58 @@
/*
bit_ops.h
Functions for dealing with conversion of data between types
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _BIT_OPS_H
#define _BIT_OPS_H
/*-----------------------------------------------------------------
Functions to deal with little endian values stored in u8 arrays
-----------------------------------------------------------------*/
static inline u16 u8array_to_u16 (const u8* item, int offset) {
return ( item[offset] | (item[offset + 1] << 8));
}
static inline u32 u8array_to_u32 (const u8* item, int offset) {
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
}
static inline void u16_to_u8array (u8* item, int offset, u16 value) {
item[offset] = (u8)value;
item[offset + 1] = (u8)(value >> 8);
}
static inline void u32_to_u8array (u8* item, int offset, u32 value) {
item[offset] = (u8)value;
item[offset + 1] = (u8)(value >> 8);
item[offset + 2] = (u8)(value >> 16);
item[offset + 3] = (u8)(value >> 24);
}
#endif // _BIT_OPS_H

View File

@@ -0,0 +1,237 @@
/*
cache.c
The cache is not visible to the user. It should be flushed
when any file is closed or changes are made to the filesystem.
This cache implements a least-used-page replacement policy. This will
distribute sectors evenly over the pages, so if less than the maximum
pages are used at once, they should all eventually remain in the cache.
This also has the benefit of throwing out old sectors, so as not to keep
too many stale pages around.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "common.h"
#include "cache.h"
#include "disc_io/disc.h"
#include "mem_allocate.h"
#define CACHE_FREE 0xFFFFFFFF
CACHE* _FAT_cache_constructor (u32 numberOfPages, const IO_INTERFACE* discInterface) {
CACHE* cache;
u32 i;
CACHE_ENTRY* cacheEntries;
if (numberOfPages < 2) {
numberOfPages = 2;
}
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
if (cache == NULL) {
return false;
}
cache->disc = discInterface;
cache->numberOfPages = numberOfPages;
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
if (cacheEntries == NULL) {
_FAT_mem_free (cache);
return false;
}
for (i = 0; i < numberOfPages; i++) {
cacheEntries[i].sector = CACHE_FREE;
cacheEntries[i].count = 0;
cacheEntries[i].dirty = false;
}
cache->cacheEntries = cacheEntries;
cache->pages = (u8*) _FAT_mem_allocate ( CACHE_PAGE_SIZE * numberOfPages);
if (cache->pages == NULL) {
_FAT_mem_free (cache->cacheEntries);
_FAT_mem_free (cache);
return false;
}
return cache;
}
void _FAT_cache_destructor (CACHE* cache) {
// Clear out cache before destroying it
_FAT_cache_flush(cache);
// Free memory in reverse allocation order
_FAT_mem_free (cache->pages);
_FAT_mem_free (cache->cacheEntries);
_FAT_mem_free (cache);
return;
}
/*
Retrieve a sector's page from the cache. If it is not found in the cache,
load it into the cache and return the page it was loaded to.
Return CACHE_FREE on error.
*/
static u32 _FAT_cache_getSector (CACHE* cache, u32 sector) {
u32 i;
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
u32 numberOfPages = cache->numberOfPages;
u32 leastUsed = 0;
u32 lowestCount = 0xFFFFFFFF;
for (i = 0; (i < numberOfPages) && (cacheEntries[i].sector != sector); i++) {
// While searching for the desired sector, also search for the leased used page
if ( (cacheEntries[i].sector == CACHE_FREE) || (cacheEntries[i].count < lowestCount) ) {
leastUsed = i;
lowestCount = cacheEntries[i].count;
}
}
// If it found the sector in the cache, return it
if ((i < numberOfPages) && (cacheEntries[i].sector == sector)) {
// Increment usage counter
cacheEntries[i].count += 1;
return i;
}
// If it didn't, replace the least used cache page with the desired sector
if ((cacheEntries[leastUsed].sector != CACHE_FREE) && (cacheEntries[leastUsed].dirty == true)) {
// Write the page back to disc if it has been written to
if (!_FAT_disc_writeSectors (cache->disc, cacheEntries[leastUsed].sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
return CACHE_FREE;
}
cacheEntries[leastUsed].dirty = false;
}
// Load the new sector into the cache
if (!_FAT_disc_readSectors (cache->disc, sector, 1, cache->pages + CACHE_PAGE_SIZE * leastUsed)) {
return CACHE_FREE;
}
cacheEntries[leastUsed].sector = sector;
// Increment the usage count, don't reset it
// This creates a paging policy of least used PAGE, not sector
cacheEntries[leastUsed].count += 1;
return leastUsed;
}
/*
Reads some data from a cache page, determined by the sector number
*/
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
if (offset + size > BYTES_PER_READ) {
return false;
}
page = _FAT_cache_getSector (cache, sector);
if (page == CACHE_FREE) {
return false;
}
memcpy (buffer, cache->pages + (CACHE_PAGE_SIZE * page) + offset, size);
return true;
}
/*
Writes some data to a cache page, making sure it is loaded into memory first.
*/
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
if (offset + size > BYTES_PER_READ) {
return false;
}
page = _FAT_cache_getSector (cache, sector);
if (page == CACHE_FREE) {
return false;
}
memcpy (cache->pages + (CACHE_PAGE_SIZE * page) + offset, buffer, size);
cache->cacheEntries[page].dirty = true;
return true;
}
/*
Writes some data to a cache page, zeroing out the page first
*/
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size) {
u32 page;
if (offset + size > BYTES_PER_READ) {
return false;
}
page = _FAT_cache_getSector (cache, sector);
if (page == CACHE_FREE) {
return false;
}
memset (cache->pages + (CACHE_PAGE_SIZE * page), 0, CACHE_PAGE_SIZE);
memcpy (cache->pages + (CACHE_PAGE_SIZE * page) + offset, buffer, size);
cache->cacheEntries[page].dirty = true;
return true;
}
/*
Flushes all dirty pages to disc, clearing the dirty flag.
Also resets all pages' page count to 0.
*/
bool _FAT_cache_flush (CACHE* cache) {
u32 i;
for (i = 0; i < cache->numberOfPages; i++) {
if (cache->cacheEntries[i].dirty) {
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, 1, cache->pages + CACHE_PAGE_SIZE * i)) {
return CACHE_FREE;
}
}
cache->cacheEntries[i].count = 0;
cache->cacheEntries[i].dirty = false;
}
return true;
}
void _FAT_cache_invalidate (CACHE* cache) {
int i;
for (i = 0; i < cache->numberOfPages; i++) {
cache->cacheEntries[i].sector = CACHE_FREE;
cache->cacheEntries[i].count = 0;
cache->cacheEntries[i].dirty = false;
}
}

View File

@@ -0,0 +1,118 @@
/*
cache.h
The cache is not visible to the user. It should be flushed
when any file is closed or changes are made to the filesystem.
This cache implements a least-used-page replacement policy. This will
distribute sectors evenly over the pages, so if less than the maximum
pages are used at once, they should all eventually remain in the cache.
This also has the benefit of throwing out old sectors, so as not to keep
too many stale pages around.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _CACHE_H
#define _CACHE_H
#include "common.h"
#include "disc_io/disc_io.h"
#define CACHE_PAGE_SIZE BYTES_PER_READ
typedef struct {
u32 sector;
u32 count;
bool dirty;
} CACHE_ENTRY;
typedef struct {
const IO_INTERFACE* disc;
u32 numberOfPages;
CACHE_ENTRY* cacheEntries;
u8* pages;
} CACHE;
/*
Read data from a sector in the cache
If the sector is not in the cache, it will be swapped in
offset is the position to start reading from
size is the amount of data to read
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, u32 sector, u32 offset, u32 size);
/*
Write data to a sector in the cache
If the sector is not in the cache, it will be swapped in.
When the sector is swapped out, the data will be written to the disc
offset is the position to start reading from
size is the amount of data to read
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size);
/*
Write data to a sector in the cache, zeroing the sector first
If the sector is not in the cache, it will be swapped in.
When the sector is swapped out, the data will be written to the disc
offset is the position to start reading from
size is the amount of data to read
Precondition: offset + size <= BYTES_PER_READ
*/
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, u32 sector, u32 offset, u32 size);
/*
Read a full sector from the cache
*/
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, u32 sector) {
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
}
/*
Write a full sector to the cache
*/
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, u32 sector) {
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, BYTES_PER_READ);
}
/*
Write any dirty sectors back to disc and clear out the contents of the cache
*/
bool _FAT_cache_flush (CACHE* cache);
/*
Clear out the contents of the cache without writing any dirty sectors first
*/
void _FAT_cache_invalidate (CACHE* cache);
CACHE* _FAT_cache_constructor (u32 numberOfPages, const IO_INTERFACE* discInterface);
void _FAT_cache_destructor (CACHE* cache);
#endif // _CACHE_H

View File

@@ -0,0 +1,54 @@
/*
common.h
Common definitions and included files for the FATlib
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _COMMON_H
#define _COMMON_H
// When compiling for NDS, make sure NDS is defined
#ifndef NDS
#if defined ARM9 || defined ARM7
#define NDS
#endif
#endif
#ifdef NDS
#include <nds/jtypes.h>
#else
#include "gba_types.h"
#endif
#define BYTES_PER_READ 512
#ifndef NULL
#define NULL 0
#endif
#endif // _COMMON_H

View File

@@ -0,0 +1,902 @@
/*
directory.c
Reading, writing and manipulation of the directory structure on
a FAT partition
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-14 - Chishm
* entryFromPath correctly finds "" and "." now
2006-08-17 - Chishm
* entryFromPath doesn't look for "" anymore - use "." to refer to the current directory
2006-08-19 - Chishm
* Fixed entryFromPath bug when looking for "." in root directory
2006-10-01 - Chishm
* Now clears the whole new cluster when linking in more clusters for a directory
2006-10-28 - Chishm
* stat returns the hostType for the st_dev value
*/
#include <string.h>
#include <ctype.h>
#include "directory.h"
#include "common.h"
#include "partition.h"
#include "file_allocation_table.h"
#include "bit_ops.h"
#include "filetime.h"
// Directory entry codes
#define DIR_ENTRY_LAST 0x00
#define DIR_ENTRY_FREE 0xE5
// Long file name directory entry
enum LFN_offset {
LFN_offset_ordinal = 0x00, // Position within LFN
LFN_offset_char0 = 0x01,
LFN_offset_char1 = 0x03,
LFN_offset_char2 = 0x05,
LFN_offset_char3 = 0x07,
LFN_offset_char4 = 0x09,
LFN_offset_flag = 0x0B, // Should be equal to ATTRIB_LFN
LFN_offset_reserved1 = 0x0C, // Always 0x00
LFN_offset_checkSum = 0x0D, // Checksum of short file name (alias)
LFN_offset_char5 = 0x0E,
LFN_offset_char6 = 0x10,
LFN_offset_char7 = 0x12,
LFN_offset_char8 = 0x14,
LFN_offset_char9 = 0x16,
LFN_offset_char10 = 0x18,
LFN_offset_reserved2 = 0x1A, // Always 0x0000
LFN_offset_char11 = 0x1C,
LFN_offset_char12 = 0x1E
};
const int LFN_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
#define LFN_END 0x40
#define LFN_DEL 0x80
bool _FAT_directory_isValidLfn (const char* name) {
u32 i;
u32 nameLength;
// Make sure the name is short enough to be valid
if ( strnlen(name, MAX_FILENAME_LENGTH) >= MAX_FILENAME_LENGTH) {
return false;
}
// Make sure it doesn't contain any invalid characters
if (strpbrk (name, "\\/:*?\"<>|") != NULL) {
return false;
}
nameLength = strnlen(name, MAX_FILENAME_LENGTH);
// Make sure the name doesn't contain any control codes
for (i = 0; i < nameLength; i++) {
if (name[i] < 0x20) {
return false;
}
}
// Otherwise it is valid
return true;
}
bool _FAT_directory_isValidAlias (const char* name) {
u32 i;
u32 nameLength;
const char* dot;
// Make sure the name is short enough to be valid
if ( strnlen(name, MAX_ALIAS_LENGTH) >= MAX_ALIAS_LENGTH) {
return false;
}
// Make sure it doesn't contain any invalid characters
if (strpbrk (name, "\\/:;*?\"<>|&+,=[]") != NULL) {
return false;
}
nameLength = strnlen(name, MAX_ALIAS_LENGTH);
// Make sure the name doesn't contain any control codes
for (i = 0; i < nameLength; i++) {
if (name[i] < 0x20) {
return false;
}
}
dot = strchr ( name, '.');
// Make sure there is only one '.'
if ((dot != NULL) && (strrchr ( name, '.') != dot)) {
return false;
}
// If there is a '.':
if (dot != NULL) {
// Make sure the filename portion is 1-8 characters long
if (((dot - 1 - name) > 8) || ((dot - 1 - name) < 1)) {
return false;
}
// Make sure the extension is 1-3 characters long, if it exists
if ((strnlen(dot + 1, MAX_ALIAS_LENGTH) > 3) || (strnlen(dot + 1, MAX_ALIAS_LENGTH) < 1)) {
return false;
}
} else {
// Make sure the entire file name is 1-8 characters long
if ((nameLength > 8) || (nameLength < 1)) {
return false;
}
}
// Since we made it through all those tests, it must be valid
return true;
}
static bool _FAT_directory_entryGetAlias (const u8* entryData, char* destName) {
int i=0;
int j=0;
destName[0] = '\0';
if (entryData[0] != DIR_ENTRY_FREE) {
if (entryData[0] == '.') {
destName[0] = '.';
if (entryData[1] == '.') {
destName[1] = '.';
destName[2] = '\0';
} else {
destName[1] = '\0';
}
} else {
// Copy the filename from the dirEntry to the string
for (i = 0; (i < 8) && (entryData[DIR_ENTRY_name + i] != ' '); i++) {
destName[i] = entryData[DIR_ENTRY_name + i];
}
// Copy the extension from the dirEntry to the string
if (entryData[DIR_ENTRY_extension] != ' ') {
destName[i++] = '.';
for ( j = 0; (j < 3) && (entryData[DIR_ENTRY_extension + j] != ' '); j++) {
destName[i++] = entryData[DIR_ENTRY_extension + j];
}
}
destName[i] = '\0';
}
}
return (destName[0] != '\0');
}
u32 _FAT_directory_entryGetCluster (const u8* entryData) {
return u8array_to_u16(entryData,DIR_ENTRY_cluster) | (u8array_to_u16(entryData, DIR_ENTRY_clusterHigh) << 16);
}
static bool _FAT_directory_incrementDirEntryPosition (PARTITION* partition, DIR_ENTRY_POSITION* entryPosition, bool extendDirectory) {
DIR_ENTRY_POSITION position;
position = *entryPosition;
u32 tempCluster;
// Increment offset, wrapping at the end of a sector
++ position.offset;
if (position.offset == BYTES_PER_READ / DIR_ENTRY_DATA_SIZE) {
position.offset = 0;
// Increment sector when wrapping
++ position.sector;
// But wrap at the end of a cluster
if ((position.sector == partition->sectorsPerCluster) && (position.cluster != FAT16_ROOT_DIR_CLUSTER)) {
position.sector = 0;
// Move onto the next cluster, making sure there is another cluster to go to
tempCluster = _FAT_fat_nextCluster(partition, position.cluster);
if (tempCluster == CLUSTER_EOF) {
if (extendDirectory) {
tempCluster = _FAT_fat_linkFreeClusterCleared (partition, position.cluster);
if (tempCluster == CLUSTER_FREE) {
return false; // This will only happen if the disc is full
}
} else {
return false; // Got to the end of the directory, not extending it
}
}
position.cluster = tempCluster;
} else if ((position.cluster == FAT16_ROOT_DIR_CLUSTER) && (position.sector == (partition->dataStart - partition->rootDirStart))) {
return false; // Got to end of root directory, can't extend it
}
}
*entryPosition = position;
return true;
}
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
u8 entryData[0x20];
bool notFound, found;
u32 maxSectors;
int lfnPos;
u8 lfnChkSum, chkSum;
char* filename;
bool lfnExists;
int i;
lfnChkSum = 0;
entryStart = entry->dataEnd;
// Make sure we are using the correct root directory, in case of FAT32
if (entryStart.cluster == FAT16_ROOT_DIR_CLUSTER) {
entryStart.cluster = partition->rootDirCluster;
}
entryEnd = entryStart;
filename = entry->filename;
// Can only be FAT16_ROOT_DIR_CLUSTER if it is the root directory on a FAT12 or FAT16 partition
if (entryStart.cluster == FAT16_ROOT_DIR_CLUSTER) {
maxSectors = partition->dataStart - partition->rootDirStart;
} else {
maxSectors = partition->sectorsPerCluster;
}
lfnExists = false;
found = false;
notFound = false;
while (!found && !notFound) {
if (_FAT_directory_incrementDirEntryPosition (partition, &entryEnd, false) == false) {
notFound = true;
}
_FAT_cache_readPartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryEnd.cluster) + entryEnd.sector, entryEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
if (entryData[DIR_ENTRY_attributes] == ATTRIB_LFN) {
// It's an LFN
if (entryData[LFN_offset_ordinal] & LFN_DEL) {
lfnExists = false;
} else if (entryData[LFN_offset_ordinal] & LFN_END) {
// Last part of LFN, make sure it isn't deleted using previous if(Thanks MoonLight)
entryStart = entryEnd; // This is the start of a directory entry
lfnExists = true;
filename[(entryData[LFN_offset_ordinal] & ~LFN_END) * 13] = '\0'; // Set end of lfn to null character
lfnChkSum = entryData[LFN_offset_checkSum];
} if (lfnChkSum != entryData[LFN_offset_checkSum]) {
lfnExists = false;
}
if (lfnExists) {
lfnPos = ((entryData[LFN_offset_ordinal] & ~LFN_END) - 1) * 13;
for (i = 0; i < 13; i++) {
filename[lfnPos + i] = entryData[LFN_offset_table[i]]; // modify this for unicode support;
}
}
} else if (entryData[DIR_ENTRY_attributes] & ATTRIB_VOL) {
// This is a volume name, don't bother with it
} else if (entryData[0] == DIR_ENTRY_LAST) {
notFound = true;
} else if ((entryData[0] != DIR_ENTRY_FREE) && (entryData[0] > 0x20) && !(entryData[DIR_ENTRY_attributes] & ATTRIB_VOL)) {
if (lfnExists) {
// Calculate file checksum
chkSum = 0;
for (i=0; i < 11; i++) {
// NOTE: The operation is an unsigned char rotate right
chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + entryData[i];
}
if (chkSum != lfnChkSum) {
lfnExists = false;
filename[0] = '\0';
}
}
if (!lfnExists) {
entryStart = entryEnd;
_FAT_directory_entryGetAlias (entryData, filename);
}
found = true;
}
}
// If no file is found, return false
if (notFound) {
return false;
} else {
// Fill in the directory entry struct
entry->dataStart = entryStart;
entry->dataEnd = entryEnd;
memcpy (entry->entryData, entryData, DIR_ENTRY_DATA_SIZE);
return true;
}
}
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster) {
entry->dataStart.cluster = dirCluster;
entry->dataStart.sector = 0;
entry->dataStart.offset = -1; // Start before the beginning of the directory
entry->dataEnd = entry->dataStart;
return _FAT_directory_getNextEntry (partition, entry);
}
bool _FAT_directory_getRootEntry (PARTITION* partition, DIR_ENTRY* entry) {
entry->dataStart.cluster = 0;
entry->dataStart.sector = 0;
entry->dataStart.offset = 0;
entry->dataEnd = entry->dataStart;
memset (entry->filename, '\0', MAX_FILENAME_LENGTH);
entry->filename[0] = '.';
memset (entry->entryData, 0, DIR_ENTRY_DATA_SIZE);
memset (entry->entryData, ' ', 11);
entry->entryData[0] = '.';
entry->entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
u16_to_u8array (entry->entryData, DIR_ENTRY_cluster, partition->rootDirCluster);
u16_to_u8array (entry->entryData, DIR_ENTRY_clusterHigh, partition->rootDirCluster >> 16);
return true;
}
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
entryStart = entry->dataStart;
entryEnd = entry->dataEnd;
bool entryStillValid;
bool finished;
int i;
int lfnPos;
u8 entryData[DIR_ENTRY_DATA_SIZE];
memset (entry->filename, '\0', MAX_FILENAME_LENGTH);
// Create an empty directory entry to overwrite the old ones with
for ( entryStillValid = true, finished = false;
entryStillValid && !finished;
entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &entryStart, false))
{
_FAT_cache_readPartialSector (partition->cache, entryData,
_FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector,
entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
if ((entryStart.cluster == entryEnd.cluster)
&& (entryStart.sector == entryEnd.sector)
&& (entryStart.offset == entryEnd.offset)) {
// Copy the entry data and stop, since this is the last section of the directory entry
memcpy (entry->entryData, entryData, DIR_ENTRY_DATA_SIZE);
finished = true;
} else {
// Copy the long file name data
lfnPos = ((entryData[LFN_offset_ordinal] & ~LFN_END) - 1) * 13;
for (i = 0; i < 13; i++) {
entry->filename[lfnPos + i] = entryData[LFN_offset_table[i]]; // modify this for unicode support;
}
}
}
if (!entryStillValid) {
return false;
}
if ((entryStart.cluster == entryEnd.cluster)
&& (entryStart.sector == entryEnd.sector)
&& (entryStart.offset == entryEnd.offset)) {
// Since the entry doesn't have a long file name, extract the short filename
if (!_FAT_directory_entryGetAlias (entry->entryData, entry->filename)) {
return false;
}
}
return true;
}
bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd) {
size_t dirnameLength;
const char* pathPosition;
const char* nextPathPosition;
u32 dirCluster;
bool foundFile;
char alias[MAX_ALIAS_LENGTH];
bool found, notFound;
pathPosition = path;
found = false;
notFound = false;
if (pathEnd == NULL) {
// Set pathEnd to the end of the path string
pathEnd = strchr (path, '\0');
}
if (pathPosition[0] == DIR_SEPARATOR) {
// Start at root directory
dirCluster = partition->rootDirCluster;
// Consume separator(s)
while (pathPosition[0] == DIR_SEPARATOR) {
pathPosition++;
}
// If the path is only specifying a directory in the form of "/" return it
if (pathPosition >= pathEnd) {
_FAT_directory_getRootEntry (partition, entry);
found = true;
}
} else {
// Start in current working directory
dirCluster = partition->cwdCluster;
}
// If the path is only specifying a directory in the form "."
// and this is the root directory, return it
if ((dirCluster == partition->rootDirCluster) && (strncasecmp(".", pathPosition, 2) == 0)) {
_FAT_directory_getRootEntry (partition, entry);
found = true;
}
while (!found && !notFound) {
// Get the name of the next required subdirectory within the path
nextPathPosition = strchr (pathPosition, DIR_SEPARATOR);
if (nextPathPosition != NULL) {
dirnameLength = nextPathPosition - pathPosition;
} else {
dirnameLength = strlen(pathPosition);
}
if (dirnameLength > MAX_FILENAME_LENGTH) {
// The path is too long to bother with
return false;
}
// Look for the directory within the path
foundFile = _FAT_directory_getFirstEntry (partition, entry, dirCluster);
while (foundFile && !found && !notFound) { // It hasn't already found the file
// Check if the filename matches
if ((dirnameLength == strnlen(entry->filename, MAX_FILENAME_LENGTH))
&& (strncasecmp(entry->filename, pathPosition, dirnameLength) == 0)) {
found = true;
}
// Check if the alias matches
_FAT_directory_entryGetAlias (entry->entryData, alias);
if ((dirnameLength == strnlen(alias, MAX_ALIAS_LENGTH))
&& (strncasecmp(alias, pathPosition, dirnameLength) == 0)) {
found = true;
}
if (found && !(entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) && (nextPathPosition != NULL)) {
// Make sure that we aren't trying to follow a file instead of a directory in the path
found = false;
}
if (!found) {
foundFile = _FAT_directory_getNextEntry (partition, entry);
}
}
if (!foundFile) {
// Check that the search didn't get to the end of the directory
notFound = true;
found = false;
} else if ((nextPathPosition == NULL) || (nextPathPosition >= pathEnd)) {
// Check that we reached the end of the path
found = true;
} else if (entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) {
dirCluster = _FAT_directory_entryGetCluster (entry->entryData);
pathPosition = nextPathPosition;
// Consume separator(s)
while (pathPosition[0] == DIR_SEPARATOR) {
pathPosition++;
}
// The requested directory was found
if (pathPosition >= pathEnd) {
found = true;
} else {
found = false;
}
}
}
if (found && !notFound) {
return true;
} else {
return false;
}
}
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry) {
DIR_ENTRY_POSITION entryStart;
DIR_ENTRY_POSITION entryEnd;
entryStart = entry->dataStart;
entryEnd = entry->dataEnd;
bool entryStillValid;
bool finished;
u8 entryData[DIR_ENTRY_DATA_SIZE];
// Create an empty directory entry to overwrite the old ones with
for ( entryStillValid = true, finished = false;
entryStillValid && !finished;
entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &entryStart, false))
{
_FAT_cache_readPartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
entryData[0] = DIR_ENTRY_FREE;
_FAT_cache_writePartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, entryStart.cluster) + entryStart.sector, entryStart.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
if ((entryStart.cluster == entryEnd.cluster) && (entryStart.sector == entryEnd.sector) && (entryStart.offset == entryEnd.offset)) {
finished = true;
}
}
if (!entryStillValid) {
return false;
}
return true;
}
static bool _FAT_directory_findEntryGap (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster, u32 size) {
DIR_ENTRY_POSITION gapStart;
DIR_ENTRY_POSITION gapEnd;
u8 entryData[DIR_ENTRY_DATA_SIZE];
u32 dirEntryRemain;
bool endOfDirectory, entryStillValid;
// Scan Dir for free entry
gapEnd.offset = 0;
gapEnd.sector = 0;
gapEnd.cluster = dirCluster;
gapStart = gapEnd;
entryStillValid = true;
dirEntryRemain = size;
endOfDirectory = false;
while (entryStillValid && !endOfDirectory && (dirEntryRemain > 0)) {
_FAT_cache_readPartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, gapEnd.cluster) + gapEnd.sector, gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
if (entryData[0] == DIR_ENTRY_LAST) {
gapStart = gapEnd;
-- dirEntryRemain;
endOfDirectory = true;
} else if (entryData[0] == DIR_ENTRY_FREE) {
if (dirEntryRemain == size) {
gapStart = gapEnd;
}
-- dirEntryRemain;
} else {
dirEntryRemain = size;
}
if (!endOfDirectory && (dirEntryRemain > 0)) {
entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &gapEnd, true);
}
}
// Make sure the scanning didn't fail
if (!entryStillValid) {
return false;
}
// Save the start entry, since we know it is valid
entry->dataStart = gapStart;
if (endOfDirectory) {
memset (entryData, DIR_ENTRY_LAST, DIR_ENTRY_DATA_SIZE);
dirEntryRemain += 1; // Increase by one to take account of End Of Directory Marker
while ((dirEntryRemain > 0) && entryStillValid) {
// Get the gapEnd before incrementing it, so the second to last one is saved
entry->dataEnd = gapEnd;
// Increment gapEnd, moving onto the next entry
entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &gapEnd, true);
-- dirEntryRemain;
// Fill the entry with blanks
_FAT_cache_writePartialSector (partition->cache, entryData, _FAT_fat_clusterToSector(partition, gapEnd.cluster) + gapEnd.sector, gapEnd.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
}
if (!entryStillValid) {
return false;
}
} else {
entry->dataEnd = gapEnd;
}
return true;
}
static bool _FAT_directory_entryExists (PARTITION* partition, const char* name, u32 dirCluster) {
DIR_ENTRY tempEntry;
bool foundFile;
char alias[MAX_ALIAS_LENGTH];
u32 dirnameLength;
dirnameLength = strnlen(name, MAX_FILENAME_LENGTH);
if (dirnameLength >= MAX_FILENAME_LENGTH) {
return false;
}
// Make sure the entry doesn't already exist
foundFile = _FAT_directory_getFirstEntry (partition, &tempEntry, dirCluster);
while (foundFile) { // It hasn't already found the file
// Check if the filename matches
if ((dirnameLength == strnlen(tempEntry.filename, MAX_FILENAME_LENGTH))
&& (strcasecmp(tempEntry.filename, name) == 0)) {
return true;
}
// Check if the alias matches
_FAT_directory_entryGetAlias (tempEntry.entryData, alias);
if ((dirnameLength == strnlen(alias, MAX_ALIAS_LENGTH))
&& (strcasecmp(alias, name) == 0)) {
return true;
}
foundFile = _FAT_directory_getNextEntry (partition, &tempEntry);
}
return false;
}
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster) {
u32 entrySize;
u8 lfnEntry[DIR_ENTRY_DATA_SIZE];
s32 i,j; // Must be signed for use when decrementing in for loop
char *tmpCharPtr;
DIR_ENTRY_POSITION curEntryPos;
bool entryStillValid;
u8 aliasCheckSum = 0;
char alias [MAX_ALIAS_LENGTH];
// Make sure the filename is not 0 length
if (strnlen (entry->filename, MAX_FILENAME_LENGTH) < 1) {
return false;
}
// Make sure the filename is at least a valid LFN
if ( !(_FAT_directory_isValidLfn (entry->filename))) {
return false;
}
// Remove trailing spaces
for (i = strlen (entry->filename) - 1; (i > 0) && (entry->filename[i] == ' '); --i) {
entry->filename[i] = '\0';
}
// Remove leading spaces
for (i = 0; (i < strlen (entry->filename)) && (entry->filename[i] == ' '); ++i) ;
if (i > 0) {
memmove (entry->filename, entry->filename + i, strlen (entry->filename + i));
}
// Remove junk in filename
i = strlen (entry->filename);
memset (entry->filename + i, '\0', MAX_FILENAME_LENGTH - i);
// Make sure the entry doesn't already exist
if (_FAT_directory_entryExists (partition, entry->filename, dirCluster)) {
return false;
}
// Clear out alias, so we can generate a new one
memset (entry->entryData, ' ', 11);
if ( strncmp(entry->filename, ".", MAX_FILENAME_LENGTH) == 0) {
// "." entry
entry->entryData[0] = '.';
entrySize = 1;
} else if ( strncmp(entry->filename, "..", MAX_FILENAME_LENGTH) == 0) {
// ".." entry
entry->entryData[0] = '.';
entry->entryData[1] = '.';
entrySize = 1;
} else if ( _FAT_directory_isValidAlias (entry->filename)) {
// Short filename
strupr (entry->filename);
entrySize = 1;
// Copy into alias
for (i = 0, j = 0; (j < 8) && (entry->filename[i] != '.') && (entry->filename[i] != '\0'); i++, j++) {
entry->entryData[j] = entry->filename[i];
}
while (j < 8) {
entry->entryData[j] = ' ';
++ j;
}
if (entry->filename[i] == '.') {
// Copy extension
++ i;
while ((entry->filename[i] != '\0') && (j < 11)) {
entry->entryData[j] = entry->filename[i];
++ i;
++ j;
}
}
while (j < 11) {
entry->entryData[j] = ' ';
++ j;
}
} else {
// Long filename needed
entrySize = ((strnlen (entry->filename, MAX_FILENAME_LENGTH) + LFN_ENTRY_LENGTH - 1) / LFN_ENTRY_LENGTH) + 1;
// Generate alias
tmpCharPtr = strrchr (entry->filename, '.');
if (tmpCharPtr == NULL) {
tmpCharPtr = strrchr (entry->filename, '\0');
}
for (i = 0, j = 0; (j < 6) && (entry->filename + i < tmpCharPtr); i++) {
if ( isalnum(entry->filename[i])) {
alias[j] = entry->filename[i];
++ j;
}
}
while (j < 8) {
alias[j] = '_';
++ j;
}
tmpCharPtr = strrchr (entry->filename, '.');
if (tmpCharPtr != NULL) {
alias[8] = '.';
// Copy extension
while ((tmpCharPtr != '\0') && (j < 12)) {
alias[j] = tmpCharPtr[0];
++ tmpCharPtr;
++ j;
}
alias[j] = '\0';
} else {
for (j = 8; j < MAX_ALIAS_LENGTH; j++) {
alias[j] = '\0';
}
}
// Get a valid tail number
alias[5] = '~';
i = 0;
do {
i++;
alias[6] = '0' + ((i / 10) % 10); // 10's digit
alias[7] = '0' + (i % 10); // 1's digit
} while (_FAT_directory_entryExists (partition, alias, dirCluster) && (i < 100));
if (i == 100) {
// Couldn't get a tail number
return false;
}
// Make it upper case
strupr (alias);
// Now copy it into the directory entry data
memcpy (entry->entryData, alias, 8);
memcpy (entry->entryData + 8, alias + 9, 3);
for (i = 0; i < 10; i++) {
if (entry->entryData[i] < 0x20) {
// Replace null and control characters with spaces
entry->entryData[i] = 0x20;
}
}
// Generate alias checksum
for (i=0; i < 11; i++)
{
// NOTE: The operation is an unsigned char rotate right
aliasCheckSum = ((aliasCheckSum & 1) ? 0x80 : 0) + (aliasCheckSum >> 1) + entry->entryData[i];
}
}
// Find or create space for the entry
if (_FAT_directory_findEntryGap (partition, entry, dirCluster, entrySize) == false) {
return false;
}
// Write out directory entry
curEntryPos = entry->dataStart;
for (entryStillValid = true, i = entrySize; entryStillValid && i > 0;
entryStillValid = _FAT_directory_incrementDirEntryPosition (partition, &curEntryPos, false), -- i )
{
if (i > 1) {
// Long filename entry
lfnEntry[LFN_offset_ordinal] = (i - 1) | (i == entrySize ? LFN_END : 0);
for (j = 0; j < 13; j++) {
if (entry->filename [(i - 2) * 13 + j] == '\0') {
if ((j > 1) && (entry->filename [(i - 2) * 13 + (j-1)] == '\0')) {
u16_to_u8array (lfnEntry, LFN_offset_table[j], 0xffff); // Padding
} else {
u16_to_u8array (lfnEntry, LFN_offset_table[j], 0x0000); // Terminating null character
}
} else {
u16_to_u8array (lfnEntry, LFN_offset_table[j], entry->filename [(i - 2) * 13 + j]);
}
}
lfnEntry[LFN_offset_checkSum] = aliasCheckSum;
lfnEntry[LFN_offset_flag] = ATTRIB_LFN;
lfnEntry[LFN_offset_reserved1] = 0;
u16_to_u8array (lfnEntry, LFN_offset_reserved2, 0);
_FAT_cache_writePartialSector (partition->cache, lfnEntry, _FAT_fat_clusterToSector(partition, curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
} else {
// Alias & file data
_FAT_cache_writePartialSector (partition->cache, entry->entryData, _FAT_fat_clusterToSector(partition, curEntryPos.cluster) + curEntryPos.sector, curEntryPos.offset * DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
}
}
return true;
}
bool _FAT_directory_chdir (PARTITION* partition, const char* path) {
DIR_ENTRY entry;
if (!_FAT_directory_entryFromPath (partition, &entry, path, NULL)) {
return false;
}
if (!(entry.entryData[DIR_ENTRY_attributes] & ATTRIB_DIR)) {
return false;
}
partition->cwdCluster = _FAT_directory_entryGetCluster (entry.entryData);
return true;
}
void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st) {
// Fill in the stat struct
// Some of the values are faked for the sake of compatibility
st->st_dev = _FAT_disc_hostType(partition->disc); // The device is the 32bit ioType value
st->st_ino = (ino_t)(_FAT_directory_entryGetCluster(entry->entryData)); // The file serial number is the start cluster
st->st_mode = (_FAT_directory_isDirectory(entry) ? S_IFDIR : S_IFREG) |
(S_IRUSR | S_IRGRP | S_IROTH) |
(_FAT_directory_isWritable (entry) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0); // Mode bits based on dirEntry ATTRIB byte
st->st_nlink = 1; // Always one hard link on a FAT file
st->st_uid = 1; // Faked for FAT
st->st_gid = 2; // Faked for FAT
st->st_rdev = st->st_dev;
st->st_size = u8array_to_u32 (entry->entryData, DIR_ENTRY_fileSize); // File size
st->st_atime = _FAT_filetime_to_time_t (
0,
u8array_to_u16 (entry->entryData, DIR_ENTRY_aDate)
);
st->st_spare1 = 0;
st->st_mtime = _FAT_filetime_to_time_t (
u8array_to_u16 (entry->entryData, DIR_ENTRY_mTime),
u8array_to_u16 (entry->entryData, DIR_ENTRY_mDate)
);
st->st_spare2 = 0;
st->st_ctime = _FAT_filetime_to_time_t (
u8array_to_u16 (entry->entryData, DIR_ENTRY_cTime),
u8array_to_u16 (entry->entryData, DIR_ENTRY_cDate)
);
st->st_spare3 = 0;
st->st_blksize = BYTES_PER_READ; // Prefered file I/O block size
st->st_blocks = (st->st_size + BYTES_PER_READ - 1) / BYTES_PER_READ; // File size in blocks
st->st_spare4[0] = 0;
st->st_spare4[1] = 0;
}

View File

@@ -0,0 +1,171 @@
/*
directory.h
Reading, writing and manipulation of the directory structure on
a FAT partition
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _DIRECTORY_H
#define _DIRECTORY_H
#include <sys/stat.h>
#include "common.h"
#include "partition.h"
#define DIR_ENTRY_DATA_SIZE 0x20
#define MAX_FILENAME_LENGTH 256
#define MAX_ALIAS_LENGTH 13
#define LFN_ENTRY_LENGTH 13
#define FAT16_ROOT_DIR_CLUSTER 0
#define DIR_SEPARATOR '/'
// File attributes
#define ATTRIB_ARCH 0x20 // Archive
#define ATTRIB_DIR 0x10 // Directory
#define ATTRIB_LFN 0x0F // Long file name
#define ATTRIB_VOL 0x08 // Volume
#define ATTRIB_SYS 0x04 // System
#define ATTRIB_HID 0x02 // Hidden
#define ATTRIB_RO 0x01 // Read only
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
typedef struct {
u32 cluster;
u32 sector;
s32 offset;
} DIR_ENTRY_POSITION;
typedef struct {
u8 entryData[DIR_ENTRY_DATA_SIZE];
DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN
DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry
char filename[MAX_FILENAME_LENGTH];
} DIR_ENTRY;
// Directory entry offsets
enum DIR_ENTRY_offset {
DIR_ENTRY_name = 0x00,
DIR_ENTRY_extension = 0x08,
DIR_ENTRY_attributes = 0x0B,
DIR_ENTRY_reserved = 0x0C,
DIR_ENTRY_cTime_ms = 0x0D,
DIR_ENTRY_cTime = 0x0E,
DIR_ENTRY_cDate = 0x10,
DIR_ENTRY_aDate = 0x12,
DIR_ENTRY_clusterHigh = 0x14,
DIR_ENTRY_mTime = 0x16,
DIR_ENTRY_mDate = 0x18,
DIR_ENTRY_cluster = 0x1A,
DIR_ENTRY_fileSize = 0x1C
};
/*
Returns true if the file specified by entry is a directory
*/
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) {
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0);
}
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) {
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0);
}
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) {
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') ||
((entry->filename[1] == '.') && entry->filename[2] == '\0')));
}
/*
Reads the first directory entry from the directory starting at dirCluster
Places result in entry
entry will be destroyed even if no directory entry is found
Returns true on success, false on failure
*/
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster);
/*
Reads the next directory entry after the one already pointed to by entry
Places result in entry
entry will be destroyed even if no directory entry is found
Returns true on success, false on failure
*/
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry);
/*
Gets the directory entry corrsponding to the supplied path
entry will be destroyed even if no directory entry is found
pathEnd specifies the end of the path string, for cutting strings short if needed
specify NULL to use the full length of path
pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR
after pathEND.
Returns true on success, false on failure
*/
bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd);
/*
Changes the current directory to the one specified by path
Returns true on success, false on failure
*/
bool _FAT_directory_chdir (PARTITION* partition, const char* path);
/*
Removes the directory entry specified by entry
Assumes that entry is valid
Returns true on success, false on failure
*/
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry);
/*
Add a directory entry to the directory specified by dirCluster
The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
updated with the new directory entry position and alias.
Returns true on success, false on failure
*/
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, u32 dirCluster);
/*
Get the start cluster of a file from it's entry data
*/
u32 _FAT_directory_entryGetCluster (const u8* entryData);
/*
Fill in the file name and entry data of DIR_ENTRY* entry.
Assumes that the entry's dataStart and dataEnd are correct
Returns true on success, false on failure
*/
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry);
/*
Fill in a stat struct based on a file entry
*/
void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st);
#endif // _DIRECTORY_H

View File

@@ -0,0 +1,184 @@
/*
disc.c
uniformed io-interface to work with Chishm's FAT library
Written by MightyMax
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2005-11-06 - Chishm
* Added WAIT_CR modifications for NDS
2006-02-03 www.neoflash.com
* Added SUPPORT_* defines, comment out any of the SUPPORT_* defines in disc_io.h to remove support
for the given interface and stop code being linked to the binary
* Added support for MK2 MMC interface
* Added disc_Cache* functions
2006-02-05 - Chishm
* Added Supercard SD support
2006-02-26 - Cytex
* Added EFA2 support
2006-05-18 - Chishm
* Rewritten for FATlib disc.c
2006-06-19 - Chishm
* Changed read and write interface to accept a u32 instead of a u8 for the number of sectors
2006-07-11 - Chishm
* Removed disc_Cache* functions, since there is now a proper unified cache
* Removed SUPPORT_* defines
* Rewrote device detection functions
* First libfat release
2006-07-25 - Chishm
* Changed IO_INTERFACEs to const
2006-08-02 - Chishm
* Added NinjaDS
2006-12-25 - Chishm
* Added DLDI
* Removed experimental interfaces
2007-05-01 - Chishm
* Removed FCSR
*/
#include "disc.h"
#include "disc_io.h"
#ifdef NDS
#include <nds.h>
#endif
// Include known io-interfaces:
#include "io_dldi.h"
#include "io_njsd.h"
#include "io_nmmc.h"
#include "io_mpcf.h"
#include "io_m3cf.h"
#include "io_sccf.h"
#include "io_scsd.h"
#include "io_m3sd.h"
const IO_INTERFACE* ioInterfaces[] = {
&_io_dldi, // Reserved for new interfaces
#ifdef NDS
// Place Slot 1 (DS Card) interfaces here
&_io_njsd, &_io_nmmc,
#endif
// Place Slot 2 (GBA Cart) interfaces here
&_io_mpcf, &_io_m3cf, &_io_sccf, &_io_scsd, &_io_m3sd
};
/*
Hardware level disc funtions
*/
const IO_INTERFACE* _FAT_disc_gbaSlotFindInterface (void)
{
// If running on an NDS, make sure the correct CPU can access
// the GBA cart. First implemented by SaTa.
#ifdef NDS
#ifdef ARM9
sysSetCartOwner(BUS_OWNER_ARM9);
#endif
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->features & FEATURE_SLOT_GBA) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
#ifdef NDS
/*
* Check the DS card slot for a valid memory card interface
* If an interface is found, it is set as the default interace
* and it returns true. Otherwise the default interface is left
* untouched and it returns false.
*/
const IO_INTERFACE* _FAT_disc_dsSlotFindInterface (void)
{
#ifdef ARM9
sysSetCardOwner(BUS_OWNER_ARM9);
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if ((ioInterfaces[i]->features & FEATURE_SLOT_NDS) && (ioInterfaces[i]->fn_startup())) {
return ioInterfaces[i];
}
}
return NULL;
}
#endif
/*
* When running on an NDS, check the either slot for a valid memory
* card interface.
* When running on a GBA, call _FAT_disc_gbaSlotFindInterface
* If an interface is found, it is set as the default interace
* and it returns true. Otherwise the default interface is left
* untouched and it returns false.
*/
#ifdef NDS
const IO_INTERFACE* _FAT_disc_findInterface (void)
{
#ifdef ARM9
sysSetBusOwners(BUS_OWNER_ARM9, BUS_OWNER_ARM9);
#endif
int i;
for (i = 0; i < (sizeof(ioInterfaces) / sizeof(IO_INTERFACE*)); i++) {
if (ioInterfaces[i]->fn_startup()) {
return ioInterfaces[i];
}
}
return NULL;
}
#else
const IO_INTERFACE* _FAT_disc_findInterface (void)
{
return _FAT_disc_gbaSlotFindInterface();
}
#endif

View File

@@ -0,0 +1,126 @@
/*
disc.h
Interface to the low level disc functions. Used by the higher level
file system code.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef _DISC_H
#define _DISC_H
#include "../common.h"
#include "disc_io.h"
/*
Search for a block based device in the GBA slot.
Return a pointer to a usable interface if one is found,
NULL if not.
*/
extern const IO_INTERFACE* _FAT_disc_gbaSlotFindInterface (void);
/*
Search for a block based device in the DS slot.
Return a pointer to a usable interface if one is found,
NULL if not.
*/
#ifdef NDS
extern const IO_INTERFACE* _FAT_disc_dsSlotFindInterface (void);
#endif
/*
Search for a block based device in the both slots.
Return a pointer to a usable interface if one is found,
NULL if not.
*/
extern const IO_INTERFACE* _FAT_disc_findInterface (void);
/*
Check if a disc is inserted
Return true if a disc is inserted and ready, false otherwise
*/
static inline bool _FAT_disc_isInserted (const IO_INTERFACE* disc) {
return disc->fn_isInserted();
}
/*
Read numSectors sectors from a disc, starting at sector.
numSectors is between 1 and 256
sector is from 0 to 2^28
buffer is a pointer to the memory to fill
*/
static inline bool _FAT_disc_readSectors (const IO_INTERFACE* disc, u32 sector, u32 numSectors, void* buffer) {
return disc->fn_readSectors (sector, numSectors, buffer);
}
/*
Write numSectors sectors to a disc, starting at sector.
numSectors is between 1 and 256
sector is from 0 to 2^28
buffer is a pointer to the memory to read from
*/
static inline bool _FAT_disc_writeSectors (const IO_INTERFACE* disc, u32 sector, u32 numSectors, const void* buffer) {
return disc->fn_writeSectors (sector, numSectors, buffer);
}
/*
Reset the card back to a ready state
*/
static inline bool _FAT_disc_clearStatus (const IO_INTERFACE* disc) {
return disc->fn_clearStatus();
}
/*
Initialise the disc to a state ready for data reading or writing
*/
static inline bool _FAT_disc_startup (const IO_INTERFACE* disc) {
return disc->fn_startup();
}
/*
Put the disc in a state ready for power down.
Complete any pending writes and disable the disc if necessary
*/
static inline bool _FAT_disc_shutdown (const IO_INTERFACE* disc) {
return disc->fn_shutdown();
}
/*
Return a 32 bit value unique to each type of interface
*/
static inline u32 _FAT_disc_hostType (const IO_INTERFACE* disc) {
return disc->ioType;
}
/*
Return a 32 bit value that specifies the capabilities of the disc
*/
static inline u32 _FAT_disc_features (const IO_INTERFACE* disc) {
return disc->features;
}
#endif // _DISC_H

View File

@@ -0,0 +1,81 @@
/*
disc_io.h
Interface template for low level disc functions.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-16 - Chishm
* Renamed _CF_USE_DMA to _IO_USE_DMA
* Renamed _CF_ALLOW_UNALIGNED to _IO_ALLOW_UNALIGNED
*/
#ifndef _DISC_IO_H
#define _DISC_IO_H
#include "../common.h"
//----------------------------------------------------------------------
// Customisable features
// Use DMA to read the card, remove this line to use normal reads/writes
// #define _IO_USE_DMA
// Allow buffers not alligned to 16 bits when reading files.
// Note that this will slow down access speed, so only use if you have to.
// It is also incompatible with DMA
#define _IO_ALLOW_UNALIGNED
#if defined _IO_USE_DMA && defined _IO_ALLOW_UNALIGNED
#error You can't use both DMA and unaligned memory
#endif
#define FEATURE_MEDIUM_CANREAD 0x00000001
#define FEATURE_MEDIUM_CANWRITE 0x00000002
#define FEATURE_SLOT_GBA 0x00000010
#define FEATURE_SLOT_NDS 0x00000020
typedef bool (* FN_MEDIUM_STARTUP)(void) ;
typedef bool (* FN_MEDIUM_ISINSERTED)(void) ;
typedef bool (* FN_MEDIUM_READSECTORS)(u32 sector, u32 numSectors, void* buffer) ;
typedef bool (* FN_MEDIUM_WRITESECTORS)(u32 sector, u32 numSectors, const void* buffer) ;
typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ;
typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ;
struct IO_INTERFACE_STRUCT {
unsigned long ioType ;
unsigned long features ;
FN_MEDIUM_STARTUP fn_startup ;
FN_MEDIUM_ISINSERTED fn_isInserted ;
FN_MEDIUM_READSECTORS fn_readSectors ;
FN_MEDIUM_WRITESECTORS fn_writeSectors ;
FN_MEDIUM_CLEARSTATUS fn_clearStatus ;
FN_MEDIUM_SHUTDOWN fn_shutdown ;
} ;
typedef struct IO_INTERFACE_STRUCT IO_INTERFACE ;
#endif // define _DISC_IO_H

View File

@@ -0,0 +1,322 @@
/*
io_cf_common.c based on
compact_flash.c
By chishm (Michael Chisholm)
Common hardware routines for using a compact flash card. This is not reentrant
and does not do range checking on the supplied addresses. This is designed to
be as fast as possible.
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// CF Addresses & Commands
CF_REGISTERS cfRegisters = {0};
/*-----------------------------------------------------------------
_CF_isInserted
Is a compact flash card inserted?
bool return OUT: true if a CF card is inserted
-----------------------------------------------------------------*/
bool _CF_isInserted (void) {
// Change register, then check if value did change
*(cfRegisters.status) = CF_STS_INSERTED;
return ((*(cfRegisters.status) & 0xff) == CF_STS_INSERTED);
}
/*-----------------------------------------------------------------
_CF_clearStatus
Tries to make the CF card go back to idle mode
bool return OUT: true if a CF card is idle
-----------------------------------------------------------------*/
bool _CF_clearStatus (void) {
int i;
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
return true;
}
/*-----------------------------------------------------------------
_CF_readSectors
Read 512 byte sector numbered "sector" into "buffer"
u32 sector IN: address of first 512 byte sector on CF card to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _CF_readSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
u16 *buff = (u16*)buffer;
#ifdef _IO_ALLOW_UNALIGNED
u8 *buff_u8 = (u8*)buffer;
int temp;
#endif
#if (defined _IO_USE_DMA) && (defined NDS) && (defined ARM9)
DC_FlushRange( buffer, j * BYTES_PER_READ);
#endif
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT)) {
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT)) {
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Set number of sectors to read
*(cfRegisters.sectorCount) = (numSectors < 256 ? numSectors : 0); // Read a maximum of 256 sectors, 0 means 256
// Set read sector
*(cfRegisters.lba1) = sector & 0xFF; // 1st byte of sector number
*(cfRegisters.lba2) = (sector >> 8) & 0xFF; // 2nd byte of sector number
*(cfRegisters.lba3) = (sector >> 16) & 0xFF; // 3rd byte of sector number
*(cfRegisters.lba4) = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to read
*(cfRegisters.command) = CF_CMD_READ;
while (numSectors--)
{
// Wait until card is ready for reading
i = 0;
while (((*(cfRegisters.status) & 0xff)!= CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Read data
#ifdef _IO_USE_DMA
#ifdef NDS
DMA3_SRC = (u32)(cfRegisters.data);
DMA3_DEST = (u32)buff;
DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_SRC_FIX;
#else
DMA3COPY ( (cfRegisters.data), buff, 256 | DMA16 | DMA_ENABLE | DMA_SRC_FIXED);
#endif
buff += BYTES_PER_READ / 2;
#elif defined _IO_ALLOW_UNALIGNED
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = *(cfRegisters.data);
*buff_u8++ = temp & 0xFF;
*buff_u8++ = temp >> 8;
}
} else {
while(i--)
*buff++ = *(cfRegisters.data);
}
#else
i=256;
while(i--)
*buff++ = *(cfRegisters.data);
#endif
}
#if (defined _IO_USE_DMA) && (defined NDS)
// Wait for end of transfer before returning
while(DMA3_CR & DMA_BUSY);
#endif
return true;
}
/*-----------------------------------------------------------------
_CF_writeSectors
Write 512 byte sector numbered "sector" from "buffer"
u32 sector IN: address of 512 byte sector on CF card to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _CF_writeSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
u16 *buff = (u16*)buffer;
#ifdef _IO_ALLOW_UNALIGNED
u8 *buff_u8 = (u8*)buffer;
int temp;
#endif
#if defined _IO_USE_DMA && defined NDS && defined ARM9
DC_FlushRange( buffer, j * BYTES_PER_READ);
#endif
// Wait until CF card is finished previous commands
i=0;
while ((*(cfRegisters.command) & CF_STS_BUSY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
// Wait until card is ready for commands
i = 0;
while ((!(*(cfRegisters.status) & CF_STS_INSERTED)) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Set number of sectors to write
*(cfRegisters.sectorCount) = (numSectors < 256 ? numSectors : 0); // Write a maximum of 256 sectors, 0 means 256
// Set write sector
*(cfRegisters.lba1) = sector & 0xFF; // 1st byte of sector number
*(cfRegisters.lba2) = (sector >> 8) & 0xFF; // 2nd byte of sector number
*(cfRegisters.lba3) = (sector >> 16) & 0xFF; // 3rd byte of sector number
*(cfRegisters.lba4) = ((sector >> 24) & 0x0F )| CF_CMD_LBA; // last nibble of sector number
// Set command to write
*(cfRegisters.command) = CF_CMD_WRITE;
while (numSectors--)
{
// Wait until card is ready for writing
i = 0;
while (((*(cfRegisters.status) & 0xff) != CF_STS_READY) && (i < CF_CARD_TIMEOUT))
{
i++;
}
if (i >= CF_CARD_TIMEOUT)
return false;
// Write data
#ifdef _IO_USE_DMA
#ifdef NDS
DMA3_SRC = (u32)buff;
DMA3_DEST = (u32)(cfRegisters.data);
DMA3_CR = 256 | DMA_COPY_HALFWORDS | DMA_DST_FIX;
#else
DMA3COPY( buff, (cfRegisters.data), 256 | DMA16 | DMA_ENABLE | DMA_DST_FIXED);
#endif
buff += BYTES_PER_READ / 2;
#elif defined _IO_ALLOW_UNALIGNED
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = *buff_u8++;
temp |= *buff_u8++ << 8;
*(cfRegisters.data) = temp;
}
} else {
while(i--)
*(cfRegisters.data) = *buff++;
}
#else
i=256;
while(i--)
*(cfRegisters.data) = *buff++;
#endif
}
#if defined _IO_USE_DMA && defined NDS
// Wait for end of transfer before returning
while(DMA3_CR & DMA_BUSY);
#endif
return true;
}
/*-----------------------------------------------------------------
_CF_shutdown
shutdown the CF interface
-----------------------------------------------------------------*/
bool _CF_shutdown(void) {
return _CF_clearStatus() ;
}
/*-----------------------------------------------------------------
_CF_startUp
Initializes the CF interface using the supplied registers
returns true if successful, otherwise returns false
-----------------------------------------------------------------*/
bool _CF_startup(const CF_REGISTERS *usableCfRegs) {
cfRegisters = *usableCfRegs;
// See if there is a read/write register
u16 temp = *(cfRegisters.lba1);
*(cfRegisters.lba1) = (~temp & 0xFF);
temp = (~temp & 0xFF);
if (!(*(cfRegisters.lba1) == temp)) {
return false;
}
// Make sure it is 8 bit
*(cfRegisters.lba1) = 0xAA55;
if (*(cfRegisters.lba1) == 0xAA55) {
return false;
}
return true;
}

View File

@@ -0,0 +1,78 @@
/*
io_cf_common.h
By chishm (Michael Chisholm)
Common Compact Flash card values
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-16 - Chishm
* Combined all CF interfaces into one common set of routines
*/
#ifndef IO_CF_COMMON_H
#define IO_CF_COMMON_H
#include "disc_io.h"
typedef struct {
vu16* data;
vu16* status;
vu16* command;
vu16* error;
vu16* sectorCount;
vu16* lba1;
vu16* lba2;
vu16* lba3;
vu16* lba4;
} CF_REGISTERS;
// CF Card status
#define CF_STS_INSERTED 0x50
#define CF_STS_REMOVED 0x00
#define CF_STS_READY 0x58
#define CF_STS_DRQ 0x08
#define CF_STS_BUSY 0x80
// CF Card commands
#define CF_CMD_LBA 0xE0
#define CF_CMD_READ 0x20
#define CF_CMD_WRITE 0x30
#define CF_CARD_TIMEOUT 10000000
bool _CF_isInserted (void);
bool _CF_clearStatus (void);
bool _CF_readSectors (u32 sector, u32 numSectors, void* buffer);
bool _CF_writeSectors (u32 sector, u32 numSectors, void* buffer);
bool _CF_shutdown(void);
bool _CF_startup(const CF_REGISTERS *usableCfRegs);
#endif // define IO_CF_COMMON_H

View File

@@ -0,0 +1,44 @@
/*
io_dldi.h
Reserved space for post-compilation adding of an extra driver
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-12-22 - Chishm
* Original release
*/
#ifndef IO_DLDI_H
#define IO_DLDI_H
// 'DLDD'
#define DEVICE_TYPE_DLDD 0x49444C44
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_dldi ;
#endif // define IO_DLDI_H

View File

@@ -0,0 +1,73 @@
@---------------------------------------------------------------------------------
.align 4
.arm
.global _io_dldi
@---------------------------------------------------------------------------------
.equ FEATURE_MEDIUM_CANREAD, 0x00000001
.equ FEATURE_MEDIUM_CANWRITE, 0x00000002
.equ FEATURE_SLOT_GBA, 0x00000010
.equ FEATURE_SLOT_NDS, 0x00000020
_dldi_start:
@---------------------------------------------------------------------------------
@ Driver patch file standard header -- 16 bytes
.word 0xBF8DA5ED @ Magic number to identify this region
.asciz " Chishm" @ Identifying Magic string (8 bytes with null terminator)
.byte 0x01 @ Version number
.byte 0x0F @32KiB @ Log [base-2] of the size of this driver in bytes.
.byte 0x00 @ Sections to fix
.byte 0x0F @32KiB @ Log [base-2] of the allocated space in bytes.
@---------------------------------------------------------------------------------
@ Text identifier - can be anything up to 47 chars + terminating null -- 16 bytes
.align 4
.asciz "Default (No interface)"
@---------------------------------------------------------------------------------
@ Offsets to important sections within the data -- 32 bytes
.align 6
.word _dldi_start @ data start
.word _dldi_end @ data end
.word 0x00000000 @ Interworking glue start -- Needs address fixing
.word 0x00000000 @ Interworking glue end
.word 0x00000000 @ GOT start -- Needs address fixing
.word 0x00000000 @ GOT end
.word 0x00000000 @ bss start -- Needs setting to zero
.word 0x00000000 @ bss end
@---------------------------------------------------------------------------------
@ IO_INTERFACE data -- 32 bytes
_io_dldi:
.ascii "DLDI" @ ioType
.word 0x00000000 @ Features
.word _DLDI_startup @
.word _DLDI_isInserted @
.word _DLDI_readSectors @ Function pointers to standard device driver functions
.word _DLDI_writeSectors @
.word _DLDI_clearStatus @
.word _DLDI_shutdown @
@---------------------------------------------------------------------------------
_DLDI_startup:
_DLDI_isInserted:
_DLDI_readSectors:
_DLDI_writeSectors:
_DLDI_clearStatus:
_DLDI_shutdown:
mov r0, #0x00 @ Return false for every function
bx lr
@---------------------------------------------------------------------------------
.align
.pool
.space 32632 @ Fill to 32KiB
_dldi_end:
.end
@---------------------------------------------------------------------------------

View File

@@ -0,0 +1,307 @@
/*
io_efa2.c by CyteX
Based on io_mpfc.c by chishm (Michael Chisholm)
Hardware Routines for reading the NAND flash located on
EFA2 flash carts
This software is completely free. No warranty is provided.
If you use it, please give me credit and email me about your
project at cytex <at> gmx <dot> de and do not forget to also
drop chishm <at> hotmail <dot> com a line
Use with permission by Michael "Chishm" Chisholm
*/
#include "io_efa2.h"
//
// EFA2 register addresses
//
// RTC registers
#define REG_RTC_CLK (*(vu16*)0x080000c4)
#define REG_RTC_EN (*(vu16*)0x080000c8)
// "Magic" registers used for unlock/lock sequences
#define REG_EFA2_MAGIC_A (*(vu16*)0x09fe0000)
#define REG_EFA2_MAGIC_B (*(vu16*)0x08000000)
#define REG_EFA2_MAGIC_C (*(vu16*)0x08020000)
#define REG_EFA2_MAGIC_D (*(vu16*)0x08040000)
#define REG_EFA2_MAGIC_E (*(vu16*)0x09fc0000)
// NAND flash lock/unlock register
#define REG_EFA2_NAND_LOCK (*(vu16*)0x09c40000)
// NAND flash enable register
#define REG_EFA2_NAND_EN (*(vu16*)0x09400000)
// NAND flash command write register
#define REG_EFA2_NAND_CMD (*(vu8*)0x09ffffe2)
// NAND flash address/data write register
#define REG_EFA2_NAND_WR (*(vu8*)0x09ffffe0)
// NAND flash data read register
#define REG_EFA2_NAND_RD (*(vu8*)0x09ffc000)
// ID of Samsung K9K1G NAND flash chip
#define EFA2_NAND_ID 0xEC79A5C0
// first sector of udisk
#define EFA2_UDSK_START 0x40
//
// EFA2 access functions
//
// deactivate RTC ports
static inline void _EFA2_rtc_deactivate(void) {
REG_RTC_EN = 0;
}
// unlock register access
static void _EFA2_reg_unlock(void) {
REG_EFA2_MAGIC_A = 0x0d200;
REG_EFA2_MAGIC_B = 0x01500;
REG_EFA2_MAGIC_C = 0x0d200;
REG_EFA2_MAGIC_D = 0x01500;
}
// finish/lock register access
static inline void _EFA2_reg_lock(void) {
REG_EFA2_MAGIC_E = 0x1500;
}
// global reset/init/enable/unlock ?
static void _EFA2_global_unlock(void) {
_EFA2_reg_unlock();
*(vu16*)0x09880000 = 0x08000;
_EFA2_reg_lock();
}
// global lock, stealth mode
/*static void _EFA2_global_lock(void) {
// quite sure there is such a sequence, but haven't had
// a look for it upto now
}*/
// unlock NAND Flash
static void _EFA2_nand_unlock(void) {
_EFA2_reg_unlock();
REG_EFA2_NAND_LOCK = 0x01500;
_EFA2_reg_lock();
}
// lock NAND Flash
static void _EFA2_nand_lock(void) {
_EFA2_reg_unlock();
REG_EFA2_NAND_LOCK = 0x0d200;
_EFA2_reg_lock();
}
//
// Set NAND Flash chip enable and write protection bits ?
//
// val | ~CE | ~WP |
// -----+-----+-----+
// 0 | 0 | 0 |
// 1 | 1 | 0 |
// 3 | 1 | 1 |
// -----+-----+-----+
//
static void _EFA2_nand_enable(u16 val) {
_EFA2_reg_unlock();
REG_EFA2_NAND_EN = val;
_EFA2_reg_lock();
}
//
// Perform NAND reset
// NAND has to be unlocked and enabled when called
//
static inline void _EFA2_nand_reset(void) {
REG_EFA2_NAND_CMD = 0xff; // write reset command
}
//
// Read out NAND ID information, could be used for card detection
//
// | EFA2 1GBit |
// ------------------+------------+
// maker code | 0xEC |
// device code | 0x79 |
// don't care | 0xA5 |
// multi plane code | 0xC0 |
// ------------------+------------+
//
static u32 _EFA2_nand_id(void) {
u8 byte;
u32 id;
_EFA2_nand_unlock();
_EFA2_nand_enable(1);
REG_EFA2_NAND_CMD = 0x90; // write id command
REG_EFA2_NAND_WR = 0x00; // (dummy) address cycle
byte = REG_EFA2_NAND_RD; // read maker code
id = byte;
byte = REG_EFA2_NAND_RD; // read device code
id = (id << 8) | byte;
byte = REG_EFA2_NAND_RD; // read don't care
id = (id << 8) | byte;
byte = REG_EFA2_NAND_RD; // read multi plane code
id = (id << 8) | byte;
_EFA2_nand_enable(0);
_EFA2_nand_lock();
return (id);
}
//
// Start of gba_nds_fat block device description
//
/*-----------------------------------------------------------------
EFA2_clearStatus
Reads and checks NAND status information
bool return OUT: true if NAND is idle
-----------------------------------------------------------------*/
bool _EFA2_clearStatus (void)
{
// tbd: currently there is no write support, so always return
// true, there is no possibility for pending operations
return true;
}
/*-----------------------------------------------------------------
EFA2_isInserted
Checks to see if the NAND chip used by the EFA2 is present
bool return OUT: true if the correct NAND chip is found
-----------------------------------------------------------------*/
bool _EFA2_isInserted (void)
{
_EFA2_clearStatus();
return (_EFA2_nand_id() == EFA2_NAND_ID);
}
/*-----------------------------------------------------------------
EFA2_readSectors
Read "numSecs" 512 byte sectors starting from "sector" into "buffer"
No error correction, no use of spare cells, no use of R/~B signal
u32 sector IN: number of first 512 byte sector to be read
u32 numSecs IN: number of 512 byte sectors to read,
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _EFA2_readSectors (u32 sector, u32 numSecs, void* buffer)
{
int i;
#ifndef _IO_ALLOW_UNALIGNED
u8 byte;
u16 word;
#endif
// NAND page 0x40 (EFA2_UDSK_START) contains the MBR of the
// udisk and thus is sector 0. The original EFA2 firmware
// does never look at this, it only watches page 0x60, which
// contains the boot block of the FAT16 partition. That is
// fixed, so the EFA2 udisk must not be reformated, else
// the ARK Octopus and also the original Firmware won't be
// able to access the udisk anymore and I have to write a
// recovery tool.
u32 page = EFA2_UDSK_START + sector;
// future enhancement: wait for possible write operations to
// be finisched
if (!_EFA2_clearStatus()) return false;
_EFA2_nand_unlock();
_EFA2_nand_enable(1);
_EFA2_nand_reset();
// set NAND to READ1 operation mode and transfer page address
REG_EFA2_NAND_CMD = 0x00; // write READ1 command
REG_EFA2_NAND_WR = 0x00; // write address [7:0]
REG_EFA2_NAND_WR = (page ) & 0xff; // write address [15:8]
REG_EFA2_NAND_WR = (page >> 8 ) & 0xff; // write address[23:16]
REG_EFA2_NAND_WR = (page >> 16) & 0xff; // write address[26:24]
// Due to a bug in EFA2 design there is need to waste some cycles
// "by hand" instead the possibility to check the R/~B port of
// the NAND flash via a register. The RTC deactivation is only
// there to make sure the loop won't be optimized by the compiler
for (i=0 ; i < 3 ; i++) _EFA2_rtc_deactivate();
while (numSecs--)
{
// read page data
#ifdef _IO_ALLOW_UNALIGNED
// slow byte access to RAM, but works in principle
for (i=0 ; i < 512 ; i++)
((u8*)buffer)[i] = REG_EFA2_NAND_RD;
#else
// a bit faster, but DMA is not possible
for (i=0 ; i < 256 ; i++) {
byte = REG_EFA2_NAND_RD; // read lo-byte
word = byte;
byte = REG_EFA2_NAND_RD; // read hi-byte
word = word | (byte << 8);
((u16*)buffer)[i] = word;
}
#endif
}
_EFA2_nand_enable(0);
_EFA2_nand_lock();
return true;
}
/*-----------------------------------------------------------------
EFA2_writeSectors
Write "numSecs" 512 byte sectors starting at "sector" from "buffer"
u32 sector IN: address of 512 byte sector on card to write
u32 numSecs IN: number of 512 byte sectors to write
1 to 256 sectors can be written, 0 = 256
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _EFA2_writeSectors (u32 sector, u8 numSecs, void* buffer)
{
// Upto now I focused on reading NAND, write operations
// will follow
return false;
}
/*-----------------------------------------------------------------
EFA2_shutdown
unload the EFA2 interface
-----------------------------------------------------------------*/
bool _EFA2_shutdown(void)
{
return _EFA2_clearStatus();
}
/*-----------------------------------------------------------------
EFA2_startUp
initializes the EFA2 card, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _EFA2_startUp(void)
{
_EFA2_global_unlock();
return (_EFA2_nand_id() == EFA2_NAND_ID);
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_efa2 = {
DEVICE_TYPE_EFA2,
FEATURE_MEDIUM_CANREAD | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_EFA2_startUp,
(FN_MEDIUM_ISINSERTED)&_EFA2_isInserted,
(FN_MEDIUM_READSECTORS)&_EFA2_readSectors,
(FN_MEDIUM_WRITESECTORS)&_EFA2_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_EFA2_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_EFA2_shutdown
};

View File

@@ -0,0 +1,23 @@
/*
io_efa2.h by CyteX
Based on io_mpfc.h by chishm (Michael Chisholm)
Hardware Routines for reading the NAND flash located on
EFA2 flash carts
Used with permission from Cytex.
*/
#ifndef IO_EFA2_H
#define IO_EFA2_H
// 'EFA2'
#define DEVICE_TYPE_EFA2 0x32414645
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_efa2;
#endif // define IO_EFA2_H

View File

@@ -0,0 +1,334 @@
/*
io_fcsr.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for using a GBA Flash Cart and SRAM as a
block device.
The file system must be 512 byte aligned, in cart address space.
SRAM is supported.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_fcsr.h"
#include <string.h>
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
#ifdef NDS
#define SRAM_START 0x0A000000
#else
#define SRAM_START 0x0E000000
#endif
#define NO_SRAM 0xFFFFFFFF
#define FCSR 0x52534346
const char _FCSR_LabelString[] = " Chishm FAT";
u8* _FCSR_FileSysPointer = 0;
u8* _FCSR_SramSectorPointer[4] = {0,0,0,0};
u32 _FCSR_SramSectorStart[4] = {0,0,0,0};
u32 _FCSR_SramSectorEnd[4] = {0,0,0,0};
/*-----------------------------------------------------------------
_FCSR_isInserted
Is a GBA Flash Cart with a valid file system inserted?
bool return OUT: true if a GBA FC card is inserted
-----------------------------------------------------------------*/
bool _FCSR_isInserted (void)
{
bool flagFoundFileSys = false;
u32* fileSysPointer = (u32*)0x08000100; // Start at beginning of cart address space, offset by expected location of string
// Search for file system
while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys) // Only search while not at end of cart address space
{
while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
fileSysPointer += 0x40;
if ((strncmp(_FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
{
flagFoundFileSys = true;
} else {
fileSysPointer += 0x80;
}
}
return flagFoundFileSys;
}
/*-----------------------------------------------------------------
_FCSR_clearStatus
Finish any pending operations
bool return OUT: always true for GBA FC
-----------------------------------------------------------------*/
bool _FCSR_clearStatus (void)
{
return true;
}
/*-----------------------------------------------------------------
_FCSR_readSectors
Read 512 byte sector numbered "sector" into "buffer"
u32 sector IN: address of first 512 byte sector on Flash Cart to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer OUT: pointer to 512 byte buffer to store data in
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _FCSR_readSectors (u32 sector, u32 numSectors, void* buffer)
{
int i;
bool flagSramSector = false;
int readLength = numSectors * BYTES_PER_READ;
u8* src;;
u8* dst;
// Find which region this read is in
for (i = 0; (i < 4) && !flagSramSector; i++)
{
if ((sector >= _FCSR_SramSectorStart[i]) && (sector < _FCSR_SramSectorEnd[i]))
{
flagSramSector = true;
break;
}
}
// Make sure read will be completely in SRAM range if it is partially there
if ( flagSramSector && ((sector + numSectors) > _FCSR_SramSectorEnd[i]))
return false;
// Copy data to buffer
if (flagSramSector)
{
src = _FCSR_SramSectorPointer[i] + (sector - _FCSR_SramSectorStart[i]) * BYTES_PER_READ;
} else {
src = _FCSR_FileSysPointer + sector * BYTES_PER_READ;
}
dst = (u8*)buffer;
if (flagSramSector)
{
while (readLength--)
{
*dst++ = *src++;
}
} else { // Reading from Cart ROM
#ifdef _IO_USE_DMA
#ifdef NDS
#ifdef ARM9
DC_FlushRange( buffer, readLength);
#endif // ARM9
DMA3_SRC = (u32)src;
DMA3_DEST = (u32)buffer;
DMA3_CR = (readLength >> 1) | DMA_COPY_HALFWORDS;
#else // ! NDS
DMA3COPY ( src, buffer, (readLength >> 1) | DMA16 | DMA_ENABLE);
#endif // NDS
#else // !_IO_USE_DMA
memcpy (buffer, src, readLength);
#endif // _IO_USE_DMA
} // if (flagSramSector)
return true;
}
/*-----------------------------------------------------------------
_FCSR_writeSectors
Write 512 byte sector numbered "sector" from "buffer"
u32 sector IN: address of 512 byte sector on Flash Cart to read
u32 numSectors IN: number of 512 byte sectors to read,
1 to 256 sectors can be read
void* buffer IN: pointer to 512 byte buffer to read data from
bool return OUT: true if successful
-----------------------------------------------------------------*/
bool _FCSR_writeSectors (u32 sector, u8 numSectors, void* buffer)
{
int i;
bool flagSramSector = false;
u32 writeLength = numSectors * BYTES_PER_READ;
u8* src = (u8*) buffer;
u8* dst;
// Find which region this sector belongs in
for (i = 0; (i < 4) && !flagSramSector; i++)
{
if ((sector >= _FCSR_SramSectorStart[i]) && (sector < _FCSR_SramSectorEnd[i]))
{
flagSramSector = true;
break;
}
}
if (!flagSramSector)
return false;
// Entire write must be within an SRAM region
if ((sector + numSectors) > _FCSR_SramSectorEnd[i])
return false;
// Copy data to SRAM
dst = _FCSR_SramSectorPointer[i] + (sector - _FCSR_SramSectorStart[i]) * BYTES_PER_READ;
while (writeLength--)
{
*dst++ = *src++;
}
return true;
}
/*-----------------------------------------------------------------
_FCSR_shutdown
unload the Flash Cart interface
-----------------------------------------------------------------*/
bool _FCSR_shutdown(void)
{
int i;
if (_FCSR_clearStatus() == false)
return false;
_FCSR_FileSysPointer = 0;
for (i=0; i < 4; i++)
{
_FCSR_SramSectorPointer[i] = 0;
_FCSR_SramSectorStart[i] = 0;
_FCSR_SramSectorEnd[i] = 0;
}
return true;
}
/*-----------------------------------------------------------------
_FCSR_startUp
initializes the Flash Cart interface, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _FCSR_startUp(void)
{
bool flagFoundFileSys = false;
int i;
int SramRegionSize[4];
u8* srcByte;
u8* destByte;
u32* fileSysPointer = (u32*)0x08000100; // Start at beginning of cart address space, offset by expected location of string
// Search for file system
while ((fileSysPointer < (u32*)0x0A000000) && !flagFoundFileSys) // Only search while not at end of cart address space
{
while ((*fileSysPointer != FCSR) && (fileSysPointer < (u32*)0x0A000000))
fileSysPointer += 0x40;
if ((strncmp(_FCSR_LabelString, (char*)(fileSysPointer + 1), 12) == 0) && (fileSysPointer < (u32*)0x0A000000))
{
flagFoundFileSys = true;
} else {
fileSysPointer += 0x80;
}
}
if (!flagFoundFileSys)
return false;
// Flash cart file system pointer has been found
_FCSR_FileSysPointer = (u8*)(fileSysPointer - 0x40);
// Get SRAM sector regions from header block
for (i = 0; i < 4; i++)
{
_FCSR_SramSectorStart[i] = fileSysPointer[i+4];
SramRegionSize[i] = fileSysPointer[i+8];
_FCSR_SramSectorEnd[i] = _FCSR_SramSectorStart[i] + SramRegionSize[i];
}
// Calculate SRAM region pointers
_FCSR_SramSectorPointer[0] = (u8*)(SRAM_START + 4);
for (i = 1; i < 4; i++)
{
_FCSR_SramSectorPointer[i] = _FCSR_SramSectorPointer[i-1] + (SramRegionSize[i-1] * BYTES_PER_READ);
}
// Initialise SRAM with overlay if it hasn't been done so
if ( (*((u8*)SRAM_START) != 'F') || (*((u8*)(SRAM_START+1)) != 'C') || (*((u8*)(SRAM_START+2)) != 'S') || (*((u8*)(SRAM_START+3)) != 'R') )
{
*((u8*)SRAM_START) = 'F';
*((u8*)(SRAM_START+1)) = 'C';
*((u8*)(SRAM_START+2)) = 'S';
*((u8*)(SRAM_START+3)) = 'R';
for (i = 0; i < 4; i++)
{
srcByte = _FCSR_FileSysPointer + (_FCSR_SramSectorStart[i] * BYTES_PER_READ);
destByte = _FCSR_SramSectorPointer[i];
while (srcByte < _FCSR_FileSysPointer + (_FCSR_SramSectorEnd[i] * BYTES_PER_READ) )
*destByte++ = *srcByte++;
}
}
// Get SRAM sector regions from header block
for (i = 0; i < 4; i++)
{
if (SramRegionSize[i] == 0)
{
_FCSR_SramSectorStart[i] = NO_SRAM;
_FCSR_SramSectorEnd[i] = NO_SRAM;
}
}
return true;
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_fcsr = {
DEVICE_TYPE_FCSR, // 'FCSR'
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_FCSR_startUp,
(FN_MEDIUM_ISINSERTED)&_FCSR_isInserted,
(FN_MEDIUM_READSECTORS)&_FCSR_readSectors,
(FN_MEDIUM_WRITESECTORS)&_FCSR_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_FCSR_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_FCSR_shutdown
} ;

View File

@@ -0,0 +1,44 @@
/*
io_fcsr.h
Hardware Routines for using a GBA Flash Cart with SRAM
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_FCSR_H
#define IO_FCSR_H
// 'FCSR'
#define DEVICE_TYPE_FCSR 0x52534346
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_fcsr ;
#endif // define IO_FCSR_H

View File

@@ -0,0 +1,60 @@
/*
io_m3_common.c
Routines common to all version of the M3
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_m3_common.h"
static u16 _M3_readHalfword (u32 addr) {
return *((vu16*)addr);
}
void _M3_changeMode (u32 mode) {
_M3_readHalfword (0x08e00002);
_M3_readHalfword (0x0800000e);
_M3_readHalfword (0x08801ffc);
_M3_readHalfword (0x0800104a);
_M3_readHalfword (0x08800612);
_M3_readHalfword (0x08000000);
_M3_readHalfword (0x08801b66);
_M3_readHalfword (0x08000000 + (mode << 1));
_M3_readHalfword (0x0800080e);
_M3_readHalfword (0x08000000);
if ((mode & 0x0f) != 4) {
_M3_readHalfword (0x09000000);
} else {
_M3_readHalfword (0x080001e4);
_M3_readHalfword (0x080001e4);
_M3_readHalfword (0x08000188);
_M3_readHalfword (0x08000188);
}
}

View File

@@ -0,0 +1,48 @@
/*
io_m3_common.h
Routines common to all version of the M3
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3_COMMON_H
#define IO_M3_COMMON_H
#include "disc_io.h"
// Values for changing mode
#define M3_MODE_ROM 0x00400004
#define M3_MODE_MEDIA 0x00400003
extern void _M3_changeMode (u32 mode);
#endif // IO_M3_COMMON_H

View File

@@ -0,0 +1,96 @@
/*
io_m3cf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the M3 Perfect CF Adapter
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_m3cf.h"
#include "io_m3_common.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// M3 CF Addresses
#define REG_M3CF_STS ((vu16*)0x080C0000) // Status of the CF Card / Device control
#define REG_M3CF_CMD ((vu16*)0x088E0000) // Commands sent to control chip and status return
#define REG_M3CF_ERR ((vu16*)0x08820000) // Errors / Features
#define REG_M3CF_SEC ((vu16*)0x08840000) // Number of sector to transfer
#define REG_M3CF_LBA1 ((vu16*)0x08860000) // 1st byte of sector address
#define REG_M3CF_LBA2 ((vu16*)0x08880000) // 2nd byte of sector address
#define REG_M3CF_LBA3 ((vu16*)0x088A0000) // 3rd byte of sector address
#define REG_M3CF_LBA4 ((vu16*)0x088C0000) // last nibble of sector address | 0xE0
#define REG_M3CF_DATA ((vu16*)0x08800000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _M3CF_Registers = {
REG_M3CF_DATA,
REG_M3CF_STS,
REG_M3CF_CMD,
REG_M3CF_ERR,
REG_M3CF_SEC,
REG_M3CF_LBA1,
REG_M3CF_LBA2,
REG_M3CF_LBA3,
REG_M3CF_LBA4
};
bool _M3CF_startup(void) {
_M3_changeMode (M3_MODE_MEDIA);
return _CF_startup (&_M3CF_Registers);
}
const IO_INTERFACE _io_m3cf = {
DEVICE_TYPE_M3CF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_M3CF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@@ -0,0 +1,45 @@
/*
io_m3cf.h
Hardware Routines for reading a compact flash card
using the M3 CF
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3CF_H
#define IO_M3CF_H
// 'M3CF'
#define DEVICE_TYPE_M3CF 0x4643334D
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_m3cf ;
#endif // define IO_M3CF_H

View File

@@ -0,0 +1,518 @@
/*
io_m3sd.c
Hardware Routines for reading a Secure Digital card
using the M3 SD
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-25 - Chishm
* Improved startup function that doesn't delay hundreds of seconds
before reporting no card inserted.
* Fixed writeData function to timeout on error
* writeSectors function now wait until the card is ready before continuing with a transfer
2006-08-05 - Chishm
* Tries multiple times to get a Relative Card Address at startup
2006-08-07 - Chishm
* Moved the SD initialization to a common function
*/
#include "io_m3sd.h"
#include "io_sd_common.h"
#include "io_m3_common.h"
//---------------------------------------------------------------
// M3SD register addresses
#define REG_M3SD_DIR (*(vu16*)0x08800000) // direction control register
#define REG_M3SD_DAT (*(vu16*)0x09000000) // SD data line, 8 bits at a time
#define REG_M3SD_CMD (*(vu16*)0x09200000) // SD command byte
#define REG_M3SD_ARGH (*(vu16*)0x09400000) // SD command argument, high halfword
#define REG_M3SD_ARGL (*(vu16*)0x09600000) // SD command argument, low halfword
#define REG_M3SD_STS (*(vu16*)0x09800000) // command and status register
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 20000 // Time to wait for the M3 to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
//---------------------------------------------------------------
// Variables required for tracking SD state
static u32 _M3SD_relativeCardAddress = 0; // Preshifted Relative Card Address
//---------------------------------------------------------------
// Internal M3 SD functions
static inline void _M3SD_unlock (void) {
_M3_changeMode (M3_MODE_MEDIA);
}
static inline bool _M3SD_waitOnBusy (void) {
int i = 0;
while ( (REG_M3SD_STS & 0x01) == 0x00) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static inline bool _M3SD_waitForDataReady (void) {
int i = 0;
while ( (REG_M3SD_STS & 0x40) == 0x00) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static bool _M3SD_sendCommand (u16 command, u32 argument) {
REG_M3SD_STS = 0x8;
REG_M3SD_CMD = 0x40 + command; // Include the start bit
REG_M3SD_ARGH = argument >> 16;
REG_M3SD_ARGL = argument;
// The CRC7 of the command is calculated by the M3
REG_M3SD_DIR=0x29;
if (!_M3SD_waitOnBusy()) {
REG_M3SD_DIR=0x09;
return false;
}
REG_M3SD_DIR=0x09;
return true;
}
static bool _M3SD_sendByte (u8 byte) {
int i = 0;
REG_M3SD_DAT = byte;
REG_M3SD_DIR = 0x03;
REG_M3SD_STS = 0x01;
while ((REG_M3SD_STS & 0x04) == 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
return false;
}
}
return true;
}
static u8 _M3SD_getByte (void) {
int i;
// Request 8 bits of data from the SD's CMD pin
REG_M3SD_DIR = 0x02;
REG_M3SD_STS = 0x02;
// Wait for the data to be ready
i = 0;
while ((REG_M3SD_STS & 0x08) == 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
// Return an empty byte if a timeout occurs
return 0xFF;
}
}
i = 0;
while ((REG_M3SD_STS & 0x08) != 0) {
i++;
if (i >= TRANSMIT_TIMEOUT) {
// Return an empty byte if a timeout occurs
return 0xFF;
}
}
// Return the data
return (REG_M3SD_DAT & 0xff);
}
// Returns the response from the SD card to a previous command.
static bool _M3SD_getResponse (u8* dest, u32 length) {
u32 i;
u8 dataByte;
int shiftAmount;
// Wait for the card to be non-busy
for (i = 0; i < RESPONSE_TIMEOUT; i++) {
dataByte = _M3SD_getByte();
if (dataByte != SD_CARD_BUSY) {
break;
}
}
if (dest == NULL) {
return true;
}
// Still busy after the timeout has passed
if (dataByte == 0xff) {
return false;
}
// Read response into buffer
for ( i = 0; i < length; i++) {
dest[i] = dataByte;
dataByte = _M3SD_getByte();
}
// dataByte will contain the last piece of the response
// Send 16 more clocks, 8 more than the delay required between a response and the next command
i = _M3SD_getByte();
i = _M3SD_getByte();
// Shift response so that the bytes are correctly aligned
// The register may not contain properly aligned data
for (shiftAmount = 0; ((dest[0] << shiftAmount) & 0x80) != 0x00; shiftAmount++) {
if (shiftAmount >= 7) {
return false;
}
}
for (i = 0; i < length - 1; i++) {
dest[i] = (dest[i] << shiftAmount) | (dest[i+1] >> (8-shiftAmount));
}
// Get the last piece of the response from dataByte
dest[i] = (dest[i] << shiftAmount) | (dataByte >> (8-shiftAmount));
return true;
}
static inline bool _M3SD_getResponse_R1 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R1b (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R2 (u8* dest) {
return _M3SD_getResponse (dest, 17);
}
static inline bool _M3SD_getResponse_R3 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static inline bool _M3SD_getResponse_R6 (u8* dest) {
return _M3SD_getResponse (dest, 6);
}
static void _M3SD_sendClocks (u32 numClocks) {
while (numClocks--) {
_M3SD_sendByte(0xff);
}
}
static void _M3SD_getClocks (u32 numClocks) {
while (numClocks--) {
_M3SD_getByte();
}
}
bool _M3SD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
_M3SD_sendCommand (command, data);
return _M3SD_getResponse (responseBuffer, 6);
}
bool _M3SD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
_M3SD_sendCommand (command, data);
return _M3SD_getResponse (responseBuffer, 17);
}
static bool _M3SD_initCard (void) {
// Give the card time to stabilise
_M3SD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_M3SD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_M3SD_getClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_M3SD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard (_M3SD_cmd_6byte_response,
_M3SD_cmd_17byte_response,
true,
&_M3SD_relativeCardAddress);
}
static bool _M3SD_readData (void* buffer) {
u32 i;
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
u16 temp;
REG_M3SD_DIR = 0x49;
if (!_M3SD_waitForDataReady()) {
REG_M3SD_DIR = 0x09;
return false;
}
REG_M3SD_DIR = 0x09;
REG_M3SD_DIR = 0x8;
REG_M3SD_STS = 0x4;
i = REG_M3SD_DIR;
// Read data
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--)
{
temp = REG_M3SD_DIR;
*buff_u8++ = temp & 0xFF;
*buff_u8++ = temp >> 8;
}
} else {
while(i--)
*buff++ = REG_M3SD_DIR;
}
// Read end checksum
i = REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR + REG_M3SD_DIR;
return true;
}
static void _M3SD_clkout (void) {
REG_M3SD_DIR = 0x4;
REG_M3SD_DIR = 0xc;
/* __asm volatile (
"ldr r1, =0x08800000 \n"
"mov r0, #0x04 \n"
"strh r0, [r1] \n"
"mov r0, r0 \n"
"mov r0, r0 \n"
"mov r0, #0x0c \n"
"strh r0, [r1] \n"
: // Outputs
: // Inputs
: "r0", "r1" // Clobber list
);*/
}
static void _M3SD_clkin (void) {
REG_M3SD_DIR = 0x0;
REG_M3SD_DIR = 0x8;
/* __asm volatile (
"ldr r1, =0x08800000 \n"
"mov r0, #0x00 \n"
"strh r0, [r1] \n"
"mov r0, r0 \n"
"mov r0, r0 \n"
"mov r0, #0x08 \n"
"strh r0, [r1] \n"
: // Outputs
: // Inputs
: "r0", "r1" // Clobber list
);*/
}
static bool _M3SD_writeData (u8* data, u8* crc) {
int i;
u8 temp;
do {
_M3SD_clkin();
} while ((REG_M3SD_DAT & 0x100) == 0);
REG_M3SD_DAT = 0; // Start bit
_M3SD_clkout();
for (i = 0; i < BYTES_PER_READ; i++) {
temp = (*data++);
REG_M3SD_DAT = temp >> 4;
_M3SD_clkout();
REG_M3SD_DAT = temp;
_M3SD_clkout();
}
if (crc != NULL) {
for (i = 0; i < 8; i++) {
temp = (*crc++);
REG_M3SD_DAT = temp >> 4;
_M3SD_clkout();
REG_M3SD_DAT = temp;
_M3SD_clkout();
}
}
i = 32;
while (i--) {
temp += 2; // a NOP to stop the compiler optimising out the loop
}
for (i = 0; i < 32; i++) {
REG_M3SD_DAT = 0xff;
_M3SD_clkout();
}
do {
_M3SD_clkin();
} while ((REG_M3SD_DAT & 0x100) == 0);
return true;
}
//---------------------------------------------------------------
// Functions needed for the external interface
bool _M3SD_startUp (void) {
_M3SD_unlock();
return _M3SD_initCard();
}
bool _M3SD_isInserted (void) {
u8 responseBuffer [6];
// Make sure the card receives the command
if (!_M3SD_sendCommand (SEND_STATUS, 0)) {
return false;
}
// Make sure the card responds
if (!_M3SD_getResponse_R1 (responseBuffer)) {
return false;
}
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _M3SD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
if (numSectors == 1) {
// If it's only reading one sector, use the (slightly faster) READ_SINGLE_BLOCK
if (!_M3SD_sendCommand (READ_SINGLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
if (!_M3SD_readData (buffer)) {
return false;
}
} else {
// Stream the required number of sectors from the card
if (!_M3SD_sendCommand (READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
for(i=0; i < numSectors; i++, dest+=BYTES_PER_READ) {
if (!_M3SD_readData(dest)) {
return false;
}
REG_M3SD_STS = 0x8;
}
// Stop the streaming
_M3SD_sendCommand (STOP_TRANSMISSION, 0);
_M3SD_getResponse_R1b (responseBuffer);
}
return true;
}
bool _M3SD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u8 crc[8];
u8 responseBuffer[6];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
// Precalculate the data CRC
_SD_CRC16 ( data, BYTES_PER_READ, crc);
while (numSectors--) {
// Send a single sector write command
_M3SD_sendCommand (WRITE_BLOCK, offset);
if (!_M3SD_getResponse_R1 (responseBuffer)) {
return false;
}
REG_M3SD_DIR = 0x4;
REG_M3SD_STS = 0x0;
// Send the data
if (! _M3SD_writeData( data, crc)) {
return false;
}
if (numSectors > 0) {
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
// Calculate the next CRC while waiting for the card to finish writing
_SD_CRC16 ( data, BYTES_PER_READ, crc);
}
// Wait for the card to be ready for the next transfer
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_M3SD_sendCommand (SEND_STATUS, _M3SD_relativeCardAddress);
_M3SD_getResponse_R1 (responseBuffer);
i--;
if (i <= 0) {
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
}
return true;
}
bool _M3SD_clearStatus (void) {
return _M3SD_initCard ();
}
bool _M3SD_shutdown (void) {
_M3_changeMode (M3_MODE_ROM);
return true;
}
const IO_INTERFACE _io_m3sd = {
DEVICE_TYPE_M3SD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_M3SD_startUp,
(FN_MEDIUM_ISINSERTED)&_M3SD_isInserted,
(FN_MEDIUM_READSECTORS)&_M3SD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_M3SD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_M3SD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_M3SD_shutdown
} ;

View File

@@ -0,0 +1,48 @@
/*
io_m3sd.h
Hardware Routines for reading a Secure Digital card
using the M3 SD
Some code based on M3 SD drivers supplied by M3Adapter.
Some code written by SaTa may have been unknowingly used.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_M3SD_H
#define IO_M3SD_H
// 'M3SD'
#define DEVICE_TYPE_M3SD 0x4453334D
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_m3sd ;
#endif // define IO_M3SD_H

View File

@@ -0,0 +1,100 @@
/*
io_mpcf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the GBA Movie Player
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_mpcf.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// DMA
#ifdef _IO_USE_DMA
#ifndef NDS
#include "gba_dma.h"
#else
#include <nds/dma.h>
#ifdef ARM9
#include <nds/arm9/cache.h>
#endif
#endif
#endif
//---------------------------------------------------------------
// GBAMP CF Addresses
#define REG_MPCF_STS ((vu16*)0x098C0000) // Status of the CF Card / Device control
#define REG_MPCF_CMD ((vu16*)0x090E0000) // Commands sent to control chip and status return
#define REG_MPCF_ERR ((vu16*)0x09020000) // Errors / Features
#define REG_MPCF_SEC ((vu16*)0x09040000) // Number of sector to transfer
#define REG_MPCF_LBA1 ((vu16*)0x09060000) // 1st byte of sector address
#define REG_MPCF_LBA2 ((vu16*)0x09080000) // 2nd byte of sector address
#define REG_MPCF_LBA3 ((vu16*)0x090A0000) // 3rd byte of sector address
#define REG_MPCF_LBA4 ((vu16*)0x090C0000) // last nibble of sector address | 0xE0
#define REG_MPCF_DATA ((vu16*)0x09000000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _MPCF_Registers = {
REG_MPCF_DATA,
REG_MPCF_STS,
REG_MPCF_CMD,
REG_MPCF_ERR,
REG_MPCF_SEC,
REG_MPCF_LBA1,
REG_MPCF_LBA2,
REG_MPCF_LBA3,
REG_MPCF_LBA4
};
/*-----------------------------------------------------------------
_MPCF_startup
initializes the CF interface, returns true if successful,
otherwise returns false
-----------------------------------------------------------------*/
bool _MPCF_startup(void) {
return _CF_startup(&_MPCF_Registers);
}
/*-----------------------------------------------------------------
the actual interface structure
-----------------------------------------------------------------*/
const IO_INTERFACE _io_mpcf = {
DEVICE_TYPE_MPCF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_MPCF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@@ -0,0 +1,45 @@
/*
io_mpcf.h
Hardware Routines for reading a compact flash card
using the GBA Movie Player
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_MPCF_H
#define IO_MPCF_H
// 'MPCF'
#define DEVICE_TYPE_MPCF 0x4643504D
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_mpcf ;
#endif // define IO_MPCF_H

View File

@@ -0,0 +1,595 @@
/*
io_njsd.c
Hardware Routines for reading an SD card using
a NinjaDS SD adapter.
Original code supplied by NinjaMod
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-05 - Chishm
* First release
2006-08-06 - Chishm
* Removed unneeded _NJSD_writeRAM function
* Removed casts for calls to cardWriteCommand
2006-08-07 - Chishm
* Moved the SD initialization to a common function
*/
#include "io_njsd.h"
#ifdef NDS
#include <nds.h>
#include <string.h>
#include "io_sd_common.h"
#define _NJSD_SYNC
//---------------------------------------------------------------
// Card communication speeds
#define SD_CLK_167KHz 00
#define SD_CLK_250KHz 01
#define SD_CLK_5MHz 02
#define SD_CLK_25MHz 03
//---------------------------------------------------------------
// Response types
#define SD_RSP_48 0
#define SD_RSP_136 1
#define SD_RSP_DATA 2
#define SD_RSP_STREAM 3
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define IRQ_TIMEOUT 1000000
#define RESET_TIMEOUT 10000
#define COMMAND_TIMEOUT 100000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
static const u8 _NJSD_read_cmd[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40};
static const u8 _NJSD_read_end_cmd[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x41};
static int _NJSD_speed = SD_CLK_5MHz; // Default speed;
static u32 _NJSD_cardFlags;
static u32 _NJSD_relativeCardAddress = 0;
static inline bool _NJSD_waitIRQ(void) {
int i = IRQ_TIMEOUT;
while (!(REG_IF & 0x100000) && --i);
REG_IF = 0x100000;
if (i <= 0) {
return false;
} else {
return true;
}
}
static inline void _NJSD_writeCardCommand
(u8 cmd0, u8 cmd1, u8 cmd2, u8 cmd3, u8 cmd4, u8 cmd5, u8 cmd6, u8 cmd7)
{
CARD_COMMAND[0] = cmd0;
CARD_COMMAND[1] = cmd1;
CARD_COMMAND[2] = cmd2;
CARD_COMMAND[3] = cmd3;
CARD_COMMAND[4] = cmd4;
CARD_COMMAND[5] = cmd5;
CARD_COMMAND[6] = cmd6;
CARD_COMMAND[7] = cmd7;
}
static bool _NJSD_reset (void) {
int i;
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
CARD_CR2 = 0xA0406000;
i = RESET_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
return false;
}
return true;
}
static bool _NJSD_init (u32 flags) {
_NJSD_cardFlags = flags;
REG_IF = 0x100000; // Clear cart IRQ.
irqDisable (IRQ_CARD_LINE);
if (! _NJSD_reset() ) {
return false;
}
return true;
}
static bool _NJSD_sendCMDR (int speed, u8 *rsp_buf, int type, u8 cmd, u32 param) {
int i;
u32 data;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
REG_IF = 0x100000;
CARD_CR1H = CARD_CR1_ENABLE;
if ((type & 3) < 2) {
CARD_COMMAND[0] = 0xF0 | (speed << 2) | 1 | (type << 1);
} else if ((type & 3) == 2) {
CARD_COMMAND[0] = 0xE0 | (speed << 2) | 0 | (1 << 1);
} else {
CARD_COMMAND[0] = 0xF0 | (speed << 2) | 0 | (1 << 1);
}
CARD_COMMAND[1] = (type & 0x40) | ((( type >> 2) & 7) << 3);
CARD_COMMAND[2] = 0x40 | cmd;
CARD_COMMAND[3] = (param>>24) & 0xFF;
CARD_COMMAND[4] = (param>>16) & 0xFF;
CARD_COMMAND[5] = (param>>8) & 0xFF;
CARD_COMMAND[6] = (param>>0) & 0xFF;
CARD_COMMAND[7] = 0; // offset = 0
if ((type & 3) < 2) {
CARD_CR2 = _NJSD_cardFlags | 0x01000000;
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
i = 0;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data=CARD_DATA_RD;
if (rsp_buf != NULL) {
if (i == 4) {
rsp_buf[0] = (data>>0)&0xFF;
rsp_buf[1] = (data>>8)&0xFF;
rsp_buf[2] = (data>>16)&0xFF;
rsp_buf[3] = (data>>24)&0xFF;
} else if (i == 5) {
rsp_buf[4] = (data>>0)&0xFF;
rsp_buf[5] = (data>>8)&0xFF;
}
}
i++;
}
} while (CARD_CR2 & CARD_BUSY);
} else {
CARD_CR2 = _NJSD_cardFlags;
while (CARD_CR2 & CARD_BUSY);
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_writeSector (u8 *buffer, u8 *crc_buf, u32 offset) {
int i;
u8 responseBuffer[6];
u32 data;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
CARD_CR2 = 0xA0406000;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
for (i = 0; i < 65; i++)
{
CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
if (i < 64)
{
_NJSD_writeCardCommand (buffer[i*8+0], buffer[i*8+1], buffer[i*8+2], buffer[i*8+3],
buffer[i*8+4], buffer[i*8+5], buffer[i*8+6], buffer[i*8+7]);
} else {
_NJSD_writeCardCommand (crc_buf[0], crc_buf[1], crc_buf[2], crc_buf[3],
crc_buf[4], crc_buf[5], crc_buf[6], crc_buf[7]);
}
CARD_CR2 = 0xA7406000;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data=CARD_DATA_RD;
}
} while (CARD_CR2 & CARD_BUSY);
}
CARD_CR1H = CARD_CR1_ENABLE;
_NJSD_writeCardCommand (0xF0 | (1 << 2) | 1, 0x80, 0x40 | WRITE_BLOCK, (u8)(offset>>24),
(u8)(offset>>16), (u8)(offset>>8), (u8)(offset>>0), 0x00);
CARD_CR2 = 0xA7406000;
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
i = 0;
do {
// Read data if available
if (CARD_CR2 & CARD_DATA_READY) {
data = CARD_DATA_RD;
if (i == 2) {
responseBuffer[0] = (u8)(data>>0);
responseBuffer[1] = (u8)(data>>8);
responseBuffer[2] = (u8)(data>>16);
responseBuffer[3] = (u8)(data>>24);
} else if (i == 3) {
responseBuffer[4] = (u8)(data>>0);
responseBuffer[5] = (u8)(data>>8);
}
i++;
}
} while (CARD_CR2 & CARD_BUSY);
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, SEND_STATUS, _NJSD_relativeCardAddress);
i--;
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_sendCLK (int speed, int count) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
REG_IF = 0x100000;
#endif
//CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
_NJSD_writeCardCommand (0xE0 | ((speed & 3) << 2), 0, (count - 1), 0, 0, 0, 0, 0);
CARD_CR2 = _NJSD_cardFlags;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
static bool _NJSD_sendCMDN (int speed, u8 cmd, u32 param) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
REG_IF = 0x100000;
CARD_CR1H = CARD_CR1_ENABLE; // | CARD_CR1_IRQ;
_NJSD_writeCardCommand (0xF0 | ((speed & 3) << 2), 0x00, 0x40 | cmd, (param>>24) & 0xFF,
(param>>16) & 0xFF, (param>>8) & 0xFF, (param>>0) & 0xFF, 0x00);
CARD_CR2 = _NJSD_cardFlags;
i = COMMAND_TIMEOUT;
while ((CARD_CR2 & CARD_BUSY) && --i);
if (i <= 0) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
// wait for ninja DS to be done!
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
bool _NJSD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
return _NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, command, data);
}
bool _NJSD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
return _NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_136, command, data);
}
static bool _NJSD_cardInit (void) {
// If the commands succeed the first time, assume they'll always succeed
if (! _NJSD_sendCLK (SD_CLK_167KHz, 256) ) {
return false;
}
if (! _NJSD_sendCMDN (SD_CLK_167KHz, GO_IDLE_STATE, 0) ) {
return false;
}
_NJSD_sendCLK (SD_CLK_167KHz, 8);
_NJSD_sendCLK (SD_CLK_167KHz, 256);
_NJSD_sendCMDN (SD_CLK_167KHz, GO_IDLE_STATE, 0);
_NJSD_sendCLK (SD_CLK_167KHz, 8);
return _SD_InitCard (_NJSD_cmd_6byte_response,
_NJSD_cmd_17byte_response,
true,
&_NJSD_relativeCardAddress);
}
bool _NJSD_isInserted(void) {
u8 responseBuffer [8];
_NJSD_sendCMDR (SD_CLK_167KHz, responseBuffer, SD_RSP_48, SEND_STATUS, 0);
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _NJSD_clearStatus (void) {
return _NJSD_reset();
}
bool _NJSD_shutdown(void) {
return _NJSD_clearStatus();
}
bool _NJSD_startup(void) {
if (! _NJSD_init(0xA0406000) ) {
return false;
}
if (! _NJSD_cardInit() ) {
return false;
}
return true;
}
bool _NJSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u8 crc[8];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
while (numSectors--) {
_SD_CRC16 ( data, BYTES_PER_READ, crc);
if (! _NJSD_writeSector (data, crc, offset)) {
return false;
}
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
}
return true;
}
#ifdef _IO_ALLOW_UNALIGNED
bool _NJSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 tmp[BYTES_PER_READ>>2];
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
#endif
u8* tbuf = (u8*)buffer;
if (numSectors == 0) {
return false;
}
#ifdef _NJSD_SYNC
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
if (numSectors > 1) {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_DATA, READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ);
for (i = 0; i < numSectors - 2; i++) {
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf + i * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + i * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
}
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_end_cmd);
memcpy (tbuf + (numSectors - 2) * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 2) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_end_cmd);
}
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf + (numSectors - 1) * BYTES_PER_READ, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 1) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
}
} else {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_STREAM, READ_SINGLE_BLOCK, sector * BYTES_PER_READ);
if (((int)buffer & 0x03) != 0){
cardPolledTransfer (0xA1406000, tmp, BYTES_PER_READ, _NJSD_read_cmd);
memcpy (tbuf, tmp, BYTES_PER_READ);
} else {
cardPolledTransfer (0xA1406000, (u32*)tbuf, BYTES_PER_READ, _NJSD_read_cmd);
}
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
#else // not defined _IO_ALLOW_UNALIGNED
bool _NJSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
int i;
#ifdef _NJSD_SYNC
u32 old_REG_IME;
#endif
u8* tbuf = (u8*)buffer;
if (numSectors == 0) {
return false;
}
#ifdef _NJSD_SYNC
old_REG_IME = REG_IME;
REG_IME = 0;
#endif
if (numSectors > 1) {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_DATA, READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ);
for (i = 0; i < numSectors - 2; i++) {
cardPolledTransfer (0xA1406000, (u32*)(tbuf + i * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
}
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 2) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_end_cmd);
if (!_NJSD_waitIRQ ()) {
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return false;
}
cardPolledTransfer (0xA1406000, (u32*)(tbuf + (numSectors - 1) * BYTES_PER_READ), BYTES_PER_READ, _NJSD_read_cmd);
} else {
_NJSD_sendCMDR (_NJSD_speed, NULL, SD_RSP_STREAM, READ_SINGLE_BLOCK, sector * BYTES_PER_READ);
cardPolledTransfer (0xA1406000, (u32*)tbuf, BYTES_PER_READ, _NJSD_read_cmd);
}
#ifdef _NJSD_SYNC
REG_IME = old_REG_IME;
#endif
return true;
}
#endif // _IO_ALLOW_UNALIGNED
const IO_INTERFACE _io_njsd = {
DEVICE_TYPE_NJSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS,
(FN_MEDIUM_STARTUP)&_NJSD_startup,
(FN_MEDIUM_ISINSERTED)&_NJSD_isInserted,
(FN_MEDIUM_READSECTORS)&_NJSD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_NJSD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_NJSD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_NJSD_shutdown
} ;
#endif // defined NDS

View File

@@ -0,0 +1,50 @@
/*
io_njsd.h
Hardware Routines for reading an SD card using
a NinjaDS SD adapter.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-08-02 - Chishm
* Original release
*/
#ifndef IO_NJSD_H
#define IO_NJSD_H
#include "disc_io.h"
#ifdef NDS
// 'NJSD'
#define DEVICE_TYPE_NJSD 0x44534A4E
// export interface
extern const IO_INTERFACE _io_njsd;
#endif // defined NDS
#endif // define IO_NJSD_H

View File

@@ -0,0 +1,348 @@
/*
io_nmmc.c
Hardware Routines for reading an SD or MMC card using
a Neoflash MK2 or MK3.
Written by www.neoflash.com
Submit bug reports for this device to the NeoFlash forums
See license.txt for license details.
2006-02-09 - www.neoflash.com:
* First stable release
2006-02-13 - Chishm
* Added ReadMK2Config function
* Added read config test to init function so no unnecessary card commands are sent
* Changed data read and write functions to use multiple block commands
*/
#include "io_nmmc.h"
#ifdef NDS
#include <nds/card.h>
int _NMMC_spi_freq = 3;
#define MK2_CONFIG_ZIP_RAM_CLOSE (1 << 5)
#define MK2_CONFIG_GAME_FLASH_CLOSE ((1 << 4) | (1 << 0))
//#define MK2_CONFIG_ZIP_RAM_CLOSE ((1 << 5) | (1 << 1))
//#define MK2_CONFIG_GAME_FLASH_CLOSE (1 << 4)
#define MMC_READ_MULTIPLE_BLOCK 18
#define MMC_READ_BLOCK 17
#define MMC_WRITE_MULTIPLE_BLOCK 25
#define MMC_WRITE_BLOCK 24
#define MMC_STOP_TRANSMISSION 12
#define MMC_SET_BLOCKLEN 16
#define MMC_SET_BLOCK_COUNT 23
#define MMC_SEND_CSD 9
// SPI functions
static inline void _Neo_OpenSPI( u8 frequency )
{
CARD_CR1 = 0x0000A040 | frequency;
}
static inline u8 _Neo_SPI( u8 dataByte )
{
CARD_EEPDATA = dataByte;
while (CARD_CR1 & 0x80); // card busy
return CARD_EEPDATA;
}
static inline void _Neo_CloseSPI ( void )
{
CARD_CR1 = 0;
}
static inline void _Neo_MK2GameMode() {
_Neo_OpenSPI(_NMMC_spi_freq); // Enable DS Card's SPI port
_Neo_SPI(0xF1); // Switch to game mode
_Neo_CloseSPI(); // Disable DS Card's SPI port
}
static inline void _Neo_EnableEEPROM( bool enable ) {
_Neo_OpenSPI(_NMMC_spi_freq);
if(enable) _Neo_SPI(0x06);
else _Neo_SPI(0x0E);
_Neo_CloseSPI();
}
static void _Neo_WriteMK2Config(u8 config) {
_Neo_EnableEEPROM(true);
_Neo_OpenSPI(_NMMC_spi_freq);
_Neo_SPI(0xFA); // Send mem conf write command
_Neo_SPI(0x01); // Send high byte (0x01)
_Neo_SPI(config); // Send low byte
_Neo_CloseSPI();
_Neo_EnableEEPROM(false);
}
static u8 _Neo_ReadMK2Config(void)
{
u8 config;
_Neo_EnableEEPROM(true);
_Neo_OpenSPI(_NMMC_spi_freq);
_Neo_SPI(0xf8); // Send mem conf read command
_Neo_SPI(0x01); // Send high byte
config = _Neo_SPI(0x00); // Get low byte
_Neo_CloseSPI();
_Neo_EnableEEPROM(false);
return config;
}
// Low level functions
u8 selectMMC_command [8] = {0xFF, 0x00, 0x6A, 0xDF, 0x37, 0x59, 0x33, 0xA3};
static void _Neo_SelectMMC (u8 dataByte)
{
selectMMC_command[1] = dataByte; // Set enable / disable byte
cardWriteCommand (selectMMC_command); // Send "5. Use the EEPROM CS to access the MK2 MMC/SD card"
CARD_CR2 = CARD_ACTIVATE | CARD_nRESET;
while (CARD_CR2 & CARD_BUSY);
return;
}
static void _Neo_EnableMMC( bool enable )
{
if ( enable == false) {
_Neo_CloseSPI ();
_Neo_SelectMMC (0);
_Neo_SelectMMC (0);
} else {
_Neo_SelectMMC (1);
_Neo_SelectMMC (1);
_Neo_OpenSPI (_NMMC_spi_freq);
}
return;
}
static void _Neo_SendMMCCommand( u8 command, u32 argument )
{
_Neo_SPI (0xFF);
_Neo_SPI (command | 0x40);
_Neo_SPI ((argument >> 24) & 0xff);
_Neo_SPI ((argument >> 16) & 0xff);
_Neo_SPI ((argument >> 8) & 0xff) ;
_Neo_SPI (argument & 0xff);
_Neo_SPI (0x95);
_Neo_SPI (0xFF);
return;
}
static bool _Neo_CheckMMCResponse( u8 response, u8 mask ) {
u32 i;
for(i=0;i<256;i++) {
if( ( _Neo_SPI( 0xFF ) & mask ) == response )
return true;
}
return false;
}
// Neo MMC functions
static bool _Neo_InitMMC() {
_Neo_MK2GameMode();
_Neo_WriteMK2Config( MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE);
// Make sure the configuration was accepted
if (_Neo_ReadMK2Config() != (MK2_CONFIG_ZIP_RAM_CLOSE | MK2_CONFIG_GAME_FLASH_CLOSE)) {
return false; // If not, then it wasn't initialised properly
}
return true;
}
// Neo MMC driver functions
bool _NMMC_isInserted(void) {
int i;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
_Neo_SendMMCCommand(MMC_SEND_CSD, 0);
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
// consume data from card, and send clocks.
for (i = 0; i < 28; i++) {
_Neo_SPI(0xff);
}
return true;
}
bool _NMMC_clearStatus (void) {
u32 i;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
for (i = 0; i < 10; i++) {
_Neo_SPI(0xFF); // Send 10 0xFF bytes to MMC card
}
_Neo_SendMMCCommand(0, 0); // Send GO_IDLE_STATE command
if( _Neo_CheckMMCResponse( 0x01, 0xFF ) == false ) { // Check that it replied with 0x01 (not idle, no other error)
_Neo_EnableMMC( false );
return false;
}
for(i=0;i<256;i++) {
_Neo_SendMMCCommand(1, 0); // Poll with SEND_OP_COND
if( _Neo_CheckMMCResponse( 0x00, 0x01 ) == true ) { // Check for idle state
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true; // Card is now idle
}
}
_Neo_EnableMMC( false );
return false;
}
bool _NMMC_shutdown(void) {
return _NMMC_clearStatus();
}
bool _NMMC_startUp(void) {
int i;
int transSpeed;
if (_Neo_InitMMC() == false) {
return false;
}
if (_NMMC_clearStatus() == false) {
return false;
}
_Neo_EnableMMC( true ); // Open SPI port to MMC card
// Set block length
_Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTES_PER_READ );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
// Check if we can use a higher SPI frequency
_Neo_SendMMCCommand(MMC_SEND_CSD, 0);
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
for (i = 0; i < 3; i++) {
_Neo_SPI(0xFF);
}
transSpeed = _Neo_SPI (0xFF);
for (i = 0; i < 24; i++) {
_Neo_SPI(0xFF);
}
if ((transSpeed & 0xf0) >= 0x30) {
_NMMC_spi_freq = 0;
}
_Neo_EnableMMC( false );
return true;
}
bool _NMMC_writeSectors (u32 sector, u32 totalSecs, const void* buffer)
{
u32 i;
u8 *p=(u8*)buffer;
sector *= BYTES_PER_READ;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
_Neo_SendMMCCommand( 25, sector );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
while (totalSecs--) {
_Neo_SPI( 0xFC ); // Send Start Block token
for( i = 0; i < BYTES_PER_READ; i++ ) // Send a block of data
_Neo_SPI( *p++ );
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI( 0xFF ); // Send fake CRC16
if( ( _Neo_SPI( 0xFF ) & 0x0F ) != 0x05 ) { // Make sure the block was accepted
_Neo_EnableMMC( false );
return false;
}
while( _Neo_SPI( 0xFF ) == 0x00 ); // Wait for the block to be written
}
// Stop transmission block
_Neo_SPI( 0xFD ); // Send Stop Transmission Block token
for( i = 0; i < BYTES_PER_READ; i++ ) // Send a block of fake data
_Neo_SPI( 0xFF );
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI( 0xFF ); // Send fake CRC16
_Neo_SPI (0xFF); // Send 8 clocks
while( _Neo_SPI( 0xFF ) == 0x00 ); // Wait for the busy signal to clear
for ( i = 0; i < 0x10; i++) {
_Neo_SPI (0xFF); // Send clocks for the MMC card to finish what it's doing
}
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true;
}
bool _NMMC_readSectors (u32 sector, u32 totalSecs, void* buffer)
{
u32 i;
u8 *p=(u8*)buffer;
sector *= BYTES_PER_READ;
_Neo_EnableMMC( true ); // Open SPI port to MMC card
while (totalSecs--) {
_Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
if( _Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
_Neo_EnableMMC( false );
return false;
}
if( _Neo_CheckMMCResponse( 0xFE, 0xFF ) == false ) { // Check for Start Block token
_Neo_EnableMMC( false );
return false;
}
for( i = 0; i < BYTES_PER_READ; i++ ) // Read in a block of data
*p++ = _Neo_SPI( 0xFF );
_Neo_SPI( 0xFF ); // Ignore CRC16
_Neo_SPI( 0xFF ); // Ignore CRC16
sector += BYTES_PER_READ;
}
_Neo_EnableMMC( false ); // Close SPI port to MMC card
return true;
}
const IO_INTERFACE _io_nmmc = {
DEVICE_TYPE_NMMC,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_NDS,
(FN_MEDIUM_STARTUP)&_NMMC_startUp,
(FN_MEDIUM_ISINSERTED)&_NMMC_isInserted,
(FN_MEDIUM_READSECTORS)&_NMMC_readSectors,
(FN_MEDIUM_WRITESECTORS)&_NMMC_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_NMMC_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_NMMC_shutdown
} ;
#endif // defined NDS

View File

@@ -0,0 +1,53 @@
/*
io_nmmc.h
Hardware Routines for reading an SD or MMC card using
a Neoflash MK2 or MK3.
Original version written by www.neoflash.com,
moddified and used with permission of www.neoflash.com
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_NMMC_H
#define IO_NMMC_H
#include "disc_io.h"
#ifdef NDS
// 'NMMC'
#define DEVICE_TYPE_NMMC 0x434D4D4E
// export interface
extern const IO_INTERFACE _io_nmmc;
#endif // defined NDS
#endif // define IO_NMMC_H

View File

@@ -0,0 +1,47 @@
/*
io_m3_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_sc_common.h"
/*-----------------------------------------------------------------
_SC_changeMode (was SC_Unlock)
Added by MightyMax
Modified by Chishm
Modified again by loopy
1=ram(readonly), 5=ram, 3=SD interface?
-----------------------------------------------------------------*/
void _SC_changeMode(u8 mode) {
vu16 *unlockAddress = (vu16*)0x09FFFFFE;
*unlockAddress = 0xA55A ;
*unlockAddress = 0xA55A ;
*unlockAddress = mode ;
*unlockAddress = mode ;
}

View File

@@ -0,0 +1,45 @@
/*
io_sc_common.h
Routines common to all version of the Super Card
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_SC_COMMON_H
#define IO_SC_COMMON_H
#include "disc_io.h"
// Values for changing mode
#define SC_MODE_RAM 0x5
#define SC_MODE_MEDIA 0x3
#define SC_MODE_RAM_RO 0x1
extern void _SC_changeMode (u8 mode);
#endif // IO_SC_COMMON_H

View File

@@ -0,0 +1,83 @@
/*
io_sccf.c based on
compact_flash.c
By chishm (Michael Chisholm)
Hardware Routines for reading a compact flash card
using the Super Card CF
CF routines modified with help from Darkfader
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "io_sccf.h"
#include "io_sc_common.h"
#include "io_cf_common.h"
//---------------------------------------------------------------
// SC CF Addresses
#define REG_SCCF_STS ((vu16*)0x098C0000) // Status of the CF Card / Device control
#define REG_SCCF_CMD ((vu16*)0x090E0000) // Commands sent to control chip and status return
#define REG_SCCF_ERR ((vu16*)0x09020000) // Errors / Features
#define REG_SCCF_SEC ((vu16*)0x09040000) // Number of sector to transfer
#define REG_SCCF_LBA1 ((vu16*)0x09060000) // 1st byte of sector address
#define REG_SCCF_LBA2 ((vu16*)0x09080000) // 2nd byte of sector address
#define REG_SCCF_LBA3 ((vu16*)0x090A0000) // 3rd byte of sector address
#define REG_SCCF_LBA4 ((vu16*)0x090C0000) // last nibble of sector address | 0xE0
#define REG_SCCF_DATA ((vu16*)0x09000000) // Pointer to buffer of CF data transered from card
static const CF_REGISTERS _SCCF_Registers = {
REG_SCCF_DATA,
REG_SCCF_STS,
REG_SCCF_CMD,
REG_SCCF_ERR,
REG_SCCF_SEC,
REG_SCCF_LBA1,
REG_SCCF_LBA2,
REG_SCCF_LBA3,
REG_SCCF_LBA4
};
bool _SCCF_startup(void) {
_SC_changeMode (SC_MODE_MEDIA);
return _CF_startup(&_SCCF_Registers);
}
const IO_INTERFACE _io_sccf = {
DEVICE_TYPE_SCCF,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCCF_startup,
(FN_MEDIUM_ISINSERTED)&_CF_isInserted,
(FN_MEDIUM_READSECTORS)&_CF_readSectors,
(FN_MEDIUM_WRITESECTORS)&_CF_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_CF_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_CF_shutdown
} ;

View File

@@ -0,0 +1,45 @@
/*
io_sccf.h
Hardware Routines for reading a compact flash card
using the Supercard CF
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
*/
#ifndef IO_SCCF_H
#define IO_SCCF_H
// 'SCCF'
#define DEVICE_TYPE_SCCF 0x46434353
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_sccf;
#endif // define IO_SCCF_H

View File

@@ -0,0 +1,399 @@
/*
io_scsd.c
Hardware Routines for reading a Secure Digital card
using the SC SD
Some code based on scsd_c.c, written by Amadeus
and Jean-Pierre Thomasset as part of DSLinux.
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-22 - Chishm
* First release of stable code
2006-07-25 - Chishm
* Improved startup function that doesn't delay hundreds of seconds
before reporting no card inserted.
2006-08-05 - Chishm
* Tries multiple times to get a Relative Card Address at startup
2006-08-07 - Chishm
* Moved the SD initialization to a common function
2006-08-19 - Chishm
* Added SuperCard Lite support
*/
#include "io_scsd.h"
#include "io_sd_common.h"
#include "io_sc_common.h"
//---------------------------------------------------------------
// SCSD register addresses
#define REG_SCSD_CMD (*(vu16*)(0x09800000))
/* bit 0: command bit to read */
/* bit 7: command bit to write */
#define REG_SCSD_DATAWRITE (*(vu16*)(0x09000000))
#define REG_SCSD_DATAREAD (*(vu16*)(0x09100000))
#define REG_SCSD_DATAREAD_32 (*(vu32*)(0x09100000))
#define REG_SCSD_LITE_ENABLE (*(vu16*)(0x09440000))
#define REG_SCSD_LOCK (*(vu16*)(0x09FFFFFE))
/* bit 0: 1 */
/* bit 1: enable IO interface (SD,CF) */
/* bit 2: enable R/W SDRAM access */
//---------------------------------------------------------------
// Responses
#define SCSD_STS_BUSY 0x100
#define SCSD_STS_INSERTED 0x300
//---------------------------------------------------------------
// Send / receive timeouts, to stop infinite wait loops
#define NUM_STARTUP_CLOCKS 100 // Number of empty (0xFF when sending) bytes to send/receive to/from the card
#define TRANSMIT_TIMEOUT 100000 // Time to wait for the SC to respond to transmit or receive requests
#define RESPONSE_TIMEOUT 256 // Number of clocks sent to the SD card before giving up
#define BUSY_WAIT_TIMEOUT 500000
#define WRITE_TIMEOUT 3000 // Time to wait for the card to finish writing
//---------------------------------------------------------------
// Variables required for tracking SD state
static u32 _SCSD_relativeCardAddress = 0; // Preshifted Relative Card Address
//---------------------------------------------------------------
// Internal SC SD functions
extern bool _SCSD_writeData_s (u8 *data, u16* crc);
static inline void _SCSD_unlock (void) {
_SC_changeMode (SC_MODE_MEDIA);
}
static inline void _SCSD_enable_lite (void) {
REG_SCSD_LITE_ENABLE = 0;
}
static bool _SCSD_sendCommand (u8 command, u32 argument) {
u8 databuff[6];
u8 *tempDataPtr = databuff;
int length = 6;
u16 dataByte;
int curBit;
int i;
*tempDataPtr++ = command | 0x40;
*tempDataPtr++ = argument>>24;
*tempDataPtr++ = argument>>16;
*tempDataPtr++ = argument>>8;
*tempDataPtr++ = argument;
*tempDataPtr = _SD_CRC7 (databuff, 5);
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) == 0) && (--i));
if (i == 0) {
return false;
}
dataByte = REG_SCSD_CMD;
tempDataPtr = databuff;
while (length--) {
dataByte = *tempDataPtr++;
for (curBit = 7; curBit >=0; curBit--){
REG_SCSD_CMD = dataByte;
dataByte = dataByte << 1;
}
}
return true;
}
// Returns the response from the SD card to a previous command.
static bool _SCSD_getResponse (u8* dest, u32 length) {
u32 i;
int dataByte;
int numBits = length * 8;
// Wait for the card to be non-busy
i = BUSY_WAIT_TIMEOUT;
while (((REG_SCSD_CMD & 0x01) != 0) && (--i));
if (dest == NULL) {
return true;
}
if (i == 0) {
// Still busy after the timeout has passed
return false;
}
// The first bit is always 0
dataByte = 0;
numBits--;
// Read the remaining bits in the response.
// It's always most significant bit first
while (numBits--) {
dataByte = (dataByte << 1) | (REG_SCSD_CMD & 0x01);
if ((numBits & 0x7) == 0) {
// It's read a whole byte, so store it
*dest++ = (u8)dataByte;
dataByte = 0;
}
}
// Send 16 more clocks, 8 more than the delay required between a response and the next command
for (i = 0; i < 16; i++) {
dataByte = REG_SCSD_CMD;
}
return true;
}
static inline bool _SCSD_getResponse_R1 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R1b (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R2 (u8* dest) {
return _SCSD_getResponse (dest, 17);
}
static inline bool _SCSD_getResponse_R3 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static inline bool _SCSD_getResponse_R6 (u8* dest) {
return _SCSD_getResponse (dest, 6);
}
static void _SCSD_sendClocks (u32 numClocks) {
u16 temp;
do {
temp = REG_SCSD_CMD;
} while (numClocks--);
}
bool _SCSD_cmd_6byte_response (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 6);
}
bool _SCSD_cmd_17byte_response (u8* responseBuffer, u8 command, u32 data) {
_SCSD_sendCommand (command, data);
return _SCSD_getResponse (responseBuffer, 17);
}
static bool _SCSD_initCard (void) {
_SCSD_enable_lite();
// Give the card time to stabilise
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Reset the card
if (!_SCSD_sendCommand (GO_IDLE_STATE, 0)) {
return false;
}
_SCSD_sendClocks (NUM_STARTUP_CLOCKS);
// Card is now reset, including it's address
_SCSD_relativeCardAddress = 0;
// Init the card
return _SD_InitCard (_SCSD_cmd_6byte_response,
_SCSD_cmd_17byte_response,
true,
&_SCSD_relativeCardAddress);
}
static bool _SCSD_readData (void* buffer) {
u8* buff_u8 = (u8*)buffer;
u16* buff = (u16*)buffer;
volatile register u32 temp;
int i;
i = BUSY_WAIT_TIMEOUT;
while ((REG_SCSD_DATAREAD & SCSD_STS_BUSY) && (--i));
if (i == 0) {
return false;
}
i=256;
if ((u32)buff_u8 & 0x01) {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff_u8++ = (u8)temp;
*buff_u8++ = (u8)(temp >> 8);
}
} else {
while(i--) {
temp = REG_SCSD_DATAREAD_32;
temp = REG_SCSD_DATAREAD_32 >> 16;
*buff++ = temp;
}
}
for (i = 0; i < 8; i++) {
temp = REG_SCSD_DATAREAD_32;
}
temp = REG_SCSD_DATAREAD;
return true;
}
//---------------------------------------------------------------
// Functions needed for the external interface
bool _SCSD_startUp (void) {
_SCSD_unlock();
return _SCSD_initCard();
}
bool _SCSD_isInserted (void) {
u8 responseBuffer [6];
// Make sure the card receives the command
if (!_SCSD_sendCommand (SEND_STATUS, 0)) {
return false;
}
// Make sure the card responds
if (!_SCSD_getResponse_R1 (responseBuffer)) {
return false;
}
// Make sure the card responded correctly
if (responseBuffer[0] != SEND_STATUS) {
return false;
}
return true;
}
bool _SCSD_readSectors (u32 sector, u32 numSectors, void* buffer) {
u32 i;
u8* dest = (u8*) buffer;
u8 responseBuffer[6];
if (numSectors == 1) {
// If it's only reading one sector, use the (slightly faster) READ_SINGLE_BLOCK
if (!_SCSD_sendCommand (READ_SINGLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
if (!_SCSD_readData (buffer)) {
return false;
}
} else {
// Stream the required number of sectors from the card
if (!_SCSD_sendCommand (READ_MULTIPLE_BLOCK, sector * BYTES_PER_READ)) {
return false;
}
for(i=0; i < numSectors; i++, dest+=BYTES_PER_READ) {
if (!_SCSD_readData(dest)) {
return false;
}
}
// Stop the streaming
_SCSD_sendCommand (STOP_TRANSMISSION, 0);
_SCSD_getResponse_R1b (responseBuffer);
}
_SCSD_sendClocks(0x10);
return true;
}
bool _SCSD_writeSectors (u32 sector, u32 numSectors, const void* buffer) {
u16 crc[4]; // One per data line
u8 responseBuffer[6];
u32 offset = sector * BYTES_PER_READ;
u8* data = (u8*) buffer;
int i;
while (numSectors--) {
// Calculate the CRC16
_SD_CRC16 ( data, BYTES_PER_READ, (u8*)crc);
// Send write command and get a response
_SCSD_sendCommand (WRITE_BLOCK, offset);
if (!_SCSD_getResponse_R1 (responseBuffer)) {
return false;
}
// Send the data and CRC
if (! _SCSD_writeData_s (data, crc)) {
return false;
}
// Send a few clocks to the SD card
_SCSD_sendClocks(0x10);
offset += BYTES_PER_READ;
data += BYTES_PER_READ;
// Wait until card is finished programming
i = WRITE_TIMEOUT;
responseBuffer[3] = 0;
do {
_SCSD_sendCommand (SEND_STATUS, _SCSD_relativeCardAddress);
_SCSD_getResponse_R1 (responseBuffer);
i--;
if (i <= 0) {
return false;
}
} while (((responseBuffer[3] & 0x1f) != ((SD_STATE_TRAN << 1) | READY_FOR_DATA)));
}
return true;
}
bool _SCSD_clearStatus (void) {
return _SCSD_initCard ();
}
bool _SCSD_shutdown (void) {
_SC_changeMode (SC_MODE_RAM_RO);
return true;
}
const IO_INTERFACE _io_scsd = {
DEVICE_TYPE_SCSD,
FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_SLOT_GBA,
(FN_MEDIUM_STARTUP)&_SCSD_startUp,
(FN_MEDIUM_ISINSERTED)&_SCSD_isInserted,
(FN_MEDIUM_READSECTORS)&_SCSD_readSectors,
(FN_MEDIUM_WRITESECTORS)&_SCSD_writeSectors,
(FN_MEDIUM_CLEARSTATUS)&_SCSD_clearStatus,
(FN_MEDIUM_SHUTDOWN)&_SCSD_shutdown
} ;

View File

@@ -0,0 +1,48 @@
/*
io_scsd.h
Hardware Routines for reading a Secure Digital card
using the Supercard SD
Copyright (c) 2006 Michael "Chishm" Chisholm
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2006-07-11 - Chishm
* Original release
2006-07-22 - Chishm
* First release of stable code
*/
#ifndef IO_SCSD_H
#define IO_SCSD_H
// 'SCSD'
#define DEVICE_TYPE_SCSD 0x44534353
#include "disc_io.h"
// export interface
extern const IO_INTERFACE _io_scsd ;
#endif // define IO_SCSD_H

View File

@@ -0,0 +1,139 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ io_scsd_s.s
@
@ Hardware Routines for reading a Secure Digital card
@ using the SC SD
@
@ Based on code supplied by Romman
@
@ Copyright (c) 2006 Michael "Chishm" Chisholm
@
@ Redistribution and use in source and binary forms, with or without modification,
@ are permitted provided that the following conditions are met:
@
@ 1. Redistributions of source code must retain the above copyright notice,
@ this list of conditions and the following disclaimer.
@ 2. Redistributions in binary form must reproduce the above copyright notice,
@ this list of conditions and the following disclaimer in the documentation and/or
@ other materials provided with the distribution.
@ 3. The name of the author may not be used to endorse or promote products derived
@ from this software without specific prior written permission.
@
@ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
@ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
@ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
@ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
@ 2006-07-22 - Chishm
@ * First release of stable code
@
@ 2006-08-19 - Chishm
@ * Added SuperCard Lite support
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.align 4
.arm
.equ REG_SCSD_DATAWRITE, 0x09000000
.equ BYTES_PER_READ, 0x200
.equ SCSD_STS_BUSY, 0x100
.equ BUSY_WAIT_TIMEOUT, 0x10000
.equ FALSE, 0
.equ TRUE, 1
@ bool _SCSD_writeData_s (u8 *data, u16* crc)
.global _SCSD_writeData_s
_SCSD_writeData_s:
stmfd r13!, {r4-r5}
mov r5, #BYTES_PER_READ
mov r2, #REG_SCSD_DATAWRITE
@ Wait for a free data buffer on the SD card
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_busy_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #SCSD_STS_BUSY
beq _SCSD_writeData_busy_wait
ldrh r3, [r2] @ extra clock
mov r3, #0 @ start bit
strh r3,[r2]
@ Check if the data buffer is aligned on a halfword boundary
tst r0, #1
beq _SCSD_writeData_data_loop
@ Used when the source data is unaligned
_SCSD_writeData_data_loop_unaligned:
ldrb r3, [r0], #1
ldrb r4, [r0], #1
orr r3, r3, r4, lsl #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop_unaligned
b _SCSD_writeData_crc
@ Write the data to the card
@ 4 halfwords are transmitted to the Supercard at once, for timing purposes
@ Only the first halfword needs to contain data for standard SuperCards
@ For the SuperCard Lite, the data is split into 4 nibbles, one per halfword
_SCSD_writeData_data_loop:
ldrh r3, [r0], #2
@ This bit added for SCLite. Notice that the shift is not the same as in
@ the original (buggy) code supplied by Romman
add r3, r3, r3, lsl #20
mov r4, r3, lsr #8
stmia r2, {r3-r4}
subs r5, r5, #2
bne _SCSD_writeData_data_loop
@ Send the data CRC
_SCSD_writeData_crc:
cmp r1, #0
movne r0, r1
movne r1, #0
movne r5, #8
bne _SCSD_writeData_data_loop
mov r3, #0xff @ end bit
strh r3, [r2]
@ Wait for the SD card to signal that it is finished recieving
mov r4, #BUSY_WAIT_TIMEOUT
_SCSD_writeData_finished_wait:
@ Test for timeout
subs r4, r4, #1
moveq r0, #FALSE @ return false on failure
beq _SCSD_writeData_return
@ Check the busy bit of the status register
ldrh r3, [r2]
tst r3, #0x100
bne _SCSD_writeData_finished_wait
@ Send 8 more clocks, as required by the SD card
ldmia r2, {r3-r4}
@ return true for success
mov r0, #TRUE
_SCSD_writeData_return:
ldmfd r13!,{r4-r5}
bx r14

Some files were not shown because too many files have changed in this diff Show More