forked from Imagelibrary/rtems
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:
140
c/src/lib/libbsp/arm/nds/ChangeLog
Normal file
140
c/src/lib/libbsp/arm/nds/ChangeLog
Normal 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
|
||||||
260
c/src/lib/libbsp/arm/nds/Makefile.am
Normal file
260
c/src/lib/libbsp/arm/nds/Makefile.am
Normal 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
|
||||||
12
c/src/lib/libbsp/arm/nds/README
Normal file
12
c/src/lib/libbsp/arm/nds/README
Normal 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
|
||||||
114
c/src/lib/libbsp/arm/nds/block/block.c
Normal file
114
c/src/lib/libbsp/arm/nds/block/block.c
Normal 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;
|
||||||
14
c/src/lib/libbsp/arm/nds/bsp_specs
Normal file
14
c/src/lib/libbsp/arm/nds/bsp_specs
Normal 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 }
|
||||||
|
|
||||||
88
c/src/lib/libbsp/arm/nds/clock/clock.c
Normal file
88
c/src/lib/libbsp/arm/nds/clock/clock.c
Normal 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"
|
||||||
28
c/src/lib/libbsp/arm/nds/configure.ac
Normal file
28
c/src/lib/libbsp/arm/nds/configure.ac
Normal 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
|
||||||
191
c/src/lib/libbsp/arm/nds/console/console.c
Normal file
191
c/src/lib/libbsp/arm/nds/console/console.c
Normal 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;
|
||||||
|
}
|
||||||
112
c/src/lib/libbsp/arm/nds/coproc/coproc.S
Normal file
112
c/src/lib/libbsp/arm/nds/coproc/coproc.S
Normal 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
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
207
c/src/lib/libbsp/arm/nds/coproc/coproc.c
Normal file
207
c/src/lib/libbsp/arm/nds/coproc/coproc.c
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
195
c/src/lib/libbsp/arm/nds/coproc/coproc.ld
Normal file
195
c/src/lib/libbsp/arm/nds/coproc/coproc.ld
Normal 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 . */
|
||||||
|
}
|
||||||
145
c/src/lib/libbsp/arm/nds/dswifi/arm7/makefile
Normal file
145
c/src/lib/libbsp/arm/nds/dswifi/arm7/makefile
Normal 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
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
1637
c/src/lib/libbsp/arm/nds/dswifi/arm7/source/wifi_arm7.c
Normal file
1637
c/src/lib/libbsp/arm/nds/dswifi/arm7/source/wifi_arm7.c
Normal file
File diff suppressed because it is too large
Load Diff
136
c/src/lib/libbsp/arm/nds/dswifi/arm7/source/wifi_arm7.h
Normal file
136
c/src/lib/libbsp/arm/nds/dswifi/arm7/source/wifi_arm7.h
Normal 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
|
||||||
150
c/src/lib/libbsp/arm/nds/dswifi/arm9/makefile
Normal file
150
c/src/lib/libbsp/arm/nds/dswifi/arm9/makefile
Normal 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
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
63
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP.c
Normal file
63
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP.c
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
56
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP.h
Normal file
56
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP.h
Normal 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
|
||||||
304
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ARP.c
Normal file
304
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ARP.c
Normal 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.
|
||||||
|
}
|
||||||
80
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ARP.h
Normal file
80
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ARP.h
Normal 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
|
||||||
274
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Config.h
Normal file
274
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Config.h
Normal 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
|
||||||
375
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DHCP.c
Normal file
375
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DHCP.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
86
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DHCP.h
Normal file
86
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DHCP.h
Normal 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
|
||||||
492
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DNS.c
Normal file
492
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DNS.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
69
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DNS.h
Normal file
69
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_DNS.h
Normal 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
|
||||||
211
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Hub.c
Normal file
211
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Hub.c
Normal 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
|
||||||
|
|
||||||
109
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Hub.h
Normal file
109
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_Hub.h
Normal 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
|
||||||
56
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ICMP.c
Normal file
56
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ICMP.c
Normal 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;
|
||||||
|
}
|
||||||
52
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ICMP.h
Normal file
52
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_ICMP.h
Normal 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
|
||||||
124
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_IP.c
Normal file
124
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_IP.c
Normal 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);
|
||||||
|
}
|
||||||
64
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_IP.h
Normal file
64
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_IP.h
Normal 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
|
||||||
915
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_TCP.c
Normal file
915
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_TCP.c
Normal 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;
|
||||||
|
}
|
||||||
134
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_TCP.h
Normal file
134
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_TCP.h
Normal 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
|
||||||
245
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_UDP.c
Normal file
245
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_UDP.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
81
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_UDP.h
Normal file
81
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_UDP.h
Normal 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
|
||||||
295
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_memblock.c
Normal file
295
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_memblock.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
65
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_memblock.h
Normal file
65
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_memblock.h
Normal 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
|
||||||
520
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_sockets.c
Normal file
520
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_sockets.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
83
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_sockets.h
Normal file
83
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/sgIP_sockets.h
Normal 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
|
||||||
995
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/wifi_arm9.c
Normal file
995
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/wifi_arm9.c
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
122
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/wifi_arm9.h
Normal file
122
c/src/lib/libbsp/arm/nds/dswifi/arm9/source/wifi_arm9.h
Normal 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
|
||||||
179
c/src/lib/libbsp/arm/nds/dswifi/common/source/dsregs.h
Normal file
179
c/src/lib/libbsp/arm/nds/dswifi/common/source/dsregs.h
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
63
c/src/lib/libbsp/arm/nds/dswifi/common/source/spinlock.h
Normal file
63
c/src/lib/libbsp/arm/nds/dswifi/common/source/spinlock.h
Normal 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"
|
||||||
|
);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
42
c/src/lib/libbsp/arm/nds/dswifi/common/source/spinlock.s
Normal file
42
c/src/lib/libbsp/arm/nds/dswifi/common/source/spinlock.s
Normal 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
|
||||||
|
|
||||||
284
c/src/lib/libbsp/arm/nds/dswifi/common/source/wifi_shared.h
Normal file
284
c/src/lib/libbsp/arm/nds/dswifi/common/source/wifi_shared.h
Normal 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
|
||||||
|
|
||||||
27
c/src/lib/libbsp/arm/nds/dswifi/dswifi_license.txt
Normal file
27
c/src/lib/libbsp/arm/nds/dswifi/dswifi_license.txt
Normal 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.
|
||||||
89
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi7.h
Normal file
89
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi7.h
Normal 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
|
||||||
337
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi9.h
Normal file
337
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi9.h
Normal 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
|
||||||
10
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi_version.h
Normal file
10
c/src/lib/libbsp/arm/nds/dswifi/include/dswifi_version.h
Normal 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_
|
||||||
49
c/src/lib/libbsp/arm/nds/dswifi/include/netdb.h
Normal file
49
c/src/lib/libbsp/arm/nds/dswifi/include/netdb.h
Normal 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
|
||||||
61
c/src/lib/libbsp/arm/nds/dswifi/include/netinet/in.h
Normal file
61
c/src/lib/libbsp/arm/nds/dswifi/include/netinet/in.h
Normal 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
|
||||||
165
c/src/lib/libbsp/arm/nds/dswifi/include/sgIP_errno.h
Normal file
165
c/src/lib/libbsp/arm/nds/dswifi/include/sgIP_errno.h
Normal 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
|
||||||
69
c/src/lib/libbsp/arm/nds/dswifi/makefile
Normal file
69
c/src/lib/libbsp/arm/nds/dswifi/makefile
Normal 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
|
||||||
|
|
||||||
207
c/src/lib/libbsp/arm/nds/fb/fb.c
Normal file
207
c/src/lib/libbsp/arm/nds/fb/fb.c
Normal 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;
|
||||||
|
}
|
||||||
51
c/src/lib/libbsp/arm/nds/fb/fb.h
Normal file
51
c/src/lib/libbsp/arm/nds/fb/fb.h
Normal 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
|
||||||
50
c/src/lib/libbsp/arm/nds/include/bsp.h
Normal file
50
c/src/lib/libbsp/arm/nds/include/bsp.h
Normal 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
|
||||||
36
c/src/lib/libbsp/arm/nds/include/my_ipc.h
Normal file
36
c/src/lib/libbsp/arm/nds/include/my_ipc.h
Normal 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
|
||||||
32
c/src/lib/libbsp/arm/nds/include/sys/iosupport.h
Normal file
32
c/src/lib/libbsp/arm/nds/include/sys/iosupport.h
Normal 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
|
||||||
35
c/src/lib/libbsp/arm/nds/include/tm27.h
Normal file
35
c/src/lib/libbsp/arm/nds/include/tm27.h
Normal 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
|
||||||
29
c/src/lib/libbsp/arm/nds/include/types.h
Normal file
29
c/src/lib/libbsp/arm/nds/include/types.h
Normal 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
|
||||||
100
c/src/lib/libbsp/arm/nds/irq/irq.c
Normal file
100
c/src/lib/libbsp/arm/nds/irq/irq.c
Normal 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;
|
||||||
|
}
|
||||||
62
c/src/lib/libbsp/arm/nds/irq/irq.h
Normal file
62
c/src/lib/libbsp/arm/nds/irq/irq.h
Normal 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
|
||||||
102
c/src/lib/libbsp/arm/nds/libfat/gba/include/fat.h
Normal file
102
c/src/lib/libbsp/arm/nds/libfat/gba/include/fat.h
Normal 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
|
||||||
117
c/src/lib/libbsp/arm/nds/libfat/include/fat.h
Normal file
117
c/src/lib/libbsp/arm/nds/libfat/include/fat.h
Normal 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
|
||||||
107
c/src/lib/libbsp/arm/nds/libfat/nds/include/fat.h
Normal file
107
c/src/lib/libbsp/arm/nds/libfat/nds/include/fat.h
Normal 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
|
||||||
58
c/src/lib/libbsp/arm/nds/libfat/source/bit_ops.h
Normal file
58
c/src/lib/libbsp/arm/nds/libfat/source/bit_ops.h
Normal 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
|
||||||
237
c/src/lib/libbsp/arm/nds/libfat/source/cache.c
Normal file
237
c/src/lib/libbsp/arm/nds/libfat/source/cache.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
118
c/src/lib/libbsp/arm/nds/libfat/source/cache.h
Normal file
118
c/src/lib/libbsp/arm/nds/libfat/source/cache.h
Normal 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
|
||||||
54
c/src/lib/libbsp/arm/nds/libfat/source/common.h
Normal file
54
c/src/lib/libbsp/arm/nds/libfat/source/common.h
Normal 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
|
||||||
902
c/src/lib/libbsp/arm/nds/libfat/source/directory.c
Normal file
902
c/src/lib/libbsp/arm/nds/libfat/source/directory.c
Normal 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;
|
||||||
|
}
|
||||||
171
c/src/lib/libbsp/arm/nds/libfat/source/directory.h
Normal file
171
c/src/lib/libbsp/arm/nds/libfat/source/directory.h
Normal 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
|
||||||
184
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc.c
Normal file
184
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc.c
Normal 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
|
||||||
126
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc.h
Normal file
126
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc.h
Normal 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
|
||||||
81
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc_io.h
Normal file
81
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/disc_io.h
Normal 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
|
||||||
322
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_cf_common.c
Normal file
322
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_cf_common.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
44
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_dldi.h
Normal file
44
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_dldi.h
Normal 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
|
||||||
73
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_dldi.s
Normal file
73
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_dldi.s
Normal 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
|
||||||
|
@---------------------------------------------------------------------------------
|
||||||
307
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_efa2.c
Normal file
307
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_efa2.c
Normal 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
|
||||||
|
};
|
||||||
23
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_efa2.h
Normal file
23
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_efa2.h
Normal 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
|
||||||
334
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_fcsr.c
Normal file
334
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_fcsr.c
Normal 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
|
||||||
|
} ;
|
||||||
44
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_fcsr.h
Normal file
44
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_fcsr.h
Normal 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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
96
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3cf.c
Normal file
96
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3cf.c
Normal 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
|
||||||
|
} ;
|
||||||
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3cf.h
Normal file
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3cf.h
Normal 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
|
||||||
518
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3sd.c
Normal file
518
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3sd.c
Normal 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
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
48
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3sd.h
Normal file
48
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_m3sd.h
Normal 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
|
||||||
100
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_mpcf.c
Normal file
100
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_mpcf.c
Normal 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
|
||||||
|
} ;
|
||||||
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_mpcf.h
Normal file
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_mpcf.h
Normal 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
|
||||||
595
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_njsd.c
Normal file
595
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_njsd.c
Normal 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
|
||||||
50
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_njsd.h
Normal file
50
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_njsd.h
Normal 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
|
||||||
348
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_nmmc.c
Normal file
348
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_nmmc.c
Normal 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
|
||||||
53
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_nmmc.h
Normal file
53
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_nmmc.h
Normal 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
|
||||||
@@ -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 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
83
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_sccf.c
Normal file
83
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_sccf.c
Normal 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
|
||||||
|
} ;
|
||||||
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_sccf.h
Normal file
45
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_sccf.h
Normal 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
|
||||||
399
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd.c
Normal file
399
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd.c
Normal 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
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
48
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd.h
Normal file
48
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd.h
Normal 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
|
||||||
139
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd_s.s
Normal file
139
c/src/lib/libbsp/arm/nds/libfat/source/disc_io/io_scsd_s.s
Normal 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
Reference in New Issue
Block a user