Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
authorJohn Hodge <[email protected]>
Wed, 3 Oct 2012 05:37:10 +0000 (13:37 +0800)
committerJohn Hodge <[email protected]>
Wed, 3 Oct 2012 05:37:10 +0000 (13:37 +0800)
428 files changed:
.gitignore
AcessNative/Makefile [new file with mode: 0644]
AcessNative/RunTest
AcessNative/acesskernel_src/Makefile
AcessNative/acesskernel_src/helpers.c
AcessNative/acesskernel_src/include/arch.h
AcessNative/acesskernel_src/include/threads_int.h [new file with mode: 0644]
AcessNative/acesskernel_src/nativefs.c
AcessNative/acesskernel_src/server.c
AcessNative/acesskernel_src/syscalls.c
AcessNative/acesskernel_src/threads.c
AcessNative/acesskernel_src/time.c [new file with mode: 0644]
AcessNative/ld-acess_src/binary.c
AcessNative/ld-acess_src/elf_load.c
AcessNative/ld-acess_src/exports.c
AcessNative/ld-acess_src/exports.h
AcessNative/ld-acess_src/main.c
AcessNative/ld-acess_src/memory.c
AcessNative/syscalls.h
BuildConf/armv6/Makefile.cfg [new file with mode: 0644]
BuildConf/armv6/default.mk [new file with mode: 0644]
BuildConf/armv6/raspberrypi.mk [new file with mode: 0644]
BuildConf/armv7/Makefile.cfg
BuildConf/armv7/realview_pb.mk
BuildConf/armv7/tegra2.mk
BuildConf/x86/default.mk
BuildConf/x86_64/Makefile.cfg
BuildConf/x86_64/default.mk
KernelLand/Kernel/Makefile
KernelLand/Kernel/arch/armv6/Makefile [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/debug.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/arch.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/assembly.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/lock.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/mm_virt.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/options.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/include/proc.h [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/lib.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/lib.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/link.ld [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/main.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/mm_phys.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/mm_virt.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/pci.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/proc.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/proc.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/start.S [new file with mode: 0644]
KernelLand/Kernel/arch/armv6/time.c [new file with mode: 0644]
KernelLand/Kernel/arch/armv7/Makefile
KernelLand/Kernel/arch/armv7/lib.c
KernelLand/Kernel/arch/armv7/link.ld
KernelLand/Kernel/arch/armv7/mm_virt.c
KernelLand/Kernel/arch/armv7/proc.c
KernelLand/Kernel/arch/armv7/vpci_tegra2.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/Makefile
KernelLand/Kernel/arch/x86/errors.c
KernelLand/Kernel/arch/x86/irq.c
KernelLand/Kernel/arch/x86/main.c
KernelLand/Kernel/arch/x86/mboot.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86/mm_phys.c
KernelLand/Kernel/arch/x86/mm_virt.c
KernelLand/Kernel/arch/x86/proc.c
KernelLand/Kernel/arch/x86/start.asm
KernelLand/Kernel/arch/x86/vpci.c [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/Makefile
KernelLand/Kernel/arch/x86_64/desctab.asm
KernelLand/Kernel/arch/x86_64/errors.c
KernelLand/Kernel/arch/x86_64/include/arch.h
KernelLand/Kernel/arch/x86_64/include/archinit.h [new file with mode: 0644]
KernelLand/Kernel/arch/x86_64/lib.c
KernelLand/Kernel/arch/x86_64/link.ld
KernelLand/Kernel/arch/x86_64/main.c
KernelLand/Kernel/arch/x86_64/mm_phys.c
KernelLand/Kernel/arch/x86_64/mm_virt.c
KernelLand/Kernel/arch/x86_64/proc.c
KernelLand/Kernel/arch/x86_64/start32.asm
KernelLand/Kernel/arch/x86_64/vpci.c [new file with mode: 0644]
KernelLand/Kernel/bin/elf.c
KernelLand/Kernel/binary.c
KernelLand/Kernel/debug.c
KernelLand/Kernel/drv/fifo.c
KernelLand/Kernel/drv/pci.c
KernelLand/Kernel/drv/proc.c
KernelLand/Kernel/drv/vpci.c [new file with mode: 0644]
KernelLand/Kernel/drv/vterm.c
KernelLand/Kernel/drv/vterm_font_8x16.h
KernelLand/Kernel/drv/vterm_termbuf.c
KernelLand/Kernel/drv/zero-one.c [new file with mode: 0644]
KernelLand/Kernel/drvutil.c [deleted file]
KernelLand/Kernel/drvutil_disk.c [new file with mode: 0644]
KernelLand/Kernel/drvutil_video.c [new file with mode: 0644]
KernelLand/Kernel/heap.c
KernelLand/Kernel/include/acess.h
KernelLand/Kernel/include/api_drv_disk.h
KernelLand/Kernel/include/api_drv_video.h
KernelLand/Kernel/include/bootmod.h [new file with mode: 0644]
KernelLand/Kernel/include/ctype.h [new file with mode: 0644]
KernelLand/Kernel/include/errno.h
KernelLand/Kernel/include/events.h
KernelLand/Kernel/include/hal_proc.h
KernelLand/Kernel/include/init.h
KernelLand/Kernel/include/mboot.h
KernelLand/Kernel/include/modules.h
KernelLand/Kernel/include/pmemmap.h [new file with mode: 0644]
KernelLand/Kernel/include/rwlock.h [new file with mode: 0644]
KernelLand/Kernel/include/threads_int.h
KernelLand/Kernel/include/timers_int.h [new file with mode: 0644]
KernelLand/Kernel/include/tpl_mm_phys_bitmap.h
KernelLand/Kernel/include/tpl_mm_phys_stack.h
KernelLand/Kernel/include/vfs.h
KernelLand/Kernel/include/vfs_ext.h
KernelLand/Kernel/include/vfs_int.h
KernelLand/Kernel/include/virtual_pci.h [new file with mode: 0644]
KernelLand/Kernel/lib.c
KernelLand/Kernel/libc.c [new file with mode: 0644]
KernelLand/Kernel/logging.c
KernelLand/Kernel/modules.c
KernelLand/Kernel/pmemmap.c [new file with mode: 0644]
KernelLand/Kernel/rwlock.c [new file with mode: 0644]
KernelLand/Kernel/syscalls.c
KernelLand/Kernel/system.c
KernelLand/Kernel/threads.c
KernelLand/Kernel/time.c
KernelLand/Kernel/vfs/dir.c
KernelLand/Kernel/vfs/fs/devfs.c
KernelLand/Kernel/vfs/fs/root.c
KernelLand/Kernel/vfs/handle.c
KernelLand/Kernel/vfs/io.c
KernelLand/Kernel/vfs/main.c
KernelLand/Kernel/vfs/mmap.c
KernelLand/Kernel/vfs/mount.c
KernelLand/Kernel/vfs/nodecache.c
KernelLand/Kernel/vfs/open.c
KernelLand/Kernel/vfs/select.c
KernelLand/Modules/Display/NVidia/main.c [new file with mode: 0644]
KernelLand/Modules/Display/NVidia/regs.c [new file with mode: 0644]
KernelLand/Modules/Display/NVidia/regs.h [new file with mode: 0644]
KernelLand/Modules/Display/Tegra2Vid/Registers.txt [new file with mode: 0644]
KernelLand/Modules/Display/Tegra2Vid/main.c
KernelLand/Modules/Display/Tegra2Vid/tegra2.h
KernelLand/Modules/Display/VESA/main.c
KernelLand/Modules/Display/VIAVideo/main.c
KernelLand/Modules/Filesystems/Ext2/dir.c
KernelLand/Modules/Filesystems/Ext2/ext2.c
KernelLand/Modules/Filesystems/Ext2/ext2_common.h
KernelLand/Modules/Filesystems/Ext2/ext2fs.h
KernelLand/Modules/Filesystems/Ext2/write.c
KernelLand/Modules/Filesystems/FAT/Makefile
KernelLand/Modules/Filesystems/FAT/common.h [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/dir.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fat.c
KernelLand/Modules/Filesystems/FAT/fatio.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/FAT/fs_fat.h
KernelLand/Modules/Filesystems/FAT/nodecache.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/InitRD/GenerateInitRD.php
KernelLand/Modules/Filesystems/InitRD/files.lst
KernelLand/Modules/Filesystems/InitRD/initrd.h
KernelLand/Modules/Filesystems/InitRD/main.c
KernelLand/Modules/Filesystems/NTFS/common.h
KernelLand/Modules/Filesystems/NTFS/dir.c
KernelLand/Modules/Filesystems/NTFS/main.c
KernelLand/Modules/Filesystems/RAMDisk/Makefile [new file with mode: 0644]
KernelLand/Modules/Filesystems/RAMDisk/ramdisk.c [new file with mode: 0644]
KernelLand/Modules/Filesystems/RAMDisk/ramdisk.h [new file with mode: 0644]
KernelLand/Modules/IPStack/adapters.c
KernelLand/Modules/IPStack/buffer.c
KernelLand/Modules/IPStack/icmp.c
KernelLand/Modules/IPStack/include/adapters_api.h
KernelLand/Modules/IPStack/init.h [new file with mode: 0644]
KernelLand/Modules/IPStack/interface.c
KernelLand/Modules/IPStack/interface.h [new file with mode: 0644]
KernelLand/Modules/IPStack/ipv4.c
KernelLand/Modules/IPStack/ipv6.c
KernelLand/Modules/IPStack/link.c
KernelLand/Modules/IPStack/main.c
KernelLand/Modules/IPStack/routing.c
KernelLand/Modules/IPStack/tcp.c
KernelLand/Modules/Input/Keyboard/main.c
KernelLand/Modules/Input/Mouse/main.c
KernelLand/Modules/Input/PS2KbMouse/8042.c
KernelLand/Modules/Input/PS2KbMouse/pl050.c
KernelLand/Modules/Makefile.tpl
KernelLand/Modules/Network/E1000/Makefile [new file with mode: 0644]
KernelLand/Modules/Network/E1000/e1000.c [new file with mode: 0644]
KernelLand/Modules/Network/E1000/e1000.h [new file with mode: 0644]
KernelLand/Modules/Network/VIARhineII/rhine2.c
KernelLand/Modules/Network/VIARhineII/rhine2_hw.h
KernelLand/Modules/Storage/ATA/Makefile
KernelLand/Modules/Storage/ATA/common.h
KernelLand/Modules/Storage/ATA/io.c
KernelLand/Modules/Storage/ATA/main.c
KernelLand/Modules/Storage/ATA/mbr.c [deleted file]
KernelLand/Modules/Storage/FDDv2/main.c
KernelLand/Modules/Storage/LVM/include/lvm.h
KernelLand/Modules/Storage/LVM/lvm.h
KernelLand/Modules/Storage/LVM/lvm_int.h
KernelLand/Modules/Storage/LVM/main.c
KernelLand/Modules/Storage/LVM/mbr.c
KernelLand/Modules/Storage/LVM/volumes.c
KernelLand/Modules/USB/Core/Makefile
KernelLand/Modules/USB/Core/hub.c
KernelLand/Modules/USB/Core/include/usb_core.h
KernelLand/Modules/USB/Core/include/usb_host.h
KernelLand/Modules/USB/Core/include/usb_hub.h
KernelLand/Modules/USB/Core/main.c
KernelLand/Modules/USB/Core/portctl.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb.c
KernelLand/Modules/USB/Core/usb.h
KernelLand/Modules/USB/Core/usb_devinit.c
KernelLand/Modules/USB/Core/usb_info.c [new file with mode: 0644]
KernelLand/Modules/USB/Core/usb_io.c
KernelLand/Modules/USB/Core/usb_lowlevel.c
KernelLand/Modules/USB/Core/usb_lowlevel.h
KernelLand/Modules/USB/Core/usb_poll.c
KernelLand/Modules/USB/EHCI/Makefile [new file with mode: 0644]
KernelLand/Modules/USB/EHCI/ehci.c [new file with mode: 0644]
KernelLand/Modules/USB/EHCI/ehci.h
KernelLand/Modules/USB/HID/keyboard.c
KernelLand/Modules/USB/HID/main.c
KernelLand/Modules/USB/MSC/Makefile [new file with mode: 0644]
KernelLand/Modules/USB/MSC/common.h [new file with mode: 0644]
KernelLand/Modules/USB/MSC/main.c [new file with mode: 0644]
KernelLand/Modules/USB/MSC/msc_proto.h [new file with mode: 0644]
KernelLand/Modules/USB/MSC/scsi.c [new file with mode: 0644]
KernelLand/Modules/USB/MSC/scsi.h [new file with mode: 0644]
KernelLand/Modules/USB/UHCI/uhci.c
KernelLand/Modules/USB/UHCI/uhci.h
KernelLand/Modules/x86/VGAText/vga.c
Makefile
Makefile.cfg
Notes/SIF.txt [new file with mode: 0644]
Notes/VirtualPCI.txt [new file with mode: 0644]
RunQemu
RunQemuArm
TODO.txt [new file with mode: 0644]
Tools/DiskTool/src/Makefile [new file with mode: 0644]
Tools/DiskTool/src/actions.c [new file with mode: 0644]
Tools/DiskTool/src/helpers.c [new file with mode: 0644]
Tools/DiskTool/src/include/acess.h [new file with mode: 0644]
Tools/DiskTool/src/include/acess_logging.h [new file with mode: 0644]
Tools/DiskTool/src/include/arch.h [new file with mode: 0644]
Tools/DiskTool/src/include/disktool_common.h [new file with mode: 0644]
Tools/DiskTool/src/include/modules.h [new file with mode: 0644]
Tools/DiskTool/src/include/mutex.h [new file with mode: 0644]
Tools/DiskTool/src/include/rwlock.h [new file with mode: 0644]
Tools/DiskTool/src/logging.c [new file with mode: 0644]
Tools/DiskTool/src/main.c [new file with mode: 0644]
Tools/DiskTool/src/nativefs.c [new symlink]
Tools/DiskTool/src/script.c [new file with mode: 0644]
Tools/DiskTool/src/threads.c [new file with mode: 0644]
Tools/DiskTool/src/time.c [new file with mode: 0644]
Tools/DiskTool/src/vfs_handles.c [new file with mode: 0644]
Tools/GCCProxy/gccproxy.sh [new file with mode: 0755]
Tools/GCCProxy/getconfig.mk [new file with mode: 0644]
Usermode/Applications/CLIShell_src/main.c
Usermode/Applications/Makefile.cfg
Usermode/Applications/Makefile.tpl
Usermode/Applications/axwin2_src/Makefile [deleted file]
Usermode/Applications/axwin2_src/SIF.txt [deleted file]
Usermode/Applications/axwin2_src/Shell_src/Makefile [deleted file]
Usermode/Applications/axwin2_src/Shell_src/main.c [deleted file]
Usermode/Applications/axwin2_src/WM/Makefile [deleted file]
Usermode/Applications/axwin2_src/WM/commandline.c [deleted file]
Usermode/Applications/axwin2_src/WM/common.h [deleted file]
Usermode/Applications/axwin2_src/WM/decorator.c [deleted file]
Usermode/Applications/axwin2_src/WM/font_8x16.h [deleted file]
Usermode/Applications/axwin2_src/WM/helpers.c [deleted file]
Usermode/Applications/axwin2_src/WM/image.c [deleted file]
Usermode/Applications/axwin2_src/WM/image.h [deleted file]
Usermode/Applications/axwin2_src/WM/input.c [deleted file]
Usermode/Applications/axwin2_src/WM/interface.c [deleted file]
Usermode/Applications/axwin2_src/WM/main.c [deleted file]
Usermode/Applications/axwin2_src/WM/messages.c [deleted file]
Usermode/Applications/axwin2_src/WM/render.c [deleted file]
Usermode/Applications/axwin2_src/WM/resources/LogoSmall.sif [deleted file]
Usermode/Applications/axwin2_src/WM/resources/cursor.h [deleted file]
Usermode/Applications/axwin2_src/WM/video.c [deleted file]
Usermode/Applications/axwin2_src/WM/video_text.c [deleted file]
Usermode/Applications/axwin2_src/WM/wm.c [deleted file]
Usermode/Applications/axwin2_src/WM/wm.h [deleted file]
Usermode/Applications/axwin2_src/notes.txt [deleted file]
Usermode/Applications/axwin3_src/Interface/main.c
Usermode/Applications/axwin3_src/Makefile
Usermode/Applications/axwin3_src/WM/Makefile
Usermode/Applications/axwin3_src/WM/decorator.c
Usermode/Applications/axwin3_src/WM/include/common.h
Usermode/Applications/axwin3_src/WM/include/messages.h [deleted file]
Usermode/Applications/axwin3_src/WM/include/wm_hotkeys.h [new file with mode: 0644]
Usermode/Applications/axwin3_src/WM/include/wm_messages.h [deleted file]
Usermode/Applications/axwin3_src/WM/input.c
Usermode/Applications/axwin3_src/WM/ipc.c
Usermode/Applications/axwin3_src/WM/main.c
Usermode/Applications/axwin3_src/WM/renderers/passthru.c
Usermode/Applications/axwin3_src/WM/renderers/widget.c
Usermode/Applications/axwin3_src/WM/video.c
Usermode/Applications/axwin3_src/WM/wm_hotkeys.c [new file with mode: 0644]
Usermode/Applications/axwin3_src/WM/wm_input.c
Usermode/Applications/axwin3_src/include/framebuffer_messages.h [new file with mode: 0644]
Usermode/Applications/axwin3_src/include/ipcmessages.h
Usermode/Applications/axwin3_src/include/wm_messages.h [new file with mode: 0644]
Usermode/Applications/axwin3_src/libaxwin3.so_src/msg.c
Usermode/Applications/axwin3_src/libaxwin3.so_src/r_widget.c
Usermode/Applications/axwin3_src/libaxwin3.so_src/wm.c
Usermode/Applications/cat_src/main.c
Usermode/Applications/dhcpclient_src/main.c
Usermode/Applications/ip_src/addr.c
Usermode/Applications/ip_src/routes.c
Usermode/Applications/ip_src/rules.mk
Usermode/Applications/login_src/main.c
Usermode/Applications/ls_src/main.c
Usermode/Applications/lspci_src/Makefile [new file with mode: 0644]
Usermode/Applications/lspci_src/main.c [new file with mode: 0644]
Usermode/Applications/mount_src/main.c
Usermode/Applications/rules.mk
Usermode/Applications/wget_src/Makefile [new file with mode: 0644]
Usermode/Applications/wget_src/main.c [new file with mode: 0644]
Usermode/Libraries/Makefile.cfg
Usermode/Libraries/Makefile.tpl
Usermode/Libraries/acess.ld_src/acess_armv6.ld.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/Makefile
Usermode/Libraries/ld-acess.so_src/_stublib.c
Usermode/Libraries/ld-acess.so_src/arch/armv6.S.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/arch/armv6.ld [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/arch/armv7.ld
Usermode/Libraries/ld-acess.so_src/arch/syscalls.s.h
Usermode/Libraries/ld-acess.so_src/elf.c
Usermode/Libraries/ld-acess.so_src/export.c
Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/terminal.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/acess/intdefs.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/stddef_.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/sys/basic_drivers.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/sys/param.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/sys/stat.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/sys/sys.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/sys/types.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/include_exp/unistd.h [new file with mode: 0644]
Usermode/Libraries/ld-acess.so_src/lib.c
Usermode/Libraries/ld-acess.so_src/main.c
Usermode/Libraries/libaxwin2.so_src/Makefile [deleted file]
Usermode/Libraries/libaxwin2.so_src/common.h [deleted file]
Usermode/Libraries/libaxwin2.so_src/main.c [deleted file]
Usermode/Libraries/libaxwin2.so_src/messages.c [deleted file]
Usermode/Libraries/libaxwin2.so_src/windows.c [deleted file]
Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/axwin.h [new file with mode: 0644]
Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/keysyms.h [new symlink]
Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/menu.h [new file with mode: 0644]
Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/widget.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/Makefile
Usermode/Libraries/libc.so_src/arch/armv6.S [new file with mode: 0644]
Usermode/Libraries/libc.so_src/fileIO.c
Usermode/Libraries/libc.so_src/heap.c
Usermode/Libraries/libc.so_src/include_exp/assert.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/ctype.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/errno.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/setjmp.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/signal.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/stdio.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/stdlib.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/string.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/include_exp/time.h [new file with mode: 0644]
Usermode/Libraries/libc.so_src/perror.c [new file with mode: 0644]
Usermode/Libraries/libc.so_src/rules.mk
Usermode/Libraries/libc.so_src/stdlib.c
Usermode/Libraries/libc.so_src/string.c
Usermode/Libraries/libimage.so_src/include_exp/image.h [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/Makefile
Usermode/Libraries/libnet.so_src/include_exp/net.h [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/main.c
Usermode/Libraries/libnet.so_src/net.h [deleted file]
Usermode/Libraries/libnet.so_src/socket.c [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/dirent.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/fcntl.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/grp.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/pwd.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/sys/resource.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/sys/time.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/sys/wait.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/syslog.h [new file with mode: 0644]
Usermode/Libraries/libposix.so_src/include_exp/termios.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/Makefile [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/getaddrinfo.c [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/include_exp/arpa/inet.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/include_exp/netdb.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/include_exp/netinet/in.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/include_exp/sys/socket.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/include_exp/sys/un.h [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/main.c [new file with mode: 0644]
Usermode/Libraries/libpsocket.so_src/socket.c [new file with mode: 0644]
Usermode/Libraries/libreadline.so_src/include_exp/readline.h [new file with mode: 0644]
Usermode/Libraries/libreadline.so_src/main.c
Usermode/Libraries/liburi.so_src/include_exp/uri.h [new file with mode: 0644]
Usermode/Libraries/rules.mk
Usermode/Makefile.cfg
Usermode/include/acess/devices.h [deleted file]
Usermode/include/acess/devices/terminal.h [deleted file]
Usermode/include/acess/intdefs.h [deleted file]
Usermode/include/acess/sys.h [deleted file]
Usermode/include/axwin/axwin.h [deleted file]
Usermode/include/axwin/messages.h [deleted file]
Usermode/include/axwin2/axwin.h [deleted file]
Usermode/include/axwin2/messages.h [deleted file]
Usermode/include/axwin3/axwin.h [deleted file]
Usermode/include/axwin3/menu.h [deleted file]
Usermode/include/axwin3/widget.h [deleted file]
Usermode/include/ctype.h [deleted file]
Usermode/include/errno.h [deleted file]
Usermode/include/fcntl.h [deleted file]
Usermode/include/image.h [deleted file]
Usermode/include/net.h [deleted symlink]
Usermode/include/readline.h [deleted file]
Usermode/include/setjmp.h [deleted file]
Usermode/include/signal.h [deleted file]
Usermode/include/sqlite3.h [deleted file]
Usermode/include/stddef.h [deleted file]
Usermode/include/stdint.h [deleted file]
Usermode/include/stdio.h [deleted file]
Usermode/include/stdlib.h [deleted file]
Usermode/include/string.h [deleted file]
Usermode/include/sys/basic_drivers.h [deleted file]
Usermode/include/sys/socket.h [deleted file]
Usermode/include/sys/stat.h [deleted file]
Usermode/include/sys/sys.h [deleted file]
Usermode/include/sys/types.h [deleted file]
Usermode/include/time.h [deleted file]
Usermode/include/unistd.h [deleted file]
Usermode/include/uri.h [deleted file]

index c2b6411..fe240ee 100644 (file)
@@ -42,3 +42,7 @@ obj-*/
 Makefile.user.cfg
 QemuLog.txt
 Screenshots/
+
+Tools/*/src/obj/
+Tools/*/src/Makefile.BuildNum
+Tools/DiskTool/DiskTool
diff --git a/AcessNative/Makefile b/AcessNative/Makefile
new file mode 100644 (file)
index 0000000..c9cd481
--- /dev/null
@@ -0,0 +1,4 @@
+
+all:
+       @$(MAKE) -C acesskernel_src
+       @$(MAKE) -C ld-acess_src
index 9137ff9..6ea88b6 100755 (executable)
@@ -1,5 +1,6 @@
 #!/bin/sh
 trap '' 2
-./AcessKernel --rootapp /Acess/SBin/login
+#$1 ./AcessKernel --rootapp /Acess/SBin/login
+$1 ./AcessKernel --rootapp /Acess/Apps/AxWin/3.0/AxWinWM
 trap 2
 killall ld-acess
index 4cc939e..fddfbcc 100644 (file)
@@ -13,7 +13,7 @@ endif
 \r
 KERNEL_SRC = ../../KernelLand/Kernel/\r
 \r
-KERNEL_OBJ := logging.o adt.o lib.o drvutil.o debug.o messages.o\r
+KERNEL_OBJ := logging.o adt.o lib.o libc.o debug.o messages.o drvutil_disk.o drvutil_video.o\r
 KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o\r
 KERNEL_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o\r
 KERNEL_OBJ += vfs/fs/root.o vfs/fs/devfs.o\r
@@ -25,7 +25,7 @@ N_OBJ := main.o
 BUILDINFO_OBJ := obj-$(PLATFORM)/buildinfo.o\r
 BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c)\r
 \r
-OBJ := helpers.o threads.o server.o syscalls.o\r
+OBJ := helpers.o threads.o server.o syscalls.o time.o\r
 OBJ += video.o keyboard.o mouse.o nativefs.o vfs_handle.o ui_sdl.o\r
 OBJ := $(addprefix obj-$(PLATFORM)/,$(OBJ))\r
 N_OBJ := $(addprefix obj-$(PLATFORM)/,$(N_OBJ))\r
@@ -35,7 +35,7 @@ DEPFILES  = $(filter %.o,$(OBJ) $(N_OBJ) $(K_OBJ))
 DEPFILES := $(DEPFILES:%=%.dep)\r
 \r
 CPPFLAGS += -I include/ -I $(KERNEL_SRC)include/\r
-CFLAGS += -Wall -g\r
+CFLAGS += -Wall -g -std=gnu99\r
 LDFLAGS += -lSDL -lSDLmain -g -Wl,--defsym,__buildnum=$(BUILD_NUM)\r
 \r
 ifeq ($(PLATFORM),win)\r
@@ -79,8 +79,12 @@ $(N_OBJ): obj-$(PLATFORM)/%.o: %.c
 \r
 $(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) Makefile\r
        @echo "" > $@\r
+       $(eval _GITHASH=$(shell git log -n 1 | head -n 1 | awk '{print $$2}'))\r
+       $(eval _GITCHANGED=$(shell git status --porcelain | grep -c '^ M '))\r
        @echo "const char gsKernelVersion[] = \"$(ACESS_VERSION)\";" >> $@\r
-       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@\r
+       @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@\r
+       @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@\r
+       @echo "                           \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@\r
        @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@\r
 $(BUILDINFO_OBJ): $(BUILDINFO_SRC)\r
        @echo [CC] -o $@\r
index fb3e48c..3cf273e 100644 (file)
@@ -93,6 +93,10 @@ void Heap_Deallocate(void *Ptr)
        free(Ptr);
 }
 
+void Heap_Dump(void)
+{
+}
+
 tPAddr MM_GetPhysAddr(tVAddr VAddr)
 {
        return VAddr;   // HACK!
@@ -121,3 +125,8 @@ Sint64 now(void)
        return tv.tv_sec * 1000 + tv.tv_usec/1000;
 }
 
+void IPStack_SendDebugText(const char *str)
+{
+       // nop
+}
+
index f513530..03474cf 100644 (file)
@@ -37,8 +37,12 @@ struct sShortSpinlock
 
 #define SHORTLOCK(...)
 #define SHORTREL(...)
+#define CPU_HAS_LOCK(...)      0
 
 //#define      NUM_CFG_ENTRIES 10
 
+extern void    Debug_PutCharDebug(char ch);
+extern void    Debug_PutStringDebug(const char *str);
+
 #endif
 
diff --git a/AcessNative/acesskernel_src/include/threads_int.h b/AcessNative/acesskernel_src/include/threads_int.h
new file mode 100644 (file)
index 0000000..1294a5f
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _THREADS_INT_H_
+#define _THREADS_INT_H_
+
+/**
+ * \brief IPC Message
+ */
+typedef struct sMessage
+{
+       struct sMessage *Next;  //!< Next message in thread's inbox
+       tTID    Source; //!< Source thread ID
+       Uint    Length; //!< Length of message data in bytes
+       Uint8   Data[]; //!< Message data
+} tMsg;
+
+typedef struct sProcess
+{
+        int    nThreads;
+        int    NativePID;
+       char    *CWD;
+       char    *Chroot;
+        int    MaxFD;
+} tProcess;
+
+struct sThread
+{
+       struct sThread  *GlobalNext;
+       struct sThread  *Next;
+
+        int    KernelTID;
+
+       tTID    TID, PID;
+       tUID    UID, GID;
+
+       struct sThread  *Parent;
+
+       char    *ThreadName;
+
+        int    Status; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
+        int    ExitStatus;
+        int    _errno;
+
+       // Threads waiting for this thread to exit.
+       // Quit logic:
+       // - Wait for `WaitingThreads` to be non-null (maybe?)
+       // - Wake first in the queue, wait for it to be removed
+       // - Repeat
+       // - Free thread and quit kernel thread
+       struct sThread  *WaitingThreads;
+       struct sThread  *WaitingThreadsEnd;
+
+       tProcess        *Process;       
+
+       Uint32  Events, WaitMask;
+       void    *EventSem;      // Should be SDL_sem, but I don't want SDL in this header
+
+       // Message queue
+       tMsg * volatile Messages;       //!< Message Queue
+       tMsg    *LastMessage;   //!< Last Message (speeds up insertion)
+};
+
+enum {
+       THREAD_STAT_NULL,       // Invalid process
+       THREAD_STAT_ACTIVE,     // Running and schedulable process
+       THREAD_STAT_SLEEPING,   // Message Sleep
+       THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+       THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
+       THREAD_STAT_QUEUESLEEP, // Queue
+       THREAD_STAT_EVENTSLEEP, // Event sleep
+       THREAD_STAT_WAITING,    // ??? (Waiting for a thread)
+       THREAD_STAT_PREINIT,    // Being created
+       THREAD_STAT_ZOMBIE,     // Died/Killed, but parent not informed
+       THREAD_STAT_DEAD,       // Awaiting burial (free)
+       THREAD_STAT_BURIED      // If it's still on the list here, something's wrong
+};
+extern struct sThread  *Threads_GetThread(Uint TID);
+
+#endif
+
index 4f1b377..0e791b8 100644 (file)
@@ -5,7 +5,7 @@
  * nativefs.c\r
  * - Host filesystem access\r
  */\r
-#define DEBUG  1\r
+#define DEBUG  0\r
 #define off_t  _acess_off_t\r
 #include <acess.h>     // Acess\r
 #include <vfs.h>       // Acess\r
@@ -31,21 +31,26 @@ typedef struct
 tVFS_Node      *NativeFS_Mount(const char *Device, const char **Arguments);\r
 void   NativeFS_Unmount(tVFS_Node *Node);\r
 tVFS_Node      *NativeFS_FindDir(tVFS_Node *Node, const char *Name);\r
-char   *NativeFS_ReadDir(tVFS_Node *Node, int Position);\r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+ int   NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX]);\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer);\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer);\r
+void   NativeFS_Close(tVFS_Node *Node);\r
 \r
 // === GLOBALS ===\r
 tVFS_NodeType  gNativeFS_FileNodeType = {\r
-       .Read = NativeFS_Read\r
+       .Read = NativeFS_Read,\r
+       .Write = NativeFS_Write,\r
+       .Close = NativeFS_Close\r
 };\r
 tVFS_NodeType  gNativeFS_DirNodeType = {\r
        .FindDir = NativeFS_FindDir,\r
        .ReadDir = NativeFS_ReadDir,\r
+       .Close = NativeFS_Close\r
 };\r
 tVFS_Driver    gNativeFS_Driver = {\r
-       "nativefs", 0,\r
-       NativeFS_Mount, NativeFS_Unmount,\r
-       NULL,\r
+       .Name = "nativefs",\r
+       .InitDevice = NativeFS_Mount,\r
+       .Unmount = NativeFS_Unmount\r
 };\r
 \r
 // === CODE ===\r
@@ -63,7 +68,7 @@ tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)
        \r
        dp = opendir(Device);\r
        if(!dp) {\r
-               Log_Warning("NativeFS", "ERRO: Unable to open device root '%s'", Device);\r
+               Log_Warning("NativeFS", "ERROR: Unable to open device root '%s'", Device);\r
                return NULL;\r
        }\r
        \r
@@ -78,11 +83,11 @@ tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments)
        ret->Data = strdup(Device);\r
        ret->ImplInt = strlen(ret->Data);\r
        ret->ImplPtr = info;\r
-       ret->Inode = (Uint64)dp;\r
+       ret->Inode = (Uint64)(tVAddr)dp;\r
        ret->Flags = VFS_FFLAG_DIRECTORY;\r
 \r
        ret->Type = &gNativeFS_DirNodeType;     \r
-       \r
+\r
        return ret;\r
 }\r
 \r
@@ -90,7 +95,7 @@ void NativeFS_Unmount(tVFS_Node *Node)
 {\r
        tNativeFS       *info = Node->ImplPtr;\r
        Inode_ClearCache( info->InodeHandle );\r
-       closedir( (void *)Node->Inode );\r
+       closedir( (void *)(tVAddr)Node->Inode );\r
        free(Node->Data);\r
        free(Node);\r
        free(info);\r
@@ -99,12 +104,18 @@ void NativeFS_Unmount(tVFS_Node *Node)
 void NativeFS_Close(tVFS_Node *Node)\r
 {\r
        tNativeFS       *info = Node->ImplPtr;\r
-       Inode_UncacheNode( info->InodeHandle, Node->Inode );\r
+       DIR     *dp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? (DIR*)(tVAddr)Node->Inode : 0;\r
+       FILE    *fp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? 0 : (FILE*)(tVAddr)Node->Inode;\r
+       \r
+       if( Inode_UncacheNode( info->InodeHandle, Node->Inode ) == 1 ) {\r
+               if(dp)  closedir(dp);\r
+               if(fp)  fclose(fp);\r
+       }\r
 }\r
 \r
 tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)\r
 {\r
-       char    *path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
+       char    *path;\r
        tNativeFS       *info = Node->ImplPtr;\r
        tVFS_Node       baseRet;\r
        struct stat statbuf;\r
@@ -112,6 +123,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        ENTER("pNode sName", Node, Name);\r
        \r
        // Create path\r
+       path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
        strcpy(path, Node->Data);\r
        path[Node->ImplInt] = '/';\r
        strcpy(path + Node->ImplInt + 1, Name);\r
@@ -132,7 +144,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        if( S_ISDIR(statbuf.st_mode) )\r
        {\r
                LOG("Directory");\r
-               baseRet.Inode = (Uint64) opendir(path);\r
+               baseRet.Inode = (Uint64)(tVAddr) opendir(path);\r
                baseRet.Type = &gNativeFS_DirNodeType;\r
                baseRet.Flags |= VFS_FFLAG_DIRECTORY;\r
                baseRet.Size = -1;\r
@@ -140,7 +152,7 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        else\r
        {\r
                LOG("File");\r
-               baseRet.Inode = (Uint64) fopen(path, "r+");\r
+               baseRet.Inode = (Uint64)(tVAddr) fopen(path, "r+");\r
                baseRet.Type = &gNativeFS_FileNodeType;\r
                \r
                fseek( (FILE*)(tVAddr)baseRet.Inode, 0, SEEK_END );\r
@@ -156,11 +168,10 @@ tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)
        return Inode_CacheNode(info->InodeHandle, &baseRet);\r
 }\r
 \r
-char *NativeFS_ReadDir(tVFS_Node *Node, int Position)\r
+int NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX])\r
 {\r
        struct dirent   *ent;\r
        DIR     *dp = (void*)(tVAddr)Node->Inode;\r
-       char    *ret;\r
 \r
        ENTER("pNode iPosition", Node, Position);\r
 \r
@@ -172,26 +183,42 @@ char *NativeFS_ReadDir(tVFS_Node *Node, int Position)
        } while(Position-- && ent);\r
 \r
        if( !ent ) {\r
-               LEAVE('n');\r
-               return NULL;\r
+               LEAVE('i', -ENOENT);\r
+               return -ENOENT;\r
        }\r
        \r
-       ret = strdup(ent->d_name);\r
+       strncpy(Dest, ent->d_name, FILENAME_MAX);\r
 \r
        // TODO: Unlock node    \r
 \r
-       LEAVE('s', ret);\r
-       return ret;\r
+       LEAVE('i', 0);\r
+       return 0;\r
 }\r
 \r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
 {\r
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
-       if( fseek( (void *)Node->Inode, Offset, SEEK_SET ) != 0 )\r
+       ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+       if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
        {\r
                LEAVE('i', 0);\r
                return 0;\r
        }\r
        LEAVE('-');\r
-       return fread( Buffer, 1, Length, (void *)Node->Inode );\r
+       return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
+}\r
+\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
+{\r
+       FILE    *fp = (FILE *)(tVAddr)Node->Inode;\r
+       ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+       if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
+       {\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       size_t ret = fwrite( Buffer, 1, Length, fp );\r
+       fflush( fp );\r
+       LEAVE('i', ret);\r
+       return ret;\r
+\r
 }\r
index 7bb5033..2e3f3a9 100644 (file)
 # include <unistd.h>
 # include <sys/socket.h>
 # include <netinet/in.h>
+# include <arpa/inet.h>        // inet_ntop
 #endif
 #include "../syscalls.h"
 //#include <debug.h>
 
-#define        USE_TCP 0
+#define        USE_TCP 1
 #define MAX_CLIENTS    16
 
 // === TYPES ===
@@ -27,6 +28,7 @@ typedef struct {
         int    ClientID;
        SDL_Thread      *WorkerThread;
        #if USE_TCP
+        int    Socket;
        #else
        tRequestHeader  *CurrentRequest;
        struct sockaddr_in      ClientAddr;
@@ -42,6 +44,7 @@ extern void   Threads_SetThread(int TID);
 // HACK: Should have these in a header
 extern void    Log_Debug(const char *Subsys, const char *Message, ...);
 extern void    Log_Notice(const char *Subsys, const char *Message, ...);
+extern void    Log_Warning(const char *Subsys, const char *Message, ...);
 
 // === PROTOTYPES ===
 tClient        *Server_GetClient(int ClientID);
@@ -102,12 +105,19 @@ tClient *Server_GetClient(int ClientID)
        
        // Allocate a thread for the process
        ret->ClientID = ClientID;
+       #if USE_TCP
+       ret->Socket = 0;
+       #else
        ret->CurrentRequest = NULL;
+       #endif
                
        if( !ret->WorkerThread ) {
+               #if USE_TCP
+               #else
                ret->WaitFlag = SDL_CreateCond();
                ret->Mutex = SDL_CreateMutex();
                SDL_mutexP( ret->Mutex );
+               #endif
                ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
        }
        
@@ -117,28 +127,92 @@ tClient *Server_GetClient(int ClientID)
 int Server_WorkerThread(void *ClientPtr)
 {
        tClient *Client = ClientPtr;
+       
+       #if USE_TCP
+       for( ;; )
+       {
+               fd_set  fds;
+                int    nfd = Client->Socket;
+               FD_ZERO(&fds);
+               FD_SET(Client->Socket, &fds);
+               
+               select(nfd, &fds, NULL, NULL, NULL);    // TODO: Timeouts?
+               
+               if( FD_ISSET(Client->Socket, &fds) )
+               {
+                       const int       ciMaxParamCount = 6;
+                       char    lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
+                       tRequestHeader  *hdr = (void*)lbuf;
+                       size_t  len = recv(Client->Socket, hdr, sizeof(*hdr), 0);
+                       if( len != sizeof(hdr) ) {
+                               // Oops?
+                       }
+
+                       if( hdr->NParams > ciMaxParamCount ) {
+                               // Oops.
+                       }
+
+                       len = recv(Client->Socket, hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
+                       if( len != hdr->NParams*sizeof(tRequestValue) ) {
+                               // Oops.
+                       }
+
+                       // Get buffer size
+                       size_t  hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
+                       size_t  bufsize = hdrsize;
+                        int    i;
+                       for( i = 0; i < hdr->NParams; i ++ )
+                       {
+                               if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
+                                       ;
+                               else {
+                                       bufsize += hdr->Params[i].Length;
+                               }
+                       }
+
+                       // Allocate full buffer
+                       hdr = malloc(bufsize);
+                       memcpy(hdr, lbuf, hdrsize);
+                       len = recv(Client->Socket, hdr->Params + hdr->NParams, bufsize - hdrsize, 0);
+                       if( len != bufsize - hdrsize ) {
+                               // Oops?
+                       }
+
+                        int    retlen;
+                       tRequestHeader  *retHeader;
+                       retHeader = SyscallRecieve(hdr, &retlen);
+                       if( !retHeader ) {
+                               // Some sort of error
+                       }
+                       
+                       send(Client->Socket, retHeader, retlen, 0); 
+
+                       // Clean up
+                       free(hdr);
+               }
+       }
+       #else
        tRequestHeader  *retHeader;
        tRequestHeader  errorHeader;
         int    retSize = 0;
         int    sentSize;
         int    cur_client_id = 0;
-       
-       #if USE_TCP
-       #else
        for( ;; )
        {
                // Wait for something to do
                while( Client->CurrentRequest == NULL )
                        SDL_CondWait(Client->WaitFlag, Client->Mutex);
                
+//             Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
+               
                if(Client->ClientID != cur_client_id) {
+//                     Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
+//                             cur_client_id, Client->ClientID);
                        Threads_SetThread( Client->ClientID );
                        cur_client_id = Client->ClientID;
                }
                
-               // Get the response
-               retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
-
+               // Debug
                {
                        int     callid = Client->CurrentRequest->CallID;
                        Log_Debug("AcessSrv", "Client %i request %i %s",
@@ -147,7 +221,9 @@ int Server_WorkerThread(void *ClientPtr)
                                );
                }
                
-               
+               // Get the response
+               retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
+
                if( !retHeader ) {
                        // Return an error to the client
                        printf("ERROR: SyscallRecieve failed\n");
@@ -249,18 +325,55 @@ int Server_ListenThread(void *Unused)
        for( ;; )
        {
                #if USE_TCP
-               struct sockaddr_in      client;
-               uint    clientSize = sizeof(client);
-                int    clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
+               struct sockaddr_in      clientaddr;
+               socklen_t       clientSize = sizeof(clientaddr);
+                int    clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
                if( clientSock < 0 ) {
                        perror("SyscallServer - accept");
                        break ;
                }
+
+               char    addrstr[4*8+8+1];
+               inet_ntop(clientaddr.sin_family, &clientaddr.sin_addr, addrstr, sizeof(addrstr));
+               Log_Debug("Server", "Client connection %s:%i\n", addrstr, ntohs(clientaddr.sin_port));
                
-               Log("Client connection %x:%i\n",
-                       ntohl(client.sin_addr), ntohs(client.sin_port)
-                       );
+               // Perform auth
+               size_t  len;
+               tRequestAuthHdr authhdr;
+               len = recv(clientSock, &authhdr, sizeof(authhdr), 0);
+               if( len != sizeof(authhdr) ) {
+                       // Some form of error?
+               }
+               
+               tClient *client;
+               if( authhdr.pid == 0 ) {
+                       // Allocate PID and client structure/thread
+                       client = Server_GetClient(0);
+                       client->Socket = clientSock;
+                       authhdr.pid = client->ClientID;
+               }
+               else {
+                       // Get client structure and make sure it's unused
+                       // - Auth token / verifcation?
+                       client = Server_GetClient(authhdr.pid);
+                       if( client->Socket != 0 ) {
+                               Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
+                                       authhdr.pid, client, addrstr, clientaddr.sin_port);
+                               authhdr.pid = 0;
+                       }
+                       else {
+                               client->Socket = clientSock;
+                       }
+               }
                
+               len = send(clientSock, &authhdr, sizeof(authhdr), 0);
+               if( len != sizeof(authhdr) ) {
+                       // Ok, this is an error
+                       perror("Sending auth reply");
+               }
+
+               // All done, client thread should be watching now               
+
                #else
                char    data[BUFSIZ];
                tRequestHeader  *req = (void*)data;
@@ -302,8 +415,8 @@ int Server_ListenThread(void *Unused)
                        continue;
                }
                
-               Log_Debug("AcessSrv", "Message from Client %i (%p)",
-                       client->ClientID, client);
+//             Log_Debug("AcessSrv", "Message from Client %i (%p)",
+//                     client->ClientID, client);
 
                // Make a copy of the request data      
                req = malloc(length);
index 58dc801..9b9fda4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Syscall Distribution
  */
-#define DEBUG  1
+#define DEBUG  0
 #include <acess.h>
 #include <threads.h>
 #include <events.h>
@@ -194,10 +194,21 @@ SYSCALL2(Syscall_SendMessage, "id", int, void *,
        return Proc_SendMessage(a0, Sizes[1], a1);
 );
 
-SYSCALL2(Syscall_GetMessage, "dd", Uint *, void *,
-       if( Sizes[0] < sizeof(*a0) )
+SYSCALL2(Syscall_GetMessage, "dd", uint32_t *, void *,
+       if( a0 && Sizes[0] < sizeof(*a0) ) {
+               Log_Notice("Syscalls", "Syscall_GetMessage - Arg 1 Undersize (%i < %i)",
+                       Sizes[0], sizeof(*a0));
                return -1;
-       return Proc_GetMessage(a0, a1);
+       }
+       Uint    tmp;
+        int    rv;
+       if( a0 ) {
+               rv = Proc_GetMessage(&tmp, a1);
+               *a0 = tmp;
+       }
+       else
+               rv = Proc_GetMessage(NULL, a1);
+       return rv;
 );
 
 SYSCALL1(Syscall_WaitEvent, "i", int,
@@ -298,7 +309,7 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
        }
        formatString[i] = '\0';
        
-       //LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
+       LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
        
        {
                char    argListData[argListLen];
@@ -341,7 +352,13 @@ tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
                                }
                                
                                // Check for non-resident data
-                               if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
+                               if( Request->Params[i].Length == 0 )
+                               {
+                                       returnData[i] = NULL;
+                                       *(void**)&argListData[argListLen] = NULL;
+                                       argListLen += sizeof(void*);
+                               }
+                               else if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
                                {
                                        // Allocate and zero the buffer
                                        returnData[i] = calloc(1, Request->Params[i].Length);
index 71fa294..a7aace8 100644 (file)
@@ -15,7 +15,9 @@
 #include <acess.h>
 #include <mutex.h>
 #include <semaphore.h>
+#include <rwlock.h>
 #include <events.h>
+#include <threads_int.h>
 
 #undef CLONE_VM        // Such a hack
 #undef off_t   
@@ -41,49 +43,6 @@ typedef struct sState
 }      tState;
 #endif
 
-typedef struct sProcess
-{
-        int    nThreads;
-        int    NativePID;
-       char    *CWD;
-       char    *Chroot;
-        int    MaxFD;
-} tProcess;
-
-struct sThread
-{
-       struct sThread  *GlobalNext;
-       struct sThread  *Next;
-
-        int    KernelTID;
-
-       tTID    TID, PID;
-       tUID    UID, GID;
-
-       struct sThread  *Parent;
-
-       char    *ThreadName;
-
-        int    State;  // 0: Dead, 1: Active, 2: Paused, 3: Asleep
-        int    ExitStatus;
-        int    _errno;
-
-       // Threads waiting for this thread to exit.
-       // Quit logic:
-       // - Wait for `WaitingThreads` to be non-null (maybe?)
-       // - Wake first in the queue, wait for it to be removed
-       // - Repeat
-       // - Free thread and quit kernel thread
-       struct sThread  *WaitingThreads;
-       struct sThread  *WaitingThreadsEnd;
-
-       tProcess        *Process;       
-
-       Uint32  Events, WaitMask;
-       SDL_sem *EventSem;
-
-};
-
 // === PROTOTYPES ===
  int   Threads_Wake(tThread *Thread);
 
@@ -95,7 +54,7 @@ tProcess gProcessZero = {
        .MaxFD = 100
 };
 tThread        gThreadZero = {
-       .State=1,
+       .Status=THREAD_STAT_ACTIVE,
        .ThreadName="ThreadZero",
        .Process = &gProcessZero
 };
@@ -136,13 +95,14 @@ void Threads_SetThread(int TID)
        Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
 }
 
-tThread        *Threads_GetThread(int TID)
+tThread        *Threads_GetThread(Uint TID)
 {
        tThread *thread;
        for( thread = gpThreads; thread; thread = thread->GlobalNext )
        {
-               if( thread->TID == TID )
+               if( thread->TID == TID ) {
                        return thread;
+               }
        }
        return NULL;
 }
@@ -232,7 +192,7 @@ tTID Threads_WaitTID(int TID, int *Status)
                if(!thread)     return -1;
                
                us->Next = NULL;
-               us->State = 3;
+               us->Status = THREAD_STAT_WAITING;
                // TODO: Locking
                if(thread->WaitingThreadsEnd)
                {
@@ -298,7 +258,7 @@ void Threads_Exit(int TID, int Status)
 
 int Threads_Wake(tThread *Thread)
 {
-       Thread->State = 0;
+       Thread->Status = THREAD_STAT_ACTIVE;
        Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
        return 0;
 }
@@ -332,6 +292,9 @@ int Threads_Fork(void)
        return thread->PID;
 }
 
+// --------------------------------------------------------------------
+// Mutexes 
+// --------------------------------------------------------------------
 int Mutex_Acquire(tMutex *Mutex)
 {
        if(!Mutex->Protector.IsValid) {
@@ -347,6 +310,9 @@ void Mutex_Release(tMutex *Mutex)
        pthread_mutex_unlock( &Mutex->Protector.Mutex );
 }
 
+// --------------------------------------------------------------------
+// Semaphores
+// --------------------------------------------------------------------
 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
 {
        memset(Sem, 0, sizeof(tSemaphore));
@@ -368,6 +334,36 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
        return AmmountToAdd;
 }
 
+// --------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+       if( !Lock->ReaderWaiting ) {
+               Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
+               pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
+       }
+       pthread_rwlock_rdlock( (void*)Lock->ReaderWaiting );
+       return 0;
+}
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+       if( !Lock->ReaderWaiting ) {
+               Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
+               pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
+       }
+       pthread_rwlock_wrlock( (void*)Lock->ReaderWaiting );
+       return 0;
+}
+void RWLock_Release(tRWLock *Lock)
+{
+       pthread_rwlock_unlock( (void*)Lock->ReaderWaiting );
+}
+
+
+// --------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------
 Uint32 Threads_WaitEvents(Uint32 Mask)
 {
        Uint32  rv;
@@ -397,3 +393,8 @@ void Threads_PostEvent(tThread *Thread, Uint32 Events)
        }
 }
 
+void Threads_ClearEvent(Uint32 EventMask)
+{
+       gpCurrentThread->Events &= ~EventMask;
+}
+
diff --git a/AcessNative/acesskernel_src/time.c b/AcessNative/acesskernel_src/time.c
new file mode 100644 (file)
index 0000000..89669cf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Acess2 Native Kernel
+ * - Acess kernel emulation on another OS using SDL and UDP
+ *
+ * time.c
+ * - Timer code
+ */
+#include <acess.h>
+#include <timers.h>
+
+struct sTimer {
+       tTimer  *Next;
+       Sint64  FiresAfter;
+       void    (*Callback)(void*);
+       void    *Argument;
+       BOOL    bActive;
+};
+
+// === CODE ===
+tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument)
+{
+       return NULL;
+}
+
+tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
+{
+       return NULL;
+}
+
+void Time_FreeTimer(tTimer *Timer)
+{
+}
+
+void Time_ScheduleTimer(tTimer *Timer, int Delta)
+{
+}
+
+void Time_RemoveTimer(tTimer *Timer)
+{
+}
index 6235431..d04ac6d 100644 (file)
@@ -1,7 +1,11 @@
 /*
- * AcessNative
+ * AcessNative Dynamic Linker
+ * - By John Hodge (thePowersGang)
+ * 
+ * binary.c
+ * - Provides binary loading and type abstraction
  */
-#define DEBUG  1
+#define DEBUG  0
 #include "common.h"
 #include <stdint.h>
 #include <stdio.h>
@@ -24,6 +28,7 @@ extern uintptr_t      ElfRelocate(void *Base);
 extern int     ElfGetSymbol(void *Base, char *Name, uintptr_t *ret, size_t *size);
 extern int     ciNumBuiltinSymbols;
 extern tSym    caBuiltinSymbols[];
+extern char    **gEnvP;
 
 // === PROTOTYPES ===
 void   Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format);
@@ -109,7 +114,8 @@ void *Binary_LoadLibrary(const char *Name)
        }
 
        ret = Binary_Load(path, (uintptr_t*)&entry);
-       printf("LOADED '%s' to %p (Entry=%p)\n", path, ret, entry);
+       if( ret != (void*)-1 )
+               Debug("LOADED '%s' to %p (Entry=%p)", path, ret, entry);
        free(path);
        
        #if DEBUG
@@ -120,7 +126,7 @@ void *Binary_LoadLibrary(const char *Name)
                #if DEBUG
                printf("Calling '%s' entry point %p\n", Name, entry);
                #endif
-               entry(ret, 0, argv, NULL);
+               entry(ret, 0, argv, gEnvP);
        }
 
        return ret;
index 590da37..909c24a 100644 (file)
@@ -3,7 +3,7 @@
  *\r
  * ELF Executable Loader Code\r
  */\r
-#define DEBUG  1\r
+#define DEBUG  0\r
 #include <stdlib.h>\r
 #include <stdio.h>\r
 #include <string.h>\r
@@ -190,9 +190,9 @@ void *Elf64Load(int FD, Elf64_Ehdr *hdr)
        \r
        ENTER("iFD", FD);\r
        \r
-       #if BITS <= 32\r
-       Warning("ELF64 being loaded in 32-bit env, this may not work");\r
-       #endif\r
+       if( sizeof(void*) == 4) {\r
+               Warning("ELF64 being loaded in 32-bit env, this may not work");\r
+       }\r
 \r
        // Check for a program header\r
        if(hdr->e_phoff == 0) {\r
index 406e55f..fc336c8 100644 (file)
@@ -5,7 +5,7 @@
  * - Exported functions
  */
 #define DONT_INCLUDE_SYSCALL_NAMES 1
-#include "../../Usermode/include/acess/sys.h"
+#include "../../Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h"
 #include "../syscalls.h"
 #include "exports.h"
 #include <stdarg.h>
@@ -68,14 +68,16 @@ int acess_reopen(int FD, const char *Path, int Flags) {
 size_t acess_read(int FD, void *Dest, size_t Bytes) {
        if(FD & NATIVE_FILE_MASK)
                return native_read(FD & (NATIVE_FILE_MASK-1), Dest, Bytes);
-       DEBUG("read(0x%x, 0x%x, *%p)", FD, Bytes, Dest);
+//     if( FD > 2 )
+               DEBUG("read(0x%x, 0x%x, *%p)", FD, Bytes, Dest);
        return _Syscall(SYS_READ, ">i >i <d", FD, Bytes, Bytes, Dest);
 }
 
 size_t acess_write(int FD, const void *Src, size_t Bytes) {
        if(FD & NATIVE_FILE_MASK)
                return native_write(FD & (NATIVE_FILE_MASK-1), Src, Bytes);
-       DEBUG("write(0x%x, 0x%x, %p\"%.*s\")", FD, Bytes, Src, Bytes, (char*)Src);
+//     if( FD > 2 )
+               DEBUG("write(0x%x, 0x%x, %p\"%.*s\")", FD, Bytes, Src, Bytes, (char*)Src);
        return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src);
 }
 
@@ -95,8 +97,8 @@ uint64_t acess_tell(int FD) {
 
 int acess_ioctl(int fd, int id, void *data) {
         int    len;
-       // NOTE: 1024 byte size is a hack
        DEBUG("ioctl(%i, %i, %p)", fd, id, data);
+       // NOTE: The length here is hacky and could break
        if( data == NULL )
                len = 0;
        else
@@ -267,7 +269,7 @@ int acess_SysGetMessage(int *SourceTID, void *Data)
        int lastlen;
 
        lastlen = _Syscall(SYS_GETMSG, "<d <d",
-               SourceTID ? sizeof(int) : 0, SourceTID,
+               SourceTID ? sizeof(uint32_t) : 0, SourceTID,
                Data ? 1024 : 0, Data
                );
        return lastlen;
@@ -285,7 +287,7 @@ void acess__SysDebug(const char *Format, ...)
        
        va_start(args, Format);
        
-       printf("[_SysDebug %i]", giSyscall_ClientID);
+       printf("[_SysDebug %i] ", giSyscall_ClientID);
        vprintf(Format, args);
        printf("\n");
        
index feb5bfd..121a3ae 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _EXPORTS_H_
 #define _EXPORTS_H_
 
+#include <stddef.h>
+
 // Syscall request (used by acess_*)
 extern uint64_t        _Syscall(int SyscallID, const char *ArgTypes, ...);
 
index 80c5b7a..0c9b743 100644 (file)
@@ -15,6 +15,9 @@ extern void   Request_Preinit(void);
 // === PROTOTYPES ===
 void   CallUser(void *Entry, int argc, char *argv[], char **envp) __attribute__((noreturn));
 
+// === GLOBALS ===
+char   **gEnvP;
+
 // === CODE ===
 int main(int argc, char *argv[], char **envp)
 {
@@ -25,6 +28,8 @@ int main(int argc, char *argv[], char **envp)
         int    (*appMain)(int, char *[], char **);
        void    *base;
         int    rv;
+
+       gEnvP = envp;
        
        Request_Preinit();
 
index f1147c2..2e9612c 100644 (file)
@@ -53,7 +53,7 @@ uintptr_t FindFreeRange(size_t ByteCount, int MaxBits)
 
        end <<= (sizeof(intptr_t)*8-MaxBits);
        end >>= (sizeof(intptr_t)*8-MaxBits);
-       printf("end = %p\n", (void*)end);
+//     printf("end = %p\n", (void*)end);
        
 //     for( base = 0; base < end - size; base -= PAGE_SIZE )
        for( base = end - size + 1; base > 0; base -= PAGE_SIZE )
index d1a0bdc..37bc88c 100644 (file)
  * uint8_t     paramData[SUM(params[].Lengh)];
  */
 
+typedef struct {
+       uint32_t        pid;
+       uint32_t        key;
+} tRequestAuthHdr;
+
 typedef struct sRequestValue {
        /// \see eArgumentTypes
        uint16_t        Type;
diff --git a/BuildConf/armv6/Makefile.cfg b/BuildConf/armv6/Makefile.cfg
new file mode 100644 (file)
index 0000000..00ed889
--- /dev/null
@@ -0,0 +1,18 @@
+
+ARM_CPUNAME = gerneric-armv6
+CC = arm-armv6-eabi-gcc -mcpu=$(ARM_CPUNAME)
+AS = arm-armv6-eabi-gcc -mcpu=$(ARM_CPUNAME) -c
+LD = arm-armv6-eabi-ld
+OBJDUMP = arm-armv6-eabi-objdump
+DISASM = $(OBJDUMP) -d -S
+ARCHDIR = armv6
+STRIP = arm-elf-strip
+
+ASSUFFIX = S
+
+# Default Configuration
+ifeq ($(PLATFORM),)
+       PLATFORM=raspberrypi
+$(warning Defaulting to "PLATFORM=$(PLATFORM)")
+endif
+
diff --git a/BuildConf/armv6/default.mk b/BuildConf/armv6/default.mk
new file mode 100644 (file)
index 0000000..3b3cc8b
--- /dev/null
@@ -0,0 +1,7 @@
+
+ifeq ($(PLATFORM),default)
+       $(error Please select a platform)
+endif
+
+#MODULES += armv7/GIC
+MODULES += Filesystems/InitRD
diff --git a/BuildConf/armv6/raspberrypi.mk b/BuildConf/armv6/raspberrypi.mk
new file mode 100644 (file)
index 0000000..01f08df
--- /dev/null
@@ -0,0 +1,3 @@
+
+include $(ACESSDIR)/BuildConf/armv6/default.mk
+ARM_CPUNAME = arm1176jzf-s
index 9be93a7..340fa0d 100644 (file)
@@ -1,7 +1,8 @@
 
-CC = arm-elf-gcc
-AS = arm-elf-gcc -c
-LD = arm-elf-ld
+ARM_CPUNAME = gerneric-armv7
+CC = arm-eabi-gcc -mcpu=$(ARM_CPUNAME)
+AS = arm-eabi-gcc -mcpu=$(ARM_CPUNAME) -c
+LD = arm-eabi-ld
 OBJDUMP = arm-elf-objdump
 DISASM = $(OBJDUMP) -d -S
 ARCHDIR = armv7
index 4b284ee..abb08e2 100644 (file)
@@ -1,5 +1,6 @@
 
 include $(ACESSDIR)/BuildConf/armv7/default.mk
 
+ARM_CPUNAME = cortex-a8
 MODULES += Input/PS2KbMouse
 MODULES += Display/PL110
index 4abc5c8..24eddf5 100644 (file)
@@ -1,4 +1,6 @@
 
 include $(ACESSDIR)/BuildConf/armv7/default.mk
 
+ARM_CPUNAME = cortex-a9
 MODULES += Display/Tegra2Vid
+MODULES += USB/Core USB/EHCI
index 51bb9fc..ff8de6e 100644 (file)
@@ -3,6 +3,7 @@ MODULES += Storage/ATA
 MODULES += Storage/FDDv2
 MODULES += Network/NE2000 Network/RTL8139
 MODULES += Network/VIARhineII
+MODULES += Network/E1000
 MODULES += Display/VESA
 MODULES += Display/BochsGA
 #MODULES += Display/VIAVideo
@@ -10,6 +11,9 @@ MODULES += Input/PS2KbMouse
 MODULES += x86/ISADMA x86/VGAText
 
 MODULES += USB/Core USB/UHCI
+#MODULES += USB/EHCI
 #USB/OHCI
-MODULES += USB/HID
+MODULES += USB/HID USB/MSC
 #MODULES += Interfaces/UDI
+
+DYNMODS += Filesystems/InitRD
index 6aa3afc..ebca2d9 100644 (file)
@@ -1,6 +1,6 @@
 
-PREFIX := x86_64-pc-elf
-#PREFIX := x86_64-none-elf
+#PREFIX := x86_64-pc-elf
+PREFIX := x86_64-none-elf
 
 CC := $(PREFIX)-gcc
 LD := $(PREFIX)-ld
index 2afabe8..51960b0 100644 (file)
@@ -1,8 +1,5 @@
 
-MODULES += Storage/ATA
-MODULES += Storage/FDDv2
-MODULES += Network/NE2000 Network/RTL8139
-MODULES += Display/BochsGA
-MODULES += Interfaces/UDI
-MODULES += Input/PS2KbMouse
-MODULES += x86/ISADMA x86/VGAText
+include $(ACESSDIR)/BuildConf/x86/default.mk
+
+MODULES := $(filter-out Display/VESA,$(MODULES))
+
index 81a2928..a82bbc9 100644 (file)
@@ -25,10 +25,11 @@ ASFLAGS         += -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
 CPPFLAGS       += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\"
 CPPFLAGS       += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
 CPPFLAGS       += -D KERNEL_VERSION=$(KERNEL_VERSION) -ffreestanding
-CFLAGS         += -Wall -fno-stack-protector -Wstrict-prototypes -g
+CFLAGS         += -Wall -fno-stack-protector -Wstrict-prototypes -std=gnu99 -g
 CFLAGS         += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized
 CFLAGS          += -O3
 LDFLAGS                += -T arch/$(ARCHDIR)/link.ld -g
+LIBGCC_PATH     := $(shell $(CC) -print-libgcc-file-name)
 
 ifeq ($(PLATFORM),default)
        OBJDIR := obj-$(ARCH)/
@@ -51,10 +52,12 @@ BUILDINFO_OBJ := $(OBJDIR)buildinfo.o$(OBJSUFFIX)
 BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
 
 OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
-OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
+OBJ += pmemmap.o
+OBJ += heap.o logging.o debug.o lib.o libc.o adt.o time.o
+OBJ += drvutil_video.o drvutil_disk.o
 OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
-OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += threads.o mutex.o semaphore.o workqueue.o events.o rwlock.o
+OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o drv/vpci.o
 OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
 OBJ += binary.o bin/elf.o bin/pe.o
 OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
@@ -85,10 +88,6 @@ clean:
 # Creates a stripped and compressed copy of the kernel
 # and installs it to the target
 install: $(BIN) 
-       @cp $(BIN) $(BIN)_
-       @$(STRIP) $(BIN)_
-       @gzip -c $(BIN)_ > $(GZBIN)
-       @$(RM) $(BIN)_
        $(xCP) $(GZBIN) $(DISTROOT)
 
 # Compile API documentation
@@ -98,16 +97,18 @@ apidoc:
 # Output binary
 # - Links kernel
 # - Disassembles it
-# - Gets a line count
 # - Increments the build count
 # - Does whatever architecture defined rules
 $(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../../BuildConf/$(ARCH)/Makefile.cfg ../../BuildConf/$(ARCH)/$(PLATFORM).mk
        @echo --- LD -o $(BIN)
-       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
+       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) $(LIBGCC_PATH) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
        @$(DISASM) -S $(BIN) > $(BIN).dsm
-       @wc -l $(SRCFILES) include/*.h > LineCounts.$(ARCH).txt
        @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum.$(ARCH)
        $(POSTBUILD)
+       @cp $(BIN) $(BIN)_
+       @$(STRIP) $(BIN)_ || true
+       @gzip -c $(BIN)_ > $(GZBIN)
+       @$(RM) $(BIN)_
 
 # Assembly Sources
 $(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile
@@ -115,7 +116,7 @@ $(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile
        @mkdir -p $(dir $@)
        @$(AS) $(ASFLAGS) $< -o $@
 ifeq ($(AS_SUFFIX),S)
-       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
+       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
 endif
 
 # C Sources
@@ -123,7 +124,7 @@ $(OBJDIR)%.o$(OBJSUFFIX): %.c Makefile
        @echo --- CC -o $@
        @mkdir -p $(dir $@)
        @$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
-       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
+       @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
 
 # Build-time linked modules
 %.xo.$(ARCH):
@@ -133,14 +134,18 @@ $(OBJDIR)%.o$(OBJSUFFIX): %.c Makefile
 include/syscalls.h include/syscalls.inc.asm:   syscalls.lst Makefile GenSyscalls.pl
        perl GenSyscalls.pl
 
-# Rules based on the makefile
-Makefile:      ../../Makefile.cfg arch/$(ARCHDIR)/Makefile
+# Differences for the makefile
+Makefile:      ../../Makefile.cfg ../../BuildConf/$(ARCH)/Makefile.cfg ../../BuildConf/$(ARCH)/$(PLATFORM).mk arch/$(ARCHDIR)/Makefile
 
 # Build-time information (git hash and build number)
 $(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
+       $(eval _GITHASH=$(shell git log -n 1 | head -n 1 | awk '{print $$2}'))
+       $(eval _GITCHANGED=$(shell git status --porcelain | grep -c '^ M '))
        @echo "#include <acess.h>" > $@
-       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+       @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@
        @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
+       @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@
+       @echo "                           \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@
 # Compile rule for buildinfo (needs a special one because it's not a general source file)
 $(BUILDINFO_OBJ): $(BUILDINFO_SRC)
        @echo --- CC -o $@
@@ -148,3 +153,4 @@ $(BUILDINFO_OBJ): $(BUILDINFO_SRC)
 
 # Dependency Files
 -include $(DEPFILES)
+
diff --git a/KernelLand/Kernel/arch/armv6/Makefile b/KernelLand/Kernel/arch/armv6/Makefile
new file mode 100644 (file)
index 0000000..b6768e3
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# Acess2 Kernel
+# arm7 Architecture Makefile
+# arch/arm7/Makefile
+
+CPPFLAGS       =
+CFLAGS         =
+ASFLAGS                =
+
+CPPFLAGS += -DMMU_PRESENT=1
+LDFLAGS += 
+LIBGCC_PATH = $(shell $(CC) --print-libgcc-file-name)
+
+A_OBJ  = start.ao main.o lib.o lib.ao time.o pci.o debug.o
+A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+
+#main.c: Makefile.BuildNum.$(ARCH)
+
+ifeq ($(PLATFORM),tegra2)
+       POSTBUILD = arm-elf-objcopy $(BIN) -O binary $(BIN)
+endif
diff --git a/KernelLand/Kernel/arch/armv6/debug.c b/KernelLand/Kernel/arch/armv6/debug.c
new file mode 100644 (file)
index 0000000..7b9e55d
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/debug.c
+ * - ARM7 Debug output
+ * NOTE: Currently designed for the realview-pb-a8 emulated by Qemu
+ */
+#include <acess.h>
+
+// === CONSTANTS ===
+//#define UART0_BASE   0x10009000
+#define UART0_BASE     0xF1000000      // Boot time mapped
+
+// === PROTOTYPES ===
+void   KernelPanic_SetMode(void);
+void   KernelPanic_PutChar(char Ch);
+void   StartupPrint(const char *str);
+
+// === GLOBALS ===
+ int   giDebug_SerialInitialised = 0;
+
+// === CODE ===
+void Debug_PutCharDebug(char ch)
+{
+       if(ch == '\n')
+               Debug_PutCharDebug('\r');
+
+       #if PLATFORM_is_tegra2
+       // Tegra2
+       while( !(*(volatile Uint32*)(UART0_BASE + 0x14) & (1 << 5)) )
+               ;
+       #endif
+       
+//     *(volatile Uint32*)(SERIAL_BASE + SERIAL_REG_DATA) = ch;
+       *(volatile Uint32*)(UART0_BASE) = ch;
+}
+
+void Debug_PutStringDebug(const char *str)
+{
+       for( ; *str; str++ )
+               Debug_PutCharDebug( *str );
+}
+
+void KernelPanic_SetMode(void)
+{
+}
+
+void KernelPanic_PutChar(char ch)
+{
+//     Debug_PutCharDebug(ch);
+}
+
+void StartupPrint(const char *str)
+{
+}
+
diff --git a/KernelLand/Kernel/arch/armv6/include/arch.h b/KernelLand/Kernel/arch/armv6/include/arch.h
new file mode 100644 (file)
index 0000000..837a5e1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Acess2
+ * ARM7 Architecture Header
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+// === CONSTANTS ===
+#define INVLPTR        ((void*)-1)
+#define BITS   32
+#define PAGE_SIZE      0x1000
+#define KERNEL_BASE    0x80000000      // 2GiB
+
+// === TYPES ===
+typedef unsigned int   Uint;
+typedef unsigned char  Uint8;
+typedef unsigned short Uint16;
+typedef unsigned long  Uint32;
+typedef unsigned long long     Uint64;
+typedef signed int     Sint;
+typedef signed char    Sint8;
+typedef signed short   Sint16;
+typedef signed long    Sint32;
+typedef signed long long       Sint64;
+
+typedef int    size_t;
+typedef char   BOOL;
+
+typedef Uint32 tVAddr;
+typedef Uint32 tPAddr;
+
+#include "lock.h"
+
+// --- Debug
+extern void    Debug_PutCharDebug(char Ch);
+extern void    Debug_PutStringDebug(const char *String);
+
+// This should be elsewhere, but CBF
+extern void    MM_SetupPhys(void);
+extern int     MM_InitialiseVirtual(void);
+
+#define NO_IO_BUS      1
+
+#endif
diff --git a/KernelLand/Kernel/arch/armv6/include/assembly.h b/KernelLand/Kernel/arch/armv6/include/assembly.h
new file mode 100644 (file)
index 0000000..0c5c57f
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Acess2 ARMv7
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/include/assembly.h
+ * - Assembly specific macros
+ */
+#ifndef _ASSEMBLY_H_
+#define _ASSEMBLY_H_
+
+#define PUSH_GPRS \
+       str r0, [sp,#-1*4];\
+       str r1, [sp,#-2*4];\
+       str r2, [sp,#-3*4];\
+       str r3, [sp,#-4*4];\
+       str r4, [sp,#-5*4];\
+       str r5, [sp,#-6*4];\
+       str r6, [sp,#-7*4];\
+       str r7, [sp,#-8*4];\
+       str r8, [sp,#-9*4];\
+       str r9, [sp,#-10*4];\
+       str r10, [sp,#-11*4];\
+       str r11, [sp,#-12*4];\
+       str r12, [sp,#-13*4];\
+       str sp, [sp,#-14*4];\
+       str lr, [sp,#-15*4];\
+       sub sp, #16*4
+
+#define POP_GPRS add sp, #16*4; \
+       ldr r0, [sp,#-1*4]; \
+       ldr r1, [sp,#-2*4]; \
+       ldr r2, [sp,#-3*4]; \
+       ldr r3, [sp,#-4*4]; \
+       ldr r4, [sp,#-5*4]; \
+       ldr r5, [sp,#-6*4]; \
+       ldr r6, [sp,#-7*4]; \
+       ldr r7, [sp,#-8*4]; \
+       ldr r8, [sp,#-9*4]; \
+       ldr r9, [sp,#-10*4]; \
+       ldr r10, [sp,#-11*4]; \
+       ldr r11, [sp,#-12*4]; \
+       ldr r12, [sp,#-13*4]; \
+       ldr lr, [sp,#-15*4];
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv6/include/lock.h b/KernelLand/Kernel/arch/armv6/include/lock.h
new file mode 100644 (file)
index 0000000..6688af4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * lock.h - Hardware level spinlocks
+ */
+#ifndef _LOCK_H_
+#define _LOCK_H_
+
+// === CODE ===
+struct sShortSpinlock {
+        int    Lock;
+};
+
+// --- Spinlocks ---
+static inline int IS_LOCKED(struct sShortSpinlock *Lock)
+{
+       return !!Lock->Lock;
+}
+
+static inline int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
+{
+       // TODO: Handle multiple CPUs
+       return !!Lock->Lock;
+}
+
+static inline int SHORTLOCK(struct sShortSpinlock *Lock)
+{
+       #if 0
+       // Coped from linux, yes, but I know what it does now :)
+       Uint    tmp;
+       __asm__ __volatile__ (
+       "1:     ldrex   %0, [%1]\n"     // Exclusive LOAD
+       "       teq     %0, #0\n"       // Check if zero
+       "       strexeq %0, %2, [%1]\n" // Set to one if it is zero (releasing lock on the memory)
+       "       teqeq   %0, #0\n"       // If the lock was avaliable, check if the write succeeded
+       "       bne     1b"     // If the lock was unavaliable, or the write failed, loop
+               : "=&r" (tmp)   // Temp
+               : "r" (&Lock->Lock), "r" (1)
+               : "cc"  // Condition codes clobbered
+               );
+       #elif 1
+       while( *(volatile int*)&Lock->Lock )    ;
+       Lock->Lock = 1;
+       #else
+        int    v = 1;
+       while( v )
+               __asm__ __volatile__ (
+                       "swp %0, %0, [%1]"
+                       : "=r" (v) : "r" (&Lock->Lock)
+                       : "cc"
+                       );
+       #endif
+       return 1;
+}
+
+static inline void SHORTREL(struct sShortSpinlock *Lock)
+{
+       Lock->Lock = 0;
+}
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv6/include/mm_virt.h b/KernelLand/Kernel/arch/armv6/include/mm_virt.h
new file mode 100644 (file)
index 0000000..c1f10de
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Acess2
+ * ARM7 Virtual Memory Manager Header
+ */
+#ifndef _MM_VIRT_H_
+#define _MM_VIRT_H_
+
+#include "options.h"
+
+#define USER_STACK_COMM    0x04000     // Pages to allocate up front
+#define USER_STACK_SIZE           0x10000      // Stack space
+#define USER_STACK_TOP 0x78000000
+
+#define MM_USER_MIN    0x00001000
+#define USER_LIB_MAX   0x70000000
+#define MM_PPD_HANDLES 0x7F800000
+#define MM_TABLE1USER  0x7FC00000      // 2 GiB - 4 MiB
+#define MM_TABLE0USER  0x7FE00000      // 2 GiB - 2 MiB
+#define MM_KSTACK_BASE 0x7FE00000
+#define MM_KSTACK_END  0x80000000
+
+// Page Blocks are 12-bits wide (12 address bits used)
+// Hence, the table is 16KiB large (and must be so aligned)
+// and each block addresses 1MiB of data
+
+// First level table is aligned to 16KiB (restriction of TTBR reg)
+// - VMSAv6 uses two TTBR regs, determined by bit 31
+
+//#define KERNEL_BASE  0x80000000      // 2GiB
+
+#define MM_KHEAP_BASE  0x80800000      // 8MiB of kernel code
+#define MM_KHEAP_MAX   0xC0000000      // ~1GiB of kernel heap
+
+#define MM_MODULE_MIN  0xC0000000      // - 0xD0000000
+#define MM_MODULE_MAX  0xCF000000
+
+#define MM_GLOBALSTACKS        0xCF000000      // Global stacks
+#define MM_GLOBALSTACKS_END    0xD0000000
+
+// PMM Data, giving it 256MiB is overkill, but it's unused atm
+#define MM_MAXPHYSPAGE (1024*1024)
+// 2^(32-12) max pages
+// 8.125 bytes per page (for bitmap allocation)
+// = 8.125 MiB
+#define MM_PMM_BASE    0xE0000000
+#define MM_PMM_END     0xF0000000
+
+#define MM_HWMAP_BASE  0xF0000000      // Ent 0xF00
+#define MM_HWMAP_END   0xFE000000
+#define MM_TMPMAP_BASE 0xFE000000
+#define MM_TMPMAP_END  0xFF000000
+
+#define MM_KERNEL_VFS  0xFF000000      // 
+#define MM_TABLE1KERN  0xFF800000      // - 0x???????? 4MiB
+//#define MM_TABLE0KERN        0xFFC00000      // - 0xFFE04000 16KiB
+
+#endif
diff --git a/KernelLand/Kernel/arch/armv6/include/options.h b/KernelLand/Kernel/arch/armv6/include/options.h
new file mode 100644 (file)
index 0000000..4947158
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 ARMv6 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * options.h
+ * - C/ASM Shared constants
+ */
+#ifndef _ARMV7_OPTIONS_H_
+#define _ARMV7_OPTIONS_H_
+
+#define KERNEL_BASE    0x80000000
+
+#if PLATFORM_is_raspberrypi
+# define UART0_PADDR   0x7E215040      // Realview
+#else
+# error Unknown platform
+#endif
+
+#define MM_KSTACK_SIZE 0x2000  // 2 Pages
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv6/include/proc.h b/KernelLand/Kernel/arch/armv6/include/proc.h
new file mode 100644 (file)
index 0000000..d6ef3d5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * proc.h - Arch-Dependent Process Management
+ */
+#ifndef _PROC_H_
+#define _PROC_H_
+
+#define MAX_CPUS       4
+#define USER_MAX       0x80000000
+
+// === STRUCTURES ===
+typedef struct {
+       Uint32  IP, SP;
+       Uint32  UserIP, UserSP;
+} tTaskState;
+
+typedef struct {
+       Uint32  Base;
+} tMemoryState;
+
+typedef struct {
+       union {
+               Uint32  Num;
+               Uint32  Error;
+       };
+       union {
+               Uint32  Arg1;
+               Uint32  Return;
+       };
+       union {
+               Uint32  Arg2;
+               Uint32  RetHi;
+       };
+       Uint32  Arg3;
+       Uint32  Arg4;
+       Uint32  Arg5;
+       Uint32  Arg6;   // R6
+} tSyscallRegs;
+
+// === MACROS ===
+#define HALT() do{}while(0)
+
+// === PROTOTYPES ===
+
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv6/lib.S b/KernelLand/Kernel/arch/armv6/lib.S
new file mode 100644 (file)
index 0000000..e2f0613
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/lib.S
+ * - Assembly editions of library functions
+ */
+#include "include/assembly.h"
+
+.globl __memcpy_byte
+__memcpy_byte:
+1:
+       tst r2, r2      @ Check counter
+       moveq pc, lr    @ Return if zero
+       ldrb r3, [r1],#1        @ Read
+       strb r3, [r0],#1        @ Write
+       sub r2, #1
+       b 1b
+
+@ 
+@ Pre-aligned memcpy (32-bit blocks)
+@ 
+.globl __memcpy_align4
+__memcpy_align4:
+       push {r4}
+       mvn r3, #3      @ Mask for checking length
+       
+       @ 4 byte chunk copies
+1:     tst r2, r3
+       ldrne r4, [r1],#4
+       strne r4, [r0],#4
+       subne r2, #4
+       bne 1b
+
+       @ single byte copies to finish off
+2:     tst r2, #3
+       beq 3f
+       ldrb r4, [r1],#1
+       strb r4, [r0],#1
+       sub r2, #1
+       b 2b
+
+3:     pop {r4}
+       mov pc, lr
+
+@
+@ Division
+@
+.globl __divmod32_asm
+__divmod32_asm:
+       push {r4}
+       mov r4, #0      @ Return value
+       mov r3, #1      @ add value
+
+       @ Scan up for first larger multiple of 2
+1:     cmp r0, r1      @ N < D
+       bmi 2f          @ ^^
+       lsl r1, r1, #1  @ D <<= 1
+       lsls r3, r3, #1 @ add <<= 1
+       beq .err        @ result is zero
+       b 1b
+       
+       @ Go back down
+2:     lsrs r3, r3, #1 @ add >>= 1
+       beq 3f          @ Done (value is zero)
+       lsr r1, r1, #1  @ D >>= 1
+       cmp r0, r1      @ N < D
+       bmi 2b
+       sub r0, r1      @ N -= D
+       add r4, r3      @ ret += add
+       b 2b
+3:
+       tst r2, r2      @ Remainder (if wanted)
+       strne r0,[r2]
+       mov r0, r4      @ Return value
+       pop {r4}
+       mov pc, lr
+.err:
+       mov r0, #0
+       tst r2, r2
+       strne r0, [r2]
+       pop {r4}
+       mov pc, lr
+
diff --git a/KernelLand/Kernel/arch/armv6/lib.c b/KernelLand/Kernel/arch/armv6/lib.c
new file mode 100644 (file)
index 0000000..7894e3a
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Acess2 ARM7 Port
+ *
+ * lib.c - Library Functions
+ */
+#include <acess.h>
+#include "../helpers.h"
+
+// === IMPORTS ===
+extern void    __memcpy_align4(void *_dest, const void *_src, size_t _length);
+extern void    __memcpy_byte(void *_dest, const void *_src, size_t _length);
+extern Uint32  __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
+
+// === PROTOTYPES ===
+Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
+Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
+#if 0
+Uint64 __udivdi3(Uint64 Num, Uint64 Den);
+Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+Uint32 __udivsi3(Uint32 Num, Uint32 Den);
+Uint32 __umodsi3(Uint32 Num, Uint32 Den);
+Sint32 __divsi3(Sint32 Num, Sint32 Den);
+Sint32 __modsi3(Sint32 Num, Sint32 Den);
+#endif
+
+// === CODE ===
+void *memcpy(void *_dest, const void *_src, size_t _length)
+{
+       Uint8   *dst8 = _dest;
+       const Uint8     *src8 = _src;
+
+       if( ((tVAddr)_dest & 3) == 0 && ((tVAddr)_src & 3) == 0 )
+       {
+               __memcpy_align4(_dest, _src, _length);
+               return _dest;
+       }
+
+       // Handle small copies / Non-aligned
+       if( _length < 4 || ((tVAddr)_dest & 3) != ((tVAddr)_src & 3) )
+       {
+               __memcpy_byte(_dest, _src, _length);
+               return _dest;
+       }
+
+       // Force alignment
+       while( (tVAddr)dst8 & 3 ) *dst8 ++ = *src8++, _length --;
+
+       __memcpy_align4(dst8, src8, _length);
+       
+       return _dest;
+}
+
+int memcmp(const void *_m1, const void *_m2, size_t _length)
+{
+       const Uint32    *m1, *m2;
+       const Uint8     *m1_8 = _m1, *m2_8 = _m2;
+
+       // Handle small copies / Non-aligned
+       if( _length < 4 || ((tVAddr)_m1 & 3) != ((tVAddr)_m1 & 3) )
+       {
+               for( ; _length--; m1_8++,m2_8++ ) {
+                       if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+               }
+               return 0;
+       }
+
+       // Force alignment
+       for( ; (tVAddr)m1_8 & 3; m1_8 ++, m2_8 ++) {
+               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+       }
+       m1 = (void *)m1_8;      m2 = (void *)m2_8;
+
+       // DWORD copies
+       for( ; _length > 3; _length -= 4, m1++, m2++)
+               if(*m1 != *m2)  return *m1 - *m2;
+
+       // Trailing bytes
+       m1_8 = (void*)m1;       m2_8 = (void*)m2;
+       for( ; _length; _length --, m1_8++, m2_8++ )
+               if(*m1_8 != *m2_8)      return *m1_8 - *m2_8;
+       
+       return 0;
+}
+
+void *memset(void *_dest, int _value, size_t _length)
+{
+       Uint32  *dst, val32;
+       Uint8   *dst8 = _dest;
+
+       _value = (Uint8)_value;
+
+       // Handle small copies
+       if( _length < 4 )
+       {
+               for( ; _length--; dst8++ )
+                       *dst8 = _value;
+               return _dest;
+       }
+
+       val32 = _value;
+       val32 |= val32 << 8;
+       val32 |= val32 << 16;
+       
+       // Force alignment
+       while( (tVAddr)dst8 & 3 ) *dst8 ++ = _value;
+       dst = (void *)dst8;
+
+       // DWORD copies
+       for( ; _length > 3; _length -= 4)
+               *dst++ = val32;
+
+       // Trailing bytes
+       dst8 = (void*)dst;
+       for( ; _length; _length -- )
+               *dst8 ++ = _value;
+       
+       return _dest;
+}
+
+DEF_DIVMOD(64)
+DEF_DIVMOD(32)
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
+{
+       Uint64  ret;
+       if(Den == 0)    return 0;       // TODO: #div0
+       if(Num < Den) {
+               if(Rem) *Rem = Num;
+               return 0;
+       }
+       if(Num == 0) {
+               if(Rem) *Rem = 0;
+               return 0;
+       }
+       if(Den == 1) {
+               if(Rem) *Rem = 0;
+               return Num;
+       }
+       if(Den == 2) {
+               if(Rem) *Rem = Num & 1;
+               return Num >> 1;
+       }
+       if(Den == 16) {
+               if(Rem) *Rem = Num & 0xF;
+               return Num >> 4;
+       }
+       if(Den == 32) {
+               if(Rem) *Rem = Num & 0x1F;
+               return Num >> 5;
+       }
+       if(Den == 0x1000) {
+               if(Rem) *Rem = Num & 0xFFF;
+               return Num >> 12;
+       }
+       
+       if( !(Den >> 32) && !(Num >> 32) ) {
+               if(Rem) *Rem = 0;       // Clear high bits
+               return __divmod32_asm(Num, Den, (Uint32*)Rem);
+       }
+
+       ret = __divmod64(Num, Den, Rem);
+       return ret;
+}
+
+#if 0
+// Unsigned Divide 64-bit Integer
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+       return DivMod64U(Num, Den, NULL);
+}
+
+// Unsigned Modulus 64-bit Integer
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+       Uint64  ret = 0;
+       DivMod64U(Num, Den, &ret);
+       return ret;
+}
+
+Uint32 __udivsi3(Uint32 Num, Uint32 Den)
+{
+       return __divmod32_asm(Num, Den, NULL);
+}
+
+Uint32 __umodsi3(Uint32 Num, Uint32 Den)
+{
+       Uint32  rem;
+       __divmod32_asm(Num, Den, &rem);
+       return rem;
+}
+#endif
+
+static inline Sint32 DivMod32S(Sint32 Num, Sint32 Den, Sint32 *Rem)
+{
+       Sint32  ret = 1;
+       if( Num < 0 ) {
+               ret = -ret;
+               Num = -Num;
+       }
+       if( Den < 0 ) {
+               ret = -ret;
+               Den = -Den;
+       }
+       if(ret < 0)
+               ret = -__divmod32(Num, Den, (Uint32*)Rem);
+       else
+               ret = __divmod32(Num, Den, (Uint32*)Rem);
+       return ret;
+}
+
+#if 0
+Sint32 __divsi3(Sint32 Num, Sint32 Den)
+{
+       return DivMod32S(Num, Den, NULL);
+}
+
+Sint32 __modsi3(Sint32 Num, Sint32 Den)
+{
+       Sint32  rem;
+       DivMod32S(Num, Den, &rem);
+       return rem;
+}
+#endif
+
diff --git a/KernelLand/Kernel/arch/armv6/link.ld b/KernelLand/Kernel/arch/armv6/link.ld
new file mode 100644 (file)
index 0000000..2ad5afe
--- /dev/null
@@ -0,0 +1,59 @@
+ENTRY (_start)
+
+_kernel_base = 0x80000000;
+_usertext_vbase = 0xFFFFE000;
+
+SECTIONS
+{
+       . = 0;
+       .init :
+       {
+               *(.init)
+       }
+       . += _kernel_base;
+       .text : AT( ADDR(.text) - _kernel_base )
+       {
+               *(.text*)
+               *(.rodata*)
+       }
+       __exidx_start = .;
+       .ARM.exidx   : { *(.ARM.exidx*) }
+       __exidx_end = .;
+       .ARM.extab : { *(.ARM.extab*) }
+                       
+
+       /* HACKS: User accesible .text section */
+       . = ALIGN(0x1000);
+       gUsertextPhysStart = . - _kernel_base;
+       . = _usertext_vbase;
+       .usertext : AT( gUsertextPhysStart )
+       {
+               *(.usertext)
+       }
+       . += gUsertextPhysStart + _kernel_base - _usertext_vbase;
+       
+       /* 0x4000 (4 pages) alignment needed for root table */
+       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+       {
+               *(.padata)
+               *(.data*)
+               
+               gKernelSymbols = .;
+               *(KEXPORT)
+               gKernelSymbolsEnd = .;
+               
+               gKernelModules = .;
+               *(KMODULES)
+               gKernelModulesEnd = .;
+       }
+       .bss : AT( ADDR(.bss) - _kernel_base )
+       {
+               bss_start = .;
+               *(.bss*)
+               *(COMMON*)
+               . = ALIGN(0x1000);
+               *(.pabss)
+               bss_end = .;
+       }
+       gKernelEnd = .;
+}
diff --git a/KernelLand/Kernel/arch/armv6/main.c b/KernelLand/Kernel/arch/armv6/main.c
new file mode 100644 (file)
index 0000000..248c17c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Acess2
+ *
+ * ARM7 Entrypoint
+ * arch/arm7/main.c
+ */
+#define DEBUG  0
+
+#include <acess.h>
+#include <modules.h>
+
+// === IMPORTS ===
+extern void    Interrupts_Setup(void);
+extern void    Arch_LoadBootModules(void);
+extern void    Heap_Install(void);
+extern void    Threads_Init(void);
+extern void    System_Init(const char *Commandline);
+
+// === PROTOTYPES ===
+ int   kmain(void);
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args);
+
+// === CODE ===
+int kmain(void)
+{
+       LogF("Acess2 ARMv7 v"EXPAND_STR(KERNEL_VERSION)"\n");
+       LogF(" Git Hash %s\n", gsGitHash);
+       LogF(" Build %i\n", BUILD_NUM);
+       
+       MM_SetupPhys();
+
+       LogF("Heap Setup...\n");
+       Heap_Install();
+
+       LogF("Threads Init...\n");
+       Threads_Init();
+       
+       LogF("VFS Init...\n");
+       VFS_Init();
+
+       // Boot modules?
+       Module_EnsureLoaded("armv7_GIC");
+
+       //
+       LogF("Moving to arch-independent init\n");
+       #if PLATFORM_is_tegra2
+       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=Tegra2Vid");
+       #else
+       System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=PL110");
+       #endif
+//     System_Init("Acess2.armv7.bin /Acess=initrd:");
+       //TODO: 
+       LogF("End of kmain(), for(;;) Threads_Sleep();\n");
+       for(;;)
+               Threads_Sleep();
+}
+
+void Arch_LoadBootModules(void)
+{
+}
+
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args)
+{
+       Uint32  ret = -1, err = 0;
+       Uint32  addr;
+       ENTER("iNum xArgs[0] xArgs[1] xArgs[2] xArgs[3]",
+               Num, Args[0], Args[1], Args[2], Args[3]
+               );
+       switch(Num)
+       {
+       case 1:
+//             Log_Debug("ARMv7", "__clear_cache(%p, %p)", Args[0], Args[1]);
+               // Align
+               Args[0] &= ~0xFFF;
+               Args[1] += 0xFFF;       Args[1] &= ~0xFFF;
+               // Invalidate!
+               for( addr = Args[0]; addr < Args[1]; addr += 0x1000 )
+               {
+                       LOG("addr = %p", addr);
+                       __asm__ __volatile__ (
+                               "mcrlt p15, 0, %0, c7, c5, 1;\n\t"
+                               "mcrlt p15, 0, %0, c7, c6, 1;\n\t"
+                               :
+                               : "r" (addr)
+                               );
+               }
+               ret = 0;
+               break;
+       }
+       Args[0] = ret;  // RetLow
+       Args[1] = 0;    // RetHi
+       Args[2] = err;  // Errno
+       LEAVE('x', ret);
+       return ret;
+}
+
diff --git a/KernelLand/Kernel/arch/armv6/mm_phys.c b/KernelLand/Kernel/arch/armv6/mm_phys.c
new file mode 100644 (file)
index 0000000..5e4a242
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Acess2
+ *
+ * ARM7 Physical Memory Manager
+ * arch/arm7/mm_phys.c
+ */
+#define DEBUG  0
+
+#include <acess.h>
+#include <mm_virt.h>
+
+#define MM_NUM_RANGES  1       // Single range
+#define MM_RANGE_MAX   0
+#define TRACE_ALLOCS   0
+
+#define NUM_STATIC_ALLOC       4
+
+char   gStaticAllocPages[NUM_STATIC_ALLOC][PAGE_SIZE] __attribute__ ((section(".padata")));
+tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {
+       (tPAddr)(&gStaticAllocPages[0]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[1]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[2]) - KERNEL_BASE,
+       (tPAddr)(&gStaticAllocPages[3]) - KERNEL_BASE
+};
+extern char    gKernelEnd[];
+
+
+#include <tpl_mm_phys_bitmap.h>
+
+//#define REALVIEW_LOWRAM_SIZE 0x10000000
+#define REALVIEW_LOWRAM_SIZE   (32*1024*1024)
+
+void MM_SetupPhys(void)
+{
+       LogF("MM_SetupPhys: ()\n");
+       MM_Tpl_InitPhys( REALVIEW_LOWRAM_SIZE/0x1000, NULL );
+}
+
+int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length )
+{
+       switch(Index)
+       {
+       case 0:
+               *Start = ((tVAddr)&gKernelEnd - KERNEL_BASE + 0xFFF) & ~0xFFF;
+               *Length = REALVIEW_LOWRAM_SIZE - *Start;
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/**
+ * \brief Takes a physical address and returns the ID of its range
+ * \param Addr Physical address of page
+ * \return Range ID from eMMPhys_Ranges
+ */
+int MM_int_GetRangeID( tPAddr Addr )
+{
+       return MM_RANGE_MAX;    // ARM doesn't need ranges
+}
diff --git a/KernelLand/Kernel/arch/armv6/mm_virt.c b/KernelLand/Kernel/arch/armv6/mm_virt.c
new file mode 100644 (file)
index 0000000..2dc1147
--- /dev/null
@@ -0,0 +1,1080 @@
+/*
+ * Acess2
+ * 
+ * ARM7 Virtual Memory Manager
+ * - arch/arm7/mm_virt.c
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+
+#define TRACE_MAPS     0
+
+#define AP_KRW_ONLY    1       // Kernel page
+#define AP_KRO_ONLY    5       // Kernel RO page
+#define AP_RW_BOTH     3       // Standard RW
+#define AP_RO_BOTH     7       // COW Page
+#define AP_RO_USER     2       // User RO Page
+#define PADDR_MASK_LVL1        0xFFFFFC00
+
+// === IMPORTS ===
+extern Uint32  kernel_table0[];
+
+// === TYPES ===
+typedef struct
+{
+       tPAddr  PhysAddr;
+       Uint8   Size;
+       Uint8   Domain;
+       BOOL    bExecutable;
+       BOOL    bGlobal;
+       BOOL    bShared;
+        int    AP;
+} tMM_PageInfo;
+
+//#define FRACTAL(table1, addr)        ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
+#define FRACTAL(table1, addr)  ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
+#define USRFRACTAL(addr)       (*((Uint32*)(0x7FDFF000) + ((addr)>>22)))
+#define TLBIALL()      __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
+#define TLBIMVA(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1" : : "r" (((addr)&~0xFFF)|1):"memory")
+#define DCCMVAC(addr)  __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" ((addr)&~0xFFF))
+
+// === PROTOTYPES ===
+void   MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
+ int   MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
+ int   MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+ int   MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+tVAddr MM_NewUserStack(void);
+tPAddr MM_AllocateZero(tVAddr VAddr);
+tPAddr MM_AllocateRootTable(void);
+void   MM_int_CloneTable(Uint32 *DestEnt, int Table);
+tPAddr MM_Clone(void);
+tVAddr MM_NewKStack(int bGlobal);
+void   MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
+//void MM_DumpTables(tVAddr Start, tVAddr End);
+void   MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch);
+
+// === GLOBALS ===
+tPAddr giMM_ZeroPage;
+
+// === CODE ===
+int MM_InitialiseVirtual(void)
+{
+       return 0;
+}
+
+void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
+{
+       if(VAddr & 0x80000000) {
+               *Table0 = (void*)&kernel_table0;        // Level 0
+               *Table1 = (void*)MM_TABLE1KERN; // Level 1
+       }
+       else {
+               *Table0 = (void*)MM_TABLE0USER;
+               *Table1 = (void*)MM_TABLE1USER;
+       }
+}
+
+int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
+{
+       Uint32  *table0, *table1;
+       Uint32  *desc;
+       tPAddr  paddr;
+       
+       ENTER("xVAddr iDomain", VAddr, Domain);
+
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
+
+       desc = &table0[ VAddr>>20];
+       LOG("desc = %p", desc);
+       
+       // table0: 4 bytes = 1 MiB
+
+       LOG("desc[0] = %x", desc[0]);
+       LOG("desc[1] = %x", desc[1]);
+       LOG("desc[2] = %x", desc[2]);
+       LOG("desc[3] = %x", desc[3]);
+
+       if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
+        || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
+       {
+               // Error?
+               LEAVE('i', 1);
+               return 1;
+       }
+
+       paddr = MM_AllocPhys();
+       if( !paddr )
+       {
+               // Error
+               LEAVE('i', 2);
+               return 2;
+       }
+       
+       *desc = paddr | (Domain << 5) | 1;
+       desc[1] = desc[0] + 0x400;
+       desc[2] = desc[0] + 0x800;
+       desc[3] = desc[0] + 0xC00;
+
+       if( VAddr < 0x80000000 ) {
+               USRFRACTAL(VAddr) = paddr | 0x13;
+       }
+       else {
+               FRACTAL(table1, VAddr) = paddr | 0x13;
+       }
+
+       // TLBIALL 
+       TLBIALL();
+       
+       memset( (void*)&table1[ (VAddr >> 12) & ~(1024-1) ], 0, 0x1000 );
+
+       LEAVE('i', 0);
+       return 0;
+}      
+
+int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+       Uint32  *table0, *table1;
+       Uint32  *desc;
+
+       ENTER("pVAddr ppi", VAddr, pi);
+
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       desc = &table0[ VAddr >> 20 ];
+       LOG("desc = %p", desc);
+
+       switch(pi->Size)
+       {
+       case 12:        // Small Page
+       case 16:        // Large Page
+               LOG("Page");
+               if( (*desc & 3) == 0 ) {
+                       MM_int_AllocateCoarse( VAddr, pi->Domain );
+               }
+               desc = &table1[ VAddr >> 12 ];
+               LOG("desc (2) = %p", desc);
+               if( pi->Size == 12 )
+               {
+                       // Small page
+                       // - Error if overwriting a large page
+                       if( (*desc & 3) == 1 )  LEAVE_RET('i', 1);
+                       if( pi->PhysAddr == 0 ) {
+                               *desc = 0;
+                               TLBIMVA( VAddr );
+                               DCCMVAC( (tVAddr) desc );
+//                             #warning "HACK: TLBIALL"
+//                             TLBIALL();                              
+                               LEAVE('i', 0);
+                               return 0;
+                       }
+
+                       *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
+                       if(!pi->bExecutable)    *desc |= 1;     // XN
+                       if(!pi->bGlobal)        *desc |= 1 << 11;       // nG
+                       if( pi->bShared)        *desc |= 1 << 10;       // S
+                       *desc |= (pi->AP & 3) << 4;     // AP
+                       *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
+                       TLBIMVA( VAddr );       
+//                     #warning "HACK: TLBIALL"
+//                     TLBIALL();
+                       DCCMVAC( (tVAddr) desc );
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               else
+               {
+                       // Large page
+                       Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo");
+               }
+               break;
+       case 20:        // Section or unmapped
+               Log_Warning("MMVirt", "TODO: Implement sections in MM_int_SetPageInfo");
+               break;
+       case 24:        // Supersection
+               // Error if not aligned
+               if( VAddr & 0xFFFFFF ) {
+                       LEAVE('i', 1);
+                       return 1;
+               }
+               if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
+               {
+                       if( pi->PhysAddr == 0 ) {
+                               *desc = 0;
+                       }
+                       else {
+                               // Apply
+                               *desc = pi->PhysAddr & 0xFF000000;
+//                             *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
+//                             *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
+                               *desc |= 2 | (1 << 18);
+                       }
+                       // TODO: Apply to all entries
+                       Log_Warning("MMVirt", "TODO: Apply changes to all entries of supersections");
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               // TODO: What here?
+               Log_Warning("MMVirt", "TODO: 24-bit not on supersection?");
+               LEAVE('i', 1);
+               return 1;
+       }
+
+       LEAVE('i', 1);
+       return 1;
+}
+
+int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+       Uint32  *table0, *table1;
+       Uint32  desc;
+
+//     LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi);
+       
+       MM_int_GetTables(VAddr, &table0, &table1);
+
+       desc = table0[ VAddr >> 20 ];
+
+//     if( VAddr > 0x90000000)
+//             LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
+       
+       pi->bExecutable = 1;
+       pi->bGlobal = 0;
+       pi->bShared = 0;
+       pi->AP = 0;
+
+       switch( (desc & 3) )
+       {
+       // 0: Unmapped
+       case 0:
+               pi->PhysAddr = 0;
+               pi->Size = 20;
+               pi->Domain = 0;
+               return 1;
+
+       // 1: Coarse page table
+       case 1:
+               // Domain from top level table
+               pi->Domain = (desc >> 5) & 7;
+               // Get next level
+               desc = table1[ VAddr >> 12 ];
+//             LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
+               switch( desc & 3 )
+               {
+               // 0: Unmapped
+               case 0: 
+                       pi->Size = 12;
+                       return 1;
+               // 1: Large Page (64KiB)
+               case 1:
+                       pi->Size = 16;
+                       pi->PhysAddr = desc & 0xFFFF0000;
+                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+                       pi->bExecutable = !(desc & 0x8000);
+                       pi->bShared = (desc >> 10) & 1;
+                       return 0;
+               // 2/3: Small page
+               case 2:
+               case 3:
+                       pi->Size = 12;
+                       pi->PhysAddr = desc & 0xFFFFF000;
+                       pi->bExecutable = !(desc & 1);
+                       pi->bGlobal = !(desc >> 11);
+                       pi->bShared = (desc >> 10) & 1;
+                       pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+                       return 0;
+               }
+               return 1;
+       
+       // 2: Section (or Supersection)
+       case 2:
+               if( desc & (1 << 18) ) {
+                       // Supersection
+                       pi->PhysAddr = desc & 0xFF000000;
+                       pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
+                       pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
+                       pi->Size = 24;
+                       pi->Domain = 0; // Supersections default to zero
+                       pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+                       return 0;
+               }
+               
+               // Section
+               pi->PhysAddr = desc & 0xFFF80000;
+               pi->Size = 20;
+               pi->Domain = (desc >> 5) & 7;
+               pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+               return 0;
+
+       // 3: Reserved (invalid)
+       case 3:
+               pi->PhysAddr = 0;
+               pi->Size = 20;
+               pi->Domain = 0;
+               return 2;
+       }
+       return 2;
+}
+
+// --- Exports ---
+tPAddr MM_GetPhysAddr(const void *Ptr)
+{
+       tVAddr  VAddr = (tPAddr)Ptr;
+       tMM_PageInfo    pi;
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return 0;
+       return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
+}
+
+Uint MM_GetFlags(tVAddr VAddr)
+{
+       tMM_PageInfo    pi;
+        int    ret;
+
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return 0;
+
+       ret = 0;
+       
+       switch(pi.AP)
+       {
+       case 0:
+               break;
+       case AP_KRW_ONLY:
+               ret |= MM_PFLAG_KERNEL;
+               break;
+       case AP_KRO_ONLY:
+               ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
+               break;
+       case AP_RW_BOTH:
+               break;
+       case AP_RO_BOTH:
+               ret |= MM_PFLAG_COW;
+               break;
+       case AP_RO_USER:
+               ret |= MM_PFLAG_RO;
+               break;
+       }
+
+       if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
+       return ret;
+}
+
+void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+{
+       tMM_PageInfo    pi;
+       Uint    curFlags;
+       
+       if( MM_int_GetPageInfo(VAddr, &pi) )
+               return ;
+       
+       curFlags = MM_GetFlags(VAddr);
+       if( (curFlags & Mask) == Flags )
+               return ;
+       curFlags &= ~Mask;
+       curFlags |= Flags;
+
+       if( curFlags & MM_PFLAG_COW )
+               pi.AP = AP_RO_BOTH;
+       else
+       {
+               switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
+               {
+               case 0:
+                       pi.AP = AP_RW_BOTH;     break;
+               case MM_PFLAG_KERNEL:
+                       pi.AP = AP_KRW_ONLY;    break;
+               case MM_PFLAG_RO:
+                       pi.AP = AP_RO_USER;     break;
+               case MM_PFLAG_KERNEL|MM_PFLAG_RO:
+                       pi.AP = AP_KRO_ONLY;    break;
+               }
+       }
+       
+       pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
+
+       MM_int_SetPageInfo(VAddr, &pi);
+}
+
+int MM_IsValidBuffer(tVAddr Addr, size_t Size)
+{
+       tMM_PageInfo    pi;
+        int    bUser = 0;
+       
+       Size += Addr & (PAGE_SIZE-1);
+       Addr &= ~(PAGE_SIZE-1);
+
+       if( MM_int_GetPageInfo(Addr, &pi) )     return 0;
+       Addr += PAGE_SIZE;
+
+       if(pi.AP != AP_KRW_ONLY && pi.AP != AP_KRO_ONLY)
+               bUser = 1;
+
+       while( Size >= PAGE_SIZE )
+       {
+               if( MM_int_GetPageInfo(Addr, &pi) )
+                       return 0;
+               if(bUser && (pi.AP == AP_KRW_ONLY || pi.AP == AP_KRO_ONLY))
+                       return 0;
+               Addr += PAGE_SIZE;
+               Size -= PAGE_SIZE;
+       }
+       
+       return 1;
+}
+
+int MM_Map(tVAddr VAddr, tPAddr PAddr)
+{
+       tMM_PageInfo    pi = {0};
+       #if TRACE_MAPS
+       Log("MM_Map %P=>%p", PAddr, VAddr);
+       #endif
+       
+       pi.PhysAddr = PAddr;
+       pi.Size = 12;
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
+       pi.bExecutable = 1;
+       if( MM_int_SetPageInfo(VAddr, &pi) ) {
+//             MM_DerefPhys(pi.PhysAddr);
+               return 0;
+       }
+       return pi.PhysAddr;
+}
+
+tPAddr MM_Allocate(tVAddr VAddr)
+{
+       tMM_PageInfo    pi = {0};
+       
+       ENTER("pVAddr", VAddr);
+
+       pi.PhysAddr = MM_AllocPhys();
+       if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
+       pi.Size = 12;
+       if(VAddr < USER_STACK_TOP)
+               pi.AP = AP_RW_BOTH;
+       else
+               pi.AP = AP_KRW_ONLY;
+       pi.bExecutable = 0;
+       if( MM_int_SetPageInfo(VAddr, &pi) ) {
+               MM_DerefPhys(pi.PhysAddr);
+               LEAVE('i', 0);
+               return 0;
+       }
+       LEAVE('x', pi.PhysAddr);
+       return pi.PhysAddr;
+}
+
+tPAddr MM_AllocateZero(tVAddr VAddr)
+{
+       if( !giMM_ZeroPage ) {
+               giMM_ZeroPage = MM_Allocate(VAddr);
+               MM_RefPhys(giMM_ZeroPage);
+               memset((void*)VAddr, 0, PAGE_SIZE);
+       }
+       else {
+               MM_RefPhys(giMM_ZeroPage);
+               MM_Map(VAddr, giMM_ZeroPage);
+       }
+       MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+       return giMM_ZeroPage;
+}
+
+void MM_Deallocate(tVAddr VAddr)
+{
+       tMM_PageInfo    pi;
+       
+       if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
+       if( pi.PhysAddr == 0 )  return;
+       MM_DerefPhys(pi.PhysAddr);
+       
+       pi.PhysAddr = 0;
+       pi.AP = 0;
+       pi.bExecutable = 0;
+       MM_int_SetPageInfo(VAddr, &pi);
+}
+
+tPAddr MM_AllocateRootTable(void)
+{
+       tPAddr  ret;
+       
+       ret = MM_AllocPhysRange(2, -1);
+       if( ret & 0x1000 ) {
+               MM_DerefPhys(ret);
+               MM_DerefPhys(ret+0x1000);
+               ret = MM_AllocPhysRange(3, -1);
+               if( ret & 0x1000 ) {
+                       MM_DerefPhys(ret);
+                       ret += 0x1000;
+//                     Log("MM_AllocateRootTable: Second try not aligned, %P", ret);
+               }
+               else {
+                       MM_DerefPhys(ret + 0x2000);
+//                     Log("MM_AllocateRootTable: Second try aligned, %P", ret);
+               }
+       }
+//     else
+//             Log("MM_AllocateRootTable: Got it in one, %P", ret);
+       return ret;
+}
+
+void MM_int_CloneTable(Uint32 *DestEnt, int Table)
+{
+       tPAddr  table;
+       Uint32  *tmp_map;
+       Uint32  *cur = (void*)MM_TABLE1USER;
+//     Uint32  *cur = &FRACTAL(MM_TABLE1USER,0);
+        int    i;
+       
+       table = MM_AllocPhys();
+       if(!table)      return ;
+
+       cur += 256*Table;
+       
+       tmp_map = MM_MapTemp(table);
+       
+       for( i = 0; i < 1024; i ++ )
+       {
+//             Log_Debug("MMVirt", "cur[%i] (%p) = %x", Table*256+i, &cur[Table*256+i], cur[Table*256+i]);
+               switch(cur[i] & 3)
+               {
+               case 0: tmp_map[i] = 0; break;
+               case 1:
+                       tmp_map[i] = 0;
+                       Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable (%p)", (Table*256+i)*0x1000);
+                       // Large page?
+                       break;
+               case 2:
+               case 3:
+                       // Small page
+                       // - If full RW
+//                     Debug("%p cur[%i] & 0x230 = 0x%x", Table*256*0x1000, i, cur[i] & 0x230);
+                       if( (cur[i] & 0x230) == 0x010 )
+                       {
+                               void    *dst, *src;
+                               tPAddr  newpage;
+                               newpage = MM_AllocPhys();
+                               src = (void*)( (Table*256+i)*0x1000 );
+                               dst = MM_MapTemp(newpage);
+//                             Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
+                               memcpy(dst, src, PAGE_SIZE);
+                               MM_FreeTemp( dst );
+                               tmp_map[i] = newpage | (cur[i] & 0xFFF);
+                       }
+                       else
+                       {
+                               if( (cur[i] & 0x230) == 0x030 )
+                                       cur[i] |= 0x200;        // Set to full RO (Full RO=COW, User RO = RO)
+                               tmp_map[i] = cur[i];
+                               MM_RefPhys( tmp_map[i] & ~0xFFF );
+                       }
+                       break;
+               }
+       }
+       MM_FreeTemp( tmp_map );
+
+       DestEnt[0] = table + 0*0x400 + 1;
+       DestEnt[1] = table + 1*0x400 + 1;
+       DestEnt[2] = table + 2*0x400 + 1;
+       DestEnt[3] = table + 3*0x400 + 1;
+}
+
+tPAddr MM_Clone(void)
+{
+       tPAddr  ret;
+       Uint32  *new_lvl1_1, *new_lvl1_2, *cur;
+       Uint32  *tmp_map;
+        int    i;
+
+//     MM_DumpTables(0, KERNEL_BASE);
+       
+       ret = MM_AllocateRootTable();
+
+       cur = (void*)MM_TABLE0USER;
+       new_lvl1_1 = MM_MapTemp(ret);
+       new_lvl1_2 = MM_MapTemp(ret+0x1000);
+       tmp_map = new_lvl1_1;
+       for( i = 0; i < 0x800-4; i ++ )
+       {
+               // HACK! Ignore the original identity mapping
+               if( i == 0 && Threads_GetTID() == 0 ) {
+                       tmp_map[0] = 0;
+                       continue;
+               }
+               if( i == 0x400 )
+                       tmp_map = &new_lvl1_2[-0x400];
+               switch( cur[i] & 3 )
+               {
+               case 0: tmp_map[i] = 0; break;
+               case 1:
+                       MM_int_CloneTable(&tmp_map[i], i);
+                       i += 3; // Tables are alocated in blocks of 4
+                       break;
+               case 2:
+               case 3:
+                       Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i);
+                       tmp_map[i] = 0;
+                       break;
+               }
+       }
+
+       // Allocate Fractal table
+       {
+                int    j, num;
+               tPAddr  tmp = MM_AllocPhys();
+               Uint32  *table = MM_MapTemp(tmp);
+               Uint32  sp;
+               register Uint32 __SP asm("sp");
+
+               // Map table to last 4MiB of user space
+               new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1;
+               new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1;
+               new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1;
+               new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1;
+               
+               tmp_map = new_lvl1_1;
+               for( j = 0; j < 512; j ++ )
+               {
+                       if( j == 256 )
+                               tmp_map = &new_lvl1_2[-0x400];
+                       if( (tmp_map[j*4] & 3) == 1 )
+                       {
+                               table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00;
+                               table[j] |= 0x813;      // nG, Kernel Only, Small page, XN
+                       }
+                       else
+                               table[j] = 0;
+               }
+               // Fractal
+               table[j++] = (ret + 0x0000) | 0x813;
+               table[j++] = (ret + 0x1000) | 0x813;
+               // Nuke the rest
+               for(      ; j < 1024; j ++ )
+                       table[j] = 0;
+               
+               // Get kernel stack bottom
+               sp = __SP & ~(MM_KSTACK_SIZE-1);
+               j = (sp / 0x1000) % 1024;
+               num = MM_KSTACK_SIZE/0x1000;
+
+//             Log("num = %i, sp = %p, j = %i", num, sp, j);
+               
+               // Copy stack pages
+               for(; num--; j ++, sp += 0x1000)
+               {
+                       tVAddr  page;
+                       void    *tmp_page;
+                       
+                       page = MM_AllocPhys();
+//                     Log("page = %P", page);
+                       table[j] = page | 0x813;
+
+                       tmp_page = MM_MapTemp(page);
+                       memcpy(tmp_page, (void*)sp, 0x1000);
+                       MM_FreeTemp( tmp_page );
+               }
+
+               MM_FreeTemp( table );
+       }
+
+       MM_FreeTemp( new_lvl1_1 );
+       MM_FreeTemp( new_lvl1_2 );
+
+//     Log("MM_Clone: ret = %P", ret);
+
+       return ret;
+}
+
+void MM_ClearUser(void)
+{
+        int    i, j;
+       const int       user_table_count = USER_STACK_TOP / (256*0x1000);
+       Uint32  *cur = (void*)MM_TABLE0USER;
+       Uint32  *tab;
+       
+//     MM_DumpTables(0, 0x80000000);
+
+//     Log("user_table_count = %i (as opposed to %i)", user_table_count, 0x800-4);
+
+       for( i = 0; i < user_table_count; i ++ )
+       {
+               switch( cur[i] & 3 )
+               {
+               case 0: break;  // Already unmapped
+               case 1: // Sub pages
+                       tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+                       for( j = 0; j < 1024; j ++ )
+                       {
+                               switch( tab[j] & 3 )
+                               {
+                               case 0: break;  // Unmapped
+                               case 1:
+                                       Log_Error("MMVirt", "TODO: Support large pages in MM_ClearUser");
+                                       break;
+                               case 2:
+                               case 3:
+                                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE-1) );
+                                       break;
+                               }
+                       }
+                       MM_DerefPhys( cur[i] & ~(PAGE_SIZE-1) );
+                       cur[i+0] = 0;
+                       cur[i+1] = 0;
+                       cur[i+2] = 0;
+                       i += 3;
+                       break;
+               case 2:
+               case 3:
+                       Log_Error("MMVirt", "TODO: Implement sections/supersections in MM_ClearUser");
+                       break;
+               }
+               cur[i] = 0;
+       }
+       
+       // Final block of 4 tables are KStack
+       i = 0x800 - 4;
+       
+       // Clear out unused stacks
+       {
+               register Uint32 __SP asm("sp");
+                int    cur_stack_base = ((__SP & ~(MM_KSTACK_SIZE-1)) / PAGE_SIZE) % 1024;
+
+               tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+               
+               // First 512 is the Table1 mapping + 2 for Table0 mapping
+               for( j = 512+2; j < 1024; j ++ )
+               {
+                       // Skip current stack
+                       if( j == cur_stack_base ) {
+                               j += (MM_KSTACK_SIZE / PAGE_SIZE) - 1;
+                               continue ;
+                       }
+                       if( !(tab[j] & 3) )     continue;
+                       ASSERT( (tab[j] & 3) == 2 );
+                       MM_DerefPhys( tab[j] & ~(PAGE_SIZE) );
+                       tab[j] = 0;
+               }
+       }
+       
+
+//     MM_DumpTables(0, 0x80000000);
+}
+
+void *MM_MapTemp(tPAddr PAddr)
+{
+       tVAddr  ret;
+       tMM_PageInfo    pi;
+
+       for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
+       {
+               if( MM_int_GetPageInfo(ret, &pi) == 0 )
+                       continue;
+
+//             Log("MapTemp %P at %p by %p", PAddr, ret, __builtin_return_address(0));
+               MM_RefPhys(PAddr);      // Counter the MM_Deallocate in FreeTemp
+               MM_Map(ret, PAddr);
+               
+               return (void*)ret;
+       }
+       Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
+       return 0;
+}
+
+void MM_FreeTemp(void *Ptr)
+{
+       tVAddr  VAddr = (tVAddr)Ptr;
+       if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
+               Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
+               return ;
+       }
+       
+       MM_Deallocate(VAddr);
+}
+
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
+{
+       tVAddr  ret;
+        int    i;
+       tMM_PageInfo    pi;
+
+       ENTER("xPAddr iNPages", PAddr, NPages);
+
+       // Scan for a location
+       for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
+       {
+//             LOG("checking %p", ret);
+               // Check if there is `NPages` free pages
+               for( i = 0; i < NPages; i ++ )
+               {
+                       if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
+                               break;
+               }
+               // Nope, jump to after the used page found and try again
+//             LOG("i = %i, ==? %i", i, NPages);
+               if( i != NPages ) {
+                       ret += i * PAGE_SIZE;
+                       continue ;
+               }
+       
+               // Map the pages        
+               for( i = 0; i < NPages; i ++ )
+                       MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAGE_SIZE);
+               // and return
+               LEAVE('p', ret);
+               return ret;
+       }
+       Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
+       LEAVE('p', 0);
+       return 0;
+}
+
+tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
+{
+       tPAddr  phys;
+       tVAddr  ret;
+
+       phys = MM_AllocPhysRange(Pages, MaxBits);
+       if(!phys) {
+               Log_Warning("MMVirt", "No space left for a %i page block (MM_AllocDMA)", Pages);
+               return 0;
+       }
+       
+       ret = MM_MapHWPages(phys, Pages);
+       *PAddr = phys;
+
+       return ret;
+}
+
+void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
+{
+       Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
+}
+
+tVAddr MM_NewKStack(int bShared)
+{
+       tVAddr  min_addr, max_addr;
+       tVAddr  addr, ofs;
+
+       if( bShared ) {
+               min_addr = MM_GLOBALSTACKS;
+               max_addr = MM_GLOBALSTACKS_END;
+       }
+       else {
+               min_addr = MM_KSTACK_BASE;
+               max_addr = MM_KSTACK_END;
+       }
+
+       // Locate a free slot
+       for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
+       {
+               tMM_PageInfo    pi;
+               if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) )    break;
+       }
+
+       // Check for an error   
+       if(addr >= max_addr) {
+               return 0;
+       }
+
+       // 1 guard page
+       for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
+       {
+               if( MM_Allocate(addr + ofs) == 0 )
+               {
+                       while(ofs)
+                       {
+                               ofs -= PAGE_SIZE;
+                               MM_Deallocate(addr + ofs);
+                       }
+                       Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
+                       return 0;
+               }
+       }
+       return addr + ofs;
+}
+
+tVAddr MM_NewUserStack(void)
+{
+       tVAddr  addr, ofs;
+
+       addr = USER_STACK_TOP - USER_STACK_SIZE;
+       if( MM_GetPhysAddr( (void*)(addr + PAGE_SIZE) ) ) {
+               Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
+                       addr + PAGE_SIZE
+                       );
+               return 0;
+       }
+
+       // 1 guard page
+       for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
+       {
+               tPAddr  rv;
+               if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
+                       rv = MM_Allocate(addr + ofs);
+               else
+                       rv = MM_AllocateZero(addr + ofs);
+               if(rv == 0)
+               {
+                       while(ofs)
+                       {
+                               ofs -= PAGE_SIZE;
+                               MM_Deallocate(addr + ofs);
+                       }
+                       Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
+                       return 0;
+               }
+               MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
+       }
+//     Log("Return %p", addr + ofs);
+//     MM_DumpTables(0, 0x80000000);
+       return addr + ofs;
+}
+
+void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
+{
+       if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
+       {
+               Debug("%p => %8s - 0x%7x %i %x %s",
+                       Start, "ZERO", Len,
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
+                       );
+       }
+       else
+       {
+               Debug("%p => %8x - 0x%7x %i %x %s",
+                       Start, Info->PhysAddr-Len, Len,
+                       Info->Domain, Info->AP,
+                       Info->bGlobal ? "G" : "nG"
+                       );
+       }
+}
+
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+       tVAddr  range_start = 0, addr;
+       tMM_PageInfo    pi, pi_old;
+        int    i = 0, inRange=0;
+       
+       memset(&pi_old, 0, sizeof(pi_old));
+
+       Debug("Page Table Dump (%p to %p):", Start, End);
+       range_start = Start;
+       for( addr = Start; i == 0 || (addr && addr < End); i = 1 )
+       {
+                int    rv;
+//             Log("addr = %p", addr);
+               rv = MM_int_GetPageInfo(addr, &pi);
+               if( rv
+                || pi.Size != pi_old.Size
+                || pi.Domain != pi_old.Domain
+                || pi.AP != pi_old.AP
+                || pi.bGlobal != pi_old.bGlobal
+                || pi_old.PhysAddr != pi.PhysAddr )
+               {
+                       if(inRange) {
+                               MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old);
+                       }
+                       addr &= ~((1 << pi.Size)-1);
+                       range_start = addr;
+               }
+               
+               pi_old = pi;
+               // Handle the zero page
+               if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
+                       pi_old.PhysAddr += 1 << pi_old.Size;
+               addr += 1 << pi_old.Size;
+               inRange = (rv == 0);
+       }
+       if(inRange)
+               MM_int_DumpTableEnt(range_start, addr - range_start, &pi);
+       Debug("Done");
+}
+
+// NOTE: Runs in abort context, not much difference, just a smaller stack
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
+{
+        int    rv;
+       tMM_PageInfo    pi;
+       
+       rv = MM_int_GetPageInfo(Addr, &pi);
+       
+       // Check for COW
+       if( rv == 0 &&  pi.AP == AP_RO_BOTH )
+       {
+               pi.AP = AP_RW_BOTH;
+               if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage )
+               {
+                       tPAddr  newpage;
+                       newpage = MM_AllocPhys();
+                       if( !newpage ) {
+                               Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO");
+                               for(;;);
+                       }
+                       
+                       #if TRACE_COW
+                       Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC,
+                               newpage, MM_GetRefCount(pi.PhysAddr));
+                       #endif
+
+                       MM_DerefPhys(pi.PhysAddr);
+                       pi.PhysAddr = newpage;
+                       pi.AP = AP_RW_BOTH;
+                       MM_int_SetPageInfo(Addr, &pi);
+                       
+                       memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE );
+
+                       return ;
+               }
+               else if( MM_GetRefCount(pi.PhysAddr) > 1 )
+               {
+                       // Duplicate the page
+                       tPAddr  newpage;
+                       void    *dst, *src;
+                       
+                       newpage = MM_AllocPhys();
+                       if(!newpage) {
+                               Log_Error("MMVirt", "Unable to allocate new page for COW");
+                               for(;;);
+                       }
+                       dst = MM_MapTemp(newpage);
+                       src = (void*)(Addr & ~(PAGE_SIZE-1));
+                       memcpy( dst, src, PAGE_SIZE );
+                       MM_FreeTemp( dst );
+                       
+                       #if TRACE_COW
+                       Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
+                               pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr));
+                       #endif
+
+                       MM_DerefPhys(pi.PhysAddr);
+                       pi.PhysAddr = newpage;
+               }
+               #if TRACE_COW
+               else {
+                       Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P",
+                               Addr, PC, pi.PhysAddr);
+               }
+               #endif
+               // Unset COW
+               pi.AP = AP_RW_BOTH;
+               MM_int_SetPageInfo(Addr, &pi);
+               return ;
+       }
+       
+
+       Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
+               (bPrefetch ? " - Prefetch" : "")
+               );
+       if( Addr < 0x80000000 )
+               MM_DumpTables(0, 0x80000000);
+       else
+               MM_DumpTables(0x80000000, -1);
+       for(;;);
+}
+
diff --git a/KernelLand/Kernel/arch/armv6/pci.c b/KernelLand/Kernel/arch/armv6/pci.c
new file mode 100644 (file)
index 0000000..2e674bb
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *
+ */
+#include <acess.h>
+#include <drv_pci_int.h>
+
+// Realview
+//#define PCI_BASE     0x60000000
+
+//#define PCI_BASE     0xF0400000      // VMM Mapping
+#define PCI_BASE       0
+
+// === CODE ===
+void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
+{
+       #if PCI_BASE
+       Uint32  address = PCI_BASE | Addr;
+       *(Uint32*)(address) = Data;
+       #else
+       #endif
+}
+
+Uint32 PCI_CfgReadDWord(Uint32 Addr)
+{
+       #if PCI_BASE
+       Uint32  address = PCI_BASE | Addr;
+       return *(Uint32*)address;
+       #else
+       return 0xFFFFFFFF;
+       #endif
+}
+
diff --git a/KernelLand/Kernel/arch/armv6/proc.S b/KernelLand/Kernel/arch/armv6/proc.S
new file mode 100644 (file)
index 0000000..1979058
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.S
+ * - Process management assembly
+ */
+
+#include "include/assembly.h"
+
+.globl KernelThreadHeader
+@ SP+12: Argument 1
+@ SP+8: Argument Count
+@ SP+4: Function
+@ SP+0: Thread Pointer
+KernelThreadHeader:
+       ldr r0, [sp],#4
+       @ TODO: Do something with the thread pointer
+       
+       ldr r4, [sp],#4 @ Function
+       @ Get argument
+       ldr r0, [sp],#4
+
+       blx r4
+       
+       ldr r0, =0
+       bl Threads_Exit
+       b .
+
+.globl SwitchTask
+@ R0: New stack
+@ R1: Pointer to where to save old stack
+@ R2: New IP
+@ R3: Pointer to save old IP
+@ SP+0: New address space
+SwitchTask:
+       push {r4-r12,lr}
+
+       @ Save IP       
+       ldr r4, =.return
+       str r4, [r3]
+       @ Save SP
+       str sp, [r1]
+
+       @ Only update TTBR0 if the task has an explicit address space
+       ldr r1, [sp,#4*10]
+       tst r1, r1
+       mcrne p15, 0, r1, c2, c0, 0     @ Set TTBR0 to r0
+#      mov r1, #1
+       mcrne p15, 0, r1, c8, c7, 0     @ TLBIALL - Invalid user space
+
+       @ Restore state
+       mov sp, r0
+       bx r2
+
+.return:
+       pop {r4-r12,pc}
+
+.extern MM_Clone
+.extern MM_DumpTables
+.globl Proc_CloneInt
+Proc_CloneInt:
+       @ R0: SP Destination
+       @ R1: Mem Destination
+       push {r4-r12,lr}
+       mov r4, r1      @ Save mem destination
+       str sp, [r0]    @ Save SP to SP dest
+
+       bl MM_Clone
+       str r0, [r4]    @ Save clone return to Mem Dest
+
+       ldr r0, =Proc_CloneInt_new
+       pop {r4-r12,pc}
+Proc_CloneInt_new:
+       mov r0, #0
+       pop {r4-r12,pc}
+
+@ R0: New user SP
+@ Return: Old user SP
+.globl Proc_int_SwapUserSP
+Proc_int_SwapUserSP:
+       cps #31 @ Go to system mode
+       mov r1, sp
+       tst r0, r0      @ Only update if non-zero
+       movne sp, r0
+       mov r0, r1
+       cps #19
+       mov pc, lr
+
+.section .usertext, "ax"
+.globl Proc_int_DropToUser
+@ R0: User IP
+@ R1: User SP
+Proc_int_DropToUser:
+       cps #16
+       mov sp, r1
+       mov pc, r0
+
+.section .rodata
+csProc_CloneInt_NewTaskMessage:
+       .asciz "New task PC=%p, R4=%p, sp=%p"
+csProc_CloneInt_OldTaskMessage:
+       .asciz "Parent task PC=%p, R4=%p, SP=%p"
+
+@ vim: ft=armv7
diff --git a/KernelLand/Kernel/arch/armv6/proc.c b/KernelLand/Kernel/arch/armv6/proc.c
new file mode 100644 (file)
index 0000000..cd998f2
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.c
+ * - ARM7 Process Switching
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <hal_proc.h>
+
+// === IMPORTS ===
+extern tThread gThreadZero;
+extern tProcess        gProcessZero;
+extern void    SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
+extern void    KernelThreadHeader(void);       // Actually takes args on stack
+extern void    Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
+extern Uint32  Proc_int_SwapUserSP(Uint32 NewSP);
+extern Uint32  Proc_CloneInt(Uint32 *SP, Uint32 *MemPtr);
+extern tVAddr  MM_NewKStack(int bGlobal);      // TODO: Move out into a header
+extern tVAddr  MM_NewUserStack(void);
+extern char    kernel_table0[];
+
+// === PROTOTYPES ===
+void   Proc_IdleThread(void *unused);
+
+// === GLOBALS ===
+tThread        *gpCurrentThread = &gThreadZero;
+tThread *gpIdleThread = NULL;
+
+// === CODE ===
+void ArchThreads_Init(void)
+{
+       gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
+}
+
+void Proc_IdleThread(void *unused)
+{
+       Threads_SetPriority(gpIdleThread, -1);
+       for(;;) {
+               Proc_Reschedule();
+               __asm__ __volatile__ ("wfi");
+       }
+}
+
+void Proc_Start(void)
+{
+       tTID    tid;
+
+       tid = Proc_NewKThread( Proc_IdleThread, NULL );
+       gpIdleThread = Threads_GetThread(tid);
+       gpIdleThread->ThreadName = (char*)"Idle Thread";
+}
+
+int GetCPUNum(void)
+{
+       return 0;
+}
+
+tThread *Proc_GetCurThread(void)
+{
+       return gpCurrentThread;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
+{
+       Uint32  *usr_sp;
+        int    i;
+       const char      **envp;
+       tVAddr  delta;
+
+//     Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
+//             Entrypoint, Base, ArgC, ArgV, DataSize);
+
+       // Write data to the user's stack
+       usr_sp = (void*)MM_NewUserStack();
+       usr_sp -= (DataSize+3)/4;
+       memcpy(usr_sp, ArgV, DataSize);
+       free(ArgV);
+
+       // Adjust user's copy of the arguments
+       delta = (tVAddr)usr_sp -  (tVAddr)ArgV;
+       ArgV = (void*)usr_sp;
+       for(i = 0; ArgV[i]; i ++)       ArgV[i] += delta;
+       envp = &ArgV[i+1];
+       for(i = 0; envp[i]; i ++)       envp[i] += delta;
+       
+       *--usr_sp = (Uint32)envp;
+       *--usr_sp = (Uint32)ArgV;
+       *--usr_sp = (Uint32)ArgC;
+       *--usr_sp = Base;
+       
+       // Drop to user code
+       Log_Debug("Proc", "Proc_int_DropToUser(%p, %p)", Entrypoint, usr_sp);
+       Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
+}
+
+void Proc_ClearProcess(tProcess *Process)
+{
+       Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
+tTID Proc_Clone(Uint Flags)
+{
+       tThread *new;
+       Uint32  pc, sp, mem;
+
+       new = Threads_CloneTCB(Flags);
+       if(!new)        return -1;
+
+       // Actual clone magic
+       pc = Proc_CloneInt(&sp, &mem);
+       if(pc == 0) {
+               Log("Proc_Clone: In child");
+               return 0;
+       }
+       
+       new->SavedState.IP = pc;
+       new->SavedState.SP = sp;
+       new->SavedState.UserSP = Proc_int_SwapUserSP(0);
+       new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
+       new->Process->MemState.Base = mem;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+{
+       tThread *new;
+       Uint32  sp;
+
+       new = Threads_CloneThreadZero();
+       if(!new)        return -1;
+       if(new->ThreadName)     free(new->ThreadName);
+       new->ThreadName = NULL;
+
+       new->KernelStack = MM_NewKStack(1);
+       if(!new->KernelStack) {
+               // TODO: Delete thread
+               Log_Error("Proc", "Unable to allocate kernel stack");
+               return -1;
+       }       
+
+       sp = new->KernelStack;
+       
+       *(Uint32*)(sp -= 4) = (Uint)Ptr;
+       *(Uint32*)(sp -= 4) = (Uint)Fnc;
+       *(Uint32*)(sp -= 4) = (Uint)new;
+
+       new->SavedState.SP = sp;
+       new->SavedState.IP = (Uint)KernelThreadHeader;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
+{
+       tThread *new;
+       Uint32  sp;
+
+       new = Threads_CloneTCB(0);
+       if(!new)        return -1;
+       free(new->ThreadName);
+       new->ThreadName = NULL;
+
+       // TODO: Non-shared stack
+       new->KernelStack = MM_NewKStack(1);
+       if(!new->KernelStack) {
+               // TODO: Delete thread
+               Log_Error("Proc", "Unable to allocate kernel stack");
+               return -1;
+       }       
+
+       sp = new->KernelStack;
+       
+       *(Uint32*)(sp -= 4) = (Uint)Ptr;
+       *(Uint32*)(sp -= 4) = (Uint)Fnc;
+       *(Uint32*)(sp -= 4) = (Uint)new;
+
+       new->SavedState.SP = sp;
+       new->SavedState.IP = (Uint)KernelThreadHeader;
+
+       Threads_AddActive(new);
+
+       return new->TID;
+}
+
+void Proc_CallFaultHandler(tThread *Thread)
+{
+
+}
+
+void Proc_Reschedule(void)
+{
+       tThread *cur, *next;
+
+       cur = gpCurrentThread;
+
+       next = Threads_GetNextToRun(0, cur);
+       if(!next)       next = gpIdleThread;
+       if(!next || next == cur)        return;
+
+       Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
+               next, next->TID, next->ThreadName,
+               next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
+               next->SavedState.UserSP
+               );
+
+       Log("Requested by %p", __builtin_return_address(0));
+       
+       gpCurrentThread = next;
+
+       cur->SavedState.UserSP = Proc_int_SwapUserSP( next->SavedState.UserSP );
+
+       SwitchTask(
+               next->SavedState.SP, &cur->SavedState.SP,
+               next->SavedState.IP, &cur->SavedState.IP,
+               next->Process->MemState.Base
+               );
+       
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       
+}
+
diff --git a/KernelLand/Kernel/arch/armv6/start.S b/KernelLand/Kernel/arch/armv6/start.S
new file mode 100644 (file)
index 0000000..4be9767
--- /dev/null
@@ -0,0 +1,370 @@
+
+#include "include/assembly.h"
+#include "include/options.h"
+
+@
+@ Exception defs taken from ARM DDI 0406B
+@ 
+.section .init
+interrupt_vector_table:
+ivt_reset:     b _start        @ 0x00 Reset
+ivt_undef:     b Undef_Handler @ 0x04 #UD
+ivt_svc:       b SVC_Handler   @ 0x08 SVC (used to be called SWI)
+ivt_prefetch:  b PrefetchAbort @ 0x0C Prefetch abort
+ivt_data:      b DataAbort     @ 0x10 Data abort
+ivt_unused:    b .             @ 0x14 Not Used
+ivt_irq:       b IRQHandler    @ 0x18 IRQ
+ivt_fiq:       b .             @ 0x1C FIQ (Fast interrupt)
+
+.globl _start
+_start:
+       ldr r2, =UART0_PADDR
+       mov r1, #'A'
+       str r1, [r2]    
+
+       ldr r0, =kernel_table0-KERNEL_BASE
+       mcr p15, 0, r0, c2, c0, 1       @ Set TTBR1 to r0
+       mcr p15, 0, r0, c2, c0, 0       @ Set TTBR0 to r0 too (for identity)
+
+       mov r1, #'c'
+       str r1, [r2]    
+
+       mov r0, #1
+       mcr p15, 0, r0, c2, c0, 2       @ Set TTCR to 1 (50/50 split)
+
+       mov r1, #'e'
+       str r1, [r2]    
+       
+       mov r0, #3
+       mcr p15, 0, r0, c3, c0, 0       @ Set Domain 0 to Manager
+
+       mov r1, #'s'
+       str r1, [r2]    
+
+       @ Enable VMSA
+       mrc p15, 0, r0, c1, c0, 0
+       orr r0, r0, #1
+       orr r0, r0, #1 << 23
+       mcr p15, 0, r0, c1, c0, 0
+
+       @ HACK: Set ASID to non zero
+       mov r0, #1
+       MCR p15,0,r0,c13,c0,1
+
+       ldr r2, =0xF1000000
+       mov r1, #'s'
+       str r1, [r2]    
+
+       @ Enable access faults on domains 0 & 1
+       mov r0, #0x55   @ 01010101b
+       mcr p15, 0, r0, c3, c0, 0
+
+       mov r1, #'2'
+       str r1, [r2]    
+
+       @
+       @ Check for security extensions
+       @
+       mrc p15, 0, r0, c0, c1, 1
+       and r0, #0xF0
+       @ - Present
+       ldrne r0,=KERNEL_BASE
+       mcrne p15, 0, r0, c12, c0, 0    @ Set the VBAR (brings exceptions into high memory)
+       @ - Absent
+       mrceq p15, 0, r0, c1, c0, 0     @ Set SCTLR.V
+       orreq r0, #0x2000
+       mcreq p15, 0, r0, c1, c0, 0
+
+       mov r1, #'-'
+       str r1, [r2]    
+
+       @ Prepare for interrupts
+       cps #18 @ IRQ Mode
+       ldr sp, =irqstack+0x1000        @ Set up stack
+       cps #23 @ Abort Mode
+       ldr sp, =abortstack+0x1000
+       cps #19
+
+       mov r1, #'a'
+       str r1, [r2]    
+       mov r1, #'r'
+       str r1, [r2]    
+       mov r1, #'m'
+       str r1, [r2]    
+       mov r1, #13
+       str r1, [r2]    
+       mov r1, #10
+       str r1, [r2]    
+
+.extern bss_start
+.extern bss_size_div_4
+.zero_bss:
+       ldr r0, =bss_start
+       ldr r1, =bss_end
+       mov r3, #0
+.zero_bss_loop:
+       str r3, [r0],#4
+       cmp r0, r1
+       bls .zero_bss_loop
+
+.goto_c:
+       ldr sp, =0x80000000-8   @ Set up stack (top of user range)
+       ldr r0, =kmain
+       mov pc, r0
+1:     b 1b    @ Infinite loop
+
+.comm irqstack, 0x1000 @ ; 4KiB Stack
+.comm abortstack, 0x1000       @ ; 4KiB Stack
+
+.extern SyscallHandler
+SVC_Handler:
+@      sub lr, #4
+       srsdb sp!, #19  @ Save state to stack
+       cpsie ifa, #19  @ Ensure we're in supervisor with interrupts enabled (should already be there)
+       push {r0-r12}
+
+       ldr r4, [lr,#-4]
+       mvn r5, #0xFF000000
+       and r4, r5
+
+       tst r4, #0x1000 
+       bne .arm_specifics
+
+       push {r4}
+
+       mov r0, sp
+       ldr r4, =SyscallHandler
+       blx r4
+       
+@      ldr r0, =csSyscallPrintRetAddr
+@      ldr r1, [sp,#9*4+5*4]
+@      ldr r4, =Log
+@      blx r4
+       
+       pop {r2}        @ errno
+       pop {r0,r1}     @ Ret/RetHi
+       add sp, #2*4    @ Saved r2/r3
+
+       pop {r4-r12}
+       rfeia sp!       @ Pop state (actually RFEFD)
+.arm_specifics:
+       and r4, #0xFF
+       mov r0, r4      @ Number
+       mov r1, sp      @ Arguments
+       
+       ldr r4, =ARMv7_int_HandleSyscalls
+       blx r4
+
+       add sp, #4*4
+       pop {r4-r12}
+       rfeia sp!
+
+
+.globl gpIRQHandler
+gpIRQHandler:  .long   0
+IRQ_saved_sp:  .long   0
+IRQ_saved_lr:  .long   0
+.globl IRQHandler
+IRQHandler:
+       sub lr, #4      @ Adjust LR to the correct value
+       srsdb sp!, #19  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+       cps #19
+
+       PUSH_GPRS
+
+@      ldr r0, =csIRQ_Tag
+@      ldr r1, =csIRQ_Fmt
+@      ldr r4, =Log_Debug
+@      blx r4
+       
+       @ Call the registered handler
+       ldr r0, gpIRQHandler
+       blx r0
+
+       @ Restore CPU state
+       POP_GPRS
+       cpsie i
+       rfeia sp!       @ Pop state (actually RFEFD)
+       bx lr
+
+.globl DataAbort
+DataAbort:
+       sub lr, #8      @ Adjust LR to the correct value
+       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@      cpsid ifa, #19
+       PUSH_GPRS
+
+       mov r3, #0      @ not a prefetch abort
+       mrc p15, 0, r2, c5, c0, 0       @ Read DFSR (Data Fault Status Register) to R2
+       mrc p15, 0, r1, c6, c0, 0       @ Read DFAR (Data Fault Address Register) into R1
+       mov r0, lr      @ PC
+       ldr r4, =MM_PageFault
+       blx r4
+
+       POP_GPRS
+       rfeia sp!       @ Pop state (actually RFEFD)
+
+.globl PrefetchAbort
+PrefetchAbort:
+       sub lr, #4      @ Adjust LR to the correct value
+       srsdb sp!, #23  @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@      cpsid ifa, #19
+       PUSH_GPRS
+
+       ldr r0, =csAbort_Tag
+       ldr r1, =csPrefetchAbort_Fmt
+#      mov r2, lr
+       mrc p15, 0, r2, c6, c0, 2       @ Read IFAR (Instruction Fault Address Register) into R3
+       mrc p15, 0, r3, c5, c0, 1       @ Read IFSR (Instruction Fault Status Register) into R3
+       ldr r5, =Log_Error
+       blx r5
+
+.loop:
+       wfi
+       b .loop
+.globl Undef_Handler
+Undef_Handler:
+       wfi
+       b Undef_Handler
+
+.globl abort
+abort:
+       wfi
+       b abort
+
+
+.section .rodata
+csIRQ_Tag:
+csAbort_Tag:
+       .asciz "ARMv7"
+csIRQ_Fmt:
+       .asciz "IRQ"
+csDataAbort_Fmt:
+       .asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x"
+csPrefetchAbort_Fmt:
+       .asciz "Prefetch Abort at %p, IFSR=%x"
+csSyscallPrintRetAddr:
+       .asciz "Syscall ret to %p"
+
+.section .padata
+.globl kernel_table0
+
+kernel_table0:
+       .long 0x00000402        @ Identity map the first 1 MiB
+       .rept 0x7FC - 1
+               .long 0
+       .endr
+       .long user_table1_map + 0x000 - KERNEL_BASE + 1 @ 0x7FC00000
+       .long user_table1_map + 0x400 - KERNEL_BASE + 1 @ 0x7FD00000
+       .long user_table1_map + 0x800 - KERNEL_BASE + 1 @ KStacks
+       .long user_table1_map + 0xC00 - KERNEL_BASE + 1
+       @ 0x80000000 - User/Kernel split
+       .long 0x00000402        @ Map first 4 MiB to 2GiB (KRW only)
+       .long 0x00100402        @ 
+       .long 0x00200402        @ 
+       .long 0x00300402        @ 
+       .rept 0xF00 - 0x800 - 4
+               .long 0
+       .endr
+#if PCI_PADDR
+       .long PCI_PADDR +  0*(1 << 20) + 0x402  @ Map PCI config space
+       .long PCI_PADDR +  1*(1 << 20) + 0x402
+       .long PCI_PADDR +  2*(1 << 20) + 0x402
+       .long PCI_PADDR +  3*(1 << 20) + 0x402
+       .long PCI_PADDR +  4*(1 << 20) + 0x402
+       .long PCI_PADDR +  5*(1 << 20) + 0x402
+       .long PCI_PADDR +  6*(1 << 20) + 0x402
+       .long PCI_PADDR +  7*(1 << 20) + 0x402
+       .long PCI_PADDR +  8*(1 << 20) + 0x402
+       .long PCI_PADDR +  9*(1 << 20) + 0x402
+       .long PCI_PADDR + 10*(1 << 20) + 0x402
+       .long PCI_PADDR + 11*(1 << 20) + 0x402
+       .long PCI_PADDR + 12*(1 << 20) + 0x402
+       .long PCI_PADDR + 13*(1 << 20) + 0x402
+       .long PCI_PADDR + 14*(1 << 20) + 0x402
+       .long PCI_PADDR + 15*(1 << 20) + 0x402
+#else
+       .rept 16
+               .long 0
+       .endr
+#endif
+       .long hwmap_table_0 + 0x000 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0x400 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0x800 - KERNEL_BASE + 1
+       .long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1
+       .rept 0xFF8 - 0xF00 - 16 - 4
+               .long 0
+       .endr
+       @ Page fractals
+       .long kernel_table1_map + 0x000 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0x400 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0x800 - KERNEL_BASE + 1
+       .long kernel_table1_map + 0xC00 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x000 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x400 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0x800 - KERNEL_BASE + 1
+       .long kernel_exception_map + 0xC00 - KERNEL_BASE + 1
+
+@ PID0 user table
+.globl user_table1_map
+@ User table1 data table (only the first half is needed)
+@ - Abused to provide kernel stacks in the unused half of the table
+user_table1_map:       @ Size = 4KiB (only 2KiB used)
+       .rept 0x800/4-1
+               .long 0
+       .endr
+       .long user_table1_map - KERNEL_BASE + 0x13      @ ...1FF000 = 0x7FDFF000
+       @ Kernel stack zone
+       .long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13       @ ...200000 = 0x7FE00000
+       .long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13       @ ...201000 = 0x7FE01000
+       .rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2
+               .long 0
+       .endr
+       #if MM_KSTACK_SIZE != 0x2000
+       #error Kernel stack size not changed in start.S
+       #endif
+       .long stack + 0x0000 - KERNEL_BASE + 0x13       @ Kernel Stack
+       .long stack + 0x1000 - KERNEL_BASE + 0x13       @ 
+
+.globl kernel_table1_map
+kernel_table1_map:     @ Size = 4KiB
+       .rept (0xF00+16)/4
+               .long 0
+       .endr
+       .long hwmap_table_0 - KERNEL_BASE + 0x13
+       .rept 0xFF8/4 - (0xF00+16)/4 - 1
+               .long 0
+       .endr
+       .long kernel_table1_map - KERNEL_BASE + 0x13
+       .long kernel_exception_map - KERNEL_BASE + 0x13
+
+@ Hardware mappings 
+.globl hwmap_table_0
+hwmap_table_0:
+       .long UART0_PADDR + 0x13        @ UART0
+       .rept 1024 - 1
+               .long 0
+       .endr
+.globl kernel_exception_map
+kernel_exception_map:
+       @ Padding
+       .rept 1024-256
+               .long 0
+       .endr
+       @ Align to nearly the end
+       .rept 256-16
+               .long   0
+       .endr
+       .long 0x212     @ Map first page for exceptions (Kernel RO, Execute)
+       .rept 16-1-2
+               .long 0
+       .endr
+       .long gUsertextPhysStart + 0x22 @ User .text (User RO, Kernel RW, because both is COW)
+       .long 0
+       
+.section .padata
+stack:
+       .space MM_KSTACK_SIZE, 0        @ Original kernel stack
+
+// vim: ts=8 ft=armv7
+
diff --git a/KernelLand/Kernel/arch/armv6/time.c b/KernelLand/Kernel/arch/armv6/time.c
new file mode 100644 (file)
index 0000000..d4ae4fa
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Acess2
+ *
+ * ARM7 Time code
+ * arch/arm7/time.c
+ */
+#include <acess.h>
+
+// === GLOBALS ===
+tTime  giTimestamp;
+
+// === CODE ===
+tTime now(void)
+{
+       return giTimestamp;
+}
index fad1b55..5429fe6 100644 (file)
@@ -12,6 +12,7 @@ LDFLAGS += `$(CC) --print-libgcc-file-name`
 
 A_OBJ  = start.ao main.o lib.o lib.ao time.o pci.o debug.o
 A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+A_OBJ += vpci_$(PLATFORM).o
 
 #main.c: Makefile.BuildNum.$(ARCH)
 
index 5a6928e..65c457c 100644 (file)
@@ -14,12 +14,15 @@ extern Uint32       __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
 // === PROTOTYPES ===
 Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
 Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
+#if 0
 Uint64 __udivdi3(Uint64 Num, Uint64 Den);
 Uint64 __umoddi3(Uint64 Num, Uint64 Den);
 Uint32 __udivsi3(Uint32 Num, Uint32 Den);
 Uint32 __umodsi3(Uint32 Num, Uint32 Den);
 Sint32 __divsi3(Sint32 Num, Sint32 Den);
 Sint32 __modsi3(Sint32 Num, Sint32 Den);
+#endif
+void   abort(void);
 
 // === CODE ===
 void *memcpy(void *_dest, const void *_src, size_t _length)
@@ -160,6 +163,7 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
        return ret;
 }
 
+#if 0
 // Unsigned Divide 64-bit Integer
 Uint64 __udivdi3(Uint64 Num, Uint64 Den)
 {
@@ -215,3 +219,9 @@ Sint32 __modsi3(Sint32 Num, Sint32 Den)
        DivMod32S(Num, Den, &rem);
        return rem;
 }
+#endif
+
+void abort(void)
+{
+       for(;;);
+}
index d10dcc4..fbd3582 100644 (file)
@@ -27,9 +27,33 @@ SECTIONS
                *(.usertext)
        }
        . += gUsertextPhysStart + _kernel_base - _usertext_vbase;
-       
+
+       /DISCARD/           : { *(.ARM.extab.init .ARM.exidx.init)      }
+       .ARM.extab          : AT( ADDR(.ARM.extab) - _kernel_base)
+       {
+               *(.ARM.extab* .gnu.linkonce.armextab.*)
+       }
+       PROVIDE_HIDDEN ( __exidx_start = . );
+       .ARM.exidx          : AT( ADDR(.ARM.exidx) - _kernel_base)
+       {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+       }
+       PROVIDE_HIDDEN ( __exidx_end = . );
+       .eh_frame_hdr       : AT( ADDR(.eh_frame_hdr) - _kernel_base) {
+               *(.eh_frame_hdr)
+       }
+       .eh_frame           : AT( ADDR(.eh_frame) - _kernel_base) ONLY_IF_RO
+       {
+               KEEP (*(.eh_frame))
+       }
+       .gcc_except_table   : AT( ADDR(.gcc_except_table) - _kernel_base) ONLY_IF_RO
+       {
+               *(.gcc_except_table .gcc_except_table.*)
+       }
+
        /* 0x4000 (4 pages) alignment needed for root table */
-       .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+       . = ALIGN(0x4000);
+       .data : AT( ADDR(.data) - _kernel_base )
        {
                *(.padata)
                *(.data*)
@@ -42,7 +66,7 @@ SECTIONS
                *(KMODULES)
                gKernelModulesEnd = .;
        }
-       .bss : AT( ADDR(.bss) - _kernel_base )
+       .bss ALIGN(0x1000) : AT( ADDR(.bss) - _kernel_base )
        {
                bss_start = .;
                *(.bss*)
index 90655b6..85f9b27 100644 (file)
@@ -320,12 +320,12 @@ int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
 }
 
 // --- Exports ---
-tPAddr MM_GetPhysAddr(tVAddr VAddr)
+tPAddr MM_GetPhysAddr(const void *Ptr)
 {
        tMM_PageInfo    pi;
-       if( MM_int_GetPageInfo(VAddr, &pi) )
+       if( MM_int_GetPageInfo((tVAddr)Ptr, &pi) )
                return 0;
-       return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
+       return pi.PhysAddr | ((tVAddr)Ptr & ((1 << pi.Size)-1));
 }
 
 Uint MM_GetFlags(tVAddr VAddr)
@@ -535,7 +535,7 @@ void MM_int_CloneTable(Uint32 *DestEnt, int Table)
 
        cur += 256*Table;
        
-       tmp_map = (void*)MM_MapTemp(table);
+       tmp_map = MM_MapTemp(table);
        
        for( i = 0; i < 1024; i ++ )
        {
@@ -559,10 +559,10 @@ void MM_int_CloneTable(Uint32 *DestEnt, int Table)
                                tPAddr  newpage;
                                newpage = MM_AllocPhys();
                                src = (void*)( (Table*256+i)*0x1000 );
-                               dst = (void*)MM_MapTemp(newpage);
+                               dst = MM_MapTemp(newpage);
 //                             Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
                                memcpy(dst, src, PAGE_SIZE);
-                               MM_FreeTemp( (tVAddr)dst );
+                               MM_FreeTemp( dst );
                                tmp_map[i] = newpage | (cur[i] & 0xFFF);
                        }
                        else
@@ -575,7 +575,7 @@ void MM_int_CloneTable(Uint32 *DestEnt, int Table)
                        break;
                }
        }
-       MM_FreeTemp( (tVAddr) tmp_map );
+       MM_FreeTemp( tmp_map );
 
        DestEnt[0] = table + 0*0x400 + 1;
        DestEnt[1] = table + 1*0x400 + 1;
@@ -595,8 +595,8 @@ tPAddr MM_Clone(void)
        ret = MM_AllocateRootTable();
 
        cur = (void*)MM_TABLE0USER;
-       new_lvl1_1 = (void*)MM_MapTemp(ret);
-       new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000);
+       new_lvl1_1 = MM_MapTemp(ret);
+       new_lvl1_2 = MM_MapTemp(ret+0x1000);
        tmp_map = new_lvl1_1;
        for( i = 0; i < 0x800-4; i ++ )
        {
@@ -626,7 +626,7 @@ tPAddr MM_Clone(void)
        {
                 int    j, num;
                tPAddr  tmp = MM_AllocPhys();
-               Uint32  *table = (void*)MM_MapTemp(tmp);
+               Uint32  *table = MM_MapTemp(tmp);
                Uint32  sp;
                register Uint32 __SP asm("sp");
 
@@ -673,16 +673,16 @@ tPAddr MM_Clone(void)
 //                     Log("page = %P", page);
                        table[j] = page | 0x813;
 
-                       tmp_page = (void*)MM_MapTemp(page);
+                       tmp_page = MM_MapTemp(page);
                        memcpy(tmp_page, (void*)sp, 0x1000);
-                       MM_FreeTemp( (tVAddr) tmp_page );
+                       MM_FreeTemp( tmp_page );
                }
 
-               MM_FreeTemp( (tVAddr)table );
+               MM_FreeTemp( table );
        }
 
-       MM_FreeTemp( (tVAddr)new_lvl1_1 );
-       MM_FreeTemp( (tVAddr)new_lvl1_2 );
+       MM_FreeTemp( new_lvl1_1 );
+       MM_FreeTemp( new_lvl1_2 );
 
 //     Log("MM_Clone: ret = %P", ret);
 
@@ -764,7 +764,7 @@ void MM_ClearUser(void)
 //     MM_DumpTables(0, 0x80000000);
 }
 
-tVAddr MM_MapTemp(tPAddr PAddr)
+void *MM_MapTemp(tPAddr PAddr)
 {
        tVAddr  ret;
        tMM_PageInfo    pi;
@@ -778,14 +778,15 @@ tVAddr MM_MapTemp(tPAddr PAddr)
                MM_RefPhys(PAddr);      // Counter the MM_Deallocate in FreeTemp
                MM_Map(ret, PAddr);
                
-               return ret;
+               return (void*)ret;
        }
        Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
        return 0;
 }
 
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *Ptr)
 {
+       tVAddr  VAddr = (tVAddr)Ptr;
        if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
                Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
                return ;
@@ -1040,10 +1041,10 @@ void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
                                Log_Error("MMVirt", "Unable to allocate new page for COW");
                                for(;;);
                        }
-                       dst = (void*)MM_MapTemp(newpage);
+                       dst = MM_MapTemp(newpage);
                        src = (void*)(Addr & ~(PAGE_SIZE-1));
                        memcpy( dst, src, PAGE_SIZE );
-                       MM_FreeTemp( (tVAddr)dst );
+                       MM_FreeTemp( dst );
                        
                        #if TRACE_COW
                        Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
index cd998f2..9d5643e 100644 (file)
@@ -130,7 +130,7 @@ tTID Proc_Clone(Uint Flags)
        return new->TID;
 }
 
-int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+tThread *Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
 {
        tThread *new;
        Uint32  sp;
@@ -144,7 +144,7 @@ int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
        if(!new->KernelStack) {
                // TODO: Delete thread
                Log_Error("Proc", "Unable to allocate kernel stack");
-               return -1;
+               return NULL;
        }       
 
        sp = new->KernelStack;
@@ -158,7 +158,7 @@ int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
 
        Threads_AddActive(new);
 
-       return new->TID;
+       return new;
 }
 
 tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
diff --git a/KernelLand/Kernel/arch/armv7/vpci_tegra2.c b/KernelLand/Kernel/arch/armv7/vpci_tegra2.c
new file mode 100644 (file)
index 0000000..d44e9d5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Acess2 Kernel ARMv7 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci_tegra2.c
+ * - Tegra2 VPCI Definitions
+ */
+#include <virtual_pci.h>
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+tVPCI_Device   gaVPCI_Devices[] = {
+       {
+       .Vendor=0x0ACE,.Device=0x1100,
+       .Class = 0x0C032000,    // Serial, USB, ECHI
+       .BARs = {0xC5000000,0,0,0,0,0},
+       .IRQ = 0*32+20,
+       },
+       {
+       .Vendor=0x0ACE,.Device=0x1100,
+       .Class = 0x0C032000,    // Serial, USB, ECHI
+       .BARs = {0xC5004000,0,0,0,0,0},
+       .IRQ = 0*32+21,
+       },
+       {
+       .Vendor=0x0ACE,.Device=0x1100,
+       .Class = 0x0C032000,    // Serial, USB, ECHI
+       .BARs = {0xC5008000,0,0,0,0,0},
+       .IRQ = 4*32+1,
+       }
+};
+int giVPCI_DeviceCount = sizeof(gaVPCI_Devices)/sizeof(gaVPCI_Devices[0]);
+
index c83a5af..7372839 100644 (file)
@@ -20,7 +20,7 @@ endif
 ASFLAGS += -D USE_MP=$(USE_MP)
 CPPFLAGS += -DUSE_MP=$(USE_MP)
 
-A_OBJ  = start.ao main.o lib.o desctab.ao errors.o irq.o
+A_OBJ  = start.ao main.o mboot.o lib.o desctab.ao errors.o irq.o
 A_OBJ += mm_phys.o mm_virt.o
 A_OBJ += proc.o proc.ao time.o vm8086.o
-A_OBJ += kpanic.o pci.o
+A_OBJ += kpanic.o pci.o vpci.o
index f0f6e2b..8dc90b0 100644 (file)
@@ -116,6 +116,8 @@ void ErrorHandler(tRegs *Regs)
                        csaERROR_NAMES[Regs->int_num], Regs->err_code);
                Log_Warning("Arch", "at CS:EIP %04x:%08x",
                        Regs->cs, Regs->eip);
+               Error_Backtrace(Regs->eip, Regs->ebp);
+               
                MM_DumpTables(0, KERNEL_BASE);
                switch( Regs->int_num )
                {
@@ -226,14 +228,14 @@ void Error_Backtrace(Uint eip, Uint ebp)
                LogF("Backtrace: 0x%x", eip);
 //     else
 //             LogF("Backtrace: %s+0x%x", str, delta);
-       if(!MM_GetPhysAddr(ebp))
+       if(!MM_GetPhysAddr((void*)ebp))
        {
-               LogF("\nBacktrace: Invalid EBP, stopping\n");
+               LogF("\nBacktrace: Invalid EBP %p, stopping\n", ebp);
                return;
        }
        
        
-       while( MM_GetPhysAddr(ebp) && i < MAX_BACKTRACE )
+       while( MM_GetPhysAddr((void*)ebp) && i < MAX_BACKTRACE )
        {
                if( ebp >= MM_KERNEL_STACKS_END )       break;
                //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
@@ -244,7 +246,7 @@ void Error_Backtrace(Uint eip, Uint ebp)
                ebp = *(Uint*)ebp;
                i++;
        }
-       LogF("\n");
+       LogF("\r\n");
 }
 
 /**
index eb89139..0a19510 100644 (file)
@@ -61,8 +61,9 @@ int IRQ_AddHandler( int Num, void (*Callback)(int, void*), void *Ptr )
         int    i;
        for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
        {
-               if( gIRQ_Handlers[Num][i] == NULL ) {
-//                     Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
+               if( gIRQ_Handlers[Num][i] == NULL )
+               {
+                       Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
                        gIRQ_Handlers[Num][i] = Callback;
                        gaIRQ_DataPointers[Num][i] = Ptr;
                        return 1;
index 2106b6a..a2932c1 100644 (file)
@@ -9,61 +9,57 @@
 #include <init.h>
 #include <mm_virt.h>
 #include <mp.h>
+#include <pmemmap.h>
 
 #define        VGA_ERRORS      0
 
+#define KERNEL_LOAD    0x100000        // 1MiB
 #define MAX_ARGSTR_POS (0x400000-0x2000)
+#define MAX_PMEMMAP_ENTS       16
 
 // === IMPORTS ===
+extern char    gKernelEnd[];
 extern void    Heap_Install(void);
-extern void    Desctab_Install(void);
 extern void    MM_PreinitVirtual(void);
-extern void    MM_Install(tMBoot_Info *MBoot);
+extern void    MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
 extern void    MM_InstallVirtual(void);
-extern void    Threads_Init(void);
 extern int     Time_Setup(void);
-// --- Core ---
-extern void    System_Init(char *Commandline);
 
 // === PROTOTYPES ===
  int   kmain(Uint MbMagic, void *MbInfoPtr);
 
 // === GLOBALS ===
 char   *gsBootCmdLine = NULL;
-struct {
-       Uint32  PBase;
-       void    *Base;
-       Uint    Size;
-       char    *ArgString;
-}      *gaArch_BootModules;
+tBootModule    *gaArch_BootModules;
  int   giArch_NumBootModules = 0;
 
 // === CODE ===
 int kmain(Uint MbMagic, void *MbInfoPtr)
 {
-        int    i;
-       tMBoot_Module   *mods;
        tMBoot_Info     *mbInfo;
+       tPMemMapEnt     pmemmap[MAX_PMEMMAP_ENTS];
+        int    nPMemMapEnts;
 
-       LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+       LogF("%s\r\n", gsBuildInfo);
        
-       Log("MbMagic = %08x, MbInfoPtr = %p", MbMagic, MbInfoPtr);
-       
-       // Set up non-boot info dependent stuff
-       Desctab_Install();      // Set up GDT and IDT
        MM_PreinitVirtual();    // Initialise virtual mappings
-       
+
+       mbInfo = MbInfoPtr;     
+
        switch(MbMagic)
        {
        // Multiboot 1
-       case MULTIBOOT_MAGIC:
-               // Adjust Multiboot structure address
-               mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+       case MULTIBOOT_MAGIC: {
+               // TODO: Handle when this isn't in the mapped area
                gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
-               
-               MM_Install( mbInfo );   // Set up physical memory manager
-               break;
+
+               // Adjust Multiboot structure address
+               mbInfo = (void*)( (tVAddr)MbInfoPtr + KERNEL_BASE );
+
+               nPMemMapEnts = Multiboot_LoadMemoryMap(mbInfo, KERNEL_BASE, pmemmap, MAX_PMEMMAP_ENTS,
+                       KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_BASE);
+
+               break; }
        
        // Multiboot 2
        case MULTIBOOT2_MAGIC:
@@ -78,6 +74,9 @@ int kmain(Uint MbMagic, void *MbInfoPtr)
                return 0;
        }
        
+       // Set up physical memory manager
+       MM_Install(nPMemMapEnts, pmemmap);
+       
        MM_InstallVirtual();    // Clean up virtual address space
        Heap_Install();         // Create initial heap
        
@@ -92,36 +91,7 @@ int kmain(Uint MbMagic, void *MbInfoPtr)
        VFS_Init();
        
        // Load initial modules
-       mods = (void*)( mbInfo->Modules + KERNEL_BASE );
-       giArch_NumBootModules = mbInfo->ModuleCount;
-       gaArch_BootModules = malloc( giArch_NumBootModules * sizeof(*gaArch_BootModules) );
-       for( i = 0; i < mbInfo->ModuleCount; i ++ )
-       {
-                int    ofs;
-       
-               Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
-                       mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
-       
-               gaArch_BootModules[i].PBase = mods[i].Start;
-               gaArch_BootModules[i].Size = mods[i].End - mods[i].Start;
-       
-               // Always HW map the module data        
-               ofs = mods[i].Start&0xFFF;
-               gaArch_BootModules[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
-                       (gaArch_BootModules[i].Size+ofs+0xFFF) / 0x1000
-                       ) + ofs );
-               
-               // Only map the string if needed
-               if( (tVAddr)mods[i].String > MAX_ARGSTR_POS )
-               {
-                       // Assumes the string is < 4096 bytes long)
-                       gaArch_BootModules[i].ArgString = (void*)(
-                               MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
-                               );
-               }
-               else
-                       gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE;
-       }
+       gaArch_BootModules = Multiboot_LoadModules(mbInfo, KERNEL_BASE, &giArch_NumBootModules);
        
        // Pass on to Independent Loader
        Log_Log("Arch", "Starting system");
@@ -140,7 +110,9 @@ void Arch_LoadBootModules(void)
        {
                Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
                
-               if( !Module_LoadMem( gaArch_BootModules[i].Base, gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString ) )
+               if( !Module_LoadMem( gaArch_BootModules[i].Base,
+                       gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString
+                       ) )
                {
                        Log_Warning("Arch", "Unable to load module");
                }
@@ -156,5 +128,6 @@ void Arch_LoadBootModules(void)
                        MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
        }
        Log_Log("Arch", "Boot modules loaded");
-       free( gaArch_BootModules );
+       if( gaArch_BootModules )
+               free( gaArch_BootModules );
 }
diff --git a/KernelLand/Kernel/arch/x86/mboot.c b/KernelLand/Kernel/arch/x86/mboot.c
new file mode 100644 (file)
index 0000000..897c9bb
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * mboot.c
+ * - Multiboot Support
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <mboot.h>
+
+// === CODE ===
+int Multiboot_LoadMemoryMap(tMBoot_Info *MBInfo, tVAddr MapOffset, tPMemMapEnt *Map, const int MapSize, tPAddr KStart, tPAddr KEnd)
+{
+        int    nPMemMapEnts = 0;
+       tMBoot_MMapEnt  *ent = (void*)((tVAddr)MBInfo->MMapAddr + MapOffset);
+       tMBoot_MMapEnt  *last = (void*)((tVAddr)ent + MBInfo->MMapLength);
+       
+       ENTER("pMBInfo pMapOffset pMap iMapSize PKStart PKEnd",
+               MBInfo, MapOffset, Map, MapSize, KStart, KEnd);
+
+       // Check that the memory map is present
+       if( MBInfo->Flags & (1 << 6) )
+       {
+               // Build up memory map
+               nPMemMapEnts = 0;
+               while( ent < last && nPMemMapEnts < MapSize )
+               {
+                       tPMemMapEnt     *nent = &Map[nPMemMapEnts];
+                       if( !MM_GetPhysAddr(ent) )
+                               Log_KernelPanic("MBoot", "MBoot Map entry %i addres bad (%p)",
+                                       nPMemMapEnts, ent);
+       
+                       nent->Start = ent->Base;
+                       nent->Length = ent->Length;
+                       switch(ent->Type)
+                       {
+                       case 1:
+                               nent->Type = PMEMTYPE_FREE;
+                               break;
+                       default:
+                               nent->Type = PMEMTYPE_RESERVED;
+                               break;
+                       }
+                       nent->NUMADomain = 0;
+                       
+                       nPMemMapEnts ++;
+                       ent = (void*)( (tVAddr)ent + ent->Size + 4 );
+               }
+       }
+       else if( MBInfo->Flags & (1 << 0) )
+       {
+               Log_Warning("MBoot", "No memory map passed, using mem_lower and mem_upper");
+               nPMemMapEnts = 2;
+               Map[0].Start = 0;
+               Map[0].Length = MBInfo->LowMem * 1024;
+               Map[0].Type = PMEMTYPE_FREE;
+               Map[0].NUMADomain = 0;
+
+               Map[1].Start = 0x100000;
+               Map[1].Length = MBInfo->HighMem * 1024;
+               Map[1].Type = PMEMTYPE_FREE;
+               Map[1].NUMADomain = 0;
+       }
+       else
+       {
+               Log_KernelPanic("MBoot", "Multiboot didn't pass memory information");
+       }
+
+       // Ensure it's valid
+       nPMemMapEnts = PMemMap_ValidateMap(Map, nPMemMapEnts, MapSize);
+       // TODO: Error handling
+
+       // Replace kernel with PMEMTYPE_USED
+       nPMemMapEnts = PMemMap_MarkRangeUsed(
+               Map, nPMemMapEnts, MapSize,
+               KStart, KEnd - KStart
+               );
+
+       PMemMap_DumpBlocks(Map, nPMemMapEnts);
+
+       // Check if boot modules were passed
+       if( MBInfo->Flags & (1 << 3) )
+       {
+               // Replace modules with PMEMTYPE_USED
+               nPMemMapEnts = PMemMap_MarkRangeUsed(Map, nPMemMapEnts, MapSize,
+                       MBInfo->Modules, MBInfo->ModuleCount*sizeof(tMBoot_Module)
+                       );
+               LOG("MBInfo->Modules = %x", MBInfo->Modules);
+               tMBoot_Module *mods = (void*)( (tVAddr)MBInfo->Modules + MapOffset);
+               for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+               {
+                       LOG("&mods[%i] = %p", i, &mods[i]);
+                       LOG("mods[i] = {0x%x -> 0x%x}", mods[i].Start, mods[i].End);
+                       nPMemMapEnts = PMemMap_MarkRangeUsed(
+                               Map, nPMemMapEnts, MapSize,
+                               mods[i].Start, mods[i].End - mods[i].Start
+                               );
+               }
+       }
+               
+       // Debug - Output map
+       PMemMap_DumpBlocks(Map, nPMemMapEnts);
+
+       LEAVE('i', nPMemMapEnts);
+       return nPMemMapEnts;
+}
+
+tBootModule *Multiboot_LoadModules(tMBoot_Info *MBInfo, tVAddr MapOffset, int *ModuleCount)
+{
+       if( !(MBInfo->Flags & (1 << 3)) ) {
+               *ModuleCount = 0;
+               Log_Log("Arch", "No multiboot module information passed");
+               return NULL;
+       }
+
+       tMBoot_Module   *mods = (void*)( MBInfo->Modules + MapOffset );
+       *ModuleCount = MBInfo->ModuleCount;
+       tBootModule *ret = malloc( MBInfo->ModuleCount * sizeof(*ret) );
+       for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+       {
+                int    ofs;
+       
+               Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
+                       mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
+       
+               ret[i].PBase = mods[i].Start;
+               ret[i].Size = mods[i].End - mods[i].Start;
+       
+               // Always HW map the module data        
+               ofs = mods[i].Start&0xFFF;
+               ret[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
+                       (ret[i].Size+ofs+0xFFF) / 0x1000
+                       ) + ofs );
+               
+               // Only map the string if needed
+               if( !MM_GetPhysAddr( (void*)(mods[i].String + MapOffset) ) )
+               {
+                       // Assumes the string is < 4096 bytes long)
+                       ret[i].ArgString = (void*)(
+                               MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
+                               );
+               }
+               else
+                       ret[i].ArgString = (char*)(tVAddr)mods[i].String + MapOffset;
+       }
+
+       return ret;
+}
+
index 5576811..f785ba4 100644 (file)
@@ -4,19 +4,21 @@
  */
 #define DEBUG  0
 #include <acess.h>
-#include <mboot.h>
 #include <mm_virt.h>
+#include <pmemmap.h>
+#include <hal_proc.h>
 
 //#define USE_STACK    1
 #define TRACE_ALLOCS   0       // Print trace messages on AllocPhys/DerefPhys
 
+static const int addrClasses[] = {0,16,20,24,32,64};
+static const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
 
 // === IMPORTS ===
-extern char    gKernelEnd[];
 extern void    Proc_PrintBacktrace(void);
 
 // === PROTOTYPES ===
-void   MM_Install(tMBoot_Info *MBoot);
+void   MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
 //tPAddr       MM_AllocPhys(void);
 //tPAddr       MM_AllocPhysRange(int Pages, int MaxBits);
 //void MM_RefPhys(tPAddr PAddr);
@@ -28,6 +30,7 @@ tMutex        glPhysAlloc;
 Uint64 giPhysAlloc = 0;        // Number of allocated pages
 Uint64 giPageCount = 0;        // Total number of pages
 Uint64 giLastPossibleFree = 0; // Last possible free page (before all pages are used)
+Uint64 giTotalMemorySize = 0;  // Total number of allocatable pages
 
 Uint32 gaSuperBitmap[1024];    // Blocks of 1024 Pages
 Uint32 gaPageBitmap[1024*1024/32];     // Individual pages
@@ -36,92 +39,119 @@ void       **gaPageNodes = (void*)MM_PAGENODE_BASE;
 #define REFENT_PER_PAGE        (0x1000/sizeof(gaPageReferences[0]))
 
 // === CODE ===
-void MM_Install(tMBoot_Info *MBoot)
+void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges)
 {
-       Uint    kernelPages, num;
        Uint    i;
        Uint64  maxAddr = 0;
-       tMBoot_Module   *mods;
-       tMBoot_MMapEnt  *ent;
        
        // --- Find largest address
-       MBoot->MMapAddr |= KERNEL_BASE;
-       ent = (void *)( MBoot->MMapAddr );
-       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
+       for( i = 0; i < NPMemRanges; i ++ )
        {
-               // Adjust for size
-               ent->Size += 4;
-               
+               tPMemMapEnt     *ent = &PMemRanges[i];
                // If entry is RAM and is above `maxAddr`, change `maxAddr`
-               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
-                       maxAddr = ent->Base + ent->Length;
-               // Go to next entry
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+               if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED)
+               {
+                       if(ent->Start + ent->Length > maxAddr)
+                               maxAddr = ent->Start + ent->Length;
+                       giTotalMemorySize += ent->Length >> 12;
+               }
        }
        
-       if(maxAddr == 0) {      
-               giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
-       }
-       else {
-               giPageCount = maxAddr >> 12;
-       }
+       giPageCount = maxAddr >> 12;
        giLastPossibleFree = giPageCount - 1;
        
        memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
        
        // Set up allocateable space
-       ent = (void *)( MBoot->MMapAddr );
-       while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
-       {               
-               memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+       for( i = 0; i < NPMemRanges; i ++ )
+       {
+               tPMemMapEnt *ent = &PMemRanges[i];
+               if( ent->Type == PMEMTYPE_FREE )
+               {
+                       Uint64  startpg = ent->Start / PAGE_SIZE;
+                       Uint64  pgcount = ent->Length / PAGE_SIZE;
+                       while( startpg % 32 && pgcount ) {
+                               gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+                               startpg ++;
+                               pgcount --;
+                       }
+                       memsetd( &gaPageBitmap[startpg/32], 0, pgcount/32 );
+                       startpg += pgcount - pgcount%32;
+                       pgcount -= pgcount - pgcount%32;
+                       while(pgcount) {
+                               gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+                               startpg ++;
+                               pgcount --;
+                       }
+               }
+               else if( ent->Type == PMEMTYPE_USED )
+               {
+                       giPhysAlloc += ent->Length / PAGE_SIZE;
+               }
        }
-       
-       // Get used page count (Kernel)
-       kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
-       kernelPages += 0xFFF;   // Page Align
-       kernelPages >>= 12;
-       giPhysAlloc += kernelPages;     // Add to used count    
 
-       // Fill page bitmap
-       num = kernelPages/32;
-       memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
-       gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
-       
        // Fill Superpage bitmap
-       num = kernelPages/(32*32);
-       memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
-       gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
-       
-       // Mark Multiboot's pages as taken
-       // - Structure
-       MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
-       // - Module List
-       for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
-               MM_RefPhys( MBoot->Modules + (i << 12) );
-       // - Modules
-       mods = (void*)(MBoot->Modules + KERNEL_BASE);
-       for(i = 0; i < MBoot->ModuleCount; i++)
+       // - A set bit means that there are no free pages in this block of 32
+       for( i = 0; i < (giPageCount+31)/32; i ++ )
        {
-               num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
-               while(num--)
-                       MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
+               if( gaPageBitmap[i] + 1 == 0 ) {
+                       gaSuperBitmap[i/32] |= (1 << i%32);
+               }
        }
-
+       
        gaPageReferences = (void*)MM_REFCOUNT_BASE;
 
        Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)",
-               giPhysAlloc, (giPageCount*4)/1024
+               giPhysAlloc, (giTotalMemorySize*PAGE_SIZE)/(1024*1024)
                );
 }
 
+void MM_DumpStatistics(void)
+{
+        int    i, pg;
+       for( i = 1; i < numAddrClasses; i ++ )
+       {
+                int    first = (i == 1 ? 0 : (1UL << (addrClasses[i-1] - 12)));
+                int    last  = (1UL << (addrClasses[i] - 12)) - 1;
+                int    nFree = 0;
+                int    nMultiRef = 0;
+                int    totalRefs = 0;
+
+               if( last > giPageCount )
+                       last = giPageCount;
+               
+                int    total = last - first + 1;
+       
+               for( pg = first; pg < last; pg ++ )
+               {
+                       if( !MM_GetPhysAddr(&gaPageReferences[pg]) || gaPageReferences[pg] == 0 ) {
+                               nFree ++;
+                               continue ;
+                       }
+                       totalRefs += gaPageReferences[pg];
+                       if(gaPageReferences[pg] > 1)
+                               nMultiRef ++;
+               }
+               
+                int    nUsed = (total - nFree);
+               Log_Log("MMPhys", "%ipbit - %i/%i used, %i reused, %i average reference count",
+                       addrClasses[i], nUsed, total, nMultiRef,
+                       nMultiRef ? (totalRefs-(nUsed - nMultiRef)) / nMultiRef : 0
+                       );
+               
+               if( last == giPageCount )
+                       break;
+       }
+       Log_Log("MMPhys", "%lli/%lli total pages used, 0 - %i possible free range",
+               giPhysAlloc, giTotalMemorySize, giLastPossibleFree);
+}
+
 /**
  * \fn tPAddr MM_AllocPhys(void)
  * \brief Allocates a physical page from the general pool
  */
 tPAddr MM_AllocPhys(void)
 {
-       // int  a, b, c;
         int    indx = -1;
        tPAddr  ret;
        
@@ -130,10 +160,7 @@ tPAddr MM_AllocPhys(void)
        Mutex_Acquire( &glPhysAlloc );
        
        // Classful scan
-       #if 1
        {
-       const int addrClasses[] = {0,16,20,24,32,64};
-       const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
         int    i;
         int    first, last;
        for( i = numAddrClasses; i -- > 1; )
@@ -173,52 +200,6 @@ tPAddr MM_AllocPhys(void)
        // Out of memory?
        if( i <= 1 )    indx = -1;
        }
-       #elif 0
-       // Find free page
-       // Scan downwards
-       LOG("giLastPossibleFree = %i", giLastPossibleFree);
-       for( indx = giLastPossibleFree; indx >= 0; )
-       {
-               if( gaSuperBitmap[indx>>10] == -1 ) {
-                       indx -= 1024;
-                       continue;
-               }
-               
-               if( gaPageBitmap[indx>>5] == -1 ) {
-                       indx -= 32;
-                       continue;
-               }
-               
-               if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
-                       indx --;
-                       continue;
-               }
-               break;
-       }
-       if( indx >= 0 )
-               giLastPossibleFree = indx;
-       LOG("indx = %i", indx);
-       #else
-       c = giLastPossibleFree % 32;
-       b = (giLastPossibleFree / 32) % 32;
-       a = giLastPossibleFree / 1024;
-       
-       LOG("a=%i,b=%i,c=%i", a, b, c);
-       for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
-       if(a < 0) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
-                       __builtin_return_address(0), giPhysAlloc, giPageCount);
-               LEAVE('i', 0);
-               return 0;
-       }
-       for( ; gaSuperBitmap[a] & (1<<b); b-- );
-       for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
-       LOG("a=%i,b=%i,c=%i", a, b, c);
-       indx = (a << 10) | (b << 5) | c;
-       if( indx >= 0 )
-               giLastPossibleFree = indx;
-       #endif
        
        if( indx < 0 ) {
                Mutex_Release( &glPhysAlloc );
@@ -241,7 +222,7 @@ tPAddr MM_AllocPhys(void)
        }
        
        // Mark page used
-       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+       if( MM_GetPhysAddr( &gaPageReferences[indx] ) )
                gaPageReferences[indx] = 1;
        gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
        
@@ -276,7 +257,6 @@ tPAddr MM_AllocPhys(void)
  */
 tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
 {
-        int    a, b;
         int    i, idx, sidx;
        tPAddr  ret;
        
@@ -301,31 +281,6 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
        }
        idx = sidx / 32;
        sidx %= 32;
-       b = idx % 32;
-       a = idx / 32;
-       
-       #if 0
-       LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
-       
-       // Find free page
-       for( ; gaSuperBitmap[a] == -1 && a --; )        b = 31;
-       if(a < 0) {
-               Mutex_Release( &glPhysAlloc );
-               Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
-               LEAVE('i', 0);
-               return 0;
-       }
-       LOG("a = %i", a);
-       for( ; gaSuperBitmap[a] & (1 << b); b-- )       sidx = 31;
-       LOG("b = %i", b);
-       idx = a * 32 + b;
-       for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
-               LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
-       
-       LOG("idx = %i, sidx = %i", idx, sidx);
-       #else
-       
-       #endif
        
        // Check if the gap is large enough
        while( idx >= 0 )
@@ -377,7 +332,7 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
        // Mark pages used
        for( i = 0; i < Pages; i++ )
        {
-               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
+               if( MM_GetPhysAddr( &gaPageReferences[idx*32+sidx] ) )
                        gaPageReferences[idx*32+sidx] = 1;
                gaPageBitmap[ idx ] |= 1 << sidx;
                sidx ++;
@@ -419,7 +374,7 @@ void MM_RefPhys(tPAddr PAddr)
        // Reference the page
        if( gaPageReferences )
        {
-               if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+               if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
                {
                         int    i, base;
                        tVAddr  addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
@@ -481,7 +436,7 @@ void MM_DerefPhys(tPAddr PAddr)
                giLastPossibleFree = PAddr;
 
        // Dereference
-       if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
+       if( !MM_GetPhysAddr( &gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
        {
                #if TRACE_ALLOCS
                Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
@@ -493,7 +448,7 @@ void MM_DerefPhys(tPAddr PAddr)
                if(gaPageBitmap[ PAddr / 32 ] == 0)
                        gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
 
-               if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
+               if( MM_GetPhysAddr( &gaPageNodes[PAddr] ) )
                {
                        gaPageNodes[PAddr] = NULL;
                        // TODO: Free Node Page when fully unused
@@ -515,7 +470,7 @@ int MM_GetRefCount(tPAddr PAddr)
        // We don't care about non-ram pages
        if(PAddr >= giPageCount)        return -1;
 
-       if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+       if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
                return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
        
        // Check if it is freed
@@ -533,7 +488,7 @@ int MM_SetPageNode(tPAddr PAddr, void *Node)
        block_addr = (tVAddr) &gaPageNodes[PAddr];
        block_addr &= ~(PAGE_SIZE-1);
        
-       if( !MM_GetPhysAddr( block_addr ) )
+       if( !MM_GetPhysAddr( (void*)block_addr ) )
        {
                if( !MM_Allocate( block_addr ) ) {
                        Log_Warning("PMem", "Unable to allocate Node page");
@@ -552,7 +507,7 @@ int MM_GetPageNode(tPAddr PAddr, void **Node)
        if( MM_GetRefCount(PAddr) == 0 )        return 1;
        
        PAddr /= PAGE_SIZE;
-       if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
+       if( !MM_GetPhysAddr( &gaPageNodes[PAddr] ) ) {
                *Node = NULL;
                return 0;
        }
index 51a3f62..868fe86 100644 (file)
@@ -414,13 +414,14 @@ void MM_Deallocate(tVAddr VAddr)
  * \fn tPAddr MM_GetPhysAddr(tVAddr Addr)
  * \brief Checks if the passed address is accesable
  */
-tPAddr MM_GetPhysAddr(tVAddr Addr)
+tPAddr MM_GetPhysAddr(const void *Addr)
 {
-       if( !(gaPageDir[Addr >> 22] & 1) )
+       tVAddr  addr = (tVAddr)Addr;
+       if( !(gaPageDir[addr >> 22] & 1) )
                return 0;
-       if( !(gaPageTable[Addr >> 12] & 1) )
+       if( !(gaPageTable[addr >> 12] & 1) )
                return 0;
-       return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
+       return (gaPageTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF);
 }
 
 /**
@@ -694,9 +695,9 @@ tPAddr MM_Clone(int bNoUserCopy)
                        
                        MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
                        
-                       tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
+                       tmp = MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
                        memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
-                       MM_FreeTemp( (Uint)tmp );
+                       MM_FreeTemp( tmp );
                }
        }
        
@@ -717,7 +718,8 @@ tVAddr MM_NewKStack(void)
        for(base = MM_KERNEL_STACKS; base < MM_KERNEL_STACKS_END; base += MM_KERNEL_STACK_SIZE)
        {
                // Check if space is free
-               if(MM_GetPhysAddr(base) != 0)   continue;
+               if(MM_GetPhysAddr( (void*) base) != 0)
+                       continue;
                // Allocate
                //for(i = MM_KERNEL_STACK_SIZE; i -= 0x1000 ; )
                for(i = 0; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
@@ -804,9 +806,9 @@ tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
 
        // NOTE: Max of 1 page
        // `page` is the last allocated page from the previious for loop
-       tmpPage = MM_MapTemp( page );
+       tmpPage = (tVAddr)MM_MapTemp( page );
        memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize);
-       MM_FreeTemp(tmpPage);   
+       MM_FreeTemp( (void*)tmpPage );
        
        //Log("MM_NewWorkerStack: RETURN 0x%x", base);
        return base + WORKER_STACK_SIZE;
@@ -935,7 +937,7 @@ int MM_IsValidBuffer(tVAddr Addr, size_t Size)
 tPAddr MM_DuplicatePage(tVAddr VAddr)
 {
        tPAddr  ret;
-       Uint    temp;
+       void    *temp;
         int    wasRO = 0;
        
        //ENTER("xVAddr", VAddr);
@@ -960,7 +962,7 @@ tPAddr MM_DuplicatePage(tVAddr VAddr)
        
        // Copy Data
        temp = MM_MapTemp(ret);
-       memcpy( (void*)temp, (void*)VAddr, 0x1000 );
+       memcpy( temp, (void*)VAddr, 0x1000 );
        MM_FreeTemp(temp);
        
        // Restore Writeable status
@@ -976,7 +978,7 @@ tPAddr MM_DuplicatePage(tVAddr VAddr)
  * \brief Create a temporary memory mapping
  * \todo Show Luigi Barone (C Lecturer) and see what he thinks
  */
-tVAddr MM_MapTemp(tPAddr PAddr)
+void * MM_MapTemp(tPAddr PAddr)
 {
         int    i;
        
@@ -999,7 +1001,7 @@ tVAddr MM_MapTemp(tPAddr PAddr)
                        INVLPG( TEMP_MAP_ADDR + (i << 12) );
                        //LEAVE('p', TEMP_MAP_ADDR + (i << 12));
                        Mutex_Release( &glTempMappings );
-                       return TEMP_MAP_ADDR + (i << 12);
+                       return (void*)( TEMP_MAP_ADDR + (i << 12) );
                }
                Mutex_Release( &glTempMappings );
                Threads_Yield();        // TODO: Use a sleep queue here instead
@@ -1010,9 +1012,9 @@ tVAddr MM_MapTemp(tPAddr PAddr)
  * \fn void MM_FreeTemp(tVAddr PAddr)
  * \brief Free's a temp mapping
  */
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *VAddr)
 {
-        int    i = VAddr >> 12;
+        int    i = (tVAddr)VAddr >> 12;
        //ENTER("xVAddr", VAddr);
        
        if(i >= (TEMP_MAP_ADDR >> 12))
@@ -1069,7 +1071,6 @@ tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
  */
 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
 {
-       tPAddr  maxCheck = (1 << MaxBits);
        tPAddr  phys;
        tVAddr  ret;
        
@@ -1084,9 +1085,6 @@ tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
                return 0;
        }
        
-       // Bound
-       if(MaxBits >= PHYS_BITS)        maxCheck = -1;
-       
        // Fast Allocate
        if(Pages == 1 && MaxBits >= PHYS_BITS)
        {
index 281b628..f68e663 100644 (file)
@@ -467,7 +467,6 @@ void Proc_IdleThread(void *Ptr)
  */
 void Proc_Start(void)
 {
-        int    tid;
        #if USE_MP
         int    i;
        #endif
@@ -479,7 +478,7 @@ void Proc_Start(void)
                if(i)   gaCPUs[i].Current = NULL;
                
                // Create Idle Task
-               tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
+               Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
                
                // Start the AP
                if( i != giProc_BootProcessorID ) {
@@ -496,8 +495,7 @@ void Proc_Start(void)
        while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
        #else
        // Create Idle Task
-       tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
-//     gaCPUs[0].IdleThread = Threads_GetThread(tid);
+       Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
        
        // Set current task
        gaCPUs[0].Current = &gThreadZero;
@@ -588,9 +586,8 @@ void Proc_ClearThread(tThread *Thread)
 tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
 {
        Uint    esp;
-       tThread *newThread, *cur;
+       tThread *newThread;
        
-       cur = Proc_GetCurThread();
        newThread = Threads_CloneTCB(0);
        if(!newThread)  return -1;
        
@@ -666,7 +663,7 @@ tPID Proc_Clone(Uint Flags)
  * \fn int Proc_SpawnWorker(void)
  * \brief Spawns a new worker thread
  */
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
 {
        tThread *new;
        Uint    stack_contents[4];
@@ -675,7 +672,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new = Threads_CloneThreadZero();
        if(!new) {
                Warning("Proc_SpawnWorker - Out of heap space!\n");
-               return -1;
+               return NULL;
        }
 
        // Create the stack contents
@@ -697,7 +694,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new->Status = THREAD_STAT_PREINIT;
        Threads_AddActive( new );
        
-       return new->TID;
+       return new;
 }
 
 /**
@@ -711,7 +708,7 @@ Uint Proc_MakeUserStack(void)
        
        // Check Prospective Space
        for( i = USER_STACK_SZ >> 12; i--; )
-               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+               if( MM_GetPhysAddr( (void*)(base + (i<<12)) ) != 0 )
                        break;
        
        if(i != -1)     return 0;
@@ -863,6 +860,10 @@ void Proc_DumpThreadCPUState(tThread *Thread)
                __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
                while( maxBacktraceDistance -- )
                {
+                       if( !CheckMem(stack, 8) ) {
+                               regs = NULL;
+                               break;
+                       }
                        // [ebp] = oldEbp
                        // [ebp+4] = retaddr
                        
index b6026de..1d4a35d 100644 (file)
@@ -57,6 +57,7 @@ mboot:
        
 [section .text]
 [extern kmain]
+[extern Desctab_Install]
 [global start]
 start:
        ; Just show we're here
@@ -87,11 +88,15 @@ start:
 .higher_half:
        
        mov WORD [0xB8006], 0x0773      ; 's'
+       
+       push ebx        ; Multiboot Info
+       push eax        ; Multiboot Magic Value
+       ; NOTE: These are actually for kmain
+       
+       call Desctab_Install
        mov WORD [0xB8008], 0x0773      ; 's'
 
        ; Call the kernel
-       push ebx        ; Multiboot Info
-       push eax        ; Multiboot Magic Value
        mov WORD [0xB800A], 0x0732      ; '2'
        call kmain
 
diff --git a/KernelLand/Kernel/arch/x86/vpci.c b/KernelLand/Kernel/arch/x86/vpci.c
new file mode 100644 (file)
index 0000000..0319e6e
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === GLOBALS ===
+ int   giVPCI_DeviceCount = 0;
+tVPCI_Device   gaVPCI_Devices[0];
+
index a72216a..17adec9 100644 (file)
@@ -26,7 +26,8 @@ endif
 A_OBJ := start32.ao start64.ao desctab.ao proc.ao
 A_OBJ += main.o lib.o proc.o mm_virt.o mm_phys.o
 A_OBJ += kernelpanic.o errors.o time.o pci.o
-A_OBJ += vm8086.o
+A_OBJ += vm8086.o vpci.o
+A_OBJ += ../x86/mboot.o
 # rme.o
 
 POSTBUILD = objcopy $(BIN) -F elf32-i386 $(BIN)
index 6e8aa63..22b41be 100644 (file)
@@ -5,6 +5,7 @@
 [BITS 64]
 
 [extern Log]
+[extern Log_Debug]
 [extern gGDTPtr]
 [extern gGDT]
 
@@ -167,11 +168,11 @@ IRQ_AddHandler:
        push rax
        push rdx
        sub rsp, 8
-       mov rcx, rdi    ; IRQ Number
-       mov rdx, rsi    ; Callback
-       mov rsi, rax    ; Pointer
-       mov rdi, csIRQ_Assigned
-       call Log
+       mov rcx, rsi    ; IRQ Number
+       mov rdx, rdi    ; Callback
+       mov rsi, csIRQ_Assigned
+       mov rdi, csIRQ_Tag
+       call Log_Debug
        add rsp, 8
        pop rdx
        pop rax
@@ -189,9 +190,11 @@ IRQ_AddHandler:
        
 [section .rodata]
 csIRQ_Assigned:
-       db      "IRQ %p := %p (IRQ %i)",0
+       db      "IRQ %i .= %p",0
 csIRQ_Fired:
        db      "IRQ %i fired",0
+csIRQ_Tag:
+       db      "IRQ",0
 [section .text]
 
 %macro ISR_NOERRNO     1
index f7da7f9..e7812c3 100644 (file)
@@ -134,14 +134,14 @@ void Error_Backtrace(Uint IP, Uint BP)
                LogF("Backtrace: %p", IP);
        //else
        //      LogF("Backtrace: %s+0x%x", str, delta);
-       if( !MM_GetPhysAddr(BP) )
+       if( !MM_GetPhysAddr( (void*)BP ) )
        {
                LogF("\nBacktrace: Invalid BP, stopping\n");
                return;
        }
        
        
-       while( MM_GetPhysAddr(BP) && MM_GetPhysAddr(BP+8+7) && i < MAX_BACKTRACE )
+       while( MM_GetPhysAddr( (void*)BP) && MM_GetPhysAddr((void*)(BP+8+7)) && i < MAX_BACKTRACE )
        {
                //str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
                //if(str == NULL)
index bde7abd..633b167 100644 (file)
 #define BITS   64
 #define PAGE_SIZE      0x1000
 
+#ifndef MAX_CPUS
+# define MAX_CPUS      8
+#endif
+
 #define STACKED_LOCKS  2       // 0: No, 1: Per-CPU, 2: Per-Thread
 #define LOCK_DISABLE_INTS      0
 
diff --git a/KernelLand/Kernel/arch/x86_64/include/archinit.h b/KernelLand/Kernel/arch/x86_64/include/archinit.h
new file mode 100644 (file)
index 0000000..68988b8
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Acess2 Kernel x86_64
+ * - By John Hodge (thePowersGang)
+ *
+ * include/init.h
+ * - Arch-internal init functions
+ */
+#ifndef _ARCH__INIT_H_
+#define _ARCH__INIT_H_
+
+#include <pmemmap.h>
+
+extern void    MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges);
+
+#endif
+
index 5b9609a..385b677 100644 (file)
@@ -373,3 +373,6 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
        return ret;
 }
 
+EXPORT(memcpy);
+EXPORT(memset);
+
index 49fe7ae..8defcc5 100644 (file)
@@ -12,7 +12,8 @@ OUTPUT_FORMAT(elf32-i386)
 OUTPUT_ARCH(i386:x86-64)
 */
 OUTPUT_FORMAT(elf64-x86-64)
-ENTRY(start)
+lstart = start - _kernel_base;
+ENTRY(lstart)
 
 SECTIONS {
        . = 0x100000;
index 3532c80..a855a47 100644 (file)
@@ -1,33 +1,45 @@
 /*
- * Acess2 x86_64 Project
+ * Acess2 Kernel x86_64
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Kernel C entrypoint
  */
 #include <acess.h>
 #include <mboot.h>
 #include <init.h>
+#include <archinit.h>
+#include <pmemmap.h>
+
+// === CONSTANTS ===
+#define KERNEL_LOAD    0x100000
+#define MAX_PMEMMAP_ENTS       16
+#define MAX_ARGSTR_POS (0x200000-0x2000)
 
 // === IMPORTS ===
 extern void    Desctab_Init(void);
 extern void    MM_InitVirt(void);
 extern void    Heap_Install(void);
-extern void    Threads_Init(void);
 extern int     Time_Setup(void);
-extern void    System_Init(char *Commandline);
 
-extern void    MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+extern char    gKernelEnd[];
 
 // === PROTOTYPES ===
 void   kmain(Uint MbMagic, void *MbInfoPtr);
 
 // === GLOBALS ==
 char   *gsBootCmdLine = NULL;
+tBootModule    *gaArch_BootModules;
+ int   giArch_NumBootModules = 0;
 
 // === CODE ===
 void kmain(Uint MbMagic, void *MbInfoPtr)
 {
        tMBoot_Info     *mbInfo;
+       tPMemMapEnt     pmemmap[MAX_PMEMMAP_ENTS];
+        int    nPMemMapEnts;
 
-       LogF("Acess2 x86_64 v"EXPAND_STR(KERNEL_VERSION)"\n");
-       LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+       LogF("%s\r\n", gsBuildInfo);
        
        Desctab_Init();
 
@@ -41,7 +53,10 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
                // Adjust Multiboot structure address
                mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
                gsBootCmdLine = (char*)( (Uint)mbInfo->CommandLine + KERNEL_BASE);
-               MM_InitPhys_Multiboot( mbInfo );        // Set up physical memory manager
+               // TODO: ref above?
+               nPMemMapEnts = Multiboot_LoadMemoryMap(mbInfo, KERNEL_BASE, pmemmap, MAX_PMEMMAP_ENTS,
+                       KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_BASE
+                       );
                break;
        default:
                Panic("Multiboot magic invalid %08x, expected %08x\n",
@@ -49,8 +64,16 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
                return ;
        }
        
+       MM_InitPhys( nPMemMapEnts, pmemmap );   // Set up physical memory manager
        Log("gsBootCmdLine = '%s'", gsBootCmdLine);
        
+       switch(MbMagic)
+       {
+       case MULTIBOOT_MAGIC:
+               MM_RefPhys( mbInfo->CommandLine );
+               break;
+       }
+
        *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'D';
        Heap_Install();
        
@@ -64,6 +87,8 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
        Log_Log("Arch", "Starting VFS...");
        VFS_Init();
        
+       gaArch_BootModules = Multiboot_LoadModules(mbInfo, KERNEL_BASE, &giArch_NumBootModules);
+       
        *(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'Z';
        
        // Pass on to Independent Loader
@@ -77,7 +102,32 @@ void kmain(Uint MbMagic, void *MbInfoPtr)
 
 void Arch_LoadBootModules(void)
 {
-       
+        int    i, j, numPages;
+       Log("gsBootCmdLine = '%s'", gsBootCmdLine);
+       for( i = 0; i < giArch_NumBootModules; i ++ )
+       {
+               Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
+               
+               if( !Module_LoadMem( gaArch_BootModules[i].Base,
+                       gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString
+                       ) )
+               {
+                       Log_Warning("Arch", "Unable to load module");
+               }
+               
+               // Unmap and free
+               numPages = (gaArch_BootModules[i].Size + ((Uint)gaArch_BootModules[i].Base&0xFFF) + 0xFFF) >> 12;
+               MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].Base, numPages );
+               
+               for( j = 0; j < numPages; j++ )
+                       MM_DerefPhys( gaArch_BootModules[i].PBase + (j << 12) );
+               
+               if( (tVAddr) gaArch_BootModules[i].ArgString < KERNEL_BASE )
+                       MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
+       }
+       Log_Log("Arch", "Boot modules loaded");
+       if( gaArch_BootModules )
+               free( gaArch_BootModules );
 }
 
 void StartupPrint(const char *String)
index c2c215b..27c4946 100644 (file)
@@ -5,7 +5,8 @@
  */
 #define DEBUG  0
 #include <acess.h>
-#include <mboot.h>
+#include <archinit.h>
+#include <pmemmap.h>
 #include <mm_virt.h>
 
 #define TRACE_REF      0
@@ -25,7 +26,7 @@ extern char   gKernelBase[];
 extern char    gKernelEnd[];
 
 // === PROTOTYPES ===
-void   MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+//void MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges);
 //tPAddr       MM_AllocPhysRange(int Num, int Bits);
 //tPAddr       MM_AllocPhys(void);
 //void MM_RefPhys(tPAddr PAddr);
@@ -52,6 +53,7 @@ Uint64        giPhysRangeFree[NUM_MM_PHYS_RANGES];    // Number of free pages in each rang
 Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES];   // First free page in each range
 Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES];    // Last free page in each range
 Uint64 giMaxPhysPage = 0;      // Maximum Physical page
+Uint64 giTotalMemorySize = 0;
 // Only used in init, allows the init code to provide pages for use by
 // the allocator before the bitmaps exist.
 // 3 entries because the are three calls to MM_AllocPhys in MM_Map
@@ -62,10 +64,8 @@ tPAddr       gaiStaticAllocPages[NUM_STATIC_ALLOC] = {0};
 /**
  * \brief Initialise the physical memory map using a Multiboot 1 map
  */
-void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
+void MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges)
 {
-       tMBoot_MMapEnt  *mmapStart;
-       tMBoot_MMapEnt  *ent;
        Uint64  maxAddr = 0;
         int    numPages, superPages;
         int    i;
@@ -73,226 +73,165 @@ void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
        tVAddr  vaddr;
        tPAddr  paddr, firstFreePage;
        
-       ENTER("pMBoot=%p", MBoot);
+       ENTER("iNPMemRanges pPMemRanges",
+               NPMemRanges, PMemRanges);
        
        // Scan the physical memory map
        // Looking for the top of physical memory
-       mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
-       LOG("mmapStart = %p", mmapStart);
-       ent = mmapStart;
-       while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
+       for( i = 0; i < NPMemRanges; i ++ )
        {
+               tPMemMapEnt     *ent = &PMemRanges[i];
                // Adjust for the size of the entry
-               ent->Size += 4;
-               LOG("ent={Type:%i,Base:0x%x,Length:%x",
-                       ent->Type, ent->Base, ent->Length);
+               LOG("%i: ent={Type:%i,Base:0x%x,Length:%x}", i, ent->Type, ent->Start, ent->Length);
                
                // If entry is RAM and is above `maxAddr`, change `maxAddr`
-               if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
-                       maxAddr = ent->Base + ent->Length;
-               
-               // Go to next entry
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+               if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED )
+               {
+                       if( ent->Start + ent->Length > maxAddr)
+                               maxAddr = ent->Start + ent->Length;
+                       giTotalMemorySize += ent->Length >> 12;
+               }
        }
        
-       // Did we find a valid end?
-       if(maxAddr == 0) {
-               // No, darn, let's just use the HighMem hack
-               giMaxPhysPage = (MBoot->HighMem >> 2) + 256;    // HighMem is a kByte value
-       }
-       else {
-               // Goodie, goodie gumdrops
-               giMaxPhysPage = maxAddr >> 12;
-       }
+       giMaxPhysPage = maxAddr >> 12;
        LOG("giMaxPhysPage = 0x%x", giMaxPhysPage);
-       
-       // Find a contigous section of memory to hold it in
-       // - Starting from the end of the kernel
-       // - We also need a region for the super bitmap
+
+       // Get counts of pages needed for basic structures
        superPages = ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12;
-       numPages = (giMaxPhysPage + 7) / 8;
-       numPages = (numPages + 0xFFF) >> 12;
+       numPages = ((giMaxPhysPage+7)/8 + 0xFFF) >> 12; // bytes to hold bitmap, divided up to nearest page
        LOG("numPages = %i, superPages = %i", numPages, superPages);
-       if(maxAddr == 0)
+       
+       // --- Allocate Bitmaps ---
+        int    todo = numPages*2 + superPages;
+        int    mapent = NPMemRanges-1;
+       vaddr = MM_PAGE_BITMAP;
+       paddr = -1;
+       while( todo )
        {
-                int    todo = numPages*2 + superPages;
-               // Ok, naieve allocation, just put it after the kernel
-               // - Allocated Bitmap
-               vaddr = MM_PAGE_BITMAP;
-               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
-               while(todo )
+               while(PMemRanges[mapent].Type != PMEMTYPE_FREE && mapent != -1)
+                       mapent --;
+               if( paddr + 1 == 0 )
+                       paddr = PMemRanges[mapent].Start;
+               if( mapent == -1 ) {
+                       // OOM During init, bad thing
+                       Log_KernelPanic("PMem", "Out of memory during init");
+                       for(;;);
+               }
+               
+               // Ensure that the static allocation pool has pages
+               for( i = 0; i < NUM_STATIC_ALLOC; i++)
                {
-                       // Allocate statics
-                       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
-                               if(gaiStaticAllocPages[i] != 0) continue;
+                       if(gaiStaticAllocPages[i] == 0)
+                       {
                                gaiStaticAllocPages[i] = paddr;
-                               paddr += 0x1000;
+                               // break to ensure we update the address correctly
+                               break;
                        }
-                       
+               }
+               
+               if( i == NUM_STATIC_ALLOC )
+               {
+                       // Map
                        MM_Map(vaddr, paddr);
-                       vaddr += 0x1000;
-                       paddr += 0x1000;
-                       
                        todo --;
                        
+                       // Update virtual pointer
+                       vaddr += 0x1000;
                        if( todo == numPages + superPages )
                                vaddr = MM_PAGE_DBLBMP;
                        if( todo == superPages )
                                vaddr = MM_PAGE_SUPBMP;
+               }               
+
+               // Update physical pointer
+               // (underflows are detected at the top of the loop)
+               paddr += 0x1000;
+               if( paddr - PMemRanges[mapent].Start > PMemRanges[mapent].Length )
+                       mapent --;
+               else {
+                       // NOTE: This hides some actually valid memory, but since the pmm
+                       // structures have an "infinite" lifetime, this is of no concequence.
+                       PMemRanges[mapent].Start += 0x1000;
+                       PMemRanges[mapent].Length -= 0x1000;
                }
        }
-       // Scan for a nice range
-       else
-       {
-                int    todo = numPages*2 + superPages;
-               paddr = 0;
-               vaddr = MM_PAGE_BITMAP;
-               // Scan!
-               for(
-                       ent = mmapStart;
-                       (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
-                       ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
-                       )
-               {
-                        int    avail;
-                       
-                       // RAM only please
-                       if( ent->Type != 1 )
-                               continue;
-                       
-                       // Let's not put it below the kernel, shall we?
-                       if( ent->Base + ent->Size < (tPAddr)&gKernelBase )
-                               continue;
-                       
-                       LOG("%x <= %x && %x > %x",
-                               ent->Base, (tPAddr)&gKernelBase,
-                               ent->Base + ent->Size, (tPAddr)&gKernelEnd - KERNEL_BASE
-                               );
-                       // Check if the kernel is in this range
-                       if( ent->Base <= (tPAddr)&gKernelBase
-                       && ent->Base + ent->Length > (tPAddr)&gKernelEnd - KERNEL_BASE )
-                       {
-                               avail = ent->Length >> 12;
-                               avail -= ((tPAddr)&gKernelEnd - KERNEL_BASE - ent->Base) >> 12;
-                               paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
-                       }
-                       // No? then we can use all of the block
-                       else
-                       {
-                               avail = ent->Length >> 12;
-                               paddr = ent->Base;
-                       }
-                       
-                       Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
-                       
-                       // Map
-                       while( todo && avail --)
-                       {
-                               // Static Allocations
-                               for( i = 0; i < NUM_STATIC_ALLOC && avail; i++) {
-                                       if(gaiStaticAllocPages[i] != 0) continue;
-                                       gaiStaticAllocPages[i] = paddr;
-                                       paddr += 0x1000;
-                                       avail --;
-                               }
-                               if(!avail)      break;
-                               
-                               // Map
-                               MM_Map(vaddr, paddr);
-                               todo --;
-                               vaddr += 0x1000;
-                               paddr += 0x1000;
-                               
-                               // Alter the destination address when needed
-                               if(todo == superPages+numPages)
-                                       vaddr = MM_PAGE_DBLBMP;
-                               if(todo == superPages)
-                                       vaddr = MM_PAGE_SUPBMP;
-                       }
-                       
-                       // Fast quit if there's nothing left to allocate
-                       if( !todo )             break;
-               }
-       }
+
+       PMemMap_DumpBlocks(PMemRanges, NPMemRanges);
+
        // Save the current value of paddr to simplify the allocation later
        firstFreePage = paddr;
        
        LOG("Clearing multi bitmap");
-       // Fill the bitmaps
-       memset(gaMultiBitmap, 0, (numPages<<12)/8);
-       // - initialise to one, then clear the avaliable areas
-       memset(gaMainBitmap, -1, (numPages<<12)/8);
-       memset(gaSuperBitmap, -1, (numPages<<12)/(8*64));
-       LOG("Setting main bitmap");
+       // Fill the bitmaps (set most to "allocated")
+       memset(gaMultiBitmap, 0, numPages<<12);
+       memset(gaMainBitmap,  255, numPages<<12);
        // - Clear all Type=1 areas
        LOG("Clearing valid regions");
-       for(
-               ent = mmapStart;
-               (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
-               ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
-               )
+       for( i = 0; i < NPMemRanges; i ++ )
        {
+               tPMemMapEnt *ent = &PMemRanges[i];
                // Check if the type is RAM
-               if(ent->Type != 1)      continue;
+               if(ent->Type != PMEMTYPE_FREE)  continue;
                
                // Main bitmap
-               base = ent->Base >> 12;
-               size = ent->Size >> 12;
-               
-               if(base & 63) {
-                       Uint64  val = -1LL << (base & 63);
-                       gaMainBitmap[base / 64] &= ~val;
-                       size -= (base & 63);
-                       base += 64 - (base & 63);
-               }
-               memset( &gaMainBitmap[base / 64], 0, size/8 );
-               if( size & 7 ) {
-                       Uint64  val = -1LL << (size & 7);
-                       val <<= (size/8)&7;
-                       gaMainBitmap[base / 64] &= ~val;
+               base = ent->Start >> 12;
+               size = ent->Length >> 12;
+
+               LOG("%i: base=%x, size=%x", i, base, size);
+               if( base % 64 + size < 64 )
+               {
+                       Uint64  bits = (1ULL << size) - 1;
+                       bits <<= base % 64;
+                       gaMainBitmap[base / 64] &= ~bits;
                }
-               
-               // Super Bitmap
-               base = ent->Base >> 12;
-               size = ent->Size >> 12;
-               size = (size + (base & 63) + 63) >> 6;
-               base = base >> 6;
-               if(base & 63) {
-                       Uint64  val = -1LL << (base & 63);
-                       gaSuperBitmap[base / 64] &= ~val;
-//                     size -= (base & 63);
-//                     base += 64 - (base & 63);
+               else
+               {
+                       if(base & 63)
+                       {
+                               // Keep lower bits
+                               Uint64  bits = (1ULL << (base & 63)) - 1;
+                               gaMainBitmap[base / 64] &= bits;
+                               
+                               size -= 64 - base % 64;
+                               base += 64 - base % 64;
+                       }
+                       LOG("%i: base=%x, size=%x", i, base, size);
+                       memset( &gaMainBitmap[base / 64], 0, (size/64)*8 );
+                       base += size & ~(64-1);
+                       size -= size & ~(64-1);
+                       LOG("%i: base=%x, size=%x", i, base, size);
+                       if( size & 63 )
+                       {
+                               // Unset lower bits (hence the bitwise not)
+                               Uint64  val = (1ULL << (size & 63)) - 1;
+                               gaMainBitmap[base / 64] &= ~val;
+                       }
                }
        }
        
-       // Reference the used pages
-       base = (tPAddr)&gKernelBase >> 12;
-       size = firstFreePage >> 12;
-       memset( &gaMainBitmap[base / 64], -1, size/8 );
-       if( size & 7 ) {
-               Uint64  val = -1LL << (size & 7);
-               val <<= (size/8)&7;
-               gaMainBitmap[base / 64] |= val;
-       }
-       
        // Free the unused static allocs
-       for( i = 0; i < NUM_STATIC_ALLOC; i++) {
-               if(gaiStaticAllocPages[i] != 0)
-                       continue;
-               gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
-                       &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
+       LOG("Freeing unused static allocations");
+       for( i = 0; i < NUM_STATIC_ALLOC; i++)
+       {
+               if(gaiStaticAllocPages[i] == 0)
+               {
+                       gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
+                               &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
+                       gaiStaticAllocPages[i] = 0;
+               }
        }
        
        // Fill the super bitmap
        LOG("Filling super bitmap");
        memset(gaSuperBitmap, 0, superPages<<12);
-       for( base = 0; base < (size+63)/64; base ++)
+       int nsuperbits = giMaxPhysPage / 64;    // 64 pages per bit
+       for( i = 0; i < (nsuperbits+63)/64; i ++)
        {
-               if( gaMainBitmap[ base ] + 1 == 0 )
-                       gaSuperBitmap[ base/64 ] |= 1LL << (base&63);
+               if( gaMainBitmap[ i ] + 1 == 0 )
+                       gaSuperBitmap[ i/64 ] |= 1ULL << (i % 64);
        }
        
-       // Set free page counts
+       // Set free page counts for each address class
        for( base = 1; base < giMaxPhysPage; base ++ )
        {
                 int    rangeID;
@@ -311,11 +250,16 @@ void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
                // Set last (when the last free page is reached, this won't be
                // updated anymore, hence will be correct)
                giPhysRangeLast[ rangeID ] = base;
-       }
-       
+       }       
+
        LEAVE('-');
 }
 
+void MM_DumpStatistics(void)
+{
+       // TODO: Statistics for x86_64 PMM
+}
+
 /**
  * \brief Allocate a contiguous range of physical pages with a maximum
  *        bit size of \a MaxBits
@@ -435,7 +379,7 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
        for( i = 0; i < Pages; i++, addr++ )
        {
                gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) )
+               if( MM_GetPhysAddr( &gaiPageReferences[addr] ) )
                        gaiPageReferences[addr] = 1;
 //             Log("page %P refcount = %i", MM_GetRefCount(addr<<12)); 
                rangeID = MM_int_GetRangeID(addr << 12);
@@ -499,7 +443,7 @@ void MM_RefPhys(tPAddr PAddr)
        {
                tVAddr  ref_base = ((tVAddr)&gaiPageReferences[ page ]) & ~0xFFF;
                // Allocate reference page
-               if( !MM_GetPhysAddr(ref_base) )
+               if( !MM_GetPhysAddr(&gaiPageReferences[page]) )
                {
                        const int       pages_per_refpage = PAGE_SIZE/sizeof(gaiPageReferences[0]);
                         int    i;
@@ -523,7 +467,7 @@ void MM_RefPhys(tPAddr PAddr)
                PAGE_ALLOC_SET(page);
                if( gaMainBitmap[page >> 6] + 1 == 0 )
                        gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+               if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
                        gaiPageReferences[page] = 1;
        }
 
@@ -541,7 +485,7 @@ void MM_DerefPhys(tPAddr PAddr)
        
        if( PAddr >> 12 > giMaxPhysPage )       return ;
        
-       if( MM_GetPhysAddr( (tVAddr) &gaiPageReferences[page] ) )
+       if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
        {
                gaiPageReferences[ page ] --;
                if( gaiPageReferences[ page ] == 0 )
@@ -578,7 +522,7 @@ int MM_GetRefCount( tPAddr PAddr )
        
        if( PAddr > giMaxPhysPage )     return 0;
 
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+       if( MM_GetPhysAddr( &gaiPageReferences[PAddr] ) ) {
                return gaiPageReferences[PAddr];
        }
 
@@ -615,7 +559,7 @@ int MM_SetPageNode(tPAddr PAddr, void *Node)
 
 //     if( !MM_GetRefCount(PAddr) )    return 1;
        
-       if( !MM_GetPhysAddr(node_page) ) {
+       if( !MM_GetPhysAddr((void*)node_page) ) {
                if( !MM_Allocate(node_page) )
                        return -1;
                memset( (void*)node_page, 0, PAGE_SIZE );
@@ -630,7 +574,7 @@ int MM_GetPageNode(tPAddr PAddr, void **Node)
 //     if( !MM_GetRefCount(PAddr) )    return 1;
        PAddr >>= 12;
        
-       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+       if( !MM_GetPhysAddr( &gapPageNodes[PAddr] ) ) {
                *Node = NULL;
                return 0;
        }
index 89aeaa1..0953cbf 100644 (file)
@@ -128,9 +128,9 @@ void MM_int_ClonePageEnt( Uint64 *Ent, void *NextLevel, tVAddr Addr, int bTable
 
                ASSERT(paddr != curpage);
                        
-               tmp = (void*)MM_MapTemp(paddr);
+               tmp = MM_MapTemp(paddr);
                memcpy( tmp, NextLevel, 0x1000 );
-               MM_FreeTemp( (tVAddr)tmp );
+               MM_FreeTemp( tmp );
                
                #if TRACE_COW
                Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
@@ -269,9 +269,9 @@ void MM_int_DumpTablesEnt(tVAddr RangeStart, size_t Length, tPAddr Expected)
        #define CANOICAL(addr)  ((addr)&0x800000000000?(addr)|0xFFFF000000000000:(addr))
        LogF("%016llx => ", CANOICAL(RangeStart));
 //     LogF("%6llx %6llx %6llx %016llx => ",
-//             MM_GetPhysAddr( (tVAddr)&PAGEDIRPTR(RangeStart>>30) ),
-//             MM_GetPhysAddr( (tVAddr)&PAGEDIR(RangeStart>>21) ),
-//             MM_GetPhysAddr( (tVAddr)&PAGETABLE(RangeStart>>12) ),
+//             MM_GetPhysAddr( &PAGEDIRPTR(RangeStart>>30) ),
+//             MM_GetPhysAddr( &PAGEDIR(RangeStart>>21) ),
+//             MM_GetPhysAddr( &PAGETABLE(RangeStart>>12) ),
 //             CANOICAL(RangeStart)
 //             );
        if( gMM_ZeroPage && (PAGETABLE(RangeStart>>12) & PADDR_MASK) == gMM_ZeroPage )
@@ -340,8 +340,8 @@ void MM_DumpTables(tVAddr Start, tVAddr End)
                                expected |= expected_pml4 & PF_NX;
                                expected |= expected_pdp  & PF_NX;
                                expected |= expected_pd   & PF_NX;
-                               Log("expected (pml4 = %x, pdp = %x, pd = %x)",
-                                       expected_pml4, expected_pdp, expected_pd);
+//                             Log("expected (pml4 = %x, pdp = %x, pd = %x)",
+//                                     expected_pml4, expected_pdp, expected_pd);
                                // Dump
                                MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
                                expected = CHANGEABLE_BITS;
@@ -576,7 +576,7 @@ void MM_Deallocate(tVAddr VAddr)
 {
        tPAddr  phys;
        
-       phys = MM_GetPhysAddr(VAddr);
+       phys = MM_GetPhysAddr( (void*)VAddr );
        if(!phys)       return ;
        
        MM_Unmap(VAddr);
@@ -609,8 +609,9 @@ int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags)
 /**
  * \brief Get the physical address of a virtual location
  */
-tPAddr MM_GetPhysAddr(tVAddr Addr)
+tPAddr MM_GetPhysAddr(const void *Ptr)
 {
+       tVAddr  Addr = (tVAddr)Ptr;
        tPAddr  *ptr;
         int    ret;
        
@@ -776,7 +777,8 @@ tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
        {
                for( num = Number; num -- && ret < MM_HWMAP_TOP; ret += 0x1000 )
                {
-                       if( MM_GetPhysAddr(ret) != 0 )  break;
+                       if( MM_GetPhysAddr( (void*)ret ) != 0 )
+                               break;
                }
                if( num >= 0 )  continue;
                
@@ -807,7 +809,7 @@ void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
 //     Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
        while( Number -- )
        {
-               MM_DerefPhys( MM_GetPhysAddr(VAddr) );
+               MM_DerefPhys( MM_GetPhysAddr((void*)VAddr) );
                MM_Unmap(VAddr);
                VAddr += 0x1000;
        }
@@ -860,7 +862,7 @@ tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
 }
 
 // --- Tempory Mappings ---
-tVAddr MM_MapTemp(tPAddr PAddr)
+void *MM_MapTemp(tPAddr PAddr)
 {
        const int max_slots = (MM_TMPMAP_END - MM_TMPMAP_BASE) / PAGE_SIZE;
        tVAddr  ret = MM_TMPMAP_BASE;
@@ -879,14 +881,14 @@ tVAddr MM_MapTemp(tPAddr PAddr)
                *ent = PAddr | 3;
                MM_RefPhys(PAddr);
                INVLPG(ret);
-               return ret;
+               return (void*)ret;
        }
        return 0;
 }
 
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *Ptr)
 {
-       MM_Deallocate(VAddr);
+       MM_Deallocate((tVAddr)Ptr);
        return ;
 }
 
@@ -966,14 +968,14 @@ tPAddr MM_Clone(void)
        for( i = 1; i < KERNEL_STACK_SIZE/0x1000; i ++ )
        {
                tPAddr  phys = MM_AllocPhys();
-               tVAddr  tmpmapping;
+               void    *tmpmapping;
                MM_MapEx(kstackbase+i*0x1000, phys, 1, 0);
                
                tmpmapping = MM_MapTemp(phys);
-               if( MM_GetPhysAddr( kstackbase+i*0x1000 ) )
-                       memcpy((void*)tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
+               if( MM_GetPhysAddr( (void*)(kstackbase+i*0x1000) ) )
+                       memcpy(tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
                else
-                       memset((void*)tmpmapping, 0, 0x1000);
+                       memset(tmpmapping, 0, 0x1000);
 //             if( i == 0xF )
 //                     Debug_HexDump("MM_Clone: *tmpmapping = ", (void*)tmpmapping, 0x1000);
                MM_FreeTemp(tmpmapping);
@@ -1064,12 +1066,10 @@ tVAddr MM_NewWorkerStack(void *StackData, size_t StackSize)
                Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
        }
        else {
-               tVAddr  tmp_addr, dest;
+               void    *tmp_addr, *dest;
                tmp_addr = MM_MapTemp(phys);
-               dest = tmp_addr + (0x1000 - StackSize);
-               memcpy( (void*)dest, StackData, StackSize );
-               Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
-               Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
+               dest = (char*)tmp_addr + (0x1000 - StackSize);
+               memcpy( dest, StackData, StackSize );
                MM_FreeTemp(tmp_addr);
        }
 
@@ -1088,7 +1088,7 @@ tVAddr MM_NewKStack(void)
        Uint    i;
        for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
        {
-               if(MM_GetPhysAddr(base+KERNEL_STACK_SIZE-0x1000) != 0)
+               if(MM_GetPhysAddr( (void*)(base+KERNEL_STACK_SIZE-0x1000) ) != 0)
                        continue;
                
                //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
index 5f71a45..48504a8 100644 (file)
@@ -86,7 +86,9 @@ tMPInfo       *gMPFloatPtr = NULL;
 tAPIC  *gpMP_LocalAPIC = NULL;
 Uint8  gaAPIC_to_CPU[256] = {0};
 #endif
-tCPU   gaCPUs[MAX_CPUS];
+tCPU   gaCPUs[MAX_CPUS] = {
+       {.Current = &gThreadZero}
+       };
 tTSS   *gTSSs = NULL;
 tTSS   gTSS0 = {0};
 // --- Error Recovery ---
@@ -532,7 +534,7 @@ tTID Proc_Clone(Uint Flags)
  * \fn int Proc_SpawnWorker(void)
  * \brief Spawns a new worker thread
  */
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
 {
        tThread *new, *cur;
        Uint    stack_contents[3];
@@ -543,7 +545,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new = Threads_CloneThreadZero();
        if(!new) {
                Warning("Proc_SpawnWorker - Out of heap space!\n");
-               return -1;
+               return NULL;
        }
 
        // Create the stack contents
@@ -565,7 +567,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new->Status = THREAD_STAT_PREINIT;
        Threads_AddActive( new );
        
-       return new->TID;
+       return new;
 }
 
 /**
@@ -579,7 +581,7 @@ Uint Proc_MakeUserStack(void)
        // Check Prospective Space
        for( i = USER_STACK_SZ >> 12; i--; )
        {
-               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+               if( MM_GetPhysAddr( (void*)(base + (i<<12)) ) != 0 )
                        break;
        }
        
index 52b133c..ac05971 100644 (file)
@@ -183,6 +183,6 @@ gInitialKernelStack:
 
 [section .rodata]
 csNot64BitCapable:
-       db "Not 64-bit Capable",0
+       db "CPU does not support long-mode, please use the x86 build",0
 
 ; vim: ft=nasm
diff --git a/KernelLand/Kernel/arch/x86_64/vpci.c b/KernelLand/Kernel/arch/x86_64/vpci.c
new file mode 100644 (file)
index 0000000..0319e6e
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === GLOBALS ===
+ int   giVPCI_DeviceCount = 0;
+tVPCI_Device   gaVPCI_Devices[0];
+
index 31178e3..76724bc 100644 (file)
@@ -7,18 +7,14 @@
 #include <binary.h>\r
 \r
 #define _COMMON_H\r
-#define SysDebug(...)  LOG(v)\r
-#define DISABLE_ELF64\r
+#define SysDebug(v...) LOG(v)\r
+#if BITS <= 32\r
+# define DISABLE_ELF64\r
+#endif\r
 void   *GetSymbol(const char *Name, size_t *Size);\r
 void   *GetSymbol(const char *Name, size_t *Size) { Uint val; Binary_GetSymbol(Name, &val); if(Size)*Size=0; return (void*)val; };\r
 #define AddLoaded(a,b) do{}while(0)\r
-#define LoadLibrary(a,b,c)     0\r
-#if __STDC_HOSTED__\r
-#warning "Hosted? why!"\r
-#else\r
-#warning "freestanding - outstanding!"\r
-#endif\r
-\r
+#define LoadLibrary(a,b,c)     (Log_Debug("ELF", "Module requested lib '%s'",a),0)\r
 #include "../../../Usermode/Libraries/ld-acess.so_src/elf.c"\r
 \r
 #define DEBUG_WARN     1\r
@@ -56,7 +52,7 @@ tBinary *Elf_Load(int fp)
        switch(hdr.e_ident[4])  // EI_CLASS\r
        {\r
        case ELFCLASS32:\r
-               return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);\r
+               return Elf_Load32(fp, (void*)&hdr);\r
        case ELFCLASS64:\r
                return Elf_Load64(fp, &hdr);\r
        default:\r
@@ -297,7 +293,7 @@ tBinary *Elf_Load32(int FD, Elf32_Ehdr *Header)
 \r
 int Elf_Relocate(void *Base)\r
 {\r
-       return  ElfRelocate(Base, (char**){NULL}, "") != NULL;\r
+       return ElfRelocate(Base, (char**){NULL}, "") != NULL;\r
 }\r
 int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
 {\r
index e72de28..92baa73 100644 (file)
@@ -768,17 +768,7 @@ void *Binary_LoadKernel(const char *File)
        pKBinary->Next = glLoadedKernelLibs;
        glLoadedKernelLibs = pKBinary;
        SHORTREL( &glKBinListLock );
-       
-       // Relocate Library
-       if( !Binary_Relocate( (void*)base ) )
-       {
-               Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
-               Binary_Unload( (void*)base );
-               Binary_Dereference( pBinary );
-               LEAVE('n');
-               return 0;
-       }
-       
+
        LEAVE('p', base);
        return (void*)base;
 }
@@ -832,9 +822,12 @@ Uint Binary_GetSymbolEx(const char *Name, Uint *Value)
        tKernelBin      *pKBin;
         int    numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
        
+       LOG("numKSyms = %i", numKSyms);
+
        // Scan Kernel
        for( i = 0; i < numKSyms; i++ )
        {
+               LOG("KSym %s = %p", gKernelSymbols[i].Name, gKernelSymbols[i].Value);
                if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
                        *Value = gKernelSymbols[i].Value;
                        return 1;
@@ -891,12 +884,12 @@ int Binary_int_CheckMemFree( tVAddr _start, size_t _len )
        _start &= ~(PAGE_SIZE-1);
        LOG("_start = %p, _len = 0x%x", _start, _len);
        for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
-               if( MM_GetPhysAddr(_start) != 0 ) {
+               if( MM_GetPhysAddr( (void*)_start ) != 0 ) {
                        LEAVE('i', 1);
                        return 1;
                }
        }
-       if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 ) {
+       if( _len == PAGE_SIZE && MM_GetPhysAddr( (void*)_start ) != 0 ) {
                LEAVE('i', 1);
                return 1;
        }
index 6a50ca2..31d3b39 100644 (file)
@@ -13,6 +13,7 @@
 extern void    Threads_Dump(void);
 extern void    KernelPanic_SetMode(void);
 extern void    KernelPanic_PutChar(char Ch);
+extern void    IPStack_SendDebugText(const char *Text);
 
 // === PROTOTYPES ===
 static void    Debug_Putchar(char ch);
@@ -30,11 +31,14 @@ volatile int        gbInPutChar = 0;
 #if LOCK_DEBUG_OUTPUT
 tShortSpinlock glDebug_Lock;
 #endif
+// - Disabled because it breaks shit
+ int   gbSendNetworkDebug = 0;
 
 // === CODE ===
 static void Debug_Putchar(char ch)
 {
        Debug_PutCharDebug(ch);
+       
        if( !gbDebug_IsKPanic )
        {
                if(gbInPutChar) return ;
@@ -45,6 +49,12 @@ static void Debug_Putchar(char ch)
        }
        else
                KernelPanic_PutChar(ch);
+       
+       if( gbSendNetworkDebug )
+       {
+               char str[2] = {ch, 0};
+               IPStack_SendDebugText(str);
+       }
 }
 
 static void Debug_Puts(int UseKTerm, const char *Str)
@@ -60,7 +70,10 @@ static void Debug_Puts(int UseKTerm, const char *Str)
        }
        else
                for( len = 0; Str[len]; len ++ );
-       
+
+       if( gbSendNetworkDebug )
+               IPStack_SendDebugText(Str);
+
        // Output to the kernel terminal
        if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
        {
@@ -79,9 +92,9 @@ void Debug_DbgOnlyFmt(const char *format, va_list args)
 void Debug_Fmt(int bUseKTerm, const char *format, va_list args)
 {
        char    buf[DEBUG_MAX_LINE_LEN];
-        int    len;
+//      int    len;
        buf[DEBUG_MAX_LINE_LEN-1] = 0;
-       len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
+       /*len = */vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
        //if( len < DEBUG_MAX_LINE )
                // do something
        Debug_Puts(bUseKTerm, buf);
@@ -208,6 +221,7 @@ void Panic(const char *Fmt, ...)
        Debug_Putchar('\n');
 
        Threads_Dump();
+       Heap_Dump();
 
        for(;;) ;
 }
index 94e8aae..2adaec7 100644 (file)
@@ -26,12 +26,12 @@ typedef struct sPipe {
 // === PROTOTYPES ===
  int   FIFO_Install(char **Arguments);
  int   FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
-char   *FIFO_ReadDir(tVFS_Node *Node, int Id);
+ int   FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
 tVFS_Node      *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
- int   FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+tVFS_Node      *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
 void   FIFO_Reference(tVFS_Node *Node);
 void   FIFO_Close(tVFS_Node *Node);
- int   FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+ int   FIFO_Unlink(tVFS_Node *Node, const char *OldName);
 size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
 size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
 tPipe  *FIFO_Int_NewPipe(int Size, const char *Name);
@@ -43,7 +43,7 @@ tVFS_NodeType gFIFO_DirNodeType = {
        .ReadDir = FIFO_ReadDir,
        .FindDir = FIFO_FindDir,
        .MkNod = FIFO_MkNod,
-       .Relink = FIFO_Relink,
+       .Unlink = FIFO_Unlink,
        .IOCtl = FIFO_IOCtl
 };
 tVFS_NodeType  gFIFO_PipeNodeType = {
@@ -92,19 +92,24 @@ int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
  * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
  * \brief Reads from the FIFO root
  */
-char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX])
 {
        tPipe   *tmp = gFIFO_NamedPipes;
        
        // Entry 0 is Anon Pipes
-       if(Id == 0)     return strdup("anon");
+       if(Id == 0) {
+               strcpy(Dest, "anon");
+               return 0;
+       }
        
        // Find the id'th node
        while(--Id && tmp)      tmp = tmp->Next;
-       // If node found, return it
-       if(tmp) return strdup(tmp->Name);
-       // else error return
-       return NULL;
+       // If the list ended, error return
+       if(!tmp)
+               return -EINVAL;
+       // Return good
+       strncpy(Dest, tmp->Name, FILENAME_MAX);
+       return 0;
 }
 
 /**
@@ -142,7 +147,7 @@ tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
 /**
  * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
  */
-int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
 {
        return 0;
 }
@@ -178,12 +183,11 @@ void FIFO_Close(tVFS_Node *Node)
 }
 
 /**
- * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
- * \brief Relink a file (Deletes named pipes)
+ * \brief Delete a pipe
  */
-int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
 {
-       tPipe   *pipe, *tmp;
+       tPipe   *pipe;
        
        if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
        
@@ -200,22 +204,6 @@ int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
        }
        if(!pipe)       return 0;
        
-       // Relink a named pipe
-       if(NewName) {
-               // Check new name
-               for(tmp = gFIFO_NamedPipes;
-                       tmp;
-                       tmp = tmp->Next)
-               {
-                       if(strcmp(tmp->Name, NewName) == 0)     return 0;
-               }
-               // Create new name
-               free(pipe->Name);
-               pipe->Name = malloc(strlen(NewName)+1);
-               strcpy(pipe->Name, NewName);
-               return 1;
-       }
-       
        // Unlink the pipe
        if(Node->ImplPtr) {
                free(Node->ImplPtr);
index 2c01b96..2e1ce15 100644 (file)
@@ -1,6 +1,9 @@
 /*\r
- * AcessOS/AcessBasic v0.1\r
- * PCI Bus Driver\r
+ * Acess2 Kernel\r
+ * - By John Hodge (thePowersGang)\r
+ * \r
+ * drv/pci.c\r
+ * - PCI Enumeration and Arbitration\r
  */\r
 #define DEBUG  0\r
 #include <acess.h>\r
@@ -9,8 +12,11 @@
 #include <fs_devfs.h>\r
 #include <drv_pci.h>\r
 #include <drv_pci_int.h>\r
+#include <virtual_pci.h>\r
 \r
+#define USE_PORT_BITMAP        0\r
 #define        LIST_DEVICES    1\r
+#define PCI_MAX_BUSSES 8\r
 \r
 // === STRUCTURES ===\r
 typedef struct sPCIDevice\r
@@ -32,7 +38,7 @@ typedef struct sPCIDevice
  int   PCI_Install(char **Arguments);\r
  int   PCI_ScanBus(int ID, int bFill);\r
  \r
-char   *PCI_int_ReadDirRoot(tVFS_Node *node, int pos);\r
+ int   PCI_int_ReadDirRoot(tVFS_Node *node, int pos, char Dest[FILENAME_MAX]);\r
 tVFS_Node      *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename);\r
 Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset);\r
 size_t PCI_int_ReadDevice(tVFS_Node *node, off_t Offset, size_t Length, void *buffer);\r
@@ -41,6 +47,7 @@ size_t        PCI_int_ReadDevice(tVFS_Node *node, off_t Offset, size_t Length, void *bu
 // === GLOBALS ===\r
 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
  int   giPCI_BusCount = 1;\r
+Uint8  gaPCI_BusNumbers[PCI_MAX_BUSSES];\r
  int   giPCI_InodeHandle = -1;\r
  int   giPCI_DeviceCount = 0;\r
 tPCIDevice     *gPCI_Devices = NULL;\r
@@ -63,7 +70,9 @@ tDevFS_Driver gPCI_DriverStruct = {
        .Type = &gPCI_RootNodeType\r
        }\r
 };\r
+#if USE_PORT_BITMAP\r
 Uint32 *gaPCI_PortBitmap = NULL;\r
+#endif\r
 Uint32 gaPCI_BusBitmap[256/32];\r
  \r
 // === CODE ===\r
@@ -73,9 +82,10 @@ Uint32       gaPCI_BusBitmap[256/32];
  */\r
 int PCI_Install(char **Arguments)\r
 {\r
-        int    i, ret, bus;\r
+        int    ret, bus;\r
        void    *tmpPtr;\r
        \r
+       #if USE_PORT_BITMAP\r
        // Build Portmap\r
        gaPCI_PortBitmap = malloc( 1 << 13 );\r
        if( !gaPCI_PortBitmap ) {\r
@@ -83,18 +93,26 @@ int PCI_Install(char **Arguments)
                return MODULE_ERR_MALLOC;\r
        }\r
        memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
+        int    i;\r
        for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
                gaPCI_PortBitmap[i] = -1;\r
        for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
                gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
-       \r
+       #endif  \r
+\r
        // Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
+       giPCI_DeviceCount = 0;\r
+       giPCI_BusCount = 1;\r
+       gaPCI_BusNumbers[0] = 0;\r
        for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
        {\r
-               ret = PCI_ScanBus(bus, 0);\r
-               if(ret != MODULE_ERR_OK)        return i;\r
+               ret = PCI_ScanBus(gaPCI_BusNumbers[bus], 0);\r
+               if(ret != MODULE_ERR_OK)        return ret;\r
        }\r
-               \r
+       // TODO: PCIe\r
+       // - Add VPCI Devices\r
+       giPCI_DeviceCount += giVPCI_DeviceCount;\r
+       \r
        if(giPCI_DeviceCount == 0) {\r
                Log_Notice("PCI", "No devices were found");\r
                return MODULE_ERR_NOTNEEDED;\r
@@ -117,7 +135,33 @@ int PCI_Install(char **Arguments)
        // Rescan, filling the PCI device array\r
        for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
        {\r
-               PCI_ScanBus(bus, 1);\r
+               PCI_ScanBus(gaPCI_BusNumbers[bus], 1);\r
+       }\r
+       // Insert VPCI Devices\r
+       for( int i = 0; i < giVPCI_DeviceCount; i ++ )\r
+       {\r
+               tPCIDevice      *devinfo = &gPCI_Devices[giPCI_DeviceCount];\r
+               \r
+               devinfo->bus = -1;\r
+               devinfo->slot = i;\r
+               devinfo->fcn = 0;\r
+               devinfo->vendor = gaVPCI_Devices[i].Vendor;\r
+               devinfo->device = gaVPCI_Devices[i].Device;\r
+               devinfo->revision = gaVPCI_Devices[i].Class & 0xFF;\r
+               devinfo->class = gaVPCI_Devices[i].Class >> 8;\r
+               snprintf(devinfo->Name, sizeof(devinfo->Name), "%02x.%02x:%x", 0xFF, i, 0);\r
+\r
+               for(int j = 0; j < 256/4; j ++ )\r
+                       devinfo->ConfigCache[i] = VPCI_Read(&gaVPCI_Devices[i], j*4, 4);\r
+\r
+               memset(&devinfo->Node, 0, sizeof(devinfo->Node));\r
+               devinfo->Node.Inode = giPCI_DeviceCount;\r
+               devinfo->Node.Size = 256;\r
+               devinfo->Node.NumACLs = 1;\r
+               devinfo->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
+               devinfo->Node.Type = &gPCI_DevNodeType;\r
+\r
+               giPCI_DeviceCount ++;\r
        }\r
        \r
        // Complete Driver Structure\r
@@ -152,25 +196,12 @@ int PCI_ScanBus(int BusID, int bFill)
                        if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))\r
                                continue;\r
                        \r
-                       if(devInfo.class == PCI_OC_PCIBRIDGE)\r
-                       {\r
-                               #if LIST_DEVICES\r
-                               if( !bFill )\r
-                                       Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
-                                               BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
-                               #endif\r
-                               //TODO: Handle PCI-PCI Bridges\r
-                               //PCI_ScanBus(devInfo.???, bFill);\r
-                               giPCI_BusCount ++;\r
-                       }\r
-                       else\r
-                       {\r
-                               #if LIST_DEVICES\r
-                               if( !bFill )\r
-                                       Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x",\r
-                                               BusID, dev, fcn, devInfo.class, devInfo.vendor, devInfo.device);\r
-                               #endif\r
-                       }\r
+                       #if LIST_DEVICES\r
+                       if( !bFill )\r
+                               Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x Rev %i",\r
+                                       BusID, dev, fcn, devInfo.class,\r
+                                       devInfo.vendor, devInfo.device, devInfo.revision);\r
+                       #endif\r
                        \r
                        if( bFill ) {\r
                                devInfo.Node.Inode = giPCI_DeviceCount;\r
@@ -178,7 +209,28 @@ int PCI_ScanBus(int BusID, int bFill)
                        }\r
                        giPCI_DeviceCount ++;\r
                        \r
-                       // If bit 23 of (soemthing) is set, there are sub-functions\r
+                       switch(devInfo.ConfigCache[3] & 0x007F0000)\r
+                       {\r
+                       case 0x00:      // Normal device\r
+                               break;\r
+                       case 0x01:      // PCI-PCI Bridge\r
+                               {\r
+                               // TODO: Add to list of busses?\r
+                               Uint8   sec = (devInfo.ConfigCache[6] & 0x0000FF00) >> 8;\r
+                               #if LIST_DEVICES\r
+                               if( !bFill ) {\r
+                                       Uint8   pri = (devInfo.ConfigCache[6] & 0x000000FF) >> 0;\r
+                                       Log_Log("PCI", "- PCI-PCI Bridge %02x=>%02x", pri, sec);\r
+                               }\r
+                               #endif\r
+                               gaPCI_BusNumbers[giPCI_BusCount++] = sec;\r
+                               }\r
+                               break;\r
+                       case 0x02:      // PCI-CardBus Bridge\r
+                               break;\r
+                       }\r
+\r
+                       // If bit 8 of the Header Type register is set, there are sub-functions\r
                        if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
                                break;\r
                }\r
@@ -190,50 +242,31 @@ int PCI_ScanBus(int BusID, int bFill)
 /**\r
  * \brief Read from Root of PCI Driver\r
 */\r
-char *PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos)\r
+int PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])\r
 {\r
        ENTER("pNode iPos", Node, Pos);\r
        if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
-               LEAVE('n');\r
-               return NULL;\r
+               LEAVE_RET('i', -EINVAL);\r
        }\r
        \r
-       LEAVE('s', gPCI_Devices[Pos].Name);\r
-       return strdup( gPCI_Devices[Pos].Name );\r
+       LOG("Name = %s", gPCI_Devices[Pos].Name);\r
+       strncpy(Dest, gPCI_Devices[Pos].Name, FILENAME_MAX);\r
+       LEAVE_RET('i', 0);\r
 }\r
 /**\r
  */\r
 tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)\r
 {\r
-        int    bus,slot,fcn;\r
         int    i;\r
-       // Validate Filename (Pointer and length)\r
-       if(!filename || strlen(filename) != 7)\r
-               return NULL;\r
-       // Check for spacers\r
-       if(filename[2] != '.' || filename[5] != ':')\r
-               return NULL;\r
-       \r
-       // Get Information\r
-       if(filename[0] < '0' || filename[0] > '9')      return NULL;\r
-       bus = (filename[0] - '0')*10;\r
-       if(filename[1] < '0' || filename[1] > '9')      return NULL;\r
-       bus += filename[1] - '0';\r
-       if(filename[3] < '0' || filename[3] > '9')      return NULL;\r
-       slot = (filename[3] - '0')*10;\r
-       if(filename[4] < '0' || filename[4] > '9')      return NULL;\r
-       slot += filename[4] - '0';\r
-       if(filename[6] < '0' || filename[6] > '9')      return NULL;\r
-       fcn = filename[6] - '0';\r
        \r
        // Find Match\r
        for(i=0;i<giPCI_DeviceCount;i++)\r
        {\r
-               if(gPCI_Devices[i].bus != bus)          continue;\r
-               if(gPCI_Devices[i].slot != slot)        continue;\r
-               if(gPCI_Devices[i].fcn != fcn)  continue;\r
-               \r
-               return &gPCI_Devices[i].Node;\r
+               int cmp = strcmp(gPCI_Devices[i].Name, filename);\r
+               if( cmp > 0 )   // Sorted list\r
+                       break;\r
+               if( cmp == 0 )\r
+                       return &gPCI_Devices[i].Node;\r
        }\r
        \r
        // Error Return\r
@@ -365,6 +398,11 @@ Uint32 PCI_ConfigRead(tPCIDev ID, int Offset, int Size)
        if( Offset & (Size - 1) )       return 0;\r
 \r
        dev = &gPCI_Devices[ID];\r
+       // Detect VPCI devices\r
+       if( dev->bus == -1 ) {\r
+               return VPCI_Read(&gaVPCI_Devices[dev->slot], Offset, Size);\r
+       }\r
+\r
        addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
 \r
        dword = PCI_CfgReadDWord(addr);\r
@@ -384,10 +422,18 @@ void PCI_ConfigWrite(tPCIDev ID, int Offset, int Size, Uint32 Value)
        tPCIDevice      *dev;\r
        Uint32  dword, addr;\r
         int    shift;\r
+\r
        if( ID < 0 || ID >= giPCI_DeviceCount ) return ;\r
        if( Offset < 0 || Offset > 256 )        return ;\r
-       \r
+\r
        dev = &gPCI_Devices[ID];\r
+\r
+       // Detect VPCI devices\r
+       if( dev->bus == -1 ) {\r
+               VPCI_Write(&gaVPCI_Devices[dev->slot], Offset, Size, Value);\r
+               return ;\r
+       }\r
+\r
        addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
 \r
        if(Size != 4)\r
@@ -449,16 +495,18 @@ int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
        vendor_dev = PCI_CfgReadDWord( addr );\r
        if((vendor_dev & 0xFFFF) == 0xFFFF)     // Invalid Device\r
                return 0;\r
+       \r
+       info->bus = bus;\r
+       info->slot = slot;\r
+       info->fcn = fcn;\r
 \r
+       // Read configuration\r
        info->ConfigCache[0] = vendor_dev;\r
        for( i = 1, addr += 4; i < 256/4; i ++, addr += 4 )\r
        {\r
                info->ConfigCache[i] = PCI_CfgReadDWord(addr);\r
        }       \r
 \r
-       info->bus = bus;\r
-       info->slot = slot;\r
-       info->fcn = fcn;\r
        info->vendor = vendor_dev & 0xFFFF;\r
        info->device = vendor_dev >> 16;\r
        tmp = info->ConfigCache[2];\r
@@ -472,14 +520,7 @@ int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
 //     #endif\r
        \r
        // Make node name\r
-       info->Name[0] = '0' + bus/10;\r
-       info->Name[1] = '0' + bus%10;\r
-       info->Name[2] = '.';\r
-       info->Name[3] = '0' + slot/10;\r
-       info->Name[4] = '0' + slot%10;\r
-       info->Name[5] = ':';\r
-       info->Name[6] = '0' + fcn;\r
-       info->Name[7] = '\0';\r
+       snprintf(info->Name, 8, "%02x.%02x:%x", bus, slot, fcn);\r
        \r
        // Create VFS Node\r
        memset( &info->Node, 0, sizeof(tVFS_Node) );\r
@@ -488,7 +529,7 @@ int PCI_int_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)
        info->Node.NumACLs = 1;\r
        info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
        \r
-       info->Node.Type = &gPCI_RootNodeType;\r
+       info->Node.Type = &gPCI_DevNodeType;\r
        \r
        return 1;\r
 }\r
index 4f52f5c..9c7d909 100644 (file)
@@ -31,7 +31,7 @@ typedef struct sSysFS_Ent
  int   SysFS_RemoveFile(int ID);
 #endif
 
-char   *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
+ int   SysFS_Comm_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
 tVFS_Node      *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
 size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
 void   SysFS_Comm_CloseFile(tVFS_Node *Node);
@@ -109,12 +109,8 @@ tSysFS_Ent *gSysFS_FileList;
  */
 int SysFS_Install(char **Options)
 {
-       {
-               const char      *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
-               gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
-               gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
-               sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
-       }
+       gSysFS_Version_Kernel.Node.Size = strlen(gsBuildInfo);
+       gSysFS_Version_Kernel.Node.ImplPtr = (void*)gsBuildInfo;
 
        DevFS_AddDevice( &gSysFS_DriverInfo );
        return MODULE_ERR_OK;
@@ -254,8 +250,9 @@ int SysFS_UpdateFile(int ID, const char *Data, int Length)
        for( ent = gSysFS_FileList; ent; ent = ent->Next )
        {
                // It's a reverse sorted list
-               if(ent->Node.Inode < ID)        return 0;
-               if(ent->Node.Inode == ID)
+               if(ent->Node.Inode < (Uint64)ID)
+                       return 0;
+               if(ent->Node.Inode == (Uint64)ID)
                {
                        ent->Node.ImplPtr = (void*)Data;
                        ent->Node.Size = Length;
@@ -279,14 +276,15 @@ int SysFS_RemoveFile(int ID)
        tSysFS_Ent      *ent, *parent, *prev;
        
        prev = NULL;
-       for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
+       for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->ListNext )
        {
                // It's a reverse sorted list
-               if(ent->Node.Inode < ID)        return 0;
-               if(ent->Node.Inode == ID)       break;
+               if(ent->Node.Inode <= (Uint64)ID)       break;
+       }
+       if( !ent || ent->Node.Inode != (Uint64)ID) {
+               Log_Notice("SysFS", "ID %i not present", ID);
+               return 0;
        }
-       
-       if(!ent)        return 0;
        
        // Set up for next part
        file = ent;
@@ -300,26 +298,37 @@ int SysFS_RemoveFile(int ID)
        file->Node.Size = 0;
        file->Node.ImplPtr = NULL;
        
-       // Search parent directory
-       for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
+       // Clean out of parent directory
+       while(parent)
        {
-               if( ent == file )       break;
-       }
-       if(!ent) {
-               Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
-               return 0;
+               for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
+               {
+                       if( ent == file )       break;
+               }
+               if(!ent) {
+                       Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
+                       return 0;
+               }
+               
+               // Remove from parent directory
+               if(prev)
+                       prev->Next = ent->Next;
+               else
+                       parent->Node.ImplPtr = ent->Next;
+
+               // Free if not in use
+               if(file->Node.ReferenceCount == 0) {
+                       free(file);
+               }
+
+               if( parent->Node.ImplPtr )
+                       break;
+
+               // Remove parent from the tree
+               file = parent;
+               parent = parent->Parent;
        }
        
-       // Remove from parent directory
-       if(prev)
-               prev->Next = ent->Next;
-       else
-               parent->Node.ImplPtr = ent->Next;
-       
-       // Free if not in use
-       if(file->Node.ReferenceCount == 0)
-               free(file);
-       
        return 1;
 }
 
@@ -327,16 +336,20 @@ int SysFS_RemoveFile(int ID)
  * \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
  * \brief Reads from a SysFS directory
  */
-char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
+int SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tSysFS_Ent      *child = (tSysFS_Ent*)Node->ImplPtr;
-       if(Pos < 0 || Pos >= Node->Size)        return NULL;
+       if(Pos < 0 || (Uint64)Pos >= Node->Size)
+               return -EINVAL;
        
        for( ; child; child = child->Next, Pos-- )
        {
-               if( Pos == 0 )  return strdup(child->Name);
+               if( Pos == 0 ) {
+                       strncpy(Dest, child->Name, FILENAME_MAX);
+                       return 0;
+               }
        }
-       return NULL;
+       return -ENOENT;
 }
 
 /**
diff --git a/KernelLand/Kernel/drv/vpci.c b/KernelLand/Kernel/drv/vpci.c
new file mode 100644 (file)
index 0000000..4fccdb8
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === CODE ===
+Uint32 VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size)
+{
+       Uint32  tmp_dword = 0;
+
+       if( Size > 4 || Size == 3 || Size == 0 )
+               return 0;
+       if( Offset & (Size - 1) )
+               return 0;
+       
+       switch( Offset >> 2 )
+       {
+       case 0: // Vendor[0:15], Device[16:31]
+               tmp_dword = (Dev->Vendor) | (Dev->Device << 16);
+               break;
+       case 2: // Class Code
+               tmp_dword = Dev->Class;
+               break;
+       // 1: Command[0:15], Status[16:31]
+       // 3: Cache Line Size, Latency Timer, Header Type, BIST
+       // 4-9: BARs
+       // 10: Unused (Cardbus CIS Pointer)
+       // 11: Subsystem Vendor ID, Subsystem ID
+       // 12: Expansion ROM Address
+       // 13: Capabilities[0:8], Reserved[9:31]
+       // 14: Reserved
+       // 15: Interrupt Line, Interrupt Pin, Min Grant, Max Latency
+       default:
+               tmp_dword = Dev->Read(Dev->Ptr, Offset >> 2);
+               break;
+       }
+
+       tmp_dword >>= 8*(Offset & 3);
+       switch(Size)
+       {
+       case 4: break;
+       case 2: tmp_dword &= 0xFFFF;    break;
+       case 1: tmp_dword &= 0xFF;
+       }
+
+       return tmp_dword;
+}
+
+void VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data)
+{
+       Uint32  tmp_dword;
+       if( Size > 4 || Size == 3 || Size == 0 )
+               return ;
+       if( Offset & (Size - 1) )
+               return ;
+       
+       switch(Offset >> 2)
+       {
+       case 0: // Vendor / Device IDs
+       case 2: // Class Code
+               // READ ONLY
+               return ;
+       }
+
+       tmp_dword = Dev->Read(Dev->Ptr, Offset>>2);
+       switch(Size)
+       {
+       case 4: tmp_dword = 0;  break;
+       case 2:
+               tmp_dword &= ~(0xFFFF << ((Offset&2)*16));
+               Data |= 0xFFFF;
+               break;
+       case 1:
+               tmp_dword &= ~(0xFF << ((Offset&3)*8));
+               Data |= 0xFF;
+               break;
+       }
+       tmp_dword |= Data << ((Offset&3)*8);
+       Dev->Write(Dev->Ptr, Offset>>2, tmp_dword);
+}
index 7d30511..fc6dea2 100644 (file)
@@ -34,7 +34,7 @@ extern void   Debug_SetKTerminal(const char *File);
 
 // === PROTOTYPES ===
  int   VT_Install(char **Arguments);
-char   *VT_ReadDir(tVFS_Node *Node, int Pos);
+ int   VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *VT_FindDir(tVFS_Node *Node, const char *Name);
  int   VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
 size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
@@ -196,7 +196,6 @@ int VT_Install(char **Arguments)
 //             Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
        }
        
-       Log_Debug("VTerm", "Registering with DevFS");
        // Add to DevFS
        DevFS_AddDevice( &gVT_DrvInfo );
        
@@ -269,11 +268,12 @@ void VT_SetResolution(int Width, int Height)
  * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
  * \brief Read from the VTerm Directory
  */
-char *VT_ReadDir(tVFS_Node *Node, int Pos)
+int VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       if(Pos < 0)     return NULL;
-       if(Pos >= NUM_VTS)      return NULL;
-       return strdup( gVT_Terminals[Pos].Name );
+       if(Pos < 0)     return -EINVAL;
+       if(Pos >= NUM_VTS)      return -EINVAL;
+       strncpy(Dest, gVT_Terminals[Pos].Name, FILENAME_MAX);
+       return 0;
 }
 
 /**
@@ -353,8 +353,7 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
  */
 size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
 {
-        int    pos = 0;
-        int    avail;
+        int    pos, avail;
        tVTerm  *term = &gVT_Terminals[ Node->Inode ];
        Uint32  *codepoint_buf = Buffer;
        Uint32  *codepoint_in;
@@ -373,9 +372,10 @@ size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                avail = term->InputWrite - term->InputRead;
                if(avail < 0)
                        avail += MAX_INPUT_CHARS8;
-               if(avail > Length - pos)
-                       avail = Length - pos;
+               if(avail > Length)
+                       avail = Length;
                
+               pos = 0;
                while( avail -- )
                {
                        ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead];
@@ -395,12 +395,13 @@ size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                if(avail < 0)
                        avail += MAX_INPUT_CHARS32;
                Length /= 4;
-               if(avail > Length - pos)
-                       avail = Length - pos;
+               if(avail > Length)
+                       avail = Length;
                
                codepoint_in = (void*)term->InputBuffer;
                codepoint_buf = Buffer;
                
+               pos = 0;
                while( avail -- )
                {
                        codepoint_buf[pos] = codepoint_in[term->InputRead];
index 7c61332..b3ff127 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
+ * Font is public domain
  * Altered for Acess2
  */
 #define FONT_WIDTH     8
index b6aff95..7c29656 100644 (file)
@@ -361,6 +361,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
        }
        
        // Debug
+       #if 0
        switch(NewMode)
        {
        case TERM_MODE_TEXT:
@@ -375,6 +376,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode, int NewWidth, int NewHeight)
        //case TERM_MODE_3DACCEL:
        //      return;
        }
+       #endif
 }
 
 
diff --git a/KernelLand/Kernel/drv/zero-one.c b/KernelLand/Kernel/drv/zero-one.c
new file mode 100644 (file)
index 0000000..824f927
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/zero-one.c
+ * - /Devices/{null,zero,one}
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+
+// === PROTOTYPES ===
+ int   CoreDevs_Install(char **Arguments);
+size_t CoreDevs_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+size_t CoreDevs_Read_Zero(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t CoreDevs_Read_One (tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t CoreDevs_Read_Null(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0100, CoreDevs, CoreDevs_Install, NULL, NULL);
+tVFS_NodeType  gCoreDevs_NT_Null = {
+       .TypeName = "CoreDevs-null",
+       .Read  = CoreDevs_Read_Null,
+       .Write = CoreDevs_Write
+};
+tVFS_NodeType  gCoreDevs_NT_Zero = {
+       .TypeName = "CoreDevs-zero",
+       .Read  = CoreDevs_Read_Zero,
+       .Write = CoreDevs_Write
+};
+tVFS_NodeType  gCoreDevs_NT_One = {
+       .TypeName = "CoreDevs-one",
+       .Read  = CoreDevs_Read_One,
+       .Write = CoreDevs_Write
+};
+tDevFS_Driver  gCoreDevs_Null = {
+       NULL, "null",
+       {
+       .Size = 0,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .Type = &gCoreDevs_NT_Null
+       }
+};
+tDevFS_Driver  gCoreDevs_Zero = {
+       NULL, "zero",
+       {
+       .Size = 0,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .Type = &gCoreDevs_NT_Zero
+       }
+};
+tDevFS_Driver  gCoreDevs_One = {
+       NULL, "one",
+       {
+       .Size = 0,
+       .NumACLs = 1,
+       .ACLs = &gVFS_ACL_EveryoneRW,
+       .Type = &gCoreDevs_NT_One
+       }
+};
+
+// === CODE ===
+/**
+ * \brief Installs the CoreDevs driver
+ */
+int CoreDevs_Install(char **Options)
+{
+       DevFS_AddDevice( &gCoreDevs_Null );
+       DevFS_AddDevice( &gCoreDevs_Zero );
+       DevFS_AddDevice( &gCoreDevs_One  );
+       return MODULE_ERR_OK;
+}
+
+size_t CoreDevs_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+{
+       return Length;  // Ignore
+}
+
+size_t CoreDevs_Read_Zero(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+       memset(Buffer, 0, Length);
+       return Length;
+}
+
+size_t CoreDevs_Read_One (tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+       Uint8   *ptr = Buffer;
+       size_t  rem;
+       for( rem = Length; rem --; ptr ++ )
+               *ptr = 0xFF;
+       return Length;
+}
+
+size_t CoreDevs_Read_Null(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+       return 0;
+}
+
diff --git a/KernelLand/Kernel/drvutil.c b/KernelLand/Kernel/drvutil.c
deleted file mode 100644 (file)
index d2c86bf..0000000
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Acess2 Kernel
- * - By John Hodge
- *
- * drvutil.c
- * - Common Driver/Filesystem Helper Functions
- */
-#define DEBUG  0
-#include <acess.h>
-#include <api_drv_disk.h>
-#include <api_drv_video.h>
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
-//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
-//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
-//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
-void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
-//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
-void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
-void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
-
-// === GLOBALS ===
-tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
-       NULL,
-       DrvUtil_Video_2D_Fill,
-       DrvUtil_Video_2D_Blit
-};
-tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
-       8, 16,
-       0, 0,
-       {
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0,
-               0, 0, 0         , 0, 0, 0, 0, 0
-       }
-};
-
-// === CODE ===
-// --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
-       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
-{
-       const Uint8     *stream = Buffer;
-        int    rem = Length;
-        int    op;
-       while( rem )
-       {
-               rem --;
-               op = *stream;
-               stream ++;
-               
-               if(op > NUM_VIDEO_2DOPS) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Unknown operation %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               if(op*sizeof(void*) > SizeofHandlers) {
-                       Log_Warning("DrvUtil",
-                               "DrvUtil_Video_2DStream: Driver does not support op %i",
-                               op);
-                       return Length-rem;
-               }
-               
-               switch(op)
-               {
-               case VIDEO_2DOP_NOP:    break;
-               
-               case VIDEO_2DOP_FILL:
-                       if(rem < 10)    return Length-rem;
-                       
-                       if(!Handlers->Fill) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_FILL");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Fill(
-                               Ent,
-                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
-                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
-                               ((const Uint32*)stream)[4]
-                               );
-                       
-                       rem -= 10;
-                       stream += 10;
-                       break;
-               
-               case VIDEO_2DOP_BLIT:
-                       if(rem < 12)    return Length-rem;
-                       
-                       if(!Handlers->Blit) {
-                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
-                                       " does not support VIDEO_2DOP_BLIT");
-                               return Length-rem;
-                       }
-                       
-                       Handlers->Blit(
-                               Ent,
-                               ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
-                               ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
-                               ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
-                               );
-                       
-                       rem -= 12;
-                       stream += 12;
-                       break;
-               
-               }
-       }
-       return 0;
-}
-
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
-{
-       Uint8   *dest;
-       const Uint32    *src = Buffer;
-        int    csr_x, csr_y;
-        int    x, y;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-       ENTER("pFBInfo xOffset xLength pBuffer",
-               FBInfo, Offset, Length, Buffer);
-
-       csr_x = FBInfo->CursorX;
-       csr_y = FBInfo->CursorY;
-
-       DrvUtil_Video_RemoveCursor(FBInfo);
-
-       switch( FBInfo->BufferFormat )
-       {
-       case VIDEO_BUFFMT_TEXT:
-               {
-               const tVT_Char  *chars = Buffer;
-                int    widthInChars = FBInfo->Width/giVT_CharWidth;
-                int    heightInChars = FBInfo->Height/giVT_CharHeight;
-                int    i;
-       
-               LOG("bytes_per_px = %i", bytes_per_px);
-               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
-       
-               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
-               
-               x = Offset % widthInChars;      y = Offset / widthInChars;
-               LOG("x = %i, y = %i", x, y);    
-       
-               // Sanity Check
-               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
-               if(y >= heightInChars)  LEAVE_RET('i', 0);
-               
-               if( Offset + Length > heightInChars*widthInChars )
-               {
-                       Length = heightInChars*widthInChars - Offset;
-               }
-               
-               dest = FBInfo->Framebuffer;
-               LOG("dest = %p", dest);
-               dest += y * giVT_CharHeight * FBInfo->Pitch;
-               LOG("dest = %p", dest);
-               
-               for( i = 0; i < Length; i++ )
-               {
-                       if( y >= heightInChars )
-                       {
-                               Log_Notice("DrvUtil", "Stopped at %i", i);
-                               break;
-                       }
-
-                       VT_Font_Render(
-                               chars->Ch,
-                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
-                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
-                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
-                               );
-                       
-                       chars ++;
-                       x ++;
-                       if( x >= widthInChars )
-                       {
-                               x = 0;
-                               y ++;
-                               dest += FBInfo->Pitch*giVT_CharHeight;
-                               LOG("dest = %p", dest);
-                       }
-               }
-               Length = i * sizeof(tVT_Char);
-               }
-               break;
-       
-       case VIDEO_BUFFMT_FRAMEBUFFER:
-               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
-               {
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
-                       return 0;
-               }
-               
-               switch(FBInfo->Depth)
-               {
-               case 15:
-               case 16:
-                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
-                       break;
-               case 24:
-                       x = Offset % FBInfo->Width;
-                       y = Offset / FBInfo->Width;
-                       dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
-                       for( ; Length >= 4; Length -= 4 )
-                       {
-                               dest[x*3+0] = *src & 0xFF;
-                               dest[x*3+1] = (*src >> 8) & 0xFF;
-                               dest[x*3+2] = (*src >> 16) & 0xFF;
-                               x ++;
-                               if(x == FBInfo->Width) {
-                                       dest += FBInfo->Pitch;
-                                       x = 0;
-                               }
-                       }
-                       break;
-               case 32:
-                       // Copy to Frambuffer
-                       if( FBInfo->Pitch != FBInfo->Width*4 )
-                       {
-                               Uint32  *px;
-                               // Pitch isn't 4*Width
-                               x = Offset % FBInfo->Width;
-                               y = Offset / FBInfo->Height;
-                               
-                               px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
-
-                               for( ; Length >= 4; Length -= 4, x )
-                               {
-                                       px[x++] = *src ++;
-                                       if( x == FBInfo->Width ) {
-                                               x = 0;
-                                               px += FBInfo->Pitch;
-                                       }
-                               }
-                       }
-                       else
-                       {
-                               dest = (Uint8 *)FBInfo->Framebuffer + Offset;
-                               memcpy(dest, Buffer, Length);
-                       }
-                       break;
-               default:
-                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
-                       break;
-               }
-               break;
-       
-       case VIDEO_BUFFMT_2DSTREAM:
-               Length = DrvUtil_Video_2DStream(
-                       FBInfo, Buffer, Length,
-                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
-                       );
-               break;
-       
-       default:
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
-
-       LEAVE('x', Length);
-       return Length;
-}
-
-int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
-{
-        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
-       size_t  size;
-
-       ENTER("pBuf pBitmap", Buf, Bitmap);
-
-       // Clear old bitmap
-       if( Buf->CursorBitmap )
-       {
-               LOG("Clearing old cursor");
-               DrvUtil_Video_RemoveCursor(Buf);
-               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
-               {
-                       free( Buf->CursorSaveBuf );
-                       Buf->CursorSaveBuf = NULL;
-               }
-               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
-                       free(Buf->CursorBitmap);
-               Buf->CursorBitmap = NULL;
-       }
-       
-       // If the new bitmap is null, disable drawing
-       if( !Bitmap )
-       {
-               Buf->CursorX = -1;
-               Buf->CursorY = -1;
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       // Sanity check the bitmap
-       LOG("Sanity checking plox");
-       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
-       {
-               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
-               errno = -EINVAL;
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       // Don't take a copy of the DrvUtil provided cursor
-       if( Bitmap == &gDrvUtil_TextModeCursor )
-       {
-               LOG("No copy (provided cursor)");
-               Buf->CursorBitmap = Bitmap;
-       }
-       else
-       {
-               LOG("Make copy");
-               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
-               
-               // Take a copy
-               Buf->CursorBitmap = malloc( size );
-               memcpy(Buf->CursorBitmap, Bitmap, size);
-       }
-       
-       // Restore cursor position
-       LOG("Drawing");
-       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
-       LEAVE('i', 0);
-       return 0;
-}
-
-void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
-{
-        int    render_ox=0, render_oy=0, render_w, render_h;
-
-       ENTER("pBuf iX iY", Buf, X, Y);
-       DrvUtil_Video_RemoveCursor(Buf);
-
-       // X < 0 disables the cursor
-       if( X < 0 ) {
-               Buf->CursorX = -1;
-               LEAVE('-');
-               return ;
-       }
-
-       // Sanity checking
-       if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
-               LEAVE('-');
-               return ;
-       }
-
-       // Ensure the cursor is enabled
-       if( !Buf->CursorBitmap ) {
-               LEAVE('-');
-               return ;
-       }
-       
-       // Save cursor position (for changing the bitmap)
-       Buf->CursorX = X;       Buf->CursorY = Y;
-       // Apply cursor's center offset
-       X -= Buf->CursorBitmap->XOfs;
-       Y -= Buf->CursorBitmap->YOfs;
-       
-       // Get the width of the cursor on screen (clipping to right/bottom edges)
-       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
-       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
-
-       // Clipp to left/top edges
-       if(X < 0) {     render_ox = -X; X = 0;  }
-       if(Y < 0) {     render_oy = -Y; Y = 0;  }
-
-       // Save values
-       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
-       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
-       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
-
-       LOG("%ix%i at %i,%i offset %i,%i",
-               render_w, render_h, X, Y, render_ox, render_oy);
-
-       // Call render routine
-       DrvUtil_Video_RenderCursor(Buf);
-       LEAVE('-');
-}
-
-void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
-        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
-        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       void    *dest;
-       Uint32  *src;
-        int    x, y;
-
-       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
-       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
-       
-       LOG("dest = %p, src = %p", dest, src);
-
-       // Allocate save buffer if not already
-       if( !Buf->CursorSaveBuf )
-               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
-
-       LOG("Saving back");
-       // Save behind the cursor
-       for( y = 0; y < render_h; y ++ )
-               memcpy(
-                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
-                       (Uint8*)dest + y*Buf->Pitch,
-                       render_w*bytes_per_px
-                       );
-
-       // Draw the cursor
-       switch(Buf->Depth)
-       {
-       case 15:
-       case 16:
-               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
-               break;
-       case 24:
-               LOG("24-bit render");
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint8   *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px += 3)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                               {
-                                       px[0] = value & 0xFF;
-                                       px[1] = (value >> 8) & 0xFF;
-                                       px[2] = (value >> 16) & 0xFF;
-                               }
-                               else
-                                       ;
-                       }
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       case 32:
-               LOG("32-bit render");
-               for( y = 0; y < render_h; y ++ )
-               {
-                       Uint32  *px;
-                       px = dest;
-                       for(x = 0; x < render_w; x ++, px ++)
-                       {
-                               Uint32  value = src[x];
-                               // TODO: Should I implement alpha blending?
-                               if(value & 0xFF000000)
-                                       *px = value;
-                               else
-                                       ;       // NOP, completely transparent
-                       }
-                       LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
-                       src += Buf->CursorBitmap->W;
-                       dest = (Uint8*)dest + Buf->Pitch;
-               }
-               break;
-       default:
-               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
-               Buf->CursorX = -1;
-               break;
-       }
-}
-
-void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
-{
-        int    bytes_per_px = (Buf->Depth + 7) / 8;
-        int    y, save_pitch;
-       Uint8   *dest, *src;
-
-       // Just a little sanity
-       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
-       if( !Buf->CursorSaveBuf )       return ;
-
-//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
-
-       // Set up
-       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
-       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
-       src = Buf->CursorSaveBuf;
-       
-       // Copy each line back
-       for( y = 0; y < Buf->CursorRenderH; y ++ )
-       {
-               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
-               src += save_pitch;
-               dest += Buf->Pitch;
-       }
-       
-       // Set the cursor as removed
-       Buf->CursorX = -1;
-}
-
-void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-
-       // TODO: Handle non-32bit modes
-       if( FBInfo->Depth != 32 )       return;
-
-       // TODO: Be less hacky
-        int    pitch = FBInfo->Pitch/4;
-       Uint32  *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
-       while( H -- ) {
-               Uint32 *tmp;
-                int    i;
-               tmp = buf;
-               for(i=W;i--;tmp++)      *tmp = Colour;
-               buf += pitch;
-       }
-}
-
-void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
-{
-       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
-        int    scrnpitch = FBInfo->Pitch;
-        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
-        int    dst = DstY*scrnpitch + DstX;
-        int    src = SrcY*scrnpitch + SrcX;
-        int    tmp;
-       
-       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
-       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
-       
-       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
-       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
-       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
-       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
-       
-       //Debug("W = %i, H = %i", W, H);
-       
-       if( dst > src ) {
-               // Reverse copy
-               dst += H*scrnpitch;
-               src += H*scrnpitch;
-               while( H -- ) {
-                       dst -= scrnpitch;
-                       src -= scrnpitch;
-                       tmp = W*bytes_per_px;
-                       for( tmp = W; tmp --; ) {
-                               *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
-                       }
-               }
-       }
-       else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
-               memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
-       }
-       else {
-               // Normal copy is OK
-               while( H -- ) {
-                       memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
-                       dst += scrnpitch;
-                       src += scrnpitch;
-               }
-       }
-       //Log("Vesa_2D_Blit: RETURN");
-}
-       
-
-// --- Disk Driver Helpers ---
-Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
-               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Reading %i bytes from Block1+%i", leading, offset);
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               memcpy( Buffer, &tmp[offset], leading );
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Reading %i blocks", num);
-               ret = ReadBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Reading %i bytes from last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               memcpy( Buffer, tmp, tailings );
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
-
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
-       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
-       Uint64 BlockSize, void *Argument)
-{
-       Uint8   tmp[BlockSize]; // C99
-       Uint64  block = Start / BlockSize;
-        int    offset = Start - block * BlockSize;
-        int    leading = BlockSize - offset;
-       Uint64  num;
-        int    tailings;
-       Uint64  ret;
-       
-       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
-               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
-       
-       // Non aligned start, let's fix that!
-       if(offset != 0)
-       {
-               if(leading > Length)    leading = Length;
-               LOG("Writing %i bytes to Block1+%i", leading, offset);
-               // Read a copy of the block
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               // Modify
-               memcpy( &tmp[offset], Buffer, leading );
-               // Write Back
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               
-               if(leading == Length) {
-                       LEAVE('i', leading);
-                       return leading;
-               }
-               
-               Buffer = (Uint8*)Buffer + leading;
-               block ++;
-               num = ( Length - leading ) / BlockSize;
-               tailings = Length - num * BlockSize - leading;
-       }
-       else {
-               num = Length / BlockSize;
-               tailings = Length % BlockSize;
-       }
-       
-       // Read central blocks
-       if(num)
-       {
-               LOG("Writing %i blocks", num);
-               ret = WriteBlocks(block, num, Buffer, Argument);
-               if(ret != num ) {
-                       LEAVE('X', leading + ret * BlockSize);
-                       return leading + ret * BlockSize;
-               }
-       }
-       
-       // Read last tailing block
-       if(tailings != 0)
-       {
-               LOG("Writing %i bytes to last block", tailings);
-               block += num;
-               Buffer = (Uint8*)Buffer + num * BlockSize;
-               // Read
-               ret = ReadBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               // Modify
-               memcpy( tmp, Buffer, tailings );
-               // Write
-               ret = WriteBlocks(block, 1, tmp, Argument);
-               if(ret != 1) {
-                       LEAVE('X', leading + num * BlockSize);
-                       return leading + num * BlockSize;
-               }
-               
-       }
-       
-       LEAVE('X', Length);
-       return Length;
-}
diff --git a/KernelLand/Kernel/drvutil_disk.c b/KernelLand/Kernel/drvutil_disk.c
new file mode 100644 (file)
index 0000000..a57917d
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil_disk.c
+ * - Storage Driver Helper Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <api_drv_disk.h>
+
+// --- Disk Driver Helpers ---
+size_t DrvUtil_ReadBlock(Uint64 Start, size_t Length, void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, size_t BlockSize, void *Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+        int    offset = Start - block * BlockSize;
+       size_t  leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       size_t  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
+               Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Reading %i bytes from Block1+%i", leading, offset);
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               memcpy( Buffer, &tmp[offset], leading );
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+               leading = 0;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Reading %i blocks", num);
+               ret = ReadBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LOG("Incomplete read (%i != %i)", ret, num);
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Reading %i bytes from last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               memcpy( Buffer, tmp, tailings );
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
+
+size_t DrvUtil_WriteBlock(Uint64 Start, size_t Length, const void *Buffer,
+       tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
+       size_t BlockSize, void *Argument)
+{
+       Uint8   tmp[BlockSize]; // C99
+       Uint64  block = Start / BlockSize;
+       size_t  offset = Start - block * BlockSize;
+       size_t  leading = BlockSize - offset;
+       Uint64  num;
+        int    tailings;
+       size_t  ret;
+       
+       ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
+               Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
+       
+       // Non aligned start, let's fix that!
+       if(offset != 0)
+       {
+               if(leading > Length)    leading = Length;
+               LOG("Writing %i bytes to Block1+%i", leading, offset);
+               // Read a copy of the block
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               // Modify
+               memcpy( &tmp[offset], Buffer, leading );
+               // Write Back
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('i', 0);
+                       return 0;
+               }
+               
+               if(leading == Length) {
+                       LEAVE('i', leading);
+                       return leading;
+               }
+               
+               Buffer = (Uint8*)Buffer + leading;
+               block ++;
+               num = ( Length - leading ) / BlockSize;
+               tailings = Length - num * BlockSize - leading;
+       }
+       else {
+               num = Length / BlockSize;
+               tailings = Length % BlockSize;
+       }
+       
+       // Read central blocks
+       if(num)
+       {
+               LOG("Writing %i blocks", num);
+               ret = WriteBlocks(block, num, Buffer, Argument);
+               if(ret != num ) {
+                       LEAVE('X', leading + ret * BlockSize);
+                       return leading + ret * BlockSize;
+               }
+       }
+       
+       // Read last tailing block
+       if(tailings != 0)
+       {
+               LOG("Writing %i bytes to last block", tailings);
+               block += num;
+               Buffer = (Uint8*)Buffer + num * BlockSize;
+               // Read
+               ret = ReadBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               // Modify
+               memcpy( tmp, Buffer, tailings );
+               // Write
+               ret = WriteBlocks(block, 1, tmp, Argument);
+               if(ret != 1) {
+                       LEAVE('X', leading + num * BlockSize);
+                       return leading + num * BlockSize;
+               }
+               
+       }
+       
+       LEAVE('X', Length);
+       return Length;
+}
diff --git a/KernelLand/Kernel/drvutil_video.c b/KernelLand/Kernel/drvutil_video.c
new file mode 100644 (file)
index 0000000..2bee791
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil.c
+ * - Video Driver Helper Functions
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+
+// === PROTOTYPES ===
+//int  DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
+//size_t       DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
+//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
+//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
+void   DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
+//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
+void   DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void   DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+tDrvUtil_Video_2DHandlers      gDrvUtil_Stub_2DFunctions = {
+       NULL,
+       DrvUtil_Video_2D_Fill,
+       DrvUtil_Video_2D_Blit
+};
+tVideo_IOCtl_Bitmap    gDrvUtil_TextModeCursor = {
+       8, 16,
+       0, 0,
+       {
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0,
+               0, 0, 0         , 0, 0, 0, 0, 0
+       }
+};
+
+// === CODE ===
+// --- Video Driver Helpers ---
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
+       tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
+{
+       const Uint8     *stream = Buffer;
+        int    rem = Length;
+        int    op;
+
+       Uint16  tmp[6];
+
+       while( rem )
+       {
+               rem --;
+               op = *stream;
+               stream ++;
+               
+               if(op > NUM_VIDEO_2DOPS) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Unknown operation %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               if(op*sizeof(void*) > SizeofHandlers) {
+                       Log_Warning("DrvUtil",
+                               "DrvUtil_Video_2DStream: Driver does not support op %i",
+                               op);
+                       return Length-rem;
+               }
+               
+               switch(op)
+               {
+               case VIDEO_2DOP_NOP:    break;
+               
+               case VIDEO_2DOP_FILL:
+                       if(rem < 12)    return Length-rem;
+                       memcpy(tmp, stream, 6*2);
+                       
+                       if(!Handlers->Fill) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_FILL");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Fill(
+                               Ent, 
+                               tmp[0], tmp[1], tmp[2], tmp[3],
+                               tmp[4] | ((Uint32)tmp[5] << 16)
+                               );
+                       
+                       rem -= 12;
+                       stream += 12;
+                       break;
+               
+               case VIDEO_2DOP_BLIT:
+                       if(rem < 12)    return Length-rem;
+                       memcpy(tmp, stream, 6*2);
+                       
+                       if(!Handlers->Blit) {
+                               Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+                                       " does not support VIDEO_2DOP_BLIT");
+                               return Length-rem;
+                       }
+                       
+                       Handlers->Blit(
+                               Ent,
+                               tmp[0], tmp[1], tmp[2], tmp[3],
+                               tmp[4], tmp[5]
+                               );
+                       
+                       rem -= 12;
+                       stream += 12;
+                       break;
+               
+               }
+       }
+       return 0;
+}
+
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
+{
+       Uint8   *dest;
+       const Uint32    *src = Buffer;
+        int    csr_x, csr_y;
+        int    x, y;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+       size_t  ofs;
+       ENTER("pFBInfo xOffset xLength pBuffer",
+               FBInfo, Offset, Length, Buffer);
+
+       csr_x = FBInfo->CursorX;
+       csr_y = FBInfo->CursorY;
+
+       if( FBInfo->BackBuffer )
+               dest = FBInfo->BackBuffer;
+       else
+               dest = FBInfo->Framebuffer;
+       
+       DrvUtil_Video_RemoveCursor(FBInfo);
+
+       switch( FBInfo->BufferFormat )
+       {
+       case VIDEO_BUFFMT_TEXT:
+               {
+               const tVT_Char  *chars = Buffer;
+                int    widthInChars = FBInfo->Width/giVT_CharWidth;
+                int    heightInChars = FBInfo->Height/giVT_CharHeight;
+                int    i;
+       
+               LOG("bytes_per_px = %i", bytes_per_px);
+               LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
+       
+               Length /= sizeof(tVT_Char);     Offset /= sizeof(tVT_Char);
+               
+               x = Offset % widthInChars;      y = Offset / widthInChars;
+               LOG("x = %i, y = %i", x, y);    
+       
+               // Sanity Check
+               if(Offset > heightInChars * widthInChars)       LEAVE_RET('i', 0);
+               if(y >= heightInChars)  LEAVE_RET('i', 0);
+               
+               if( Offset + Length > heightInChars*widthInChars )
+               {
+                       Length = heightInChars*widthInChars - Offset;
+               }
+               
+               LOG("dest = %p", dest);
+               ofs = y * giVT_CharHeight * FBInfo->Pitch;
+               dest += ofs;
+               
+               for( i = 0; i < Length; i++ )
+               {
+                       if( y >= heightInChars )
+                       {
+                               Log_Notice("DrvUtil", "Stopped at %i", i);
+                               break;
+                       }
+
+                       VT_Font_Render(
+                               chars->Ch,
+                               dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
+                               VT_Colour12toN(chars->BGCol, FBInfo->Depth),
+                               VT_Colour12toN(chars->FGCol, FBInfo->Depth)
+                               );
+                       
+                       chars ++;
+                       x ++;
+                       if( x >= widthInChars )
+                       {
+                               x = 0;
+                               y ++;
+                               dest += FBInfo->Pitch*giVT_CharHeight;
+                               LOG("dest = %p", dest);
+                       }
+               }
+               if( x > 0 ) 
+                       dest += FBInfo->Pitch*giVT_CharHeight;
+               Length = i * sizeof(tVT_Char);
+               
+               break; }
+       
+       case VIDEO_BUFFMT_FRAMEBUFFER:
+               if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
+               {
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
+                       return 0;
+               }
+               
+               switch(FBInfo->Depth)
+               {
+               case 15:
+               case 16:
+                       Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
+                       dest = NULL;
+                       break;
+               case 24:
+                       x = Offset % FBInfo->Width;
+                       y = Offset / FBInfo->Width;
+                       ofs = y*FBInfo->Pitch;
+                       dest += ofs;
+                       for( ; Length >= 4; Length -= 4 )
+                       {
+                               dest[x*3+0] = *src & 0xFF;
+                               dest[x*3+1] = (*src >> 8) & 0xFF;
+                               dest[x*3+2] = (*src >> 16) & 0xFF;
+                               x ++;
+                               if(x == FBInfo->Width) {
+                                       dest += FBInfo->Pitch;
+                                       x = 0;
+                               }
+                       }
+                       break;
+               case 32:
+                       // Copy to Frambuffer
+                       if( FBInfo->Pitch != FBInfo->Width*4 )
+                       {
+                               Uint32  *px;
+                               // Pitch isn't 4*Width
+                               x = Offset % FBInfo->Width;
+                               y = Offset / FBInfo->Height;
+                               
+                               ofs = y*FBInfo->Pitch;
+                               dest += ofs;
+                               px = (void*)dest;
+
+                               for( ; Length >= 4; Length -= 4 )
+                               {
+                                       px[x++] = *src ++;
+                                       if( x == FBInfo->Width ) {
+                                               x = 0;
+                                               dest += FBInfo->Pitch;
+                                               px = (void*)dest;
+                                       }
+                               }
+                               if( x > 0 ) {
+                                       dest += FBInfo->Pitch;
+                               }
+                       }
+                       else
+                       {
+                               ofs = Offset;
+                               dest += ofs;
+                               memcpy(dest, Buffer, Length);
+                               dest += Length;
+                       }
+                       break;
+               default:
+                       Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depth %i", FBInfo->Depth);
+                       dest = NULL;
+                       break;
+               }
+               break;
+       
+       case VIDEO_BUFFMT_2DSTREAM:
+               Length = DrvUtil_Video_2DStream(
+                       FBInfo, Buffer, Length,
+                       &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
+                       );
+               dest = NULL;
+               break;
+       
+       default:
+               LEAVE('i', -1);
+               return -1;
+       }
+       if( FBInfo->BackBuffer && dest ) {
+               void    *_dst = (char*)FBInfo->Framebuffer + ofs;
+               void    *_src = (char*)FBInfo->BackBuffer + ofs;
+               size_t  len = ((tVAddr)dest - (tVAddr)FBInfo->BackBuffer) - ofs;
+       //      Log_Debug("DrvUtil", "Copy from BB %p to FB %p 0x%x bytes", _src, _dst, len);
+               memcpy(_dst, _src, len);
+       }
+
+       DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
+
+       LEAVE('x', Length);
+       return Length;
+}
+
+int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
+{
+        int    csrX = Buf->CursorX, csrY = Buf->CursorY;
+       size_t  size;
+
+       ENTER("pBuf pBitmap", Buf, Bitmap);
+
+       // Clear old bitmap
+       if( Buf->CursorBitmap )
+       {
+               LOG("Clearing old cursor");
+               DrvUtil_Video_RemoveCursor(Buf);
+               if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
+               {
+                       free( Buf->CursorSaveBuf );
+                       Buf->CursorSaveBuf = NULL;
+               }
+               if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
+                       free(Buf->CursorBitmap);
+               Buf->CursorBitmap = NULL;
+       }
+       
+       // If the new bitmap is null, disable drawing
+       if( !Bitmap )
+       {
+               Buf->CursorX = -1;
+               Buf->CursorY = -1;
+               LEAVE('i', 0);
+               return 0;
+       }
+
+       // Sanity check the bitmap
+       LOG("Sanity checking plox");
+       if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
+       {
+               Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
+               errno = -EINVAL;
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       // Don't take a copy of the DrvUtil provided cursor
+       if( Bitmap == &gDrvUtil_TextModeCursor )
+       {
+               LOG("No copy (provided cursor)");
+               Buf->CursorBitmap = Bitmap;
+       }
+       else
+       {
+               LOG("Make copy");
+               size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
+               
+               // Take a copy
+               Buf->CursorBitmap = malloc( size );
+               memcpy(Buf->CursorBitmap, Bitmap, size);
+       }
+       
+       // Restore cursor position
+       LOG("Drawing");
+       DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
+       LEAVE('i', 0);
+       return 0;
+}
+
+void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
+{
+        int    render_ox=0, render_oy=0, render_w, render_h;
+
+       ENTER("pBuf iX iY", Buf, X, Y);
+       DrvUtil_Video_RemoveCursor(Buf);
+
+       // X < 0 disables the cursor
+       if( X < 0 ) {
+               Buf->CursorX = -1;
+               LEAVE('-');
+               return ;
+       }
+
+       // Sanity checking
+       if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
+               LEAVE('-');
+               return ;
+       }
+
+       // Ensure the cursor is enabled
+       if( !Buf->CursorBitmap ) {
+               LEAVE('-');
+               return ;
+       }
+       
+       // Save cursor position (for changing the bitmap)
+       Buf->CursorX = X;       Buf->CursorY = Y;
+       // Apply cursor's center offset
+       X -= Buf->CursorBitmap->XOfs;
+       Y -= Buf->CursorBitmap->YOfs;
+       
+       // Get the width of the cursor on screen (clipping to right/bottom edges)
+       render_w = X > Buf->Width  - Buf->CursorBitmap->W ? Buf->Width  - X : Buf->CursorBitmap->W;
+       render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
+
+       // Clipp to left/top edges
+       if(X < 0) {     render_ox = -X; X = 0;  }
+       if(Y < 0) {     render_oy = -Y; Y = 0;  }
+
+       // Save values
+       Buf->CursorRenderW = render_w;  Buf->CursorRenderH = render_h;
+       Buf->CursorDestX   = X;         Buf->CursorDestY = Y;
+       Buf->CursorReadX   = render_ox; Buf->CursorReadY = render_oy;
+
+       LOG("%ix%i at %i,%i offset %i,%i",
+               render_w, render_h, X, Y, render_ox, render_oy);
+
+       // Call render routine
+       DrvUtil_Video_RenderCursor(Buf);
+       LEAVE('-');
+}
+
+void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
+        int    render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
+        int    dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       void    *dest;
+       Uint32  *src;
+        int    x, y;
+
+       dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
+       src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
+       
+       LOG("dest = %p, src = %p", dest, src);
+
+       // Allocate save buffer if not already
+       if( !Buf->CursorSaveBuf )
+               Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
+
+       LOG("Saving back");
+       // Save behind the cursor
+       for( y = 0; y < render_h; y ++ )
+               memcpy(
+                       (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
+                       (Uint8*)dest + y*Buf->Pitch,
+                       render_w*bytes_per_px
+                       );
+
+       // Draw the cursor
+       switch(Buf->Depth)
+       {
+       case 15:
+       case 16:
+               Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
+               break;
+       case 24:
+               LOG("24-bit render");
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint8   *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px += 3)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                               {
+                                       px[0] = value & 0xFF;
+                                       px[1] = (value >> 8) & 0xFF;
+                                       px[2] = (value >> 16) & 0xFF;
+                               }
+                               else
+                                       ;
+                       }
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       case 32:
+               LOG("32-bit render");
+               for( y = 0; y < render_h; y ++ )
+               {
+                       Uint32  *px;
+                       px = dest;
+                       for(x = 0; x < render_w; x ++, px ++)
+                       {
+                               Uint32  value = src[x];
+                               // TODO: Should I implement alpha blending?
+                               if(value & 0xFF000000)
+                                       *px = value;
+                               else
+                                       ;       // NOP, completely transparent
+                       }
+                       LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
+                       src += Buf->CursorBitmap->W;
+                       dest = (Uint8*)dest + Buf->Pitch;
+               }
+               break;
+       default:
+               Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
+               Buf->CursorX = -1;
+               break;
+       }
+}
+
+void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+        int    bytes_per_px = (Buf->Depth + 7) / 8;
+        int    y, save_pitch;
+       Uint8   *dest, *src;
+
+       // Just a little sanity
+       if( !Buf->CursorBitmap || Buf->CursorX == -1 )  return ;
+       if( !Buf->CursorSaveBuf )       return ;
+
+//     Debug("DrvUtil_Video_RemoveCursor: (Buf=%p) dest_x=%i, dest_y=%i", Buf, Buf->CursorDestX, Buf->CursorDestY);
+
+       // Set up
+       save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+       dest = (Uint8*)Buf->Framebuffer + Buf->CursorDestY * Buf->Pitch + Buf->CursorDestX*bytes_per_px;
+       src = Buf->CursorSaveBuf;
+       
+       // Copy each line back
+       for( y = 0; y < Buf->CursorRenderH; y ++ )
+       {
+               memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
+               src += save_pitch;
+               dest += Buf->Pitch;
+       }
+       
+       // Set the cursor as removed
+       Buf->CursorX = -1;
+}
+
+void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+
+       switch( FBInfo->Depth )
+       {
+       case 32: {
+               // TODO: Be less hacky
+               size_t  pitch = FBInfo->Pitch/4;
+               size_t  ofs = Y*pitch + X;
+               Uint32  *buf = (Uint32*)FBInfo->Framebuffer + ofs;
+               Uint32  *cbuf = NULL;
+               if( FBInfo->BackBuffer )
+                       cbuf = (Uint32*)FBInfo->BackBuffer + ofs;
+               while( H -- )
+               {
+                       Uint32 *line;
+                       line = buf;
+                       for(int i = W; i--; line++)
+                               *line = Colour;
+                       buf += pitch;
+                       if( cbuf ) {
+                               line = cbuf;
+                               for(int i = W; i--; line++ )
+                                       *line = Colour;
+                               cbuf += pitch;
+                       }
+               }
+               break; }
+       default:
+               // TODO: Handle non-32bit modes
+               Log_Warning("DrvUtil", "TODO: <32bpp _Fill");
+               break;
+       }
+}
+
+void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+       tDrvUtil_Video_BufInfo  *FBInfo = Ent;
+        int    scrnpitch = FBInfo->Pitch;
+        int    bytes_per_px = (FBInfo->Depth + 7) / 8;
+        int    dst = DstY*scrnpitch + DstX;
+        int    src = SrcY*scrnpitch + SrcX;
+        int    tmp;
+       Uint8   *framebuffer = FBInfo->Framebuffer;
+       Uint8   *backbuffer = FBInfo->BackBuffer;
+       Uint8   *sourcebuffer = (FBInfo->BackBuffer ? FBInfo->BackBuffer : FBInfo->Framebuffer);
+       
+       //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
+       //      Ent, DstX, DstY, SrcX, SrcY, W, H);
+       
+       if(SrcX + W > FBInfo->Width)    W = FBInfo->Width - SrcX;
+       if(DstX + W > FBInfo->Width)    W = FBInfo->Width - DstX;
+       if(SrcY + H > FBInfo->Height)   H = FBInfo->Height - SrcY;
+       if(DstY + H > FBInfo->Height)   H = FBInfo->Height - DstY;
+       
+       //Debug("W = %i, H = %i", W, H);
+       
+       if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px)
+       {
+               memmove(framebuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
+               if( backbuffer )
+                       memmove(backbuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
+       }
+       else if( dst > src )
+       {
+               // Reverse copy
+               dst += H*scrnpitch;
+               src += H*scrnpitch;
+               while( H -- )
+               {
+                       dst -= scrnpitch;
+                       src -= scrnpitch;
+                       tmp = W*bytes_per_px;
+                       for( tmp = W; tmp --; )
+                       {
+                               size_t  src_o = src + tmp;
+                               size_t  dst_o = src + tmp;
+                               framebuffer[dst_o] = sourcebuffer[src_o];
+                               if( backbuffer )
+                                       backbuffer[dst_o] = sourcebuffer[src_o];
+                       }
+               }
+       }
+       else {
+               // Normal copy is OK
+               while( H -- )
+               {
+                       memcpy(framebuffer + dst, sourcebuffer + src, W*bytes_per_px);
+                       if( backbuffer )
+                               memcpy(backbuffer + dst, sourcebuffer + src, W*bytes_per_px);
+                       dst += scrnpitch;
+                       src += scrnpitch;
+               }
+       }
+       //Log("Vesa_2D_Blit: RETURN");
+}
+       
+
index eefd13c..be8eeaf 100644 (file)
@@ -153,8 +153,8 @@ void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
        size_t  Bytes;
 
        if( __Bytes == 0 ) {
-               //return NULL;  // TODO: Return a known un-mapped range.
-               return INVLPTR;
+               return NULL;    // TODO: Return a known un-mapped range.
+//             return INVLPTR;
        }
        
        // Get required size
@@ -182,7 +182,8 @@ void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
                #endif
                        Mutex_Release(&glHeap); // Release spinlock
                        #if WARNINGS
-                       Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
+                       Log_Warning("Heap", "Size of heap address %p is invalid - not aligned (0x%x) [at paddr 0x%x]",
+                               head, head->Size, MM_GetPhysAddr(&head->Size));
                        Heap_Dump();
                        #endif
                        return NULL;
@@ -307,7 +308,7 @@ void Heap_Deallocate(void *Ptr)
        // Sanity check
        if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
        {
-               Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)\n",
+               Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)",
                        __builtin_return_address(0), gHeapStart, Ptr, gHeapEnd);
                return;
        }
@@ -511,14 +512,19 @@ void Heap_Dump(void)
 {
        tHeapHead       *head, *badHead;
        tHeapFoot       *foot = NULL;
+       static int      in_heap_dump;
        
+       if( in_heap_dump )      return;
+
+       in_heap_dump = 1;
+
        head = gHeapStart;
        while( (Uint)head < (Uint)gHeapEnd )
        {               
                foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
                #if VERBOSE_DUMP
                Log_Log("Heap", "%p (0x%P): 0x%08x (%i) %4C",
-                       head, MM_GetPhysAddr((tVAddr)head), head->Size, head->ValidSize, &head->Magic);
+                       head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
                Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
                if(head->File) {
                        Log_Log("Heap", "%sowned by %s:%i",
@@ -559,16 +565,20 @@ void Heap_Dump(void)
        }
        
        // If the heap is valid, ok!
-       if( (tVAddr)head == (tVAddr)gHeapEnd )
+       if( (tVAddr)head == (tVAddr)gHeapEnd ) {
+               in_heap_dump = 0;
                return ;
+       }
        
        // Check for a bad return
-       if( (tVAddr)head >= (tVAddr)gHeapEnd )
+       if( (tVAddr)head >= (tVAddr)gHeapEnd ) {
+               in_heap_dump = 0;
                return ;
+       }
 
        #if !VERBOSE_DUMP
        Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
-               head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+               head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
        if(foot)
                Log_Log("Heap", "Foot %p = {Head:%p,Magic:%4C}", foot, foot->Head, &foot->Magic);
        if(head->File) {
@@ -588,7 +598,7 @@ void Heap_Dump(void)
        while( (tVAddr)head >= (tVAddr)badHead )
        {
                Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
-                       head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+                       head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
                Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
                if(head->File)
                        Log_Log("Heap", "%sowned by %s:%i",
@@ -668,10 +678,10 @@ void Heap_Stats(void)
                #if 1
                if( head->Magic == MAGIC_FREE )
                        Log_Debug("Heap", "%p (%P) - 0x%x free",
-                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size);
+                               head->Data, MM_GetPhysAddr(&head->Data), head->Size);
                else
                        Log_Debug("Heap", "%p (%P) - 0x%x (%i) Owned by %s:%i (%lli ms old)",
-                               head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size, head->ValidSize, head->File, head->Line,
+                               head->Data, MM_GetPhysAddr(&head->Data), head->Size, head->ValidSize, head->File, head->Line,
                                now() - head->AllocateTime
                                );
                #endif
index c8cff88..41854a9 100644 (file)
@@ -15,6 +15,8 @@
 #define PACKED __attribute__((packed))
 //! Mark a function as not returning
 #define NORETURN       __attribute__((noreturn))
+//! Mark a function that its return value should be used
+#define WARN_UNUSED_RET        __attribute__((warn_unused_result))
 //! Mark a function (or variable) as deprecated
 #define DEPRECATED     __attribute__((deprecated))
 //! Mark a parameter as unused
@@ -60,7 +62,8 @@ typedef Uint64        off_t;  //!< VFS Offset
 
 extern char    __buildnum[];
 #define BUILD_NUM      ((int)(Uint)&__buildnum)
-extern const char gsGitHash[];
+extern const char      gsGitHash[];
+extern const char      gsBuildInfo[];
 
 #define VER2(major,minor)      ((((major)&0xFF)<<8)|((minor)&0xFF))
 /**
@@ -252,7 +255,7 @@ extern int  MM_Map(tVAddr VAddr, tPAddr PAddr);
  * \param Addr Address of the page to get the physical address of
  * \return Physical page mapped at \a Addr
  */
-extern tPAddr  MM_GetPhysAddr(tVAddr Addr);
+extern tPAddr  MM_GetPhysAddr(const void *Addr);
 /**
  * \brief Set the access flags on a page
  * \param VAddr        Virtual address of the page
@@ -278,12 +281,12 @@ extern Uint       MM_GetFlags(tVAddr VAddr);
  * \return Virtual address of page in memory
  * \note There is only a limited ammount of slots avaliable
  */
-extern tVAddr  MM_MapTemp(tPAddr PAddr);
+extern void    *MM_MapTemp(tPAddr PAddr);
 /**
  * \brief Free a temporarily mapped page
  * \param VAddr        Allocate virtual addres of page
  */
-extern void    MM_FreeTemp(tVAddr VAddr);
+extern void    MM_FreeTemp(void *Ptr);
 /**
  * \brief Map a physcal address range into the virtual address space
  * \param PAddr        Physical address to map in
@@ -386,16 +389,21 @@ extern int        CheckMem(const void *Mem, int Num);
 #ifdef __BIG_ENDIAN__
 #define        LittleEndian16(_val)    SwapEndian16(_val)
 #define        LittleEndian32(_val)    SwapEndian32(_val)
+#define        LittleEndian64(_val)    SwapEndian32(_val)
 #define        BigEndian16(_val)       (_val)
 #define        BigEndian32(_val)       (_val)
+#define        BigEndian64(_val)       (_val)
 #else
 #define        LittleEndian16(_val)    (_val)
 #define        LittleEndian32(_val)    (_val)
+#define        LittleEndian64(_val)    (_val)
 #define        BigEndian16(_val)       SwapEndian16(_val)
 #define        BigEndian32(_val)       SwapEndian32(_val)
+#define        BigEndian64(_val)       SwapEndian64(_val)
 #endif
 extern Uint16  SwapEndian16(Uint16 Val);
 extern Uint32  SwapEndian32(Uint32 Val);
+extern Uint64  SwapEndian64(Uint64 Val);
 /**
  * \}
  */
@@ -420,6 +428,7 @@ extern int  strucmp(const char *Str1, const char *Str2);
 extern char    *_strdup(const char *File, int Line, const char *Str);
 extern char    **str_split(const char *__str, char __ch);
 extern char    *strchr(const char *__s, int __c);
+extern char    *strrchr(const char *__s, int __c);
 extern int     strpos(const char *Str, char Ch);
 extern int     strpos8(const char *str, Uint32 search);
 extern void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
@@ -437,6 +446,8 @@ extern int  UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
  * \}
  */
 
+#include <ctype.h>
+
 /**
  * \brief Get a random number
  * \return Random number
@@ -477,10 +488,12 @@ extern int        Module_LoadFile(const char *Path, const char *ArgStr);
  */
 /**
  * \brief Create a timestamp from a time
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
  */
 extern tTime   timestamp(int sec, int mins, int hrs, int day, int month, int year);
 /**
  * \brief Extract the date/time from a timestamp
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
  */
 extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
 /**
@@ -496,7 +509,7 @@ extern Sint64       now(void);
  * \name Threads and Processes
  * \{
  */
-extern int     Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
+extern struct sThread  *Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
 extern int     Proc_Spawn(const char *Path);
 extern int     Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
 extern int     Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
index c37dfec..bde78ab 100644 (file)
@@ -161,8 +161,8 @@ typedef Uint        (*tDrvUtil_Write_Callback)(Uint64 Address, Uint Count, const void *
  * \param Argument     An argument to pass to \a ReadBlocks\r
  * \return Number of bytes read\r
  */\r
-extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
-       tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument);\r
+extern size_t DrvUtil_ReadBlock(Uint64 Start, size_t Length, void *Buffer,\r
+       tDrvUtil_Read_Callback ReadBlocks, size_t BlockSize, void *Argument);\r
 /**\r
  * \brief Writes a range to a block device using aligned writes\r
  * \param Start        Base byte offset\r
@@ -174,9 +174,9 @@ extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
  * \param Argument     An argument to pass to \a ReadBlocks and \a WriteBlocks\r
  * \return Number of bytes written\r
  */\r
-extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
+extern size_t DrvUtil_WriteBlock(Uint64 Start, size_t Length, const void *Buffer,\r
        tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
-       Uint64 BlockSize, void *Argument);\r
+       size_t BlockSize, void *Argument);\r
 \r
 /**\r
  * \}\r
index ff9c395..43d91d7 100644 (file)
@@ -341,6 +341,10 @@ typedef struct sDrvUtil_Video_BufInfo
         * \brief Bit depth of the framebuffer\r
         */\r
        short   Depth;\r
+       /**\r
+        * \brief Cached copy of the screens state (only used if not NULL)\r
+        */\r
+       void    *BackBuffer;\r
        /*\r
         * \}\r
         */\r
diff --git a/KernelLand/Kernel/include/bootmod.h b/KernelLand/Kernel/include/bootmod.h
new file mode 100644 (file)
index 0000000..0979389
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ * 
+ * include/bootmod.h
+ * - Common boot modules type
+ */
+#ifndef _BOOTMOD_H_
+#define _BOOTMOD_H_
+
+typedef struct sBootModule     tBootModule;
+
+struct sBootModule {
+       tPAddr  PBase;
+       void    *Base;
+       Uint    Size;
+       char    *ArgString;
+};
+
+#endif
+
diff --git a/KernelLand/Kernel/include/ctype.h b/KernelLand/Kernel/include/ctype.h
new file mode 100644 (file)
index 0000000..2db66c9
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Acess2 Kernel 
+ * - By John Hodge (thePowersGang)
+ * 
+ * ctype.h
+ * - 
+ */
+#ifndef _ACESS__CTYPE_H_
+#define _ACESS__CTYPE_H_
+
+extern int     isalnum(int c);
+extern int     isalpha(int c);
+extern int     isascii(int c);
+extern int     isblank(int c);
+extern int     iscntrl(int c);
+extern int     isdigit(int c);
+extern int     isgraph(int c);
+extern int     islower(int c);
+extern int     isprint(int c);
+extern int     ispunct(int c);
+extern int     isspace(int c);
+extern int     isupper(int c);
+extern int     isxdigit(int c);
+
+extern int     toupper(int c);
+extern int     tolower(int c);
+
+#endif
+
index 3652f19..31f68a0 100644 (file)
@@ -13,6 +13,7 @@ enum eErrorNums
        EINVAL, // Invalid Paramater
        ENOMEM, // No free memory
        EACCES, // Not permitted
+       EBUSY,  // Resource is busy
        ENOTFOUND,      // Item not found
        EREADONLY,      // Read only
        ENOTIMPL,       // Not implemented
@@ -20,6 +21,8 @@ enum eErrorNums
        EEXIST, // Already exists
        ENFILE, // Too many open files
        ENOTDIR,        // Not a directory
+       EIO,    // IO Error
+       EINTR,  // Operation interrupted (signal)
        
        EALREADY,       // Operation was a NOP
        EINTERNAL,      // Internal Error
index 5770940..dc9d654 100644 (file)
 
 #include <threads.h>
 
+/**
+ * \name Event Values
+ * \{
+ */
+//! Fired when a VFS wait is ready [used in select(2)]
 #define THREAD_EVENT_VFS       0x00000001
+//! Fired when an IPC Message arrives
 #define THREAD_EVENT_IPCMSG    0x00000002
+//! Fired when a signal (e.g. SIGINT) is asserted
 #define THREAD_EVENT_SIGNAL    0x00000004
+//! Timer event fire
 #define THREAD_EVENT_TIMER     0x00000008
+//! General purpose event for short waits
+//! e.g. waiting for an IRQ in a Read() call
 #define THREAD_EVENT_SHORTWAIT 0x00000010
 
+#define THREAD_EVENT_USER1     0x10000000
+#define THREAD_EVENT_USER2     0x20000000
+#define THREAD_EVENT_USER3     0x40000000
+#define THREAD_EVENT_USER4     0x80000000
+/**
+ * \}
+ */
+
 // === FUNCTIONS ===
 extern void    Threads_PostEvent(tThread *Thread, Uint32 EventMask);
 extern void    Threads_ClearEvent(Uint32 EventMask);
index 0f21a1c..5c03bda 100644 (file)
@@ -13,6 +13,7 @@
  * \brief Achitecture defined thread/process management functions
  */
 
+#include <threads.h>
 #include <threads_int.h>
 
 /**
@@ -84,6 +85,11 @@ extern void  MM_ClearUser(void);
  */
 extern void    MM_DumpTables(tVAddr Start, tVAddr End);
 
+/**
+ * \brief Dump physical memory usage statistics to the debug channel
+ */
+extern void    MM_DumpStatistics(void);
+
 /**
  * \brief Check if a buffer is valid (and all user if originally user)
  * \param Addr Base address
index 9f2fc10..6af177d 100644 (file)
@@ -7,5 +7,7 @@
 
 extern void    Arch_LoadBootModules(void);
 extern void    StartupPrint(const char *String);
+extern void    System_Init(char *Commandline);
+extern void    Threads_Init(void);
 
 #endif
index c7f33dd..61c689b 100644 (file)
@@ -4,9 +4,13 @@
  */
 #ifndef _MBOOT_H
 #define _MBOOT_H
+#include <acess.h>
 
 #define MULTIBOOT_MAGIC        0x2BADB002
 
+#include <pmemmap.h>
+#include <bootmod.h>
+
 // === TYPES ===
 typedef struct {
        Uint32  Flags;
@@ -35,4 +39,7 @@ typedef struct {
        Uint32  Type;   //1:RAM,Else Reserved
 } __attribute__ ((packed)) tMBoot_MMapEnt;
 
+extern int     Multiboot_LoadMemoryMap(tMBoot_Info *MBInfo, tVAddr MapOffset, tPMemMapEnt *Map, const int MapSize, tPAddr KStart, tPAddr KEnd);
+extern tBootModule     *Multiboot_LoadModules(tMBoot_Info *MBInfo, tVAddr MapOffset, int *ModuleCount);
+
 #endif
index d728133..1c56146 100644 (file)
@@ -73,7 +73,7 @@ typedef struct sModule
        struct sModule  *Next;  //!< Next module in list (not to be touched by the driver)
        const char      *Name;  //!< Module Name/Identifier
         int    (*Init)(char **Arguments);      //!< Module initialiser / entrypoint
-       void    (*Deinit)(void);        //!< Cleanup Function
+        int    (*Deinit)(void);        //!< Cleanup Function
        const char      **Dependencies; //!< NULL terminated list of dependencies
 } PACKED tModule;
 
diff --git a/KernelLand/Kernel/include/pmemmap.h b/KernelLand/Kernel/include/pmemmap.h
new file mode 100644 (file)
index 0000000..4b89e45
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * pmemmap.h
+ * - Physical Memory Map definitions
+ */
+#ifndef _PMEMMAP_H_
+#define _PMEMMAP_H_
+
+typedef struct sPMemMapEnt     tPMemMapEnt;
+
+enum ePMemMapEntType
+{
+       PMEMTYPE_FREE,  // Free RAM
+       PMEMTYPE_USED,  // Used by Kernel / Modules
+       PMEMTYPE_RESERVED,      // Unavaliable
+       PMEMTYPE_NVRAM, // Non-volatile
+       PMEMTYPE_UNMAPPED       // Nothing on these lines
+};
+
+struct sPMemMapEnt
+{
+       Uint64  Start;
+       Uint64  Length;
+       enum ePMemMapEntType    Type;
+       Uint16  NUMADomain;
+};
+
+extern void    PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts);
+extern int     PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset);
+extern int     PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts);
+extern int     PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts);
+extern int     PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size);
+
+#endif
+
diff --git a/KernelLand/Kernel/include/rwlock.h b/KernelLand/Kernel/include/rwlock.h
new file mode 100644 (file)
index 0000000..e0d4207
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Acess2 Kernel
+ * 
+ * rwmutex.c
+ * - Reader-Writer Mutex (Multiple Readers, One Writer)
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+#include <acess.h>
+
+typedef struct sRWLock tRWLock;
+
+struct sRWLock
+{
+       tShortSpinlock  Protector;      //!< Protector for the lock strucure
+       const char      *Name;  //!< Human-readable name
+        int    Level;  // Number of readers active
+       struct sThread  *volatile Owner;        //!< Owner of the lock (set upon getting the lock)
+       struct sThread  *ReaderWaiting;         //!< Waiting threads (readers)
+       struct sThread  *ReaderWaitingLast;     //!< Waiting threads
+       
+       struct sThread  *WriterWaiting;         //!< Waiting threads (writers)
+       struct sThread  *WriterWaitingLast;     //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex        Mutex to acquire
+ * \return zero on success, -1 if terminated
+ * 
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int     RWLock_AcquireRead(tRWLock *Lock);
+
+extern int     RWLock_AcquireWrite(tRWLock *Lock);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex        Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void    RWLock_Release(tRWLock *Lock);
+
+#endif
index 6e345d0..578fdcf 100644 (file)
@@ -1,5 +1,9 @@
 /*
- * Internal Threading header
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/threads_int.h
+ * - Internal Threading header
  * - Only for use by stuff that needs access to the thread type.
  */
 #ifndef _THREADS_INT_H_
@@ -7,6 +11,7 @@
 
 #include <threads.h>
 #include <proc.h>
+#include <timers_int.h>
 
 typedef struct sProcess        tProcess;
 
@@ -92,14 +97,17 @@ struct sThread
        
        // --- event.c
        Uint32  EventState;
+       // --- timer.c
+       tTimer  ThreadTimer;
 };
 
 
-enum {
+enum eThreadStatus {
        THREAD_STAT_NULL,       // Invalid process
        THREAD_STAT_ACTIVE,     // Running and schedulable process
        THREAD_STAT_SLEEPING,   // Message Sleep
        THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+       THREAD_STAT_RWLOCKSLEEP,        // Read-Writer lock Sleep
        THREAD_STAT_SEMAPHORESLEEP,     // Semaphore Sleep
        THREAD_STAT_QUEUESLEEP, // Queue
        THREAD_STAT_EVENTSLEEP, // Event sleep
diff --git a/KernelLand/Kernel/include/timers_int.h b/KernelLand/Kernel/include/timers_int.h
new file mode 100644 (file)
index 0000000..85a52ec
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/timers_int.h
+ * - Timer internal header
+ * - Only for use by code that needs access to timer internals
+ */
+#ifndef _KERNEL__TIMERS_INT_H_
+#define _KERNEL__TIMERS_INT_H_
+
+#include <timers.h>
+
+// === TYPEDEFS ===
+struct sTimer {
+       tTimer  *Next;
+       Sint64  FiresAfter;
+       void    (*Callback)(void*);
+       void    *Argument;
+//     tMutex  Lock;
+       BOOL    bActive;
+};
+
+#endif
+
index 39444d9..005a2f8 100644 (file)
@@ -27,6 +27,7 @@
  int   MM_int_GetRangeID( tPAddr Addr );
  int   MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length );
 void   MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap);
+void   MM_DumpStatistics(void);
 
 // === GLOBALS ===
 tMutex glPhysicalPages;
@@ -82,7 +83,7 @@ void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap)
                bitmap_page &= ~(PAGE_SIZE-1);
 
                // Only need to allocate bitmaps
-               if( !MM_GetPhysAddr( bitmap_page ) ) {
+               if( !MM_GetPhysAddr( (void*)bitmap_page ) ) {
                        if( !MM_Allocate( bitmap_page ) ) {
                                Log_KernelPanic("PMM", "Out of memory during init, this is bad");
                                return ;
@@ -112,6 +113,11 @@ void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap)
        LEAVE('-');
 }
 
+void MM_DumpStatistics(void)
+{
+       // TODO: PM Statistics for tpl_mm_phys_bitmap
+}
+
 /**
  * \brief Allocate a contiguous range of physical pages with a maximum
  *        bit size of \a MaxBits
@@ -214,7 +220,7 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
        
                LOG("if( MM_GetPhysAddr( %p ) )", &gaiPageReferences[addr]);
                // Mark as referenced if the reference count page is valid      
-               if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) ) {
+               if( MM_GetPhysAddr( &gaiPageReferences[addr] ) ) {
                        gaiPageReferences[addr] = 1;
                }
        }
@@ -270,7 +276,7 @@ tPAddr MM_AllocPhys(void)
                tPAddr  ret = 0;
                for( ret = 0; ret < giMaxPhysPage; ret ++ )
                {
-                       if( !MM_GetPhysAddr( (tVAddr)&gaPageBitmaps[ret/32] ) ) {
+                       if( !MM_GetPhysAddr( &gaPageBitmaps[ret/32] ) ) {
                                ret += PAGE_SIZE*8;
                                continue ;
                        }
@@ -311,13 +317,13 @@ void MM_RefPhys(tPAddr PAddr)
                if( gaPageBitmaps[page / 32] == 0 )
                        gaSuperBitmap[page / (32*32)] &= ~(1LL << ((page / 32) & 31));
                #endif
-               if( MM_GetPhysAddr( refpage ) )
+               if( MM_GetPhysAddr( (void*)refpage ) )
                        gaiPageReferences[page] = 1;
        }
        else
        {
                // Reference again
-               if( !MM_GetPhysAddr( refpage ) )
+               if( !MM_GetPhysAddr( (void*)refpage ) )
                {
                         int    pages_per_page, basepage, i;
                        if( MM_Allocate(refpage) == 0 ) {
@@ -344,7 +350,7 @@ void MM_RefPhys(tPAddr PAddr)
 int MM_GetRefCount(tPAddr PAddr)
 {
        PAddr >>= 12;
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+       if( MM_GetPhysAddr( &gaiPageReferences[PAddr] ) ) {
                return gaiPageReferences[PAddr];
        }
        
@@ -366,7 +372,7 @@ void MM_DerefPhys(tPAddr PAddr)
 
        ENTER("PPAddr", PAddr);
        
-       if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+       if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
        {
                if( gaiPageReferences[page] > 0 )
                        gaiPageReferences[ page ] --;
@@ -378,7 +384,7 @@ void MM_DerefPhys(tPAddr PAddr)
        else
                gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
        // Clear node if needed
-       if( MM_GetPhysAddr( (tVAddr)&gapPageNodes[page] ) ) {
+       if( MM_GetPhysAddr( &gapPageNodes[page] ) ) {
                gapPageNodes[page] = NULL;
                // TODO: Catch when all pages in this range are not using nodes
        }
@@ -409,7 +415,7 @@ int MM_SetPageNode(tPAddr PAddr, void *Node)
 
        if( !MM_GetRefCount(PAddr) )    return 1;
        
-       if( !MM_GetPhysAddr(node_page) ) {
+       if( !MM_GetPhysAddr( (void*)node_page ) ) {
                if( !MM_Allocate(node_page) )
                        return -1;
                memset( (void*)node_page, 0, PAGE_SIZE );
@@ -424,7 +430,7 @@ int MM_GetPageNode(tPAddr PAddr, void **Node)
        if( !MM_GetRefCount(PAddr) )    return 1;
        PAddr >>= 12;
        
-       if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+       if( !MM_GetPhysAddr( &gapPageNodes[PAddr] ) ) {
                *Node = NULL;
                return 0;
        }
index 46ceb97..567cfaf 100644 (file)
@@ -78,6 +78,11 @@ void MM_Tpl_InitPhys(int MaxRAMPage)
        LEAVE('-');
 }
 
+void MM_DumpStatistics(void)
+{
+       // TODO: PM Statistics for tpl_mm_phys_bitmap
+}
+
 /**
  * \brief Allocate a contiguous range of physical pages with a maximum
  *        bit size of \a MaxBits
index 7d0a26d..59824e2 100644 (file)
@@ -20,6 +20,7 @@
 #define _VFS_H
 
 #include <acess.h>
+#include <mutex.h>
 
 /**
  * \brief Thread list datatype for VFS_Select
@@ -77,7 +78,15 @@ typedef struct sVFS_NodeType tVFS_NodeType;
  * is unmapped. Nice for read-only files and memory-only files (or 
  * pseudo-readonly filesystems)
  */
-#define VFS_FFLAG_NOWRITEBACK
+#define VFS_FFLAG_NOWRITEBACK  0x1000
+
+/**
+ * \brief "Dirty Metadata" Flag
+ *
+ * Indicates that the node's metadata has been altered since the flag was last
+ * cleared. Tells the driver that it should update the inode at the next flush.
+ */
+#define VFS_FFLAG_DIRTY        0x8000
 /**
  * \}
  */
@@ -90,6 +99,11 @@ typedef struct sVFS_NodeType tVFS_NodeType;
  */
 typedef struct sVFS_Node
 {
+       /**
+        * \brief Functions associated with the node
+        */
+       tVFS_NodeType   *Type;
+       
        /**
         * \name Identifiers
         * \brief Fields used by the driver to identify what data this node
@@ -178,11 +192,6 @@ typedef struct sVFS_Node
        /**
         * \}
         */
-       
-       /**
-        * \brief Functions associated with the node
-        */
-       tVFS_NodeType   *Type;
 } tVFS_Node;
 
 /**
@@ -286,40 +295,36 @@ struct sVFS_NodeType
         * \brief Read from a directory
         * \param Node  Pointer to this node
         * \param Pos   Offset in the directory
-        * \return Pointer to the name of the item on the heap (will be freed
-        *         by the caller). If the directory end has been reached, NULL
-        *         will be returned.
-        *         If an item is required to be skipped either &::NULLNode,
-        *         ::VFS_SKIP or ::VFS_SKIPN(0...1023) will be returned.
+        * \param Dest  Destination for filename
+        * \return Zero on success, negative on error or +ve for ignore entry
         */
-       char    *(*ReadDir)(struct sVFS_Node *Node, int Pos);
+        int    (*ReadDir)(struct sVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
        
        /**
         * \brief Create a node in a directory
         * \param Node  Pointer to this node
         * \param Name  Name of the new child
         * \param Flags Flags to apply to the new child (directory or symlink)
-        * \return Zero on Success, non-zero on error (see errno.h)
+        * \return Created node or NULL on error
         */
-        int    (*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
+       tVFS_Node       *(*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
        
        /**
         * \brief Relink (Rename/Remove) a file/directory
         * \param Node  Pointer to this node
         * \param OldName       Name of the item to move/delete
-        * \param NewName       New name (or NULL if unlinking is wanted)
         * \return Zero on Success, non-zero on error (see errno.h)
         */
-        int    (*Relink)(struct sVFS_Node *Node, const char *OldName, const char *NewName);
+        int    (*Unlink)(struct sVFS_Node *Node, const char *OldName);
        
        /**
         * \brief Link a node to a name
         * \param Node  Pointer to this node (directory)
-        * \param Child Node to create a new link to
         * \param NewName       Name for the new link
+        * \param Child Node to create a new link to
         * \retur Zeron on success, non-zero on error (see errno.h)
         */
-        int    (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
+        int    (*Link)(struct sVFS_Node *Node, const char *NewName, struct sVFS_Node *Child);
         
         /**
          * \}
@@ -340,6 +345,15 @@ typedef struct sVFS_Driver
         */
        Uint    Flags;
        
+       /**
+        * \brief Detect if a volume is accessible using this driver
+        * \return Boolean success (with higher numbers being higher priority)
+        *
+        * E.g. FAT would return 1 as it's the lowest common denominator while ext2 might return 2,
+        * because it can be embedded in a FAT volume (and is a more fully featured filesystem).
+        */
+        int    (*Detect)(int FD);
+
        /**
         * \brief Callback to mount a device
         */
@@ -487,8 +501,9 @@ extern tVFS_Node    *Inode_CacheNode(int Handle, tVFS_Node *Node);
  * \brief Dereferences (and removes if needed) a node from the cache
  * \param Handle       A handle returned by Inode_GetHandle()
  * \param Inode        Value of the Inode field of the ::tVFS_Node you want to remove
+ * \return -1: Error (not present), 0: Not freed, 1: Freed
  */
-extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
+extern int     Inode_UncacheNode(int Handle, Uint64 Inode);
 /**
  * \fn void Inode_ClearCache(int Handle)
  * \brief Clears the cache for a handle
index b4d5e2a..44c70f8 100644 (file)
@@ -13,6 +13,7 @@ typedef Uint64        tInode;
 typedef Uint32 tMount;
 
 // === CONSTANTS ===
+#define FILENAME_MAX   256
 //! Maximum size of a Memory Path generated by VFS_GetMemPath
 #define        VFS_MEMPATH_SIZE        (3 + (BITS/4)*2)
 /**
@@ -29,6 +30,8 @@ typedef Uint32        tMount;
 #define        VFS_OPENFLAG_NOLINK     0x40
 //! Create the file if it doesn't exist
 #define VFS_OPENFLAG_CREATE    0x80
+//! Treat as a directory
+#define VFS_OPENFLAG_DIRECTORY 0x100
 //! Open as a user
 #define        VFS_OPENFLAG_USER       0x8000
 /**
@@ -274,7 +277,7 @@ extern Uint64       VFS_Tell(int FD);
  * \param Buffer       Destination of read data
  * \return Number of read bytes
  */
-extern Uint64  VFS_Read(int FD, Uint64 Length, void *Buffer);
+extern size_t  VFS_Read(int FD, size_t Length, void *Buffer);
 /**
  * \brief Writes data to a file
  * \param FD   File handle returned by ::VFS_Open
@@ -282,7 +285,7 @@ extern Uint64       VFS_Read(int FD, Uint64 Length, void *Buffer);
  * \param Buffer       Source of written data
  * \return Number of bytes written
  */
-extern Uint64  VFS_Write(int FD, Uint64 Length, const void *Buffer);
+extern size_t  VFS_Write(int FD, size_t Length, const void *Buffer);
 
 /**
  * \brief Reads from a specific offset in the file
@@ -292,7 +295,7 @@ extern Uint64       VFS_Write(int FD, Uint64 Length, const void *Buffer);
  * \param Buffer       Source of read data
  * \return Number of bytes read
  */
-extern Uint64  VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
+extern size_t  VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer);
 /**
  * \brief Writes to a specific offset in the file
  * \param FD   File handle returned by ::VFS_Open
@@ -301,7 +304,7 @@ extern Uint64       VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
  * \param Buffer       Source of written data
  * \return Number of bytes written
  */
-extern Uint64  VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer);
+extern size_t  VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer);
 
 /**
  * \brief Sends an IOCtl request to the driver
@@ -336,6 +339,19 @@ extern char        *VFS_GetTruePath(const char *Path);
  * \return 1 on succes, -1 on error
  */
 extern int     VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
+/**
+ * \brief Unmount a mounted filesystem
+ * \param Mountpoint   Location of the mount
+ * \return 0 on success, errno on error
+ */
+extern int     VFS_Unmount(const char *Mountpoint);
+/**
+ * \brief Attemt to unmount all fileystems
+ * \return Number of unmounted filesytems, -1 if none left to unmount
+ * \note Can return 0 when there are stil volumes mounted if there are open handles
+ */
+extern int     VFS_UnmountAll(void);
+
 /**
  * \brief Create a new directory
  * \param Path Path to new directory (absolute or relative)
@@ -353,10 +369,10 @@ extern int        VFS_Symlink(const char *Name, const char *Link);
 /**
  * \brief Read from a directory
  * \param FD   File handle returned by ::VFS_Open
- * \param Dest Destination array for the file name (max 255 bytes)
+ * \param Dest Destination array for the file name (max FILENAME_MAX bytes)
  * \return Boolean Success
  */
-extern int     VFS_ReadDir(int FD, char *Dest);
+extern int     VFS_ReadDir(int FD, char Dest[FILENAME_MAX]);
 /**
  * \brief Wait for an aciton on a file descriptor
  * \param MaxHandle    Maximum set handle in \a *Handles
index a8eadb6..232c55e 100644 (file)
@@ -5,6 +5,7 @@
 #define _VFS_INT_H
 
 #include "vfs.h"
+#include <rwlock.h>
 
 // === TYPES ===
 typedef struct sVFS_Mount {
@@ -16,6 +17,9 @@ typedef struct sVFS_Mount {
        char    *Options;
        tVFS_Driver     *Filesystem;
        tVFS_Node       *RootNode;
+       
+        int    OpenHandleCount;
+       
        char    StrData[];
 } tVFS_Mount;
 
@@ -42,9 +46,12 @@ typedef struct sVFS_MMapPage {
 } tVFS_MMapPage;
 
 // === GLOBALS ===
+extern tRWLock         glVFS_MountList;
 extern tVFS_Mount      *gVFS_Mounts;
+extern tVFS_Driver     *gVFS_Drivers;
 
 // === PROTOTYPES ===
+extern void    VFS_Deinit(void);
 // --- open.c ---
 extern char    *VFS_GetAbsPath(const char *Path);
 extern tVFS_Node       *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint);
diff --git a/KernelLand/Kernel/include/virtual_pci.h b/KernelLand/Kernel/include/virtual_pci.h
new file mode 100644 (file)
index 0000000..c6408cd
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ * 
+ * virtual_pci.h
+ * - Virtual PCI bus definitions
+ */
+#ifndef _VIRTUAL_PCI_H_
+#define _VIRTUAL_PCI_H_
+#include <acess.h>
+
+typedef struct sVPCI_Device    tVPCI_Device;
+
+struct sVPCI_Device
+{
+       void    *Ptr;
+
+       // Vendor/Device is defined at runtime as 0x0ACE:0x[ARCH][ARCH][IDX][IDX]
+       Uint16  Vendor;
+       Uint16  Device;
+       // Class code (Class, Subclass, Programming Interface, Revision)
+       Uint32  Class;
+       
+       Uint32  BARs[6];
+       Uint8   IRQ;
+       
+       /**
+        * \param Ptr   Value in sVPCI_Device.Ptr
+        * \param Data  Data to write to the specified address
+        */
+       void    (*Write)(void *Ptr, Uint8 DWord, Uint32 Data);
+       Uint32  (*Read)(void *Ptr, Uint8 DWord);
+};
+
+extern int     giVPCI_DeviceCount;
+extern tVPCI_Device    gaVPCI_Devices[];
+
+extern Uint32  VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size);
+extern void    VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data);
+#endif
+
index 7356d6f..36b877c 100644 (file)
@@ -3,38 +3,15 @@
  * Common Library Functions
  */
 #include <acess.h>
-#include <hal_proc.h>
 
 // === CONSTANTS ===
-#define        RANDOM_SEED     0xACE55052
-#define        RANDOM_A        0x00731ADE
-#define        RANDOM_C        12345
-#define        RANDOM_SPRUCE   0xf12b039
 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
 #define UNIX_TO_2K     ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
 
 // === PROTOTYPES ===
 #if 0
- int   atoi(const char *string);
- int   ParseInt(const char *string, int *Val);
-void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
- int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
- int   snprintf(char *__s, size_t __n, const char *__format, ...);
- int   sprintf(char *__s, const char *__format, ...);
-#endif
- int   tolower(int c);
-#if 0
- int   strucmp(const char *Str1, const char *Str2);
-char   *strchr(const char *__s, int __c);
- int   strpos(const char *Str, char Ch);
  Uint8 ByteSum(void *Ptr, int Size);
-size_t strlen(const char *__s);
-char   *strcpy(char *__str1, const char *__str2);
-char   *strncpy(char *__str1, const char *__str2, size_t max);
- int   strcmp(const char *str1, const char *str2);
- int   strncmp(const char *str1, const char *str2, size_t num);
-char   *_strdup(const char *File, int Line, const char *Str);
 char   **str_split(const char *__str, char __ch);
  int   strpos8(const char *str, Uint32 Search);
  int   ReadUTF8(Uint8 *str, Uint32 *Val);
@@ -42,451 +19,35 @@ char       **str_split(const char *__str, char __ch);
  int   DivUp(int num, int dem);
 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
 void   format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
- int   rand(void);
- int   CheckString(char *String);
- int   CheckMem(void *Mem, int NumBytes);
  
  int   ModUtil_LookupString(char **Array, char *Needle);
  int   ModUtil_SetIdent(char *Dest, char *Value);
  
  int   Hex(char *Dest, size_t Size, const Uint8 *SourceData);
  int   UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
+
+Uint16 SwapEndian16(Uint16 Val);
+Uint32 SwapEndian32(Uint16 Val);
+Uint64 SwapEndian64(Uint16 Val);
 #endif
 
 // === EXPORTS ===
-EXPORT(atoi);
-EXPORT(itoa);
-EXPORT(vsnprintf);
-EXPORT(snprintf);
-EXPORT(sprintf);
-EXPORT(tolower);
-EXPORT(strucmp);
-EXPORT(strchr);
-EXPORT(strpos);
 EXPORT(ByteSum);
-EXPORT(strlen);
-EXPORT(strcpy);
-EXPORT(strncpy);
-EXPORT(strcat);
-EXPORT(strncat);
-EXPORT(strcmp);
-EXPORT(strncmp);
-//EXPORT(strdup);
-EXPORT(_strdup);       // Takes File/Line too
 EXPORT(str_split);
 EXPORT(strpos8);
 EXPORT(DivUp);
 EXPORT(ReadUTF8);
 EXPORT(WriteUTF8);
 EXPORT(timestamp);
-EXPORT(CheckString);
-EXPORT(CheckMem);
 EXPORT(ModUtil_LookupString);
 EXPORT(ModUtil_SetIdent);
+EXPORT(Hex);
 EXPORT(UnHex);
 EXPORT(SwapEndian16);
 EXPORT(SwapEndian32);
-EXPORT(memmove);
+EXPORT(SwapEndian64);
 
 // === CODE ===
-/**
- * \brief Convert a string into an integer
- */
-int atoi(const char *string)
-{
-       int ret = 0;
-       ParseInt(string, &ret);
-       return ret;
-}
-int ParseInt(const char *string, int *Val)
-{
-        int    ret = 0;
-        int    bNeg = 0;
-       const char *orig_string = string;
-       
-       //Log("atoi: (string='%s')", string);
-       
-       // Clear non-numeric characters
-       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
-       if( *string == '-' ) {
-               bNeg = 1;
-               while( !('0' <= *string && *string <= '9') )    string++;
-       }
-       
-       if(*string == '0')
-       {
-               string ++;
-               if(*string == 'x')
-               {
-                       // Hex
-                       string ++;
-                       for( ;; string ++ )
-                       {
-                               if('0' <= *string && *string <= '9') {
-                                       ret *= 16;
-                                       ret += *string - '0';
-                               }
-                               else if('A' <= *string && *string <= 'F') {
-                                       ret *= 16;
-                                       ret += *string - 'A' + 10;
-                               }
-                               else if('a' <= *string && *string <= 'f') {
-                                       ret *= 16;
-                                       ret += *string - 'a' + 10;
-                               }
-                               else
-                                       break;
-                       }
-               }
-               else    // Octal
-               {
-                       for( ; '0' <= *string && *string <= '7'; string ++ )
-                       {
-                               ret *= 8;
-                               ret += *string - '0';
-                       }
-               }
-       }
-       else    // Decimal
-       {
-               for( ; '0' <= *string && *string <= '9'; string++)
-               {
-                       ret *= 10;
-                       ret += *string - '0';
-               }
-               // Error check
-               if( ret == 0 )  return 0;
-       }
-       
-       if(bNeg)        ret = -ret;
-       
-       //Log("atoi: RETURN %i", ret);
-       
-       if(Val) *Val = ret;
-       
-       return string - orig_string;
-}
-
-static const char cUCDIGITS[] = "0123456789ABCDEF";
-/**
- * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
- * \brief Convert an integer into a character string
- */
-void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
-{
-       char    tmpBuf[64+1];
-        int    pos=0, i;
-       Uint64  rem;
-
-       // Sanity check
-       if(!buf)        return;
-       
-       // Sanity Check
-       if(base > 16 || base < 2) {
-               buf[0] = 0;
-               return;
-       }
-       
-       // Convert 
-       while(num > base-1) {
-               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
-               tmpBuf[pos] = cUCDIGITS[ rem ];
-               pos++;
-       }
-       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
-       
-       // Put in reverse
-       i = 0;
-       minLength -= pos;
-       while(minLength-- > 0)  buf[i++] = pad;
-       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
-       buf[i] = 0;
-}
-
-/**
- * \brief Append a character the the vsnprintf output
- */
-#define PUTCH(c)       _putch(c)
-#define GETVAL()       do {\
-       if(isLongLong)  val = va_arg(args, Uint64);\
-       else    val = va_arg(args, unsigned int);\
-       }while(0)
-/**
- * \brief VArg String Number Print Formatted
- */
-int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
-{
-       char    c, pad = ' ';
-        int    minSize = 0, precision = -1, len;
-       char    tmpBuf[34];     // For Integers
-       const char      *p = NULL;
-        int    isLongLong = 0;
-       Uint64  val;
-       size_t  pos = 0;
-       // Flags
-        int    bPadLeft = 0;
-       
-       auto void _putch(char ch);
-
-       void _putch(char ch)
-       {
-               if(pos < __maxlen)
-               {
-                       if(__s) __s[pos] = ch;
-                       pos ++;
-               }
-       }
-
-       while((c = *__format++) != 0)
-       {
-               // Non control character
-               if(c != '%') { PUTCH(c); continue; }
-
-               c = *__format++;
-               if(c == '\0')   break;
-               
-               // Literal %
-               if(c == '%') { PUTCH('%'); continue; }
-               
-               // Pointer - Done first for debugging
-               if(c == 'p') {
-                       Uint    ptr = va_arg(args, Uint);
-                       PUTCH('*');     PUTCH('0');     PUTCH('x');
-                       for( len = BITS/4; len --; )
-                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
-                       continue ;
-               }
-               
-               // - Padding Side Flag
-               if(c == '-') {
-                       bPadLeft = 1;
-                       c = *__format++;
-               }
-               
-               // - Padding
-               if(c == '0') {
-                       pad = '0';
-                       c = *__format++;
-               }
-               else
-                       pad = ' ';
-               
-               // - Minimum length
-               if(c == '*') {  // Dynamic length
-                       minSize = va_arg(args, unsigned int);
-                       c = *__format++;
-               }
-               else if('1' <= c && c <= '9')
-               {
-                       minSize = 0;
-                       while('0' <= c && c <= '9')
-                       {
-                               minSize *= 10;
-                               minSize += c - '0';
-                               c = *__format++;
-                       }
-               }
-               else
-                       minSize = 0;
-               
-               // - Precision
-               precision = -1;
-               if( c == '.' ) {
-                       c = *__format++;
-                       
-                       if(c == '*') {  // Dynamic length
-                               precision = va_arg(args, unsigned int);
-                               c = *__format++;
-                       }
-                       else if('1' <= c && c <= '9')
-                       {
-                               precision = 0;
-                               while('0' <= c && c <= '9')
-                               {
-                                       precision *= 10;
-                                       precision += c - '0';
-                                       c = *__format++;
-                               }
-                       }
-               }
-               
-               // - Default, Long or LongLong?
-               isLongLong = 0;
-               if(c == 'l')    // Long is actually the default on x86
-               {
-                       c = *__format++;
-                       if(c == 'l') {
-                               c = *__format++;
-                               isLongLong = 1;
-                       }
-               }
-               
-               // - Now get the format code
-               p = tmpBuf;
-               switch(c)
-               {
-               case 'd':
-               case 'i':
-                       GETVAL();
-                       if( isLongLong && val >> 63 ) {
-                               PUTCH('-');
-                               val = -val;
-                       }
-                       else if( !isLongLong && val >> 31 ) {
-                               PUTCH('-');
-                               val = -(Sint32)val;
-                       }
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'u':       // Unsigned
-                       GETVAL();
-                       itoa(tmpBuf, val, 10, minSize, pad);
-                       goto printString;
-               case 'P':       // Physical Address
-                       PUTCH('0');
-                       PUTCH('x');
-                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'X':       // Hex
-                       if(BITS == 64)
-                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-                       
-               case 'x':       // Lower case hex
-                       GETVAL();
-                       itoa(tmpBuf, val, 16, minSize, pad);
-                       goto printString;
-               case 'o':       // Octal
-                       GETVAL();
-                       itoa(tmpBuf, val, 8, minSize, pad);
-                       goto printString;
-               case 'b':
-                       GETVAL();
-                       itoa(tmpBuf, val, 2, minSize, pad);
-                       goto printString;
-
-               case 'B':       //Boolean
-                       val = va_arg(args, unsigned int);
-                       if(val) p = "True";
-                       else    p = "False";
-                       goto printString;
-               
-               // String - Null Terminated Array
-               case 's':
-                       p = va_arg(args, char*);        // Get Argument
-                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
-               printString:
-                       if(!p)          p = "(null)";
-                       len = strlen(p);
-                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
-                       while(*p && precision--)        PUTCH(*p++);
-                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
-                       break;
-               
-               case 'C':       // Non-Null Terminated Character Array
-                       p = va_arg(args, char*);
-                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
-                       if(!p)  goto printString;
-                       while(minSize--)        PUTCH(*p++);
-                       break;
-               
-               // Single Character
-               case 'c':
-               default:
-                       GETVAL();
-                       PUTCH( (Uint8)val );
-                       break;
-               }
-       }
-       
-       if(__s && pos != __maxlen)
-               __s[pos] = '\0';
-       
-       return pos;
-}
-#undef PUTCH
-
-/**
- */
-int snprintf(char *__s, size_t __n, const char *__format, ...)
-{
-       va_list args;
-        int    ret;
-       
-       va_start(args, __format);
-       ret = vsnprintf(__s, __n, __format, args);
-       va_end(args);
-       
-       return ret;
-}
-
-/**
- */
-int sprintf(char *__s, const char *__format, ...)
-{
-       va_list args;
-        int    ret;
-       
-       va_start(args, __format);
-       ret = vsnprintf(__s, -1, __format, args);
-       va_end(args);
-       
-       return ret;
-}
-
-/**
- * \fn int tolower(int c)
- * \brief Converts a character to lower case
- */
-int tolower(int c)
-{
-       if('A' <= c && c <= 'Z')
-               return c - 'A' + 'a';
-       return c;
-}
-
-/**
- * \fn int strucmp(const char *Str1, const char *Str2)
- * \brief Compare \a Str1 and \a Str2 case-insensitively
- */
-int strucmp(const char *Str1, const char *Str2)
-{
-       while(*Str1 && tolower(*Str1) == tolower(*Str2))
-               Str1++, Str2++;
-       return tolower(*Str1) - tolower(*Str2);
-}
-
-/**
- * \brief Locate a byte in a string
- */
-char *strchr(const char *__s, int __c)
-{
-       for( ; *__s; __s ++ )
-       {
-               if( *__s == __c )       return (char*)__s;
-       }
-       return NULL;
-}
-
-/**
- * \fn int strpos(const char *Str, char Ch)
- * \brief Search a string for an ascii character
- */
-int strpos(const char *Str, char Ch)
-{
-        int    pos;
-       for(pos=0;Str[pos];pos++)
-       {
-               if(Str[pos] == Ch)      return pos;
-       }
-       return -1;
-}
-
 /**
  * \fn Uint8 ByteSum(void *Ptr, int Size)
  * \brief Adds the bytes in a memory region and returns the sum
@@ -499,120 +60,6 @@ Uint8 ByteSum(const void *Ptr, int Size)
        return sum;
 }
 
-/**
- * \fn size_t strlen(const char *__str)
- * \brief Get the length of string
- */
-size_t strlen(const char *__str)
-{
-       size_t  ret = 0;
-       while(*__str++) ret++;
-       return ret;
-}
-
-/**
- * \brief Copy a string to a new location
- */
-char *strcpy(char *__str1, const char *__str2)
-{
-       while(*__str2)
-               *__str1++ = *__str2++;
-       *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Copy a string to a new location
- * \note Copies at most `max` chars
- */
-char *strncpy(char *__str1, const char *__str2, size_t __max)
-{
-       while(*__str2 && __max-- >= 1)
-               *__str1++ = *__str2++;
-       if(__max)
-               *__str1 = '\0'; // Terminate String
-       return __str1;
-}
-
-/**
- * \brief Append a string to another
- */
-char *strcat(char *__dest, const char *__src)
-{
-       while(*__dest++);
-       __dest--;
-       while(*__src)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \brief Append at most \a n chars to a string from another
- * \note At most n+1 chars are written (the dest is always zero terminated)
- */
-char *strncat(char *__dest, const char *__src, size_t n)
-{
-       while(*__dest++);
-       while(*__src && n-- >= 1)
-               *__dest++ = *__src++;
-       *__dest = '\0';
-       return __dest;
-}
-
-/**
- * \fn int strcmp(const char *str1, const char *str2)
- * \brief Compare two strings return the difference between
- *        the first non-matching characters.
- */
-int strcmp(const char *str1, const char *str2)
-{
-       while(*str1 && *str1 == *str2)
-               str1++, str2++;
-       return *str1 - *str2;
-}
-
-/**
- * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
- * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
- */
-int strncmp(const char *Str1, const char *Str2, size_t num)
-{
-       if(num == 0)    return 0;       // TODO: Check what should officially happen here
-       while(--num && *Str1 && *Str1 == *Str2)
-               Str1++, Str2++;
-       return *Str1-*Str2;
-}
-
-#if 0
-/**
- * \fn char *strdup(const char *Str)
- * \brief Duplicates a string
- */
-char *strdup(const char *Str)
-{
-       char    *ret;
-       ret = malloc(strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#else
-
-/**
- * \fn char *_strdup(const char *File, int Line, const char *Str)
- * \brief Duplicates a string
- */
-char *_strdup(const char *File, int Line, const char *Str)
-{
-       char    *ret;
-       ret = Heap_Allocate(File, Line, strlen(Str)+1);
-       if( !ret )      return NULL;
-       strcpy(ret, Str);
-       return ret;
-}
-#endif
-
 /**
  * \brief Split a string using the passed character
  * \return NULL terminated array of strings on the heap
@@ -677,7 +124,7 @@ int strpos8(const char *str, Uint32 Search)
        {
                // ASCII Range
                if(Search < 128) {
-                       if(str[pos] == Search)  return pos;
+                       if(str[pos] == (char)Search)    return pos;
                        continue;
                }
                if(*(Uint8*)(str+pos) < 128)    continue;
@@ -694,6 +141,8 @@ int strpos8(const char *str, Uint32 Search)
  */
 int ReadUTF8(const Uint8 *str, Uint32 *Val)
 {
+       Uint32  outval;
+       
        *Val = 0xFFFD;  // Assume invalid character
        
        // ASCII
@@ -709,37 +158,40 @@ int ReadUTF8(const Uint8 *str, Uint32 *Val)
        
        // Two Byte
        if( (*str & 0xE0) == 0xC0 ) {
-               *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
+               outval = (*str & 0x1F) << 6;    // Upper 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 2;
        }
        
        // Three Byte
        if( (*str & 0xF0) == 0xE0 ) {
-               *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
+               outval = (*str & 0x0F) << 12;   // Upper 4 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F) << 6;   // Middle 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 3;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 3;
        }
        
        // Four Byte
        if( (*str & 0xF1) == 0xF0 ) {
-               *Val = (*str & 0x07) << 18;     // Upper 3 Bits
+               outval = (*str & 0x07) << 18;   // Upper 3 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 2;       // Validity check
+               outval |= (*str & 0x3F) << 12;  // Middle-upper 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 3;       // Validity check
+               outval |= (*str & 0x3F) << 6;   // Middle-lower 6 Bits
                str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
+               if( (*str & 0xC0) != 0x80)      return 4;       // Validity check
+               outval |= (*str & 0x3F);        // Lower 6 Bits
+               *Val = outval;
                return 4;
        }
        
@@ -911,81 +363,6 @@ void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins,
        *day += TS;     // Plus offset from leap handling above
 }
 
-/**
- * \fn int rand()
- * \brief Pseudo random number generator
- */
-int rand(void)
-{
-       #if 0
-       static Uint     state = RANDOM_SEED;
-       Uint    old = state;
-       // Get the next state value
-       giRandomState = (RANDOM_A*state + RANDOM_C);
-       // Check if it has changed, and if it hasn't, change it
-       if(state == old)        state += RANDOM_SPRUCE;
-       return state;
-       #else
-       // http://en.wikipedia.org/wiki/Xorshift
-       // 2010-10-03
-       static Uint32   x = 123456789;
-       static Uint32   y = 362436069;
-       static Uint32   z = 521288629;
-       static Uint32   w = 88675123; 
-       Uint32  t;
-       t = x ^ (x << 11);
-       x = y; y = z; z = w;
-       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
-       #endif
-}
-
-/* *
- * \name Memory Validation
- * \{
- */
-/**
- * \brief Checks if a string resides fully in valid memory
- */
-int CheckString(const char *String)
-{
-       tVAddr  addr;
-        int    bUser;
-
-       addr = (tVAddr)String;
-
-       if( !MM_GetPhysAddr( addr ) )
-               return 0;
-       
-       // Check 1st page
-       bUser = MM_IsUser( addr );
-       
-       while( *(char*)addr )
-       {
-               if( (addr & (PAGE_SIZE-1)) == 0 )
-               {
-                       if(bUser && !MM_IsUser(addr) )
-                               return 0;
-                       if(!bUser && !MM_GetPhysAddr(addr) )
-                               return 0;
-               }
-               addr ++;
-       }
-       return 1;
-}
-
-/**
- * \brief Check if a sized memory region is valid memory
- * \return Boolean success
- */
-int CheckMem(const void *Mem, int NumBytes)
-{
-       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
-}
-/* *
- * \}
- */
-
 /**
  * \brief Search a string array for \a Needle
  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
@@ -1010,7 +387,7 @@ int ModUtil_SetIdent(char *Dest, const char *Value)
 
 int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
 {
-        int    i;
+       size_t  i;
        for( i = 0; i < Size; i ++ )
        {
                sprintf(Dest + i*2, "%02x", SourceData[i]);
@@ -1023,8 +400,7 @@ int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
  */
 int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
 {
-        int    i;
-       
+       size_t  i;
        for( i = 0; i < DestSize*2; i += 2 )
        {
                Uint8   val = 0;
@@ -1060,42 +436,7 @@ Uint32 SwapEndian32(Uint32 Val)
 {
        return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
 }
-
-void *memmove(void *__dest, const void *__src, size_t len)
+Uint64 SwapEndian64(Uint64 Val)
 {
-       size_t  block_size;
-       char    *dest = __dest;
-       const char      *src = __src;
-       void    *ret = __dest;
-
-       if( len == 0 || dest == src )
-               return dest;
-       
-       if( (tVAddr)dest > (tVAddr)src + len )
-               return memcpy(dest, src, len);
-       if( (tVAddr)dest + len < (tVAddr)src )
-               return memcpy(dest, src, len);
-       
-       // NOTE: Assumes memcpy works forward
-       if( (tVAddr)dest < (tVAddr)src )
-               return memcpy(dest, src, len);
-
-       if( (tVAddr)dest < (tVAddr)src )
-               block_size = (tVAddr)src - (tVAddr)dest;
-       else
-               block_size = (tVAddr)dest - (tVAddr)src;
-       
-       block_size &= ~0xF;
-       
-       while(len >= block_size)
-       {
-               memcpy(dest, src, block_size);
-               len -= block_size;
-               dest += block_size;
-               src += block_size;
-       }
-       memcpy(dest, src, len);
-       return ret;
-       
+       return SwapEndian32(Val >> 32) | ((Uint64)SwapEndian32(Val) << 32);
 }
-
diff --git a/KernelLand/Kernel/libc.c b/KernelLand/Kernel/libc.c
new file mode 100644 (file)
index 0000000..ef94426
--- /dev/null
@@ -0,0 +1,791 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * libc.c
+ * - Kernel-land C Library
+ */
+#include <acess.h>
+#include <hal_proc.h>  // For MM_*
+
+// === CONSTANTS ===
+#define        RANDOM_SEED     0xACE55052
+#define        RANDOM_A        0x00731ADE
+#define        RANDOM_C        12345
+#define        RANDOM_SPRUCE   0xf12b039
+
+// === PROTOTYPES ===
+#if 0
+ int   atoi(const char *string);
+ int   ParseInt(const char *string, int *Val);
+void   itoa(char *buf, Uint64 num, int base, int minLength, char pad);
+ int   vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+ int   snprintf(char *__s, size_t __n, const char *__format, ...);
+ int   sprintf(char *__s, const char *__format, ...);
+ int   strucmp(const char *Str1, const char *Str2);
+char   *strchr(const char *__s, int __c);
+ int   strpos(const char *Str, char Ch);
+size_t strlen(const char *__s);
+char   *strcpy(char *__str1, const char *__str2);
+char   *strncpy(char *__str1, const char *__str2, size_t max);
+char   *strcat(char *dest, const char *source);
+ int   strcmp(const char *str1, const char *str2);
+ int   strncmp(const char *str1, const char *str2, size_t num);
+char   *_strdup(const char *File, int Line, const char *Str);
+ int   rand(void);
+void   *memmove(void *__dest, const void *__src, size_t len);
+
+ int   CheckString(char *String);
+ int   CheckMem(void *Mem, int NumBytes); 
+#endif
+
+// === EXPORTS ===
+EXPORT(atoi);
+EXPORT(itoa);
+EXPORT(vsnprintf);
+EXPORT(snprintf);
+EXPORT(sprintf);
+EXPORT(tolower);
+
+EXPORT(strucmp);
+EXPORT(strchr);
+EXPORT(strrchr);
+EXPORT(strpos);
+EXPORT(strlen);
+EXPORT(strcpy);
+EXPORT(strncpy);
+EXPORT(strcat);
+EXPORT(strncat);
+EXPORT(strcmp);
+EXPORT(strncmp);
+//EXPORT(strdup);
+EXPORT(_strdup);       // Takes File/Line too
+EXPORT(rand);
+EXPORT(memmove);
+
+EXPORT(CheckString);
+EXPORT(CheckMem);
+
+// === CODE ===
+/**
+ * \brief Convert a string into an integer
+ */
+int atoi(const char *string)
+{
+       int ret = 0;
+       ParseInt(string, &ret);
+       return ret;
+}
+int ParseInt(const char *string, int *Val)
+{
+        int    ret = 0;
+        int    bNeg = 0;
+       const char *orig_string = string;
+       
+       //Log("atoi: (string='%s')", string);
+       
+       // Clear non-numeric characters
+       while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
+       if( *string == '-' ) {
+               bNeg = 1;
+               while( !('0' <= *string && *string <= '9') )    string++;
+       }
+       
+       if(*string == '0')
+       {
+               string ++;
+               if(*string == 'x')
+               {
+                       // Hex
+                       string ++;
+                       for( ;; string ++ )
+                       {
+                               if('0' <= *string && *string <= '9') {
+                                       ret *= 16;
+                                       ret += *string - '0';
+                               }
+                               else if('A' <= *string && *string <= 'F') {
+                                       ret *= 16;
+                                       ret += *string - 'A' + 10;
+                               }
+                               else if('a' <= *string && *string <= 'f') {
+                                       ret *= 16;
+                                       ret += *string - 'a' + 10;
+                               }
+                               else
+                                       break;
+                       }
+               }
+               else    // Octal
+               {
+                       for( ; '0' <= *string && *string <= '7'; string ++ )
+                       {
+                               ret *= 8;
+                               ret += *string - '0';
+                       }
+               }
+       }
+       else    // Decimal
+       {
+               for( ; '0' <= *string && *string <= '9'; string++)
+               {
+                       ret *= 10;
+                       ret += *string - '0';
+               }
+               // Error check
+               if( ret == 0 )  return 0;
+       }
+       
+       if(bNeg)        ret = -ret;
+       
+       //Log("atoi: RETURN %i", ret);
+       
+       if(Val) *Val = ret;
+       
+       return string - orig_string;
+}
+
+static const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+ * \brief Convert an integer into a character string
+ */
+void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+{
+       char    tmpBuf[64+1];
+        int    pos=0, i;
+       Uint64  rem;
+
+       // Sanity check
+       if(!buf)        return;
+       
+       // Sanity Check
+       if(base > 16 || base < 2) {
+               buf[0] = 0;
+               return;
+       }
+       
+       // Convert 
+       while(num > base-1) {
+               num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
+               tmpBuf[pos] = cUCDIGITS[ rem ];
+               pos++;
+       }
+       tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
+       
+       // Put in reverse
+       i = 0;
+       minLength -= pos;
+       while(minLength-- > 0)  buf[i++] = pad;
+       while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
+       buf[i] = 0;
+}
+
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c)       _putch(c)
+#define GETVAL()       do {\
+       if(isLongLong)  val = va_arg(args, Uint64);\
+       else    val = va_arg(args, unsigned int);\
+       }while(0)
+/**
+ * \brief VArg String Number Print Formatted
+ */
+int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
+{
+       char    c, pad = ' ';
+        int    minSize = 0, precision = -1, len;
+       char    tmpBuf[34];     // For Integers
+       const char      *p = NULL;
+        int    isLongLong = 0;
+       Uint64  val;
+       size_t  pos = 0;
+       // Flags
+        int    bPadLeft = 0;
+       
+       auto void _putch(char ch);
+
+       void _putch(char ch)
+       {
+               if(pos < __maxlen)
+               {
+                       if(__s) __s[pos] = ch;
+               }
+               pos ++;
+       }
+
+       while((c = *__format++) != 0)
+       {
+               // Non control character
+               if(c != '%') { PUTCH(c); continue; }
+
+               c = *__format++;
+               if(c == '\0')   break;
+               
+               // Literal %
+               if(c == '%') { PUTCH('%'); continue; }
+               
+               // Pointer - Done first for debugging
+               if(c == 'p') {
+                       Uint    ptr = va_arg(args, Uint);
+                       PUTCH('*');     PUTCH('0');     PUTCH('x');
+                       for( len = BITS/4; len --; )
+                               PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
+                       continue ;
+               }
+               
+               // - Padding Side Flag
+               if(c == '-') {
+                       bPadLeft = 1;
+                       c = *__format++;
+               }
+               
+               // - Padding
+               if(c == '0') {
+                       pad = '0';
+                       c = *__format++;
+               }
+               else
+                       pad = ' ';
+               
+               // - Minimum length
+               if(c == '*') {  // Dynamic length
+                       minSize = va_arg(args, unsigned int);
+                       c = *__format++;
+               }
+               else if('1' <= c && c <= '9')
+               {
+                       minSize = 0;
+                       while('0' <= c && c <= '9')
+                       {
+                               minSize *= 10;
+                               minSize += c - '0';
+                               c = *__format++;
+                       }
+               }
+               else
+                       minSize = 0;
+               
+               // - Precision
+               precision = -1;
+               if( c == '.' ) {
+                       c = *__format++;
+                       
+                       if(c == '*') {  // Dynamic length
+                               precision = va_arg(args, unsigned int);
+                               c = *__format++;
+                       }
+                       else if('1' <= c && c <= '9')
+                       {
+                               precision = 0;
+                               while('0' <= c && c <= '9')
+                               {
+                                       precision *= 10;
+                                       precision += c - '0';
+                                       c = *__format++;
+                               }
+                       }
+               }
+               
+               // - Default, Long or LongLong?
+               isLongLong = 0;
+               if(c == 'l')    // Long is actually the default on x86
+               {
+                       c = *__format++;
+                       if(c == 'l') {
+                               c = *__format++;
+                               isLongLong = 1;
+                       }
+               }
+               
+               // - Now get the format code
+               p = tmpBuf;
+               switch(c)
+               {
+               case 'd':
+               case 'i':
+                       GETVAL();
+                       if( isLongLong && val >> 63 ) {
+                               PUTCH('-');
+                               val = -val;
+                       }
+                       else if( !isLongLong && val >> 31 ) {
+                               PUTCH('-');
+                               val = -(Sint32)val;
+                       }
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'u':       // Unsigned
+                       GETVAL();
+                       itoa(tmpBuf, val, 10, minSize, pad);
+                       goto printString;
+               case 'P':       // Physical Address
+                       PUTCH('0');
+                       PUTCH('x');
+                       if(sizeof(tPAddr) > 4)  isLongLong = 1;
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'X':       // Hex
+                       if(BITS == 64)
+                               isLongLong = 1; // TODO: Handle non-x86 64-bit archs
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+                       
+               case 'x':       // Lower case hex
+                       GETVAL();
+                       itoa(tmpBuf, val, 16, minSize, pad);
+                       goto printString;
+               case 'o':       // Octal
+                       GETVAL();
+                       itoa(tmpBuf, val, 8, minSize, pad);
+                       goto printString;
+               case 'b':
+                       GETVAL();
+                       itoa(tmpBuf, val, 2, minSize, pad);
+                       goto printString;
+
+               case 'B':       //Boolean
+                       val = va_arg(args, unsigned int);
+                       if(val) p = "True";
+                       else    p = "False";
+                       goto printString;
+               
+               // String - Null Terminated Array
+               case 's':
+                       p = va_arg(args, char*);        // Get Argument
+                       if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
+               printString:
+                       if(!p)          p = "(null)";
+                       len = strlen(p);
+                       if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
+                       while(*p && precision--)        PUTCH(*p++);
+                       if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
+                       break;
+               
+               case 'C':       // Non-Null Terminated Character Array
+                       p = va_arg(args, char*);
+                       if( !CheckMem(p, minSize) )     continue;       // No #PFs please
+                       if(!p)  goto printString;
+                       while(minSize--)        PUTCH(*p++);
+                       break;
+               
+               // Single Character
+               case 'c':
+               default:
+                       GETVAL();
+                       PUTCH( (Uint8)val );
+                       break;
+               }
+       }
+       
+       if(__s && pos != __maxlen)
+               __s[pos] = '\0';
+       
+       return pos;
+}
+#undef PUTCH
+
+/**
+ */
+int snprintf(char *__s, size_t __n, const char *__format, ...)
+{
+       va_list args;
+        int    ret;
+       
+       va_start(args, __format);
+       ret = vsnprintf(__s, __n, __format, args);
+       va_end(args);
+       
+       return ret;
+}
+
+/**
+ */
+int sprintf(char *__s, const char *__format, ...)
+{
+       va_list args;
+        int    ret;
+       
+       va_start(args, __format);
+       ret = vsnprintf(__s, -1, __format, args);
+       va_end(args);
+       
+       return ret;
+}
+
+/*
+ * ==================
+ * ctype.h
+ * ==================
+ */
+int isalnum(int c)
+{
+       return isalpha(c) || isdigit(c);
+}
+int isalpha(int c)
+{
+       return isupper(c) || islower(c);
+}
+int isascii(int c)
+{
+       return (0 <= c && c < 128);
+}
+int isblank(int c)
+{
+       if(c == '\t')   return 1;
+       if(c == ' ')    return 1;
+       return 0;
+}
+int iscntrl(int c)
+{
+       // TODO: Check iscntrl
+       if(c < ' ')     return 1;
+       return 0;
+}
+int isdigit(int c)
+{
+       return ('0' <= c && c <= '9');
+}
+int isgraph(int c)
+{
+       // TODO: Check isgraph
+       return 0;
+}
+int islower(int c)
+{
+       return ('a' <= c && c <= 'z');
+}
+int isprint(int c)
+{
+       if( ' ' <= c && c <= 0x7F )     return 1;
+       return 0;
+}
+int ispunct(int c)
+{
+       switch(c)
+       {
+       case '.':       case ',':
+       case '?':       case '!':
+               return 1;
+       default:
+               return 0;
+       }
+}
+int isspace(int c)
+{
+       if(c == ' ')    return 1;
+       if(c == '\t')   return 1;
+       if(c == '\v')   return 1;
+       if(c == '\n')   return 1;
+       if(c == '\r')   return 1;
+       return 0;
+}
+int isupper(int c)
+{
+       return ('a' <= c && c <= 'z');
+}
+int isxdigit(int c)
+{
+       return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+int toupper(int c)
+{
+       if( islower(c) )
+               return c - 0x20;
+       else
+               return c;
+}
+int tolower(int c)
+{
+       if( isupper(c) )
+               return c + 0x20;
+       else
+               return c;
+}
+
+/**
+ * \fn int strucmp(const char *Str1, const char *Str2)
+ * \brief Compare \a Str1 and \a Str2 case-insensitively
+ */
+int strucmp(const char *Str1, const char *Str2)
+{
+       while(*Str1 && tolower(*Str1) == tolower(*Str2))
+               Str1++, Str2++;
+       return tolower(*Str1) - tolower(*Str2);
+}
+
+/**
+ * \brief Locate a byte in a string
+ */
+char *strchr(const char *__s, int __c)
+{
+       for( ; *__s; __s ++ )
+       {
+               if( *__s == __c )       return (char*)__s;
+       }
+       return NULL;
+}
+
+char *strrchr(const char *__s, int __c)
+{
+       size_t ofs = strlen(__s);
+       while(--ofs && __s[ofs] != __c);
+       if( __s[ofs] == __c )
+               return (char*)__s + ofs;
+       return NULL;
+}
+
+/**
+ * \fn int strpos(const char *Str, char Ch)
+ * \brief Search a string for an ascii character
+ */
+int strpos(const char *Str, char Ch)
+{
+        int    pos;
+       for(pos=0;Str[pos];pos++)
+       {
+               if(Str[pos] == Ch)      return pos;
+       }
+       return -1;
+}
+
+/**
+ * \fn size_t strlen(const char *__str)
+ * \brief Get the length of string
+ */
+size_t strlen(const char *__str)
+{
+       size_t  ret = 0;
+       while(*__str++) ret++;
+       return ret;
+}
+
+/**
+ * \brief Copy a string to a new location
+ */
+char *strcpy(char *__str1, const char *__str2)
+{
+       while(*__str2)
+               *__str1++ = *__str2++;
+       *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Copy a string to a new location
+ * \note Copies at most `max` chars
+ */
+char *strncpy(char *__str1, const char *__str2, size_t __max)
+{
+       while(*__str2 && __max-- >= 1)
+               *__str1++ = *__str2++;
+       if(__max)
+               *__str1 = '\0'; // Terminate String
+       return __str1;
+}
+
+/**
+ * \brief Append a string to another
+ */
+char *strcat(char *__dest, const char *__src)
+{
+       while(*__dest++);
+       __dest--;
+       while(*__src)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \brief Append at most \a n chars to a string from another
+ * \note At most n+1 chars are written (the dest is always zero terminated)
+ */
+char *strncat(char *__dest, const char *__src, size_t n)
+{
+       while(*__dest++);
+       while(*__src && n-- >= 1)
+               *__dest++ = *__src++;
+       *__dest = '\0';
+       return __dest;
+}
+
+/**
+ * \fn int strcmp(const char *str1, const char *str2)
+ * \brief Compare two strings return the difference between
+ *        the first non-matching characters.
+ */
+int strcmp(const char *str1, const char *str2)
+{
+       while(*str1 && *str1 == *str2)
+               str1++, str2++;
+       return *str1 - *str2;
+}
+
+/**
+ * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
+ * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
+ */
+int strncmp(const char *Str1, const char *Str2, size_t num)
+{
+       if(num == 0)    return 0;       // TODO: Check what should officially happen here
+       while(--num && *Str1 && *Str1 == *Str2)
+               Str1++, Str2++;
+       return *Str1-*Str2;
+}
+
+#if 0
+/**
+ * \fn char *strdup(const char *Str)
+ * \brief Duplicates a string
+ */
+char *strdup(const char *Str)
+{
+       char    *ret;
+       ret = malloc(strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#else
+
+/**
+ * \fn char *_strdup(const char *File, int Line, const char *Str)
+ * \brief Duplicates a string
+ */
+char *_strdup(const char *File, int Line, const char *Str)
+{
+       char    *ret;
+       ret = Heap_Allocate(File, Line, strlen(Str)+1);
+       if( !ret )      return NULL;
+       strcpy(ret, Str);
+       return ret;
+}
+#endif
+
+/**
+ * \fn int rand()
+ * \brief Pseudo random number generator
+ */
+int rand(void)
+{
+       #if 0
+       static Uint     state = RANDOM_SEED;
+       Uint    old = state;
+       // Get the next state value
+       giRandomState = (RANDOM_A*state + RANDOM_C);
+       // Check if it has changed, and if it hasn't, change it
+       if(state == old)        state += RANDOM_SPRUCE;
+       return state;
+       #else
+       // http://en.wikipedia.org/wiki/Xorshift
+       // 2010-10-03
+       static Uint32   x = 123456789;
+       static Uint32   y = 362436069;
+       static Uint32   z = 521288629;
+       static Uint32   w = 88675123; 
+       Uint32  t;
+       t = x ^ (x << 11);
+       x = y; y = z; z = w;
+       return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
+       #endif
+}
+
+void *memmove(void *__dest, const void *__src, size_t len)
+{
+       char    *dest = __dest;
+       const char      *src = __src;
+       void    *ret = __dest;
+
+       if( len == 0 || dest == src )
+               return dest;
+       
+       if( (tVAddr)dest > (tVAddr)src + len )
+               return memcpy(dest, src, len);
+       if( (tVAddr)dest + len < (tVAddr)src )
+               return memcpy(dest, src, len);
+       
+       // NOTE: Assumes memcpy works forward
+       if( (tVAddr)dest < (tVAddr)src )
+               return memcpy(dest, src, len);
+
+       #if 0
+       size_t  block_size;
+       if( (tVAddr)dest < (tVAddr)src )
+               block_size = (tVAddr)src - (tVAddr)dest;
+       else
+               block_size = (tVAddr)dest - (tVAddr)src;
+       
+       block_size &= ~0xF;
+       
+       while(len >= block_size)
+       {
+               memcpy(dest, src, block_size);
+               len -= block_size;
+               dest += block_size;
+               src += block_size;
+       }
+       memcpy(dest, src, len);
+       return ret;
+       #else
+       for( int i = len; i--; )
+       {
+               dest[i] = src[i];
+       }
+       return ret;
+       #endif
+       
+}
+
+// NOTE: Strictly not libc, but lib.c is used by userland code too
+/**
+ * \name Memory Validation
+ * \{
+ */
+/**
+ * \brief Checks if a string resides fully in valid memory
+ */
+int CheckString(const char *String)
+{
+       tVAddr  addr;
+        int    bUser;
+
+       addr = (tVAddr)String;
+
+       if( !MM_GetPhysAddr( (void*)addr ) )
+               return 0;
+       
+       // Check 1st page
+       bUser = MM_IsUser( addr );
+       
+       while( *(char*)addr )
+       {
+               if( (addr & (PAGE_SIZE-1)) == 0 )
+               {
+                       if(bUser && !MM_IsUser(addr) )
+                               return 0;
+                       if(!bUser && !MM_GetPhysAddr((void*)addr) )
+                               return 0;
+               }
+               addr ++;
+       }
+       return 1;
+}
+
+/**
+ * \brief Check if a sized memory region is valid memory
+ * \return Boolean success
+ */
+int CheckMem(const void *Mem, int NumBytes)
+{
+       return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
+}
+/* *
+ * \}
+ */
+
index b419be3..9617b83 100644 (file)
@@ -69,14 +69,16 @@ EXPORT(Log_Debug);
 
 // === GLOBALS ===
 tShortSpinlock glLogOutput;
-#if USE_RING_BUFFER
+#if CACHE_MESSAGES
+# if USE_RING_BUFFER
 Uint8  gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
 tRingBuffer    *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
-#else
+# else
 tMutex glLog;
 tLogList       gLog;
 tLogList       gLog_Levels[NUM_LOG_LEVELS];
-#endif
+# endif        // USE_RING_BUFFER
+#endif // CACHE_MESSAGES
 
 // === CODE ===
 /**
@@ -156,6 +158,8 @@ void Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args
  */
 void Log_Int_PrintMessage(tLogEntry *Entry)
 {
+       if( CPU_HAS_LOCK(&glLogOutput) )
+               return ;        // TODO: Error?
        SHORTLOCK( &glLogOutput );
        LogF("%s%014lli%s [%-8s] %i - %s",
                csaLevelColours[Entry->Level],
index 98ca1a1..c5e7f1b 100644 (file)
@@ -8,6 +8,7 @@
 
 #define        USE_EDI 0
 #define        USE_UDI 0
+#define MODULE_FLAG_LOADERROR  0x1
 
 // === PROTOTYPES ===
  int   Module_int_Initialise(tModule *Module, const char *ArgString);
@@ -80,6 +81,15 @@ int Module_int_Initialise(tModule *Module, const char *ArgString)
                        "Module %p (%s) is for another architecture (%i)",
                        Module, Module->Name, Module->Arch
                        );
+               LEAVE('i', MODULE_ERR_BADMODULE);
+               return MODULE_ERR_BADMODULE;
+       }
+
+       LOG("Module->Flags = %x", Module->Flags);       
+       if(Module->Flags & MODULE_FLAG_LOADERROR ) {
+               Log_Warning("Module", "%s has already attempted to load and encountered errors", Module->Name);
+               LEAVE('i', MODULE_ERR_MISC);
+               return MODULE_ERR_MISC;
        }
        
        deps = Module->Dependencies;
@@ -168,7 +178,7 @@ int Module_int_Initialise(tModule *Module, const char *ArgString)
                        Log_Warning("Module", "Unable to load, reason: Miscelanious");
                        break;
                case MODULE_ERR_NOTNEEDED:
-                       Log_Debug("Module", "Unable to load, reason: Module not needed");
+//                     Log_Debug("Module", "Unable to load, reason: Module not needed");
                        break;
                case MODULE_ERR_MALLOC:
                        Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
@@ -177,6 +187,7 @@ int Module_int_Initialise(tModule *Module, const char *ArgString)
                        Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
                        break;
                }
+               Module->Flags |= MODULE_FLAG_LOADERROR;
                LEAVE_RET('i', ret);
                return ret;
        }
@@ -341,6 +352,7 @@ int Module_LoadFile(const char *Path, const char *ArgString)
 {
        void    *base;
        tModule *info;
+       tModuleLoader   *loader = NULL;
        
        // Load Binary
        base = Binary_LoadKernel(Path);
@@ -350,38 +362,40 @@ int Module_LoadFile(const char *Path, const char *ArgString)
                Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
                return 0;
        }
+
+       // TODO: I need a way of relocating the dependencies before everything else, so
+       // they can be resolved before any other link errors
+       if( !Binary_Relocate(base) ) {
+               Log_Warning("Module", "Relocation of module %s failed", Path);
+               Binary_Unload(base);
+               return 0;
+       }
        
        // Check for Acess Driver
        if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
        {
-               tModuleLoader   *tmp;
-               for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
-               {
-                       if( tmp->Detector(base) == 0 )  continue;
-                       
-                       return tmp->Loader(base);
-               }
-               
-               #if USE_EDI
-               // Check for EDI Driver
-               if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
+               for( loader = gModule_Loaders; loader; loader = loader->Next)
                {
-                       return Module_InitEDI( base );  // And intialise
+                       if( loader->Detector(base) )
+                               break;
                }
-               #endif
                
                // Unknown module type?, return error
+               if( !loader ) {
+                       Binary_Unload(base);
+                       Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
+                       return 0;
+               }
+       }
+
+       if( !Module_int_ResolveDeps(info) ) {
+               Log_Warning("Module", "Dependencies not met for '%s'", Path);
                Binary_Unload(base);
-               #if USE_EDI
-               Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
-               #else
-               Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
-               #endif
                return 0;
        }
-       
+
        // Initialise (and register)
-       if( Module_int_Initialise( info, ArgString ) )
+       if( loader ? loader->Loader(base) : Module_int_Initialise( info, ArgString ) )
        {
                Binary_Unload(base);
                return 0;
diff --git a/KernelLand/Kernel/pmemmap.c b/KernelLand/Kernel/pmemmap.c
new file mode 100644 (file)
index 0000000..21ced24
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * pmemmap.c
+ * - Physical memory map manipulation
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <pmemmap.h>
+
+// === CODE ===
+void PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts)
+{
+       for( int i = 0; i < NEnts; i ++ )
+       {
+               Log_Debug("PMemMap", "%i: %i 0x%02x %08llx+%llx",
+                       i, map[i].Type, map[i].NUMADomain,
+                       map[i].Start, map[i].Length
+                       );
+       }
+}
+
+int PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset)
+{
+       LOG("Splitting %i (%llx+%llx) at %llx", Block, map[Block].Start, map[Block].Length, Offset);
+       
+       Uint64 _len = map[Block].Length;
+       map[Block].Length = Offset;
+       if( NEnts == MaxEnts ) {
+               // out of space
+               return NEnts;
+       }
+       if( Block < NEnts ) {
+               LOG("Moving %i entries from %i to %i", (NEnts - Block-1), Block+1, Block);
+               memmove(&map[Block+2], &map[Block+1], (NEnts - Block)*sizeof(map[0]));
+       }
+       Block ++;
+       NEnts ++;
+       
+       // New (free) block
+       map[Block].Start  = map[Block-1].Start + Offset;
+       map[Block].Length = _len - Offset;
+       map[Block].Type = map[Block-1].Type;
+       map[Block].NUMADomain = map[Block-1].NUMADomain;
+       LOG("- New %i %02x %llx+%llx", map[Block].Type, map[Block].NUMADomain, map[Block].Start, map[Block].Length);
+
+       return NEnts;
+}
+
+int PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts)
+{
+       for( int i = 1; i < NEnts; i ++ )
+       {
+               // Check if the ranges are contiguous
+               if( map[i-1].Start + map[i-1].Length < map[i].Start )
+                       continue ;
+               // Check if the type is the same
+               if( map[i-1].Type != map[i].Type )
+                       continue ;
+               // Check if the NUMA Domains are the same
+               if( map[i-1].NUMADomain != map[i].NUMADomain )
+                       continue ;
+               
+               // Ok, they should be together
+               map[i-1].Length += map[i].Length;
+               memmove(&map[i], &map[i+1], (NEnts - (i+1))*sizeof(map[0]));
+               LOG("Joined %i and %i into %llx+%llx", i-1, i, map[i-1].Start, map[i-1].Length);                
+
+               // Counteract the i++ in the loop iterator
+               i --;
+               NEnts --;
+       }
+       return NEnts;
+}
+
+int PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts)
+{
+       // Sort the pmem map
+        int     bNeedsSort = 0;
+       for( int i = 1; i < NEnts; i ++ )
+       {
+               if( map[i-1].Start > map[i].Start ) {
+                       bNeedsSort = 1;
+                       break;
+               }
+       }
+       if( bNeedsSort )
+       {
+               // Use a selection/swap sort
+               for( int i = 0; i < NEnts; i ++ )
+               {
+                       int sel = i;
+                       for( int j = i+1; j < NEnts; j ++ )
+                       {
+                               if( map[j].Start < map[sel].Start )
+                                       sel = j;
+                       }
+                       if( sel != i ) {
+                               LOG("Swapping %i and %i", i, sel);
+                               LOG(" - %llx+%llx", map[i].Start, map[i].Length);
+                               LOG(" - %llx+%llx", map[sel].Start, map[sel].Length);
+                               tPMemMapEnt tmp = map[i];
+                               map[i] = map[sel];
+                               map[sel] = tmp;
+                       }
+               }
+       }
+       
+       // Ensure that the map has no overlaps
+       for( int i = 1; i < NEnts; i ++ )
+       {
+               if( map[i-1].Start + map[i-1].Length <= map[i].Start )
+                       continue ;
+               // Oops, overlap!
+               Log_Notice("Arch", "Map ranges %llx+%llx and %llx+%llx overlap",
+                       map[i-1].Start, map[i-1].Length,
+                       map[i].Start,   map[i].Length
+                       );
+       }
+       
+       NEnts = PMemMap_CompactMap(map, NEnts, MaxEnts);
+       return NEnts;
+}
+
+
+int PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size)
+{
+        int    first;
+       
+       Size = (Size + 0xFFF) & ~0xFFF;
+       Base = Base & ~0xFFF;
+       
+       first = -1;
+       for( int i = 0; i < NEnts; i ++ )
+       {
+               if( map[i].Start + map[i].Length > Base ) {
+                       first = i;
+                       break;
+               }
+       }
+       if( first == -1 ) {
+               // Not in map
+               LOG("%llx+%llx not in map (past end)", Base, Size);
+               return NEnts;
+       }
+       
+       if( map[first].Start > Base ) {
+               // Not in map
+               LOG("%llx+%llx not in map (in hole)", Base, Size);
+               return NEnts;
+       }
+       
+       // Detect single
+       if( map[first].Start <= Base && Base + Size <= map[first].Start + map[first].Length )
+       {
+               // Split before
+               if( map[first].Start < Base )
+               {
+                       if( NEnts == MaxEnts ) {
+                               // out of space... oops
+                               return NEnts;
+                       }
+                       NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Base - map[first].Start);
+                       first ++;
+               }
+               
+               // map[first].Start == Base
+               // Split after
+               if( map[first].Length > Size )
+               {
+                       if( NEnts == MaxEnts ) {
+                               // out of space
+                               return NEnts;
+                       }
+                       NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Size);
+               }
+               
+               // map[first] is now exactly the block
+               map[first].Type = PMEMTYPE_USED;
+       
+               return PMemMap_CompactMap(map, NEnts, MaxEnts);
+       }
+       else
+       {
+               // Wait... this should never happen, right?
+               Log_Notice("Arch", "Module %llx+%llx overlaps two or more ranges",
+                       Base, Size);
+               PMemMap_DumpBlocks(map, NEnts);
+               // TODO: Error?
+               return NEnts;
+       }
+}
+
+
+
diff --git a/KernelLand/Kernel/rwlock.c b/KernelLand/Kernel/rwlock.c
new file mode 100644 (file)
index 0000000..979df4a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * rwlock.c
+ * - Reader-Writer Lockes
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <threads_int.h>
+#include <rwlock.h>
+
+// === PROTOTYPES ===
+//
+// Acquire as a reader (see rwlock.h for documentation)
+//
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+       tThread *us;
+       LOG("Acquire RWLock Read %p", Lock);
+       // Get protector
+       SHORTLOCK( &Lock->Protector );
+       
+       // Check if the lock is already held by a writer
+       if( Lock->Owner )
+       {
+               LOG("Waiting");
+               SHORTLOCK( &glThreadListLock );
+               
+               // - Remove from active list
+               us = Threads_RemActive();
+               us->Next = NULL;
+               // - Mark as sleeping
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               // - Add to waiting
+               if(Lock->ReaderWaiting)
+                       Lock->ReaderWaitingLast->Next = us;
+               else
+                       Lock->ReaderWaiting = us;
+               Lock->ReaderWaitingLast = us;
+               
+               #if DEBUG_TRACE_STATE
+               Log("%p (%i %s) waiting on rwlock %p",
+                       us, us->TID, us->ThreadName, Lock);
+               #endif
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               // We're only woken when we get the lock
+               // TODO: Handle when this isn't the case
+               us->WaitPointer = NULL;
+       }
+       // Ooh, no problems then!
+       else
+       {
+               Lock->Level++;
+               SHORTREL( & Lock->Protector );
+       }
+       LOG("Obtained");
+       
+       return 0;
+}
+
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+       tThread *us;
+       
+       LOG("Acquire RWLock Write %p", Lock);
+       
+       SHORTLOCK(&Lock->Protector);
+       if( Lock->Owner || Lock->Level != 0 )
+       {
+               LOG("Waiting");
+               SHORTLOCK(&glThreadListLock);
+               
+               us = Threads_RemActive();
+               us->Next = NULL;
+               us->Status = THREAD_STAT_RWLOCKSLEEP;
+               us->WaitPointer = Lock;
+               
+               if( Lock->WriterWaiting )
+                       Lock->WriterWaitingLast->Next = us;
+               else
+                       Lock->WriterWaiting = us;
+               Lock->WriterWaitingLast = us;
+               
+               SHORTREL( &glThreadListLock );
+               SHORTREL( &Lock->Protector );
+               
+               while(us->Status == THREAD_STAT_RWLOCKSLEEP)    Threads_Yield();
+               us->WaitPointer = NULL;
+       }
+       else
+       {
+               // Nothing else is using the lock, nice :)
+               Lock->Owner = Proc_GetCurThread();
+               SHORTREL(&Lock->Protector);
+       }
+       LOG("Obtained");
+       return 0;
+}
+
+// Release a mutex
+void RWLock_Release(tRWLock *Lock)
+{
+       LOG("Release RWLock %p", Lock);
+       SHORTLOCK( &Lock->Protector );
+
+       if( Lock->Owner != Proc_GetCurThread() )
+               Lock->Level --;
+       
+       // Writers first
+       if( Lock->WriterWaiting )
+       {
+               Lock->Owner = Lock->WriterWaiting;      // Set owner
+               Lock->WriterWaiting = Lock->WriterWaiting->Next;        // Next!
+               
+               // Wake new owner
+               if( Lock->Owner->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(Lock->Owner);
+       }
+       else
+       {
+               Lock->Owner = NULL;
+               
+               while( Lock->ReaderWaiting ) {
+                       Lock->Level ++;
+                       Threads_AddActive(Lock->ReaderWaiting);
+                       Lock->ReaderWaiting = Lock->ReaderWaiting->Next;
+               }
+       }
+       SHORTREL( &Lock->Protector );
+}
+
+// === EXPORTS ===
+EXPORT(RWLock_AcquireRead);
+EXPORT(RWLock_AcquireWrite);
+EXPORT(RWLock_Release);
index 5580187..0348d57 100644 (file)
@@ -102,7 +102,7 @@ void SyscallHandler(tSyscallRegs *Regs)
        
        // -- Get the physical address of a page
        case SYS_GETPHYS:
-               ret = MM_GetPhysAddr(Regs->Arg1);
+               ret = MM_GetPhysAddr( (void*)Regs->Arg1 );
                break;
        
        // -- Map an address
@@ -275,21 +275,35 @@ void SyscallHandler(tSyscallRegs *Regs)
                        ret = -1;
                        break;
                }
-               // Sanity check the paths
-               if(!Syscall_ValidString((char*)Regs->Arg1)
-               || !Syscall_ValidString((char*)Regs->Arg2)
-               || !Syscall_ValidString((char*)Regs->Arg3)
-               || !Syscall_ValidString((char*)Regs->Arg4) ) {
-                       err = -EINVAL;
-                       ret = -1;
-                       break;
+               
+               if( !Regs->Arg1 )
+               {
+                       if( !Syscall_ValidString((char*)Regs->Arg2) ) {
+                               err = -EINVAL;
+                               ret = -1;
+                               break;
+                       }
+                       
+                       ret = VFS_Unmount((char*)Regs->Arg2);
+               }
+               else
+               {
+                       // Sanity check the paths
+                       if(!Syscall_ValidString((char*)Regs->Arg1)
+                       || !Syscall_ValidString((char*)Regs->Arg2)
+                       || (Regs->Arg3 && !Syscall_ValidString((char*)Regs->Arg3))
+                       || !Syscall_ValidString((char*)Regs->Arg4) ) {
+                               err = -EINVAL;
+                               ret = -1;
+                               break;
+                       }
+                       ret = VFS_Mount(
+                               (char*)Regs->Arg1,      // Device
+                               (char*)Regs->Arg2,      // Mount point
+                               (char*)Regs->Arg3,      // Filesystem
+                               (char*)Regs->Arg4       // Options
+                               );
                }
-               ret = VFS_Mount(
-                       (char*)Regs->Arg1,      // Device
-                       (char*)Regs->Arg2,      // Mount point
-                       (char*)Regs->Arg3,      // Filesystem
-                       (char*)Regs->Arg4       // Options
-                       );
                break;
                
        // Wait on a set of handles
index d8eba83..9224db5 100644 (file)
@@ -4,8 +4,9 @@
  * system.c
  * - Architecture Independent System Init
  */
-#define DEBUG  0
+#define DEBUG  1
 #include <acess.h>
+#include <hal_proc.h>
 
 // === IMPORTS ===
 extern void    Arch_LoadBootModules(void);
@@ -44,7 +45,12 @@ void System_Init(char *CommandLine)
        
        // - Execute the Config Script
        Log_Log("Config", "Spawning init '%s'", gsInitBinary);
-       Proc_Spawn(gsInitBinary);
+       if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
+       {
+               const char      *args[] = {gsInitBinary, 0};
+               Proc_Execve(gsInitBinary, args, &args[1], 0);
+               Log_KernelPanic("System", "Unable to spawn init '%s'", gsInitBinary);
+       }
        
        // Set the debug to be echoed to the terminal
        Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
@@ -156,7 +162,7 @@ void System_ParseVFS(char *Arg)
        // - Symbolic Link <link>=<destination>
        if(value[0] == '/')
        {
-               Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
+//             Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
                VFS_Symlink(Arg, value);
        }
        // - Mount <mountpoint>=<fs>:<device>
@@ -171,13 +177,13 @@ void System_ParseVFS(char *Arg)
                }
                // Create Mountpoint
                if( (fd = VFS_Open(Arg, 0)) == -1 ) {
-                       Log_Log("Config", "Creating directory '%s'", Arg, value);
+//                     Log_Log("Config", "Creating directory '%s'", Arg, value);
                        VFS_MkDir( Arg );
                } else {
                        VFS_Close(fd);
                }
                // Mount
-               Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+//             Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
                VFS_Mount(dev, Arg, value, "");
        }
 }
index 6099621..17cccca 100644 (file)
@@ -504,15 +504,13 @@ tThread *Threads_GetThread(Uint TID)
        tThread *thread;
        
        // Search global list
-       for(thread = gAllThreads;
-               thread;
-               thread = thread->GlobalNext)
+       for( thread = gAllThreads; thread; thread = thread->GlobalNext )
        {
                if(thread->TID == TID)
                        return thread;
        }
 
-       Log("Unable to find TID %i on main list\n", TID);
+       Log_Notice("Threads", "Unable to find TID %i on main list\n", TID);
        
        return NULL;
 }
index d8c2924..449afcd 100644 (file)
@@ -8,19 +8,11 @@
 #define DEBUG  0
 #include <acess.h>
 #include <timers.h>
+#include <timers_int.h>
 #include <events.h>
 #include <hal_proc.h>  // Proc_GetCurThread
 #include <workqueue.h>
-
-// === TYPEDEFS ===
-struct sTimer {
-       tTimer  *Next;
-       Sint64  FiresAfter;
-       void    (*Callback)(void*);
-       void    *Argument;
-//     tMutex  Lock;
-       BOOL    bActive;
-};
+#include <threads_int.h>       // Used to get thread timer
 
 // === PROTOTYPES ===
 void   Timer_CallbackThread(void *Unused);
@@ -240,11 +232,10 @@ void Time_FreeTimer(tTimer *Timer)
  */
 void Time_Delay(int Delay)
 {
-       tTimer  *t;
-       t = Time_AllocateTimer(NULL, NULL);
+       tTimer  *t = &Proc_GetCurThread()->ThreadTimer;
+       Time_InitTimer(t, NULL, NULL);
        Time_ScheduleTimer(t, Delay);
        Threads_WaitEvents(THREAD_EVENT_TIMER);
-       Time_FreeTimer(t);
 }
 
 // === EXPORTS ===
index d4c1530..cd45121 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 VFS
  * - Directory Management Functions
  */
+#define SANITY 1
 #define DEBUG  0
 #include <acess.h>
 #include <vfs.h>
@@ -36,11 +37,12 @@ int VFS_MkDir(const char *Path)
  */
 int VFS_MkNod(const char *Path, Uint Flags)
 {
+       tVFS_Mount      *mountpt;
        char    *absPath, *name;
         int    pos = 0, oldpos = 0;
         int    next = 0;
        tVFS_Node       *parent;
-        int    ret;
+       tVFS_Node       *ret;
        
        ENTER("sPath xFlags", Path, Flags);
        
@@ -60,50 +62,54 @@ int VFS_MkNod(const char *Path, Uint Flags)
        
        // Check for root
        if(absPath[0] == '\0')
-               parent = VFS_ParsePath("/", NULL, NULL);
+               parent = VFS_ParsePath("/", NULL, &mountpt);
        else
-               parent = VFS_ParsePath(absPath, NULL, NULL);
+               parent = VFS_ParsePath(absPath, NULL, &mountpt);
        
        LOG("parent = %p", parent);
        
        if(!parent) {
-               LEAVE('i', -1);
-               return -1;      // Error Check
+               errno = ENOENT;
+               goto _error;
        }
-       
+
        // Permissions Check
        if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
-               _CloseNode(parent);
-               free(absPath);
-               LEAVE('i', -1);
-               return -1;
+               errno = EACCES;
+               goto _error;
        }
        
        LOG("parent = %p", parent);
        
        if(!parent->Type || !parent->Type->MkNod) {
-               Warning("VFS_MkNod - Directory has no MkNod method");
-               LEAVE('i', -1);
-               return -1;
+               Log_Warning("VFS", "VFS_MkNod - Directory has no MkNod method");
+               errno = ENOTDIR;
+               goto _error;
        }
        
        // Create node
        ret = parent->Type->MkNod(parent, name, Flags);
+       _CloseNode(ret);
        
        // Free allocated string
        free(absPath);
        
        // Free Parent
+       ASSERT(mountpt->OpenHandleCount>0);
+       mountpt->OpenHandleCount --;
        _CloseNode(parent);
-       
-       // Error Check
-       if(ret == 0) {
-               LEAVE('i', -1);
-               return -1;
-       }
-       
-       LEAVE('i', 0);
-       return 0;
+
+       // Return whatever the driver said      
+       LEAVE('i', ret==NULL);
+       return ret==NULL;
+
+_error:
+       _CloseNode(parent);
+       ASSERT(mountpt->OpenHandleCount>0);
+       mountpt->OpenHandleCount --;
+       free(absPath);
+       LEAVE('i', -1);
+       return -1;
 }
 
 /**
@@ -123,6 +129,7 @@ int VFS_Symlink(const char *Name, const char *Link)
        realLink = VFS_GetAbsPath( Link );
        if(!realLink) {
                Log_Warning("VFS", "Path '%s' is badly formed", Link);
+               errno = EINVAL;
                LEAVE('i', -1);
                return -1;
        }
@@ -133,12 +140,19 @@ int VFS_Symlink(const char *Name, const char *Link)
        if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
                Log_Warning("VFS", "Unable to create link node '%s'", Name);
                free(realLink);
+               // errno is set by VFS_MkNod
                LEAVE('i', -2);
                return -2;      // Make link node
        }
        
        // Write link address
        fp = VFS_Open(Name, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_NOLINK);
+       if( fp == -1 ) {
+               Log_Warning("VFS", "Unable to open newly created symlink '%s'", Name);
+               free(realLink);
+               LEAVE('i', -3);
+               return -3;
+       }
        VFS_Write(fp, strlen(realLink), realLink);
        VFS_Close(fp);
        
@@ -155,7 +169,7 @@ int VFS_Symlink(const char *Name, const char *Link)
 int VFS_ReadDir(int FD, char *Dest)
 {
        tVFS_Handle     *h = VFS_GetHandle(FD);
-       char    *tmp;
+        int    rv;
        
        //ENTER("ph pDest", h, Dest);
        
@@ -164,29 +178,24 @@ int VFS_ReadDir(int FD, char *Dest)
                return 0;
        }
        
-       if(h->Node->Size != -1 && h->Position >= h->Node->Size) {
+       if(h->Node->Size != (Uint64)-1 && h->Position >= h->Node->Size) {
                //LEAVE('i', 0);
                return 0;
        }
        
        do {
-               tmp = h->Node->Type->ReadDir(h->Node, h->Position);
-               if((Uint)tmp < (Uint)VFS_MAXSKIP)
-                       h->Position += (Uint)tmp;
+               rv = h->Node->Type->ReadDir(h->Node, h->Position, Dest);
+               if(rv > 0)
+                       h->Position += rv;
                else
                        h->Position ++;
-       } while(tmp != NULL && (Uint)tmp < (Uint)VFS_MAXSKIP);
+       } while(rv > 0);
        
-       //LOG("tmp = '%s'", tmp);
-       
-       if(!tmp) {
+       if(rv < 0) {
                //LEAVE('i', 0);
                return 0;
        }
        
-       strcpy(Dest, tmp);
-       free(tmp);
-       
        //LEAVE('i', 1);
        return 1;
 }
index 1355226..9389822 100644 (file)
 void   DevFS_DelDevice(tDevFS_Driver *Device);
 #endif
 tVFS_Node      *DevFS_InitDevice(const char *Device, const char **Options);
-char   *DevFS_ReadDir(tVFS_Node *Node, int Pos);
+void   DevFS_Unmount(tVFS_Node *RootNode);
+ int   DevFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *DevFS_FindDir(tVFS_Node *Node, const char *Name);
 
 // === GLOBALS ===
 tVFS_Driver    gDevFS_Info = {
-       "devfs", 0, DevFS_InitDevice, NULL, NULL
+       .Name = "devfs",
+       .InitDevice = DevFS_InitDevice,
+       .Unmount = DevFS_Unmount
        };
 tVFS_NodeType  gDevFS_DirType = {
        .TypeName = "DevFS-Dir",
@@ -117,24 +120,32 @@ tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options)
        return &gDevFS_RootNode;
 }
 
+void DevFS_Unmount(tVFS_Node *RootNode)
+{
+       
+}
+
 /**
  * \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
  */
-char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
+int DevFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tDevFS_Driver   *dev;
        
-       if(Pos < 0)     return NULL;
+       if(Pos < 0)     return -EINVAL;
        
        for(dev = gDevFS_Drivers;
                dev && Pos--;
                dev = dev->Next
                );
        
-       if(dev)
-               return strdup(dev->Name);
-       else
-               return NULL;
+       if(dev) {
+               strncpy(Dest, dev->Name, FILENAME_MAX);
+               return 0;
+       }
+       else {
+               return -ENOENT;
+       }
 }
 
 /**
index 00829ed..5685861 100644 (file)
 
 // === PROTOTYPES ===
 tVFS_Node      *Root_InitDevice(const char *Device, const char **Options);
- int   Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+tVFS_Node      *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
 tVFS_Node      *Root_FindDir(tVFS_Node *Node, const char *Name);
-char   *Root_ReadDir(tVFS_Node *Node, int Pos);
+ int   Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 size_t Root_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
 size_t Root_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
 tRamFS_File    *Root_int_AllocFile(void);
 
 // === GLOBALS ===
 tVFS_Driver    gRootFS_Info = {
-       "rootfs", 0, Root_InitDevice, NULL, NULL
+       .Name = "rootfs", 
+       .InitDevice = Root_InitDevice
        };
 tRamFS_File    RootFS_Files[MAX_FILES];
 tVFS_ACL       RootFS_DirACLs[3] = {
@@ -60,7 +61,9 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
        
        // Create Root Node
        root = &RootFS_Files[0];
-       
+
+       root->Name[0] = '/';
+       root->Name[1] = '\0';
        root->Node.ImplPtr = root;
        
        root->Node.CTime
@@ -69,6 +72,7 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
        root->Node.NumACLs = 3;
        root->Node.ACLs = RootFS_DirACLs;
 
+       root->Node.Flags = VFS_FFLAG_DIRECTORY;
        root->Node.Type = &gRootFS_DirType;
        
        return &root->Node;
@@ -78,24 +82,27 @@ tVFS_Node *Root_InitDevice(const char *Device, const char **Options)
  * \fn int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
  * \brief Create an entry in the root directory
  */
-int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
 {
        tRamFS_File     *parent = Node->ImplPtr;
        tRamFS_File     *child;
-       tRamFS_File     *prev = (tRamFS_File *) &parent->Data.FirstChild;
+       tRamFS_File     *prev = NULL;
        
        ENTER("pNode sName xFlags", Node, Name, Flags);
        
-       LOG("%i > %i", strlen(Name)+1, sizeof(child->Name));
-       if(strlen(Name) + 1 > sizeof(child->Name))
-               LEAVE_RET('i', 0);
+       LOG("Sanity check name length - %i > %i", strlen(Name)+1, sizeof(child->Name));
+       if(strlen(Name) + 1 > sizeof(child->Name)) {
+               errno = EINVAL;
+               LEAVE_RET('n', NULL);
+       }
        
        // Find last child, while we're at it, check for duplication
        for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
        {
                if(strcmp(child->Name, Name) == 0) {
-                       LEAVE('i', 0);
-                       return 0;
+                       LOG("Duplicate");
+                       errno = EEXIST;
+                       LEAVE_RET('n', NULL);
                }
        }
        
@@ -103,6 +110,7 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        memset(child, 0, sizeof(tRamFS_File));
        
        strcpy(child->Name, Name);
+       LOG("Name = '%s'", child->Name);
        
        child->Parent = parent;
        child->Next = NULL;
@@ -125,12 +133,16 @@ int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
                child->Node.Type = &gRootFS_FileType;
        }
        
-       prev->Next = child;
+       // Append!
+       if( prev )
+               prev->Next = child;
+       else
+               parent->Data.FirstChild = child;
        
        parent->Node.Size ++;
        
-       LEAVE('i', 1);
-       return 1;
+       LEAVE('n', &child->Node);
+       return &child->Node;
 }
 
 /**
@@ -143,13 +155,12 @@ tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
        tRamFS_File     *child = parent->Data.FirstChild;
        
        ENTER("pNode sName", Node, Name);
-       //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name);
        
-       for(;child;child = child->Next)
+       for( child = parent->Data.FirstChild; child; child = child->Next )
        {
-               //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name);
                LOG("child->Name = '%s'", child->Name);
-               if(strcmp(child->Name, Name) == 0) {
+               if(strcmp(child->Name, Name) == 0)
+               {
                        LEAVE('p', &child->Node);
                        return &child->Node;
                }
@@ -163,16 +174,19 @@ tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name)
  * \fn char *Root_ReadDir(tVFS_Node *Node, int Pos)
  * \brief Get an entry from the filesystem
  */
-char *Root_ReadDir(tVFS_Node *Node, int Pos)
+int Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tRamFS_File     *parent = Node->ImplPtr;
        tRamFS_File     *child = parent->Data.FirstChild;
        
        for( ; child && Pos--; child = child->Next ) ;
        
-       if(child)       return strdup(child->Name);
+       if(child) {
+               strncpy(Dest, child->Name, FILENAME_MAX);
+               return 0;
+       }
        
-       return NULL;
+       return -ENOENT;
 }
 
 /**
index d22f965..88877ab 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 VFS
  * - AllocHandle, GetHandle
  */
+#define SANITY 1
 #define DEBUG  0
 #include <acess.h>
 #include <mm_virt.h>
@@ -25,6 +26,19 @@ tVFS_Handle  *gaUserHandles = (void*)MM_PPD_HANDLES;
 tVFS_Handle    *gaKernelHandles = (void*)MM_KERNEL_VFS;
 
 // === CODE ===
+inline void _ReferenceNode(tVFS_Node *Node)
+{
+       if( !MM_GetPhysAddr(Node->Type) ) {
+               Log_Error("VFS", "Node %p's type is invalid (%p bad pointer) - %P corrupted",
+                       Node, Node->Type, MM_GetPhysAddr(&Node->Type));
+               return ;
+       }
+       if( Node->Type && Node->Type->Reference )
+               Node->Type->Reference( Node );
+       else
+               Node->ReferenceCount ++;
+}
+
 /**
  * \fn tVFS_Handle *VFS_GetHandle(int FD)
  * \brief Gets a pointer to the handle information structure
@@ -60,7 +74,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
        {
                 int    max_handles = *Threads_GetMaxFD();
                // Allocate Buffer
-               if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+               if( MM_GetPhysAddr( gaUserHandles ) == 0 )
                {
                        Uint    addr, size;
                        size = max_handles * sizeof(tVFS_Handle);
@@ -87,7 +101,7 @@ int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
        else
        {
                // Allocate space if not already
-               if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
+               if( MM_GetPhysAddr( gaKernelHandles ) == 0 )
                {
                        Uint    addr, size;
                        size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
@@ -121,7 +135,7 @@ void VFS_ReferenceUserHandles(void)
         int    max_handles = *Threads_GetMaxFD();
 
        // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+       if( MM_GetPhysAddr( gaUserHandles ) == 0 )
                return ;
        
        for( i = 0; i < max_handles; i ++ )
@@ -130,8 +144,8 @@ void VFS_ReferenceUserHandles(void)
                h = &gaUserHandles[i];
                if( !h->Node )
                        continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
+               _ReferenceNode(h->Node);
+               h->Mount->OpenHandleCount ++;
        }
 }
 
@@ -141,7 +155,7 @@ void VFS_CloseAllUserHandles(void)
         int    max_handles = *Threads_GetMaxFD();
 
        // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+       if( MM_GetPhysAddr( gaUserHandles ) == 0 )
                return ;
        
        for( i = 0; i < max_handles; i ++ )
@@ -150,8 +164,7 @@ void VFS_CloseAllUserHandles(void)
                h = &gaUserHandles[i];
                if( !h->Node )
                        continue ;
-               if( h->Node->Type && h->Node->Type->Close )
-                       h->Node->Type->Close( h->Node );
+               _CloseNode(h->Node);
        }
 }
 
@@ -165,7 +178,7 @@ void *VFS_SaveHandles(int NumFDs, int *FDs)
         int    max_handles = *Threads_GetMaxFD();
        
        // Check if this process has any handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+       if( MM_GetPhysAddr( gaUserHandles ) == 0 )
                return NULL;
 
        // Allocate
@@ -196,8 +209,8 @@ void *VFS_SaveHandles(int NumFDs, int *FDs)
                // Reference node
                if( !h->Node )
                        continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
+               _ReferenceNode(h->Node);
+               h->Mount->OpenHandleCount ++;
        }       
 
        return ret;
@@ -213,7 +226,7 @@ void VFS_RestoreHandles(int NumFDs, void *Handles)
                return ;        
 
        // Check if there is already a set of handles
-       if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+       if( MM_GetPhysAddr( gaUserHandles ) != 0 )
                return ;
        
        
@@ -242,8 +255,8 @@ void VFS_RestoreHandles(int NumFDs, void *Handles)
        
                if( !h->Node )
                        continue ;
-               if( h->Node->Type && h->Node->Type->Reference )
-                       h->Node->Type->Reference( h->Node );
+               _ReferenceNode(h->Node);
+               h->Mount->OpenHandleCount ++;
        }
 }
 
@@ -263,8 +276,11 @@ void VFS_FreeSavedHandles(int NumFDs, void *Handles)
        
                if( !h->Node )
                        continue ;
-               if( h->Node->Type && h->Node->Type->Close )
-                       h->Node->Type->Close( h->Node );
+               _CloseNode(h->Node);
+               
+               ASSERT(h->Mount->OpenHandleCount > 0);
+               LOG("dec. mntpt '%s' to %i", h->Mount->MountPoint, h->Mount->OpenHandleCount-1);
+               h->Mount->OpenHandleCount --;
        }
        free( Handles );
 }
index e7a2a06..dc55fe2 100644 (file)
@@ -4,31 +4,50 @@
  */
 #define DEBUG  0
 #include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
+#include <vfs.h>
+#include <vfs_ext.h>
+#include <vfs_int.h>
 
 // === CODE ===
 /**
  * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
  * \brief Read data from a node (file)
  */
-Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
+size_t VFS_Read(int FD, size_t Length, void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
+       size_t  ret;
        
        ENTER("iFD XLength pBuffer", FD, Length, Buffer);
        
        h = VFS_GetHandle(FD);
-       if(!h)  LEAVE_RET('i', -1);
+       if(!h) {
+               LOG("Bad Handle");
+               LEAVE_RET('i', -1);
+       }
        
-       if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
+       if( !(h->Mode & VFS_OPENFLAG_READ) ) {
+               LOG("Bad mode");
+               LEAVE_RET('i', -1);
+       }
+       if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+               LOG("Reading directory");
+               LEAVE_RET('i', -1);
+       }
+
+       if(!h->Node->Type || !h->Node->Type->Read) {
+               LOG("No read method");
                LEAVE_RET('i', -1);
+       }
 
-       if(!h->Node->Type || !h->Node->Type->Read)      LEAVE_RET('i', 0);
+       if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
+               Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+                       h->Node->Type->Read);
+               LEAVE_RET('i', -1);
+       }
        
        ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   LEAVE_RET('i', -1);
+       if(ret == (size_t)-1)   LEAVE_RET('i', -1);
        
        h->Position += ret;
        LEAVE('X', ret);
@@ -39,10 +58,10 @@ Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
  * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
  * \brief Read data from a given offset (atomic)
  */
-Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
+size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
+       size_t  ret;
        
        h = VFS_GetHandle(FD);
        if(!h)  return -1;
@@ -54,8 +73,15 @@ Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
                Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
                return 0;
        }
+
+       if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
+               Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+                       h->Node->Type->Read);
+               LEAVE_RET('i', -1);
+       }
+       
        ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
-       if(ret == -1)   return -1;
+       if(ret == (size_t)-1)   return -1;
        return ret;
 }
 
@@ -63,10 +89,10 @@ Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
  * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
  * \brief Read data from a node (file)
  */
-Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
+size_t VFS_Write(int FD, size_t Length, const void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
+       size_t  ret;
        
        h = VFS_GetHandle(FD);
        if(!h)  return -1;
@@ -75,9 +101,15 @@ Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
        if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
 
        if( !h->Node->Type || !h->Node->Type->Write )   return 0;
+
+       if( !MM_GetPhysAddr(h->Node->Type->Write) ) {
+               Log_Error("VFS", "Node type %p(%s) write method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+                       h->Node->Type->Write);
+               return -1;
+       }
        
        ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
-       if(ret == -1)   return -1;
+       if(ret == (size_t)-1)   return -1;
 
        h->Position += ret;
        return ret;
@@ -87,10 +119,10 @@ Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
  * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
  * \brief Write data to a file at a given offset
  */
-Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
+size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer)
 {
        tVFS_Handle     *h;
-       Uint64  ret;
+       size_t  ret;
        
        h = VFS_GetHandle(FD);
        if(!h)  return -1;
@@ -99,9 +131,14 @@ Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
        if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
 
        if(!h->Node->Type || !h->Node->Type->Write)     return 0;
-       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
 
-       if(ret == -1)   return -1;
+       if( !MM_GetPhysAddr(h->Node->Type->Write) ) {
+               Log_Error("VFS", "Node type %p(%s) write method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+                       h->Node->Type->Write);
+               return -1;
+       }
+       ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+       if(ret == (size_t)-1)   return -1;
        return ret;
 }
 
@@ -144,7 +181,7 @@ int VFS_Seek(int FD, Sint64 Offset, int Whence)
        
        // Set relative to end of file
        if(Whence < 0) {
-               if( h->Node->Size == -1 )       return -1;
+               if( h->Node->Size == (Uint64)-1 )       return -1;
 
                h->Position = h->Node->Size - Offset;
                return 0;
index 5ff0e7c..0261eca 100644 (file)
@@ -27,7 +27,7 @@ void  VFS_UpdateDriverFile(void);
 EXPORT(VFS_AddDriver);
 
 // === GLOBALS ===
-tVFS_Node      NULLNode = {0};
+tVFS_Node      NULLNode = {.Type=NULL};
 tShortSpinlock slDriverListLock;
 tVFS_Driver    *gVFS_Drivers = NULL;
 char   *gsVFS_DriverFile = NULL;
@@ -65,6 +65,14 @@ int VFS_Init(void)
        return 0;
 }
 
+void VFS_Deinit(void)
+{
+       SysFS_RemoveFile(giVFS_MountFileID);
+       free(gsVFS_MountFile);
+       SysFS_RemoveFile(giVFS_DriverFileID);
+       free(gsVFS_DriverFile);
+}
+
 /**
  * \fn char *VFS_GetTruePath(const char *Path)
  * \brief Gets the true path (non-symlink) of a file
@@ -164,3 +172,9 @@ void VFS_UpdateDriverFile(void)
        if(gsVFS_DriverFile)    free(gsVFS_DriverFile);
        gsVFS_DriverFile = buf;
 }
+
+void VFS_CleanupNode(tVFS_Node *Node)
+{
+       
+}
+
index 6128869..c5015e6 100644 (file)
@@ -50,7 +50,7 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                LOG("%i pages anonymous to %p", npages, mapping_dest);
                for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
                {
-                       if( MM_GetPhysAddr(mapping_dest) ) {
+                       if( MM_GetPhysAddr((void*)mapping_dest) ) {
                                // TODO: Set flags to COW if needed (well, if shared)
                                MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
                                LOG("clear from %p, %i bytes", (void*)(mapping_base + ofs),
@@ -109,7 +109,7 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
        // - Map (and allocate) pages
        while( npages -- )
        {
-               if( MM_GetPhysAddr(mapping_dest) == 0 )
+               if( MM_GetPhysAddr( (void*)mapping_dest ) == 0 )
                {
                        if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
                        {
@@ -132,11 +132,12 @@ void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD,
                                        }
                                        // TODO: Clip read length
                                        read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
-//                                     if( read_len != PAGE_SIZE ) {
-//                                             memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
-//                                     }
+                                       // TODO: This was commented out, why?
+                                       if( read_len != PAGE_SIZE ) {
+                                               memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
+                                       }
                                }
-                               pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+                               pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( (void*)mapping_dest );
                                MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node );
                                MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
                                LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
index 1773218..1823857 100644 (file)
@@ -1,6 +1,8 @@
 /* 
  * Acess Micro - VFS Server version 1
  */
+#define SANITY 1
+#define DEBUG  0
 #include <acess.h>
 #include <vfs.h>
 #include <vfs_int.h>
@@ -14,10 +16,11 @@ extern char *gsVFS_MountFile;
 #if 0
  int   VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
 #endif
+void   VFS_int_Unmount(tVFS_Mount *Mount);
 void   VFS_UpdateMountFile(void);
 
 // === GLOBALS ===
-tMutex glVFS_MountList;
+tRWLock        glVFS_MountList;
 tVFS_Mount     *gVFS_Mounts;
 tVFS_Mount     *gVFS_RootMount = NULL;
 Uint32 giVFS_NextMountIdent = 1;
@@ -37,25 +40,76 @@ Uint32      giVFS_NextMountIdent = 1;
  */
 int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
 {
-       tVFS_Mount      *mnt;
+       tVFS_Mount      *mnt, *parent_mnt;
        tVFS_Driver     *fs;
         int    deviceLen = strlen(Device);
         int    mountLen = strlen(MountPoint);
         int    argLen = strlen(Options);
        
        // Get the filesystem
-       fs = VFS_GetFSByName(Filesystem);
-       if(!fs) {
-               Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
-               return -1;
+       if( Filesystem && Filesystem[0] )
+       {
+               fs = VFS_GetFSByName(Filesystem);
+               if(!fs) {
+                       Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
+                       return -ENOENT;
+               }
+       }
+       else
+       {
+               int fd = VFS_Open(Device, VFS_OPENFLAG_READ);
+               if( fd == -1 ) {
+                       Log_Warning("VFS", "VFS_Mount - Unable to open '%s' for autodetect", Device);
+                       return -ENOENT;
+               }
+               
+               tVFS_Driver     *bestfs = NULL;
+                int    bestrank = 0, rank;
+               for( fs = gVFS_Drivers; fs; fs = fs->Next )
+               {
+                       if(!fs->Detect) continue ;
+                       rank = fs->Detect(fd);
+                       if(!rank)       continue ;
+                       if(!bestfs || rank > bestrank) {
+                               bestfs = fs;
+                               bestrank = rank;
+                       }
+               }
+               VFS_Close(fd);
+               if( bestfs == NULL ) {
+                       Log_Warning("VFS", "VFS_Mount - Filesystem autodetection failed");
+                       return -1;
+               }
+               
+               fs = bestfs;
+       }
+       
+       // Validate the mountpoint target
+       // - Only if / is mounted
+       if( gVFS_Mounts )
+       {
+               tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt);
+               if( !mpnode ) {
+                       Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint);
+                       return -1;
+               }
+               if( mpnode->Type->Close )
+                       mpnode->Type->Close(mpnode);
+               if( parent_mnt->RootNode == mpnode ) {
+                       Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)",
+                               MountPoint, parent_mnt->MountPoint);
+                       return -1;
+               }
        }
        
        // Create mount information
        mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
        if(!mnt) {
+               ASSERT(parent_mnt->OpenHandleCount > 0);
+               parent_mnt->OpenHandleCount --;
                return -2;
        }
-       
+
        // HACK: Forces VFS_ParsePath to fall back on root  
        if(mountLen == 1 && MountPoint[0] == '/')
                mnt->MountPointLen = 0;
@@ -64,6 +118,7 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        
        // Fill Structure
        mnt->Filesystem = fs;
+       mnt->OpenHandleCount = 0;
        
        mnt->Device = &mnt->StrData[0];
        memcpy( mnt->Device, Device, deviceLen+1 );
@@ -74,13 +129,36 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
        memcpy( mnt->Options, Options, argLen+1 );
        
+       // Parse options string
+       char    *str = mnt->Options;
+        int    nArg = 0;
+       do {
+               nArg ++;
+       } while( (str = strchr(str, ',')) );
+
+       char    *args[nArg + 1];
+       str = mnt->Options;
+       nArg = 0;
+       do {
+               args[nArg++] = str;
+               str = strchr(str, ',');
+               if(str) *str = '\0';
+       } while( str );
+       args[nArg] = 0; // NULL terminal
+       
        // Initialise Volume
-       mnt->RootNode = fs->InitDevice(Device, NULL);   //&ArgString);
+       mnt->RootNode = fs->InitDevice(Device, (const char **)args);
        if(!mnt->RootNode) {
                free(mnt);
+               ASSERT(parent_mnt->OpenHandleCount>0);
+               parent_mnt->OpenHandleCount --;
                return -2;
        }
 
+       // Repair the options string
+       while( nArg -- > 1 )
+               args[nArg][-1] = ',';
+
        mnt->Identifier = giVFS_NextMountIdent++;
        #if 0
        // Ensure identifiers don't repeat
@@ -93,11 +171,11 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
        if(!gVFS_RootMount)     gVFS_RootMount = mnt;
        
        // Add to mount list
-       Mutex_Acquire( &glVFS_MountList );
+       RWLock_AcquireWrite( &glVFS_MountList );
        {
-               tVFS_Mount      *tmp;
                mnt->Next = NULL;
                if(gVFS_Mounts) {
+                       tVFS_Mount      *tmp;
                        for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
                        tmp->Next = mnt;
                }
@@ -105,27 +183,139 @@ int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem
                        gVFS_Mounts = mnt;
                }
        }
-       Mutex_Release( &glVFS_MountList );
+       RWLock_Release( &glVFS_MountList );
        
-       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+       Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, fs->Name);
        
        VFS_UpdateMountFile();
        
        return 0;
 }
 
+void VFS_int_Unmount(tVFS_Mount *Mount)
+{
+       // Decrease the open handle count for the mountpoint filesystem.
+       if( Mount != gVFS_RootMount )
+       {
+               tVFS_Mount      *mpmnt;
+               for( mpmnt = gVFS_Mounts; mpmnt; mpmnt = mpmnt->Next )
+               {
+                       if( strncmp(mpmnt->MountPoint, Mount->MountPoint, mpmnt->MountPointLen) != 0 )
+                               continue ;
+                       if( Mount->MountPoint[ mpmnt->MountPointLen ] != '/' )
+                               continue ;
+                       break;
+               }
+               if(mpmnt) {
+                       ASSERT(mpmnt->OpenHandleCount>0);
+                       mpmnt->OpenHandleCount --;
+               }
+               else {
+                       Log_Notice("VFS", "Mountpoint '%s' has no parent", Mount->MountPoint);
+               }
+       }
+
+       if( Mount->Filesystem->Unmount )
+               Mount->Filesystem->Unmount( Mount->RootNode );
+       LOG("%p (%s) unmounted", Mount, Mount->MountPoint);
+       free(Mount);
+}
+
+int VFS_Unmount(const char *Mountpoint)
+{
+       tVFS_Mount      *mount, *prev = NULL;
+       RWLock_AcquireWrite( &glVFS_MountList );
+       for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next )
+       {
+               if( strcmp(Mountpoint, mount->MountPoint) == 0 ) {
+                       if( mount->OpenHandleCount ) {
+                               LOG("Mountpoint busy");
+                               RWLock_Release(&glVFS_MountList);
+                               Log_Log("VFS", "Unmount of '%s' deferred, still busy (%i open handles)",
+                                       Mountpoint, mount->OpenHandleCount);
+                               return EBUSY;
+                       }
+                       if(prev)
+                               prev->Next = mount->Next;
+                       else
+                               gVFS_Mounts = mount->Next;
+                       break;
+               }
+       }
+       RWLock_Release( &glVFS_MountList );
+       if( !mount ) {
+               LOG("Mountpoint not found");
+               return ENOENT;
+       }
+
+       VFS_int_Unmount(mount);
+
+       VFS_UpdateMountFile();
+       
+       return EOK;
+}
+
+int VFS_UnmountAll(void)
+{
+        int    nUnmounted = 0;
+       tVFS_Mount      *mount, *prev = NULL, *next;
+
+       RWLock_AcquireWrite( &glVFS_MountList );
+       // If we've unmounted the final filesystem, all good
+       if( gVFS_Mounts == NULL) {
+               RWLock_Release( &glVFS_MountList );
+               
+               // Final unmount means VFS completely deinited
+               VFS_Deinit();
+               return -1;
+       }
+
+       for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
+       {
+               next = mount->Next;
+               
+               ASSERT(mount->OpenHandleCount >= 0);            
+
+               // Can't unmount stuff with open handles
+               if( mount->OpenHandleCount > 0 ) {
+                       LOG("%p (%s) has open handles (%i of them)",
+                               mount, mount->MountPoint, mount->OpenHandleCount);
+                       continue;
+               }
+               
+               if(prev)
+                       prev->Next = mount->Next;
+               else
+                       gVFS_Mounts = mount->Next;
+               
+               VFS_int_Unmount(mount);
+               mount = prev;
+               nUnmounted ++;
+       }
+       RWLock_Release( &glVFS_MountList );
+
+       VFS_UpdateMountFile();
+
+       return nUnmounted;
+}
+
 /**
  * \brief Gets a mount point given the identifier
  */
 tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
 {
        tVFS_Mount      *mnt;
+       
+       RWLock_AcquireRead(&glVFS_MountList);
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                if(mnt->Identifier == MountID)
-                       return mnt;
+                       break;
        }
-       return NULL;
+       if(mnt)
+               mnt->OpenHandleCount ++;
+       RWLock_Release(&glVFS_MountList);
+       return mnt;
 }
 
 /**
@@ -142,14 +332,17 @@ void VFS_UpdateMountFile(void)
        // Format:
        // <device>\t<location>\t<type>\t<options>\n
        
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
                        + strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
        }
+       RWLock_Release( &glVFS_MountList );
        
        buf = malloc( len + 1 );
        len = 0;
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                strcpy( &buf[len], mnt->Device );
@@ -168,6 +361,7 @@ void VFS_UpdateMountFile(void)
                len += strlen(mnt->Options);
                buf[len++] = '\n';
        }
+       RWLock_Release( &glVFS_MountList );
        buf[len] = 0;
        
        SysFS_UpdateFile( giVFS_MountFileID, buf, len );
index d2796c1..0d23894 100644 (file)
@@ -1,7 +1,11 @@
 /*
- * AcessMicro VFS
- * - File IO Passthru's
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * vfs/nodecache.c
+ * - VFS Node Caching facility
  */
+#define DEBUG  0
 #include <acess.h>
 #include "vfs.h"
 #include "vfs_int.h"
@@ -45,7 +49,7 @@ int Inode_GetHandle()
        gVFS_InodeCache = ent;
        SHORTREL( &glVFS_InodeCache );
        
-       return gVFS_NextInodeHandle-1;
+       return ent->Handle;
 }
 
 /**
@@ -107,7 +111,10 @@ tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
        newEnt->Next = ent;
        memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
        prev->Next = newEnt;
-               
+       newEnt->Node.ReferenceCount = 1;
+
+       LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
+
        return &newEnt->Node;
 }
 
@@ -115,42 +122,72 @@ tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
  * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
  * \brief Dereferences/Removes a cached node
  */
-void Inode_UncacheNode(int Handle, Uint64 Inode)
+int Inode_UncacheNode(int Handle, Uint64 Inode)
 {
        tInodeCache     *cache;
        tCachedInode    *ent, *prev;
        
        cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return ;
-       
-       if(Inode > cache->MaxCached)    return ;
+       if(!cache) {
+               Log_Notice("Inode", "Invalid cache handle %i used", Handle);
+               return -1;
+       }
+
+       ENTER("iHandle XInode", Handle, Inode);
+
+       if(Inode > cache->MaxCached) {
+               LEAVE('i', -1);
+               return -1;
+       }
        
        // Search Cache
        ent = cache->FirstNode;
-       prev = (tCachedInode*) &cache->FirstNode;       // Special case removal
+       prev = NULL;
        for( ; ent; prev = ent, ent = ent->Next )
        {
                if(ent->Node.Inode < Inode)     continue;
-               if(ent->Node.Inode > Inode)     return;
-               ent->Node.ReferenceCount --;
-               // Check if node needs to be freed
-               if(ent->Node.ReferenceCount == 0)
-               {
+               if(ent->Node.Inode > Inode) {
+                       LEAVE('i', -1);
+                       return -1;
+               }
+               break;
+       }
+
+       LOG("ent = %p", ent);
+
+       if( !ent ) {
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       ent->Node.ReferenceCount --;
+       // Check if node needs to be freed
+       if(ent->Node.ReferenceCount == 0)
+       {
+               if( prev )
                        prev->Next = ent->Next;
-                       if(ent->Node.Inode == cache->MaxCached)
-                       {
-                               if(ent != cache->FirstNode)
-                                       cache->MaxCached = prev->Node.Inode;
-                               else
-                                       cache->MaxCached = 0;
-                       }
-                               
-                       free(ent);
+               else
+                       cache->FirstNode = ent->Next;
+               if(ent->Node.Inode == cache->MaxCached)
+               {
+                       if(ent != cache->FirstNode && prev)
+                               cache->MaxCached = prev->Node.Inode;
+                       else
+                               cache->MaxCached = 0;
                }
-               return ;
+               
+               if(ent->Node.Data)
+                       free(ent->Node.Data);   
+               free(ent);
+               LOG("Freed");
+               LEAVE('i', 1);
+               return 1;
+       }
+       else
+       {
+               LEAVE('i', 0);
+               return 0;
        }
-       
-       return ;
 }
 
 /**
index cfb296b..e83ace8 100644 (file)
@@ -2,6 +2,7 @@
  * Acess2 VFS
  * - Open, Close and ChDir
  */
+#define SANITY 1
 #define DEBUG  0
 #include <acess.h>
 #include "vfs.h"
@@ -21,9 +22,22 @@ extern int   VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode);
 extern tVFS_Node       *VFS_MemFile_Create(const char *Path);
 
 // === PROTOTYPES ===
+void   _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag);
+void   _DereferenceMount(tVFS_Mount *Mount, const char *DebugTag);
  int   VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode );
 
 // === CODE ===
+void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag)
+{
+//     Log_Debug("VFS", "%s: inc. mntpt '%s' to %i", DebugTag, Mount->MountPoint, Mount->OpenHandleCount+1);
+       Mount->OpenHandleCount ++;
+}
+void _DereferenceMount(tVFS_Mount *Mount, const char *DebugTag)
+{
+//     Log_Debug("VFS", "%s: dec. mntpt '%s' to %i", DebugTag, Mount->MountPoint, Mount->OpenHandleCount-1);
+       ASSERT(Mount->OpenHandleCount > 0);
+       Mount->OpenHandleCount --;
+}
 /**
  * \fn char *VFS_GetAbsPath(const char *Path)
  * \brief Create an absolute path from a relative one
@@ -201,6 +215,7 @@ restart_parse:
                        *TruePath = malloc( gVFS_RootMount->MountPointLen+1 );
                        strcpy(*TruePath, gVFS_RootMount->MountPoint);
                }
+               _ReferenceMount(gVFS_RootMount, "ParsePath - Fast Tree Root");
                if(MountPoint)  *MountPoint = gVFS_RootMount;
                LEAVE('p', gVFS_RootMount->RootNode);
                return gVFS_RootMount->RootNode;
@@ -214,6 +229,7 @@ restart_parse:
        
        // Find Mountpoint
        longestMount = gVFS_RootMount;
+       RWLock_AcquireRead( &glVFS_MountList );
        for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
        {
                // Quick Check
@@ -222,25 +238,35 @@ restart_parse:
                // Length Check - If the length is smaller than the longest match sofar
                if(mnt->MountPointLen < longestMount->MountPointLen)    continue;
                // String Compare
-               cmp = strcmp(Path, mnt->MountPoint);
+               cmp = strncmp(Path, mnt->MountPoint, mnt->MountPointLen);
+               // Not a match, continue
+               if(cmp != 0)    continue;
                
                #if OPEN_MOUNT_ROOT
                // Fast Break - Request Mount Root
-               if(cmp == 0) {
+               if(Path[mnt->MountPointLen] == '\0') {
                        if(TruePath) {
                                *TruePath = malloc( mnt->MountPointLen+1 );
                                strcpy(*TruePath, mnt->MountPoint);
                        }
                        if(MountPoint)
                                *MountPoint = mnt;
+                       RWLock_Release( &glVFS_MountList );
+                       LOG("Mount %p root", mnt);
+                       _ReferenceMount(mnt, "ParsePath - Mount Root");
                        LEAVE('p', mnt->RootNode);
                        return mnt->RootNode;
                }
                #endif
-               // Not a match, continue
-               if(cmp != '/')  continue;
                longestMount = mnt;
        }
+       if(!longestMount) {
+               Log_Panic("VFS", "VFS_ParsePath - No mount for '%s'", Path);
+               return NULL;
+       }
+       
+       _ReferenceMount(longestMount, "ParsePath");
+       RWLock_Release( &glVFS_MountList );
        
        // Save to shorter variable
        mnt = longestMount;
@@ -277,9 +303,16 @@ restart_parse:
                }
                
                // Check if the node has a FindDir method
+               if( !curNode->Type )
+               {
+                       LOG("Finddir failure on '%s' - No type", Path);
+                       Log_Error("VFS", "Node at '%s' has no type (mount %s:%s)",
+                               Path, mnt->Filesystem->Name, mnt->MountPoint);
+                       goto _error;
+               }
                if( !curNode->Type->FindDir )
                {
-                       LOG("Finddir failure on '%s'", Path);
+                       LOG("Finddir failure on '%s' - No FindDir method in %s", Path, curNode->Type->TypeName);
                        goto _error;
                }
                LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
@@ -325,6 +358,7 @@ restart_parse:
                                path_buffer[ curNode->Size ] = '\0';
                                LOG("path_buffer = '%s'", path_buffer);
                                strcat(path_buffer, Path + ofs+nextSlash);
+                               // TODO: Pass to VFS_GetAbsPath to handle ../. in the symlink
                                
                                Path = path_buffer;
 //                             Log_Debug("VFS", "VFS_ParsePath: Symlink translated to '%s'", Path);
@@ -333,6 +367,7 @@ restart_parse:
 
                        // EVIL: Goto :)
                        LOG("Symlink -> '%s', restart", Path);
+                       _DereferenceMount(mnt, "ParsePath - sym");
                        goto restart_parse;
                }
                
@@ -376,7 +411,7 @@ restart_parse:
        LOG("tmpNode = %p", tmpNode);
        // Check if file was found
        if(!tmpNode) {
-               LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+               LOG("Node '%s' not found in dir '%.*s'", &Path[ofs], ofs, Path);
                goto _error;
        }
        _CloseNode( curNode );
@@ -402,6 +437,8 @@ restart_parse:
                *MountPoint = mnt;
        }
        
+       // Leave the mointpoint's count increased
+       
        LEAVE('p', tmpNode);
        return tmpNode;
 
@@ -412,6 +449,9 @@ _error:
                free(*TruePath);
                *TruePath = NULL;
        }
+       // Open failed, so decrement the open handle count
+       _DereferenceMount(mnt, "ParsePath - error");
+       
        LEAVE('n');
        return NULL;
 }
@@ -439,6 +479,13 @@ int VFS_int_CreateHandle( tVFS_Node *Node, tVFS_Mount *Mount, int Mode )
                errno = EACCES;
                LEAVE_RET('i', -1);
        }
+
+       if( MM_GetPhysAddr(Node->Type) == 0 ) {
+               Log_Error("VFS", "Node %p from mount '%s' (%s) has a bad type (%p)",
+                       Node, Mount->MountPoint, Mount->Filesystem->Name, Node->Type);
+               errno = EINTERNAL;
+               LEAVE_RET('i', -1);
+       }
        
        i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), Node, Mode );
        if( i < 0 ) {
@@ -484,10 +531,61 @@ int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
        if( !node && (Flags & VFS_OPENFLAG_CREATE) )
        {
                // TODO: Translate `Mode` into ACL and node flags
-               // Get parent, create node
-               VFS_MkNod(absPath, 0);
-               node = VFS_ParsePath(absPath, NULL, &mnt);
+               Uint    new_flags = 0;
+               
+               // Split path at final separator
+               char *file = strrchr(absPath, '/');
+               *file = '\0';
+               file ++;
+
+               // Get parent node
+               tVFS_Mount      *pmnt;
+               tVFS_Node *pnode = VFS_ParsePath(absPath, NULL, &pmnt);
+               if(!pnode) {
+                       LOG("Unable to open parent '%s'", absPath);
+                       free(absPath);
+                       errno = ENOENT;
+                       LEAVE_RET('i', -1);
+               }
+
+               // Check ACLs on the parent
+               if( !VFS_CheckACL(pnode, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
+                       errno = EACCES;
+                       goto _pnode_err;
+               }
+
+               // Check that there's a MkNod method
+               if( !pnode->Type || !pnode->Type->MkNod ) {
+                       Log_Warning("VFS", "VFS_Open - Directory has no MkNod method");
+                       errno = EINVAL;
+                       goto _pnode_err;
+               }
+               
+               node = pnode->Type->MkNod(pnode, file, new_flags);
+               if( !node ) {
+                       LOG("Cannot create node '%s' in '%s'", file, absPath);
+                       errno = ENOENT;
+                       goto _pnode_err;
+               }
+               // Set mountpoint (and increment open handle count)
+               mnt = pmnt;
+               _ReferenceMount(mnt, "Open - create");
+               // Fall through on error check
+               
+               _CloseNode(pnode);
+               _DereferenceMount(pmnt, "Open - create");
+               goto _pnode_ok;
+
+       _pnode_err:
+               if( pnode ) {
+                       _CloseNode(pnode);
+                       _DereferenceMount(pmnt, "Open - create,fail");
+                       free(absPath);
+               }
+               LEAVE('i', -1);
+               return -1;
        }
+       _pnode_ok:
        
        // Free generated path
        free(absPath);
@@ -497,7 +595,7 @@ int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
        {
                LOG("Cannot find node");
                errno = ENOENT;
-               LEAVE_RET('i', -1);
+               goto _error;
        }
        
        // Check for symlinks
@@ -506,26 +604,35 @@ int VFS_OpenEx(const char *Path, Uint Flags, Uint Mode)
                char    tmppath[node->Size+1];
                if( node->Size > MAX_PATH_LEN ) {
                        Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
-                       LEAVE_RET('i', -1);
+                       goto _error;
                }
                if( !node->Type || !node->Type->Read ) {
                        Log_Warning("VFS", "VFS_Open - No read method on symlink");
-                       LEAVE_RET('i', -1);
+                       goto _error;
                }
                // Read symlink's path
                node->Type->Read( node, 0, node->Size, tmppath );
                tmppath[ node->Size ] = '\0';
                _CloseNode( node );
+               _DereferenceMount(mnt, "Open - symlink");
                // Open the target
                node = VFS_ParsePath(tmppath, NULL, &mnt);
                if(!node) {
                        LOG("Cannot find symlink target node (%s)", tmppath);
                        errno = ENOENT;
-                       LEAVE_RET('i', -1);
+                       goto _error;
                }
        }
 
-       LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
+        int    ret = VFS_int_CreateHandle(node, mnt, Flags);
+       LEAVE_RET('x', ret);
+_error:
+       if( node )
+       {
+               _DereferenceMount(mnt, "Open - error");
+               _CloseNode(node);
+       }
+       LEAVE_RET('i', -1);
 }
 
 
@@ -568,6 +675,9 @@ int VFS_OpenChild(int FD, const char *Name, Uint Mode)
                LEAVE_RET('i', -1);
        }
 
+       // Increment open handle count, no problems with the mount going away as `h` is already open on it
+       _ReferenceMount(h->Mount, "OpenChild");
+
        LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode));
 }
 
@@ -618,7 +728,12 @@ void VFS_Close(int FD)
                Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD);
                return;
        }
-       
+
+       if( h->Node == NULL ) {
+               Log_Warning("VFS", "Non-open handle passed to VFS_Close, 0x%x", FD);
+               return ;
+       }       
+
        #if VALIDATE_VFS_FUNCTIPONS
        if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) {
                Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)",
@@ -627,8 +742,13 @@ void VFS_Close(int FD)
        }
        #endif
        
+       LOG("Handle %x", FD);
        _CloseNode(h->Node);
-       
+
+       if( h->Mount ) {
+               _DereferenceMount(h->Mount, "Close");
+       }
+
        h->Node = NULL;
 }
 
@@ -674,7 +794,7 @@ int VFS_ChDir(const char *Dest)
                *cwdptr = buf;
        }
        
-       Log("Updated CWD to '%s'", buf);
+       Log_Debug("VFS", "Updated CWD to '%s'", buf);
        
        return 1;
 }
index d2ef808..412cb1a 100644 (file)
@@ -16,6 +16,7 @@
 #include <semaphore.h>
 #include <threads.h>
 #include <events.h>
+#include <timers.h>
 
 // === CONSTANTS ===
 #define        NUM_THREADS_PER_ALLOC   4
@@ -83,16 +84,25 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                }
        }
 
-       // - Fast return for polling
-       if( Timeout && *Timeout == 0 )  return 0;
-
        // Wait for things      
-       if( !Timeout || *Timeout > 0 )
+       if( !Timeout )
        {
                LOG("Semaphore_Wait()");
                // TODO: Actual timeout
                Threads_WaitEvents( THREAD_EVENT_VFS );
        }
+       else if( *Timeout > 0 )
+       {
+               tTimer *t = Time_AllocateTimer(NULL, NULL);
+               // Clear timer event
+               Threads_ClearEvent( THREAD_EVENT_TIMER );
+               // TODO: Convert *Timeout?
+               LOG("Timeout %lli ms", *Timeout);
+               Time_ScheduleTimer( t, *Timeout );
+               // Wait for the timer or a VFS event
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER );
+               Time_FreeTimer(t);
+       }
        
        // Get return value
        ret = 0;
@@ -106,6 +116,9 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                VFS_int_Select_RemThread(*list, thisthread);
                ret = ret || *flag == wanted;
        }
+
+       Threads_ClearEvent( THREAD_EVENT_VFS );
+       Threads_ClearEvent( THREAD_EVENT_TIMER );
        
        LEAVE('i', ret);
        return ret;
@@ -142,23 +155,35 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
                LEAVE('i', ret);
                return ret;
        }
-       
-       // TODO: Implement timeout
-       LOG("Timeout = %p", Timeout);
-       
-       // Wait (only if there is no timeout, or it is greater than zero
-       if( !Timeout || *Timeout > 0 )
+
+       // Wait for things      
+       if( !Timeout )
        {
-               // TODO: Timeout
-               // TODO: Allow extra events to be waited upon
+               LOG("Semaphore_Wait()");
+               // TODO: Actual timeout
                Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
        }
-       
+       else if( *Timeout > 0 )
+       {
+               tTimer *t = Time_AllocateTimer(NULL, NULL);
+               // Clear timer event
+               Threads_ClearEvent( THREAD_EVENT_TIMER );
+               // TODO: Convert *Timeout?
+               LOG("Timeout %lli ms", *Timeout);
+               Time_ScheduleTimer( t, *Timeout );
+               // Wait for the timer or a VFS event
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER|ExtraEvents );
+               Time_FreeTimer(t);
+       }
        // Fill output (modify *Handles)
        // - Also, de-register
        ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
        ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
        ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+       
+       Threads_ClearEvent( THREAD_EVENT_VFS );
+       Threads_ClearEvent( THREAD_EVENT_TIMER );
+       
        LEAVE('i', ret);
        return ret;
 }
@@ -377,6 +402,7 @@ int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllo
                        }
                        count ++;
                        if( MaxAllowed && count >= MaxAllowed ) {
+                               Mutex_Release(&List->Lock);
                                LEAVE('i', 1);
                                return 1;
                        }
diff --git a/KernelLand/Modules/Display/NVidia/main.c b/KernelLand/Modules/Display/NVidia/main.c
new file mode 100644 (file)
index 0000000..7ebbca3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Acess2 NVidia Graphics Driver
+ * - By John Hodge (thePowersGang)
+ * 
+ * main.c
+ * - Driver Core
+ *
+ * Reference: linux/drivers/video/nvidia
+ */
+#define DEBUG  1
+#define VERSION VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include "regs.h"
+
+// === PROTOTYPES ===
+ int   NV_Install(char **Arguments);
+ int   NV_Cleanup(void);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, Video_NVidia, VERSION, NV_Install, NV_Cleanup, NULL);
+
+// === CODE ===
+int NV_Install(char **Arguments)
+{
+       return MODERR_NOTNEEDED;
+}
+
+int NV_Cleanup(void)
+{
+       return 0;
+}
+
diff --git a/KernelLand/Modules/Display/NVidia/regs.c b/KernelLand/Modules/Display/NVidia/regs.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/KernelLand/Modules/Display/NVidia/regs.h b/KernelLand/Modules/Display/NVidia/regs.h
new file mode 100644 (file)
index 0000000..6c6fd56
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Acess2 NVidia Graphics Driver
+ * - By John Hodge (thePowersGang)
+ * 
+ * regs.h
+ * - Register definitions
+ */
+#ifndef _NVIDIA__REGS_H_
+#define _NVIDIA__REGS_H_
+
+// CRT Controller Registers
+enum eNVRegs_CRTC
+{
+       NUM_CRTC_REGS
+};
+
+// Attribute Controller registers
+enum eNVRegs_ATC
+{
+       NUM_ATC_REGS
+};
+
+enum eNVRegs_GRC
+{
+       NUM_GRC_REGS
+};
+
+// Sequencer registers
+enum eNVRegs_SEQ
+{
+       NUM_SEQ_REGS
+};
+
+struct sNVRegDump
+{
+       Uint8   atc_regs[NUM_ATC_REGS];
+       Uint8   crtc_regs[NUM_CRTC_REGS];
+       Uint8   gra_regs[NUM_GRC_REGS];
+       Uint8   seq_regs[NUM_SEQ_REGS];
+};
+
+#endif
+
diff --git a/KernelLand/Modules/Display/Tegra2Vid/Registers.txt b/KernelLand/Modules/Display/Tegra2Vid/Registers.txt
new file mode 100644 (file)
index 0000000..42dce4e
--- /dev/null
@@ -0,0 +1,212 @@
+Display CMD Registers
+00000000000000d [Tegra2Vi] 0 - [0x000] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x001] = 0x00000100 (-)
+00000000000000d [Tegra2Vi] 0 - [0x002] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x003] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x004] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x005] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x006] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x007] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x008] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x009] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00C] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00D] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00E] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x010] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x011] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x012] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x013] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x014] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x015] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x016] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x017] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x018] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x019] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x01A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x028] = 0x0000011A (-)
+00000000000000d [Tegra2Vi] 0 - [0x029] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02C] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02D] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02E] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x030] = 0xF000F800 (-)
+00000000000000d [Tegra2Vi] 0 - [0x031] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x032] = 0x00000020 (-)
+00000000000000d [Tegra2Vi] 0 - [0x033] = 0x00000114 (-)
+00000000000000d [Tegra2Vi] 0 - [0x034] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x035] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x036] = 0x00050155 (-)
+00000000000000d [Tegra2Vi] 0 - [0x037] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x038] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x039] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03C] = 0x0009060C (-)
+00000000000000d [Tegra2Vi] 0 - [0x03D] = 0x000F021C (-)
+00000000000000d [Tegra2Vi] 0 - [0x03E] = 0x000D0210 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x040] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x041] = 0x00000000 (DC_CMD_STATE_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x042] = 0x00000010 (DC_CMD_DISPLAY_WINDOW_HEADER_0)
+00000000000000d [Tegra2Vi] 0 - [0x043] = 0x00000000 (DC_CMD_REG_ACT_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - Display COM Registers
+00000000000000d [Tegra2Vi] 0 - [0x300] = 0x00000000 (DC_COM_CRC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x301] = 0x00000000 (DC_COM_CRC_CHECKSUM_0)
+00000000000000d [Tegra2Vi] 0 - [0x302] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE0_0)
+00000000000000d [Tegra2Vi] 0 - [0x303] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE1_0)
+00000000000000d [Tegra2Vi] 0 - [0x304] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE2_0)
+00000000000000d [Tegra2Vi] 0 - [0x305] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE3_0)
+00000000000000d [Tegra2Vi] 0 - [0x306] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY0_0)
+00000000000000d [Tegra2Vi] 0 - [0x307] = 0x01000000 (DC_COM_PIN_OUTPUT_POLARITY1_0)
+00000000000000d [Tegra2Vi] 0 - [0x308] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY2_0)
+00000000000000d [Tegra2Vi] 0 - [0x309] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY3_0)
+00000000000000d [Tegra2Vi] 0 - [0x30A] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA0_0)
+00000000000000d [Tegra2Vi] 0 - [0x30B] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA1_0)
+00000000000000d [Tegra2Vi] 0 - [0x30C] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA2_0)
+00000000000000d [Tegra2Vi] 0 - [0x30D] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA3_0)
+00000000000000d [Tegra2Vi] 0 - [0x30E] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE0_0)
+00000000000000d [Tegra2Vi] 0 - [0x30F] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE1_0)
+00000000000000d [Tegra2Vi] 0 - [0x310] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE2_0)
+00000000000000d [Tegra2Vi] 0 - [0x311] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE3_0)
+00000000000000d [Tegra2Vi] 0 - [0x312] = 0x00000000 (DC_COM_PIN_INPUT_DATA0_0)
+00000000000000d [Tegra2Vi] 0 - [0x313] = 0x00000000 (DC_COM_PIN_INPUT_DATA1_0)
+00000000000000d [Tegra2Vi] 0 - [0x314] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT0_0)
+00000000000000d [Tegra2Vi] 0 - [0x315] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT1_0)
+00000000000000d [Tegra2Vi] 0 - [0x316] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT2_0)
+00000000000000d [Tegra2Vi] 0 - [0x317] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT3_0)
+00000000000000d [Tegra2Vi] 0 - [0x318] = 0x00210222 (DC_COM_PIN_OUTPUT_SELECT4_0)
+00000000000000d [Tegra2Vi] 0 - [0x319] = 0x00002200 (DC_COM_PIN_OUTPUT_SELECT5_0)
+00000000000000d [Tegra2Vi] 0 - [0x31A] = 0x00020000 (DC_COM_PIN_OUTPUT_SELECT6_0)
+00000000000000d [Tegra2Vi] 0 - [0x31B] = 0x00000000 (DC_COM_PIN_MISC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x31C] = 0x00840152 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31D] = 0x00000144 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31E] = 0x00700111 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31F] = 0x00000077 (-)
+00000000000000d [Tegra2Vi] 0 - [0x320] = 0x01070023 (-)
+00000000000000d [Tegra2Vi] 0 - [0x321] = 0x0000D317 (-)
+00000000000000d [Tegra2Vi] 0 - [0x322] = 0xEAEE54C2 (-)
+00000000000000d [Tegra2Vi] 0 - [0x323] = 0x6BDC5DA4 (-)
+00000000000000d [Tegra2Vi] 0 - [0x324] = 0x05004210 (-)
+00000000000000d [Tegra2Vi] 0 - [0x325] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x326] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x327] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x328] = 0x00000400 (-)
+00000000000000d [Tegra2Vi] 0 - [0x329] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - Display DISP Registers
+00000000000000d [Tegra2Vi] 0 - [0x400] = 0x00000000 (DC_DISP_DISP_SIGNAL_OPTIONS0_0)
+00000000000000d [Tegra2Vi] 0 - [0x401] = 0x00000000 (DC_DISP_DISP_SIGNAL_OPTIONS1_0)
+00000000000000d [Tegra2Vi] 0 - [0x402] = 0x00000000 (DC_DISP_DISP_WIN_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x403] = 0x00000020 (DC_DISP_MEM_HIGH_PRIORITY_0)
+00000000000000d [Tegra2Vi] 0 - [0x404] = 0x00000001 (DC_DISP_MEM_HIGH_PRIORITY_TIMER_0)
+00000000000000d [Tegra2Vi] 0 - [0x405] = 0x00000000 (DC_DISP_DISP_TIMING_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x406] = 0x0001000B (DC_DISP_REF_TO_SYNC_0)
+00000000000000d [Tegra2Vi] 0 - [0x407] = 0x0004003A (DC_DISP_SYNC_WIDTH_0)
+00000000000000d [Tegra2Vi] 0 - [0x408] = 0x0004003A (DC_DISP_BACK_PORCH_0)
+00000000000000d [Tegra2Vi] 0 - [0x409] = 0x03000400 (DC_DISP_DISP_ACTIVE_0)
+00000000000000d [Tegra2Vi] 0 - [0x40A] = 0x0004003A (DC_DISP_FRONT_PORCH_0)
+00000000000000d [Tegra2Vi] 0 - [0x40B] = 0x00000918 (DC_DISP_H_PULSE0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x40C] = 0x1D970F55 (DC_DISP_H_PULSE0_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x40D] = 0x02AA0AC5 (DC_DISP_H_PULSE0_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x40E] = 0x039B00AA (DC_DISP_H_PULSE0_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x40F] = 0x044D1989 (DC_DISP_H_PULSE0_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x410] = 0x00000480 (DC_DISP_H_PULSE1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x411] = 0x198B1E2D (DC_DISP_H_PULSE1_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x412] = 0x04910669 (DC_DISP_H_PULSE1_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x413] = 0x08381FA4 (DC_DISP_H_PULSE1_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x414] = 0x009C0625 (DC_DISP_H_PULSE1_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x415] = 0x00000608 (DC_DISP_H_PULSE2_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x416] = 0x0C001469 (DC_DISP_H_PULSE2_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x417] = 0x07690B17 (DC_DISP_H_PULSE2_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x418] = 0x00360257 (DC_DISP_H_PULSE2_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x419] = 0x1F1809D6 (DC_DISP_H_PULSE2_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x41A] = 0x000007D0 (DC_DISP_V_PULSE0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x41B] = 0x15CB1886 (DC_DISP_V_PULSE0_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x41C] = 0x02401EA8 (DC_DISP_V_PULSE0_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x41D] = 0x09750264 (DC_DISP_V_PULSE0_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x41E] = 0x00000010 (DC_DISP_V_PULSE1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x41F] = 0x16BA0A17 (DC_DISP_V_PULSE1_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x420] = 0x1AE21A90 (DC_DISP_V_PULSE1_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x421] = 0x06860AD7 (DC_DISP_V_PULSE1_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x422] = 0x00000000 (DC_DISP_V_PULSE2_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x423] = 0x0CC31C03 (DC_DISP_V_PULSE2_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x424] = 0x00000000 (DC_DISP_V_PULSE3_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x425] = 0x07071A0E (DC_DISP_V_PULSE3_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x426] = 0x02960DA3 (DC_DISP_M0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x427] = 0x1F8C1951 (DC_DISP_M1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x428] = 0x15070003 (DC_DISP_DI_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x429] = 0x0000CEF5 (DC_DISP_PP_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x42A] = 0x10D08381 (DC_DISP_PP_SELECT_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x42B] = 0x1C2CB600 (DC_DISP_PP_SELECT_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x42C] = 0x73B3DE7D (DC_DISP_PP_SELECT_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x42D] = 0x0779CA03 (DC_DISP_PP_SELECT_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x42E] = 0x00000005 (DC_DISP_DISP_CLOCK_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x42F] = 0x00000000 (DC_DISP_DISP_INTERFACE_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x430] = 0x00000200 (DC_DISP_DISP_COLOR_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x431] = 0x00010001 (DC_DISP_SHIFT_CLOCK_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x432] = 0x00000005 (DC_DISP_DATA_ENABLE_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x433] = 0x00000000 (DC_DISP_SERIAL_INTERFACE_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x434] = 0x00000000 (DC_DISP_LCD_SPI_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x435] = 0x00DA0731 (DC_DISP_BORDER_COLOR_0)
+00000000000000d [Tegra2Vi] 0 - [0x436] = 0x00E9B832 (DC_DISP_COLOR_KEY0_LOWER_0)
+00000000000000d [Tegra2Vi] 0 - [0x437] = 0x006B4475 (DC_DISP_COLOR_KEY0_UPPER_0)
+00000000000000d [Tegra2Vi] 0 - [0x438] = 0x000FA6FB (DC_DISP_COLOR_KEY1_LOWER_0)
+00000000000000d [Tegra2Vi] 0 - [0x439] = 0x00304301 (DC_DISP_COLOR_KEY1_UPPER_0)
+00000000000000d [Tegra2Vi] 0 - [0x43A] = 0x00000000 (_DC_DISP_UNUSED_43A)
+00000000000000d [Tegra2Vi] 0 - [0x43B] = 0x00000000 (_DC_DISP_UNUSED_43B)
+00000000000000d [Tegra2Vi] 0 - [0x43C] = 0x004962ED (DC_DISP_CURSOR_FOREGROUND_0)
+00000000000000d [Tegra2Vi] 0 - [0x43D] = 0x0063462E (DC_DISP_CURSOR_BACKGROUND_0)
+00000000000000d [Tegra2Vi] 0 - [0x43E] = 0x3021352C (DC_DISP_CURSOR_START_ADDR_0)
+00000000000000d [Tegra2Vi] 0 - [0x43F] = 0x3021352C (DC_DISP_CURSOR_START_ADDR_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x440] = 0x21B10B4B (DC_DISP_CURSOR_POSITION_0)
+00000000000000d [Tegra2Vi] 0 - [0x441] = 0x21B10B4B (DC_DISP_CURSOR_POSITION_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x442] = 0x00000030 (DC_DISP_INIT_SEQ_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x443] = 0x8C0BF46E (DC_DISP_SPI_INIT_SEQ_DATA_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x444] = 0xE08C7EBA (DC_DISP_SPI_INIT_SEQ_DATA_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x445] = 0x89A6A8FD (DC_DISP_SPI_INIT_SEQ_DATA_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x446] = 0x80D5BC36 (DC_DISP_SPI_INIT_SEQ_DATA_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x480] = 0x00000000 (DC_DISP_DC_MCCIF_FIFOCTRL_0)
+00000000000000d [Tegra2Vi] 0 - [0x481] = 0xCF401F1F (DC_DISP_MCCIF_DISPLAY0A_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x482] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY0B_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x483] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY0C_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x484] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY1B_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x4C0] = 0x00000000 (DC_DISP_DAC_CRT_CTRL_0)
+00000000000000d [Tegra2Vi] 0 - [0x4C1] = 0x00000002 (DC_DISP_DISP_MISC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - WINC_A Registers
+00000000000000d [Tegra2Vi] 0 - [0x700] = 0x40000040 (DC_WIN_A_WIN_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x701] = 0x00000000 (DC_WIN_A_BYTE_SWAP_0)
+00000000000000d [Tegra2Vi] 0 - [0x702] = 0x00000000 (DC_WIN_A_BUFFER_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x703] = 0x00000006 (DC_WIN_A_COLOR_DEPTH_0)
+00000000000000d [Tegra2Vi] 0 - [0x704] = 0x00000000 (DC_WIN_A_POSITION_0)
+00000000000000d [Tegra2Vi] 0 - [0x705] = 0x03000400 (DC_WIN_A_SIZE_0)
+00000000000000d [Tegra2Vi] 0 - [0x706] = 0x03000800 (DC_WIN_A_PRESCALED_SIZE_0)
+00000000000000d [Tegra2Vi] 0 - [0x707] = 0x00000000 (DC_WIN_A_H_INITIAL_DDA_0)
+00000000000000d [Tegra2Vi] 0 - [0x708] = 0x00000000 (DC_WIN_A_V_INITIAL_DDA_0)
+00000000000000d [Tegra2Vi] 0 - [0x709] = 0x10051004 (DC_WIN_A_DDA_INCREMENT_0)
+00000000000000d [Tegra2Vi] 0 - [0x70A] = 0x00000800 (DC_WIN_A_LINE_STRIDE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70B] = 0x00000000 (DC_WIN_A_BUF_STRIDE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70C] = 0x00000000 (DC_WIN_A_BUFFER_ADDR_MODE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70D] = 0x00000000 (DC_WIN_A_DV_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x70E] = 0x00000404 (DC_WIN_A_BLEND_NOKEY_0)
+00000000000000d [Tegra2Vi] 0 - [0x70F] = 0x0000FF00 (-)
+00000000000000d [Tegra2Vi] 0 - [0x710] = 0x0000FF00 (-)
+00000000000000d [Tegra2Vi] 0 - [0x711] = 0x00EB0B0D (-)
+00000000000000d [Tegra2Vi] 0 - [0x712] = 0x000C270E (-)
+00000000000000d [Tegra2Vi] 0 - [0x713] = 0x00263E09 (-)
+00000000000000d [Tegra2Vi] 0 - [0x714] = 0x446996C9 (-)
+00000000000000d [Tegra2Vi] 0 - WINBUF_A
+00000000000000d [Tegra2Vi] 0 - [0x800] = 0x1C022000 (DC_WINBUF_A_START_ADDR_0)
+00000000000000d [Tegra2Vi] 0 - [0x801] = 0x1C022000 (DC_WINBUF_A_START_ADDR_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x802] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x803] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x804] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x805] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x806] = 0x00000000 (DC_WINBUF_A_ADDR_H_OFFSET_0)
+00000000000000d [Tegra2Vi] 0 - [0x807] = 0x00000000 (DC_WINBUF_A_ADDR_H_OFFSET_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x808] = 0x00000000 (DC_WINBUF_A_ADDR_V_OFFSET_0)
+00000000000000d [Tegra2Vi] 0 - [0x809] = 0x00000000 (DC_WINBUF_A_ADDR_V_OFFSET_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x80A] = 0x00000000 (DC_WINBUF_A_UFLOW_STATUS)
index 41afc7f..e19a5ff 100644 (file)
@@ -3,6 +3,7 @@
  * - Driver core
  */
 #define DEBUG  0
+#define DUMP_REGISTERS 1
 #define VERSION        ((0<<8)|10)
 #include <acess.h>
 #include <errno.h>
@@ -63,6 +64,11 @@ tDrvUtil_Video_BufInfo       gTegra2Vid_DrvUtil_BufInfo;
 tVideo_IOCtl_Pos       gTegra2Vid_CursorPos;
 
 // === CODE ===
+inline void _dumpreg(int i)
+{
+       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x (%s)", i, gpTegra2Vid_IOMem[i],
+               (csaTegra2Vid_RegisterNames[i] ? csaTegra2Vid_RegisterNames[i] : "-"));
+}
 /**
  */
 int Tegra2Vid_Install(char **Arguments)
@@ -71,33 +77,23 @@ int Tegra2Vid_Install(char **Arguments)
 //     KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
 
        gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
-       #if 0
+       #if DUMP_REGISTERS
        {
                Log_Debug("Tegra2Vid", "Display CMD Registers");
-               for( int i = 0x000; i <= 0x01A; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
-               for( int i = 0x028; i <= 0x043; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+               for( int i = 0x000; i <= 0x01A; i ++ )  _dumpreg(i);
+               for( int i = 0x028; i <= 0x043; i ++ )  _dumpreg(i);
                Log_Debug("Tegra2Vid", "Display COM Registers");
-               for( int i = 0x300; i <= 0x329; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+               for( int i = 0x300; i <= 0x329; i ++ )  _dumpreg(i);
                Log_Debug("Tegra2Vid", "Display DISP Registers");
-               for( int i = 0x400; i <= 0x446; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
-               for( int i = 0x480; i <= 0x484; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
-               for( int i = 0x4C0; i <= 0x4C1; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
-
+               for( int i = 0x400; i <= 0x446; i ++ )  _dumpreg(i);
+               for( int i = 0x480; i <= 0x484; i ++ )  _dumpreg(i);
+               for( int i = 0x4C0; i <= 0x4C1; i ++ )  _dumpreg(i);
                Log_Debug("Tegra2Vid", "WINC_A Registers");
-               for( int i = 0x700; i <= 0x714; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+               for( int i = 0x700; i <= 0x714; i ++ )  _dumpreg(i);
                Log_Debug("Tegra2Vid", "WINBUF_A");
-               for( int i = 0x800; i <= 0x80A; i ++ )
-                       Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+               for( int i = 0x800; i <= 0x80A; i ++ )  _dumpreg(i);
        }
        #endif
-//     return 1;
 
        // HACK!!!
 #if 0
@@ -120,13 +116,26 @@ int Tegra2Vid_Install(char **Arguments)
                );
        memset(gpTegra2Vid_Framebuffer, 0xFF, 0x1000);
 
-//     gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] &= ~0x40;
+#if 0
+       gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] = (1 << 30);
        gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
+       gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0];
+       gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
+               gTegra2Vid_DrvUtil_BufInfo.Pitch =
+               1680*4;
+       gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
+       gTegra2Vid_DrvUtil_BufInfo.Width = 1680;
+       gTegra2Vid_DrvUtil_BufInfo.Height = 1050;
+#else
+       gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 13; // Could be 13 (BGR/RGB)
+       gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
+               gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
+       gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
        gTegra2Vid_DrvUtil_BufInfo.Width = 1024;
        gTegra2Vid_DrvUtil_BufInfo.Height = 768;
-       gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
-       gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
        gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
+#endif
+       gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
 
 
 //     Tegra2Vid_int_SetMode(4);
@@ -309,16 +318,16 @@ int Tegra2Vid_int_SetMode(int Mode)
 {
        const struct sTegra2_Disp_Mode  *mode = &caTegra2Vid_Modes[Mode];
         int    w = mode->W, h = mode->H;       // Horizontal/Vertical Active
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP; 
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0)  = (mode->HS << 16)  | mode->HS;
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0)  = (mode->VBP << 16) | mode->HBP;
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16)   | mode->W;
-
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (h << 16) | w;
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8;     // BASE888
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12;    // Could be 13 (BGR/RGB)
-       *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (h << 16) | w;
+       gpTegra2Vid_IOMem[DC_DISP_FRONT_PORCH_0] = (mode->VFP << 16) | mode->HFP; 
+       gpTegra2Vid_IOMem[DC_DISP_SYNC_WIDTH_0]  = (mode->HS << 16)  | mode->HS;
+       gpTegra2Vid_IOMem[DC_DISP_BACK_PORCH_0]  = (mode->VBP << 16) | mode->HBP;
+       gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (mode->H << 16)   | mode->W;
+
+       gpTegra2Vid_IOMem[DC_WIN_A_POSITION_0] = 0;
+       gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
+       gpTegra2Vid_IOMem[DC_DISP_DISP_COLOR_CONTROL_0] = 0x8;  // BASE888
+       gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
+       gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
 
        Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
 
@@ -331,6 +340,7 @@ int Tegra2Vid_int_SetMode(int Mode)
 
                giTegra2Vid_FramebufferSize = w*h*4;            
 
+               // TODO: Does this need RAM or unmapped space?
                gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
                        (giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
                        32,
@@ -344,10 +354,12 @@ int Tegra2Vid_int_SetMode(int Mode)
                                );
                
                // Tell hardware
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0;        // Y offset
-               *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0;        // X offset
+               gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0] = gTegra2Vid_FramebufferPhys;
+               gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_V_OFFSET_0] = 0;     // Y offset
+               gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_H_OFFSET_0] = 0;     // X offset
        }
 
+       gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
+       
        return 0;
 }
index c36b05e..7e3fdf5 100644 (file)
@@ -18,11 +18,13 @@ const struct sTegra2_Disp_Mode
        Uint16  HBP, VBP;
 }      caTegra2Vid_Modes[] = {
        // TODO: VESA timings
-//     {720,  487,  16,33,   63, 33,   59, 133},       // NTSC 2
-//     {720,  576,  12,33,   63, 33,   69, 193},       // PAL 2 (VFP shown as 2/33, used 33)
-//     {720,  483,  16, 6,   63,  6,   59,  30},       // 480p
-//     {1280, 720,  70, 5,  804,  6,  220,  20},       // 720p
-//     {1920,1080,  44, 4,  884,  5,  148,  36},       // 1080p
+       {1024, 768,  58, 4,   58,  4,   58,   4},       // 1024x768 (reset), RtS=11,4
+       // TV Timings
+       {720,  487,  16,33,   63, 33,   59, 133},       // NTSC 2
+       {720,  576,  12,33,   63, 33,   69, 193},       // PAL 2 (VFP shown as 2/33, used 33)
+       {720,  483,  16, 6,   63,  6,   59,  30},       // 480p
+       {1280, 720,  70, 5,  804,  6,  220,  20},       // 720p
+       {1920,1080,  44, 4,  884,  5,  148,  36},       // 1080p
        // TODO: Can all but HA/VA be constant and those select the resolution?
 };
 const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]);
@@ -161,6 +163,12 @@ enum eTegra2_Disp_Regs
        DC_WIN_A_BUFFER_ADDR_MODE_0,
        DC_WIN_A_DV_CONTROL_0,
        DC_WIN_A_BLEND_NOKEY_0,
+       DC_WIN_A_BLEND_1WIN_0,
+       DC_WIN_A_BLEND_2WIN_B_0,
+       DC_WIN_A_BLEND_2WIN_C_0,
+       DC_WIN_A_BLEND_3WIN_BC_0,
+       DC_WIN_A_HP_FETCH_CONTROL_0,
+
        
        DC_WINBUF_A_START_ADDR_0 = 0x800,
        DC_WINBUF_A_START_ADDR_NS_0,
@@ -170,5 +178,192 @@ enum eTegra2_Disp_Regs
        DC_WINBUF_A_ADDR_V_OFFSET_NS_0,
 };
 
+#if DEBUG || DUMP_REGISTERS
+const char * const csaTegra2Vid_RegisterNames[] = {
+       [0x000] = "DC_CMD_GENERAL_INCR_SYNCPT_0",
+       "DC_CMD_GENERAL_INCR_SYNCPT_CNTRL_0",
+       "DC_CMD_GENERAL_INCR_SYNCPT_ERROR_0",
+       [0x008] = "DC_CMD_WIN_A_INCR_SYNCPT_0",
+       "DC_CMD_WIN_A_INCR_SYNCPT_CNTRL_0",
+       "DC_CMD_WIN_A_INCR_SYNCPT_ERROR_0",
+       [0x010] = "DC_CMD_WIN_B_INCR_SYNCPT_0",
+       "DC_CMD_WIN_B_INCR_SYNCPT_CNTRL_0",
+       "DC_CMD_WIN_B_INCR_SYNCPT_ERROR_0",
+       [0x018] = "DC_CMD_WIN_C_INCR_SYNCPT_0",
+       "DC_CMD_WIN_C_INCR_SYNCPT_CNTRL_0",
+       "DC_CMD_WIN_C_INCR_SYNCPT_ERROR_0",
+       [0x028] = "DC_CMD_CONT_SYNCPT_VSYNC_0",
+       [0x030] = "DC_CMD_CTXSW_0",
+       "DC_CMD_DISPLAY_COMMAND_OPTION0_0",
+       "DC_CMD_DISPLAY_COMMAND_0",
+       "DC_CMD_SIGNAL_RAISE_0",
+       [0x036] = "DC_CMD_DISPLAY_POWER_CONTROL_0",
+       "DC_CMD_INT_STATUS_0",
+       "DC_CMD_INT_MASK_0",
+       "DC_CMD_INT_ENABLE_0",
+       "DC_CMD_INT_TYPE_0",
+       "DC_CMD_INT_POLARITY_0",
+       "DC_CMD_SIGNAL_RAISE1_0",
+       "DC_CMD_SIGNAL_RAISE2_0",
+       "DC_CMD_SIGNAL_RAISE3_0",
+       
+       [0x040] = "DC_CMD_STATE_ACCESS_0",
+       "DC_CMD_STATE_CONTROL_0",
+       "DC_CMD_DISPLAY_WINDOW_HEADER_0",       // 042
+       "DC_CMD_REG_ACT_CONTROL_0",     // 043
+
+       [0x300] = "DC_COM_CRC_CONTROL_0",
+       "DC_COM_CRC_CHECKSUM_0",        // 301
+       "DC_COM_PIN_OUTPUT_ENABLE0_0",  // 302
+       "DC_COM_PIN_OUTPUT_ENABLE1_0",  // 303
+       "DC_COM_PIN_OUTPUT_ENABLE2_0",  // 304
+       "DC_COM_PIN_OUTPUT_ENABLE3_0",  // 305
+       "DC_COM_PIN_OUTPUT_POLARITY0_0",        // 306
+       "DC_COM_PIN_OUTPUT_POLARITY1_0",        // 307
+       "DC_COM_PIN_OUTPUT_POLARITY2_0",        // 308
+       "DC_COM_PIN_OUTPUT_POLARITY3_0",        // 309
+       "DC_COM_PIN_OUTPUT_DATA0_0",    // 30A
+       "DC_COM_PIN_OUTPUT_DATA1_0",    // 30B
+       "DC_COM_PIN_OUTPUT_DATA2_0",    // 30C
+       "DC_COM_PIN_OUTPUT_DATA3_0",    // 30D
+       "DC_COM_PIN_INPUT_ENABLE0_0",   // 30E
+       "DC_COM_PIN_INPUT_ENABLE1_0",   // 30F
+       "DC_COM_PIN_INPUT_ENABLE2_0",   // 310
+       "DC_COM_PIN_INPUT_ENABLE3_0",   // 311
+       "DC_COM_PIN_INPUT_DATA0_0",     // 312
+       "DC_COM_PIN_INPUT_DATA1_0",     // 313
+       "DC_COM_PIN_OUTPUT_SELECT0_0",  // 314
+       "DC_COM_PIN_OUTPUT_SELECT1_0",  // 315
+       "DC_COM_PIN_OUTPUT_SELECT2_0",  // 316
+       "DC_COM_PIN_OUTPUT_SELECT3_0",  // 317
+       "DC_COM_PIN_OUTPUT_SELECT4_0",  // 318
+       "DC_COM_PIN_OUTPUT_SELECT5_0",  // 319
+       "DC_COM_PIN_OUTPUT_SELECT6_0",  // 31A
+       "DC_COM_PIN_MISC_CONTROL_0",    // 31B
+       // TODO: Complete
+
+       [0x400] = "DC_DISP_DISP_SIGNAL_OPTIONS0_0",
+       "DC_DISP_DISP_SIGNAL_OPTIONS1_0", // 401
+       "DC_DISP_DISP_WIN_OPTIONS_0",   // 402
+       "DC_DISP_MEM_HIGH_PRIORITY_0",  // 403
+       "DC_DISP_MEM_HIGH_PRIORITY_TIMER_0",    // 404
+       "DC_DISP_DISP_TIMING_OPTIONS_0",        // 405
+       "DC_DISP_REF_TO_SYNC_0",        // 406 (TrimSlice 0x0001 000B)
+       "DC_DISP_SYNC_WIDTH_0",         // 407 (TrimSlice 0x0004 003A)
+       "DC_DISP_BACK_PORCH_0",         // 408 (TrimSlice 0x0004 003A)
+       "DC_DISP_DISP_ACTIVE_0",        // 409 (TrimSlice 0x0300 0400)
+       "DC_DISP_FRONT_PORCH_0",        // 40A (TrimSlice 0x0004 003A)
+       "DC_DISP_H_PULSE0_CONTROL_0",   // 40B
+       "DC_DISP_H_PULSE0_POSITION_A_0",        // 40C
+       "DC_DISP_H_PULSE0_POSITION_B_0",        // 40D
+       "DC_DISP_H_PULSE0_POSITION_C_0",        // 40E
+       "DC_DISP_H_PULSE0_POSITION_D_0",        // 40F
+       "DC_DISP_H_PULSE1_CONTROL_0",   // 410
+       "DC_DISP_H_PULSE1_POSITION_A_0",        // 411
+       "DC_DISP_H_PULSE1_POSITION_B_0",        // 412
+       "DC_DISP_H_PULSE1_POSITION_C_0",        // 413
+       "DC_DISP_H_PULSE1_POSITION_D_0",        // 414
+       "DC_DISP_H_PULSE2_CONTROL_0",   // 415
+       "DC_DISP_H_PULSE2_POSITION_A_0",        // 416
+       "DC_DISP_H_PULSE2_POSITION_B_0",        // 417
+       "DC_DISP_H_PULSE2_POSITION_C_0",        // 418
+       "DC_DISP_H_PULSE2_POSITION_D_0",        // 419
+       "DC_DISP_V_PULSE0_CONTROL_0",   // 41A
+       "DC_DISP_V_PULSE0_POSITION_A_0",        // 41B
+       "DC_DISP_V_PULSE0_POSITION_B_0",        // 41C
+       "DC_DISP_V_PULSE0_POSITION_C_0",        // 41D
+       "DC_DISP_V_PULSE1_CONTROL_0",   // 41E
+       "DC_DISP_V_PULSE1_POSITION_A_0",        // 41F
+       "DC_DISP_V_PULSE1_POSITION_B_0",        // 420
+       "DC_DISP_V_PULSE1_POSITION_C_0",        // 421
+       "DC_DISP_V_PULSE2_CONTROL_0",   // 422
+       "DC_DISP_V_PULSE2_POSITION_A_0",        // 423
+       "DC_DISP_V_PULSE3_CONTROL_0",   // 424
+       "DC_DISP_V_PULSE3_POSITION_A_0",        // 425
+       "DC_DISP_M0_CONTROL_0",         // 426
+       "DC_DISP_M1_CONTROL_0",         // 427
+       "DC_DISP_DI_CONTROL_0",         // 428
+       "DC_DISP_PP_CONTROL_0",         // 429
+       "DC_DISP_PP_SELECT_A_0",        // 42A
+       "DC_DISP_PP_SELECT_B_0",        // 42B
+       "DC_DISP_PP_SELECT_C_0",        // 42C
+       "DC_DISP_PP_SELECT_D_0",        // 42D
+       "DC_DISP_DISP_CLOCK_CONTROL_0", // 42E
+       "DC_DISP_DISP_INTERFACE_CONTROL_0",//42F
+       "DC_DISP_DISP_COLOR_CONTROL_0", // 430
+       "DC_DISP_SHIFT_CLOCK_OPTIONS_0",        // 431
+       "DC_DISP_DATA_ENABLE_OPTIONS_0",        // 432
+       "DC_DISP_SERIAL_INTERFACE_OPTIONS_0",   // 433
+       "DC_DISP_LCD_SPI_OPTIONS_0",    // 434
+       "DC_DISP_BORDER_COLOR_0",       // 435
+       "DC_DISP_COLOR_KEY0_LOWER_0",   // 436
+       "DC_DISP_COLOR_KEY0_UPPER_0",   // 437
+       "DC_DISP_COLOR_KEY1_LOWER_0",   // 438
+       "DC_DISP_COLOR_KEY1_UPPER_0",   // 439
+       "_DC_DISP_UNUSED_43A",
+       "_DC_DISP_UNUSED_43B",
+       "DC_DISP_CURSOR_FOREGROUND_0",  // 43C - IMPORTANT
+       "DC_DISP_CURSOR_BACKGROUND_0",  // 43D - IMPORTANT
+       "DC_DISP_CURSOR_START_ADDR_0",  // 43E - IMPORTANT
+       "DC_DISP_CURSOR_START_ADDR_NS_0",       // 43F - IMPORTANT
+       "DC_DISP_CURSOR_POSITION_0",    // 440 - IMPORTANT
+       "DC_DISP_CURSOR_POSITION_NS_0", // 441 - IMPORTANT
+       "DC_DISP_INIT_SEQ_CONTROL_0",   // 442
+       "DC_DISP_SPI_INIT_SEQ_DATA_A_0",        // 443
+       "DC_DISP_SPI_INIT_SEQ_DATA_B_0",        // 444
+       "DC_DISP_SPI_INIT_SEQ_DATA_C_0",        // 445
+       "DC_DISP_SPI_INIT_SEQ_DATA_D_0",        // 446
+
+       [0x480] = "DC_DISP_DC_MCCIF_FIFOCTRL_0",
+       "DC_DISP_MCCIF_DISPLAY0A_HYST_0",       // 481
+       "DC_DISP_MCCIF_DISPLAY0B_HYST_0",       // 482
+       "DC_DISP_MCCIF_DISPLAY0C_HYST_0",       // 483
+       "DC_DISP_MCCIF_DISPLAY1B_HYST_0",       // 484
+
+       [0x4C0] = "DC_DISP_DAC_CRT_CTRL_0",
+       "DC_DISP_DISP_MISC_CONTROL_0",  // 4C1
+
+       [0x500] = "DC_WINC_A_COLOR_PALETTE_0",
+       [0x600] = "DC_WINC_A_PALETTE_COLOR_EXT_0",
+       [0x700] = "DC_WIN_A_WIN_OPTIONS_0",
+       "DC_WIN_A_BYTE_SWAP_0",         // 701
+       "DC_WIN_A_BUFFER_CONTROL_0",    // 702
+       "DC_WIN_A_COLOR_DEPTH_0",       // 703
+       "DC_WIN_A_POSITION_0",          // 704
+       "DC_WIN_A_SIZE_0",              // 705 (TrimSlice 0x0300 0400)
+       "DC_WIN_A_PRESCALED_SIZE_0",
+       "DC_WIN_A_H_INITIAL_DDA_0",
+       "DC_WIN_A_V_INITIAL_DDA_0",
+       "DC_WIN_A_DDA_INCREMENT_0",
+       "DC_WIN_A_LINE_STRIDE_0",
+       "DC_WIN_A_BUF_STRIDE_0",
+       "DC_WIN_A_BUFFER_ADDR_MODE_0",
+       "DC_WIN_A_DV_CONTROL_0",
+       "DC_WIN_A_BLEND_NOKEY_0",
+       "DC_WIN_A_BLEND_1WIN_0",
+       "DC_WIN_A_BLEND_2WIN_B_0",
+       "DC_WIN_A_BLEND_2WIN_C_0",
+       "DC_WIN_A_BLEND_3WIN_BC_0",
+       "DC_WIN_A_HP_FETCH_CONTROL_0",
+       
+       [0x800] = "DC_WINBUF_A_START_ADDR_0",
+       [0x801] = "DC_WINBUF_A_START_ADDR_NS_0",
+       [0x806] = "DC_WINBUF_A_ADDR_H_OFFSET_0",
+       [0x807] = "DC_WINBUF_A_ADDR_H_OFFSET_NS_0",
+       [0x808] = "DC_WINBUF_A_ADDR_V_OFFSET_0",
+       [0x809] = "DC_WINBUF_A_ADDR_V_OFFSET_NS_0",
+       [0x80A] = "DC_WINBUF_A_UFLOW_STATUS"
+};
+#endif
+
+// Bit definitions
+/// \name DC_CMD_STATE_CONTROL_0
+/// \{
+#define GEN_ACT_REQ    0x0001
+#define WIN_A_ACT_REQ  0x0002
+#define WIN_B_ACT_REQ  0x0004
+#define WIN_C_ACT_REQ  0x0008
+/// \}
+
 #endif
 
index 3f2f1c9..13fe798 100644 (file)
@@ -67,11 +67,19 @@ tTimer      *gpVesaCursorTimer;
  int   gbVesa_CursorVisible = 0;\r
 // --- 2D Video Stream Handlers ---\r
 tDrvUtil_Video_BufInfo gVesa_BufInfo;\r
+// --- Settings ---\r
+// int gbVesa_DisableFBCache;  // Disables the main-memory framebuffer cache\r
 \r
 // === CODE ===\r
 int Vesa_Install(char **Arguments)\r
 {\r
         int    rv;\r
+\r
+//     for( int i = 0; Arguments[i]; i ++ )\r
+//     {\r
+//             if( strcmp(Aguments[i], "nocache") == 0 )\r
+//                     gbVesa_DisableFBCache = 1;\r
+//     }\r
        \r
        gpVesa_BiosState = VM8086_Init();\r
        \r
@@ -359,6 +367,8 @@ int Vesa_Int_SetMode(int mode)
        \r
        Mutex_Release( &glVesa_Lock );\r
 \r
+       gVesa_BufInfo.BackBuffer  = realloc(gVesa_BufInfo.BackBuffer,\r
+               gVesa_Modes[mode].height * gVesa_Modes[mode].pitch);\r
        gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
        gVesa_BufInfo.Pitch = gVesa_Modes[mode].pitch;\r
        gVesa_BufInfo.Width = gVesa_Modes[mode].width;\r
index 1291113..30844eb 100644 (file)
@@ -24,8 +24,8 @@ const struct sVGA_Timings
         int    HFP, HSync, HDisplay, HBP;
         int    VFP, VSync, VDisplay, VBP;
 } csaTimings[] = {
-       {40, 128, 800, 88,    1, 4, 600, 23},   // SVGA @ 60Hz
-       {24, 136, 1024, 160,  3, 6, 768, 29},   // XGA @ 60Hz
+       {40, 128,  800,  88,  1, 4,  600, 23},  // SVGA @ 60Hz
+       {24, 136, 1024, 160,  3, 6,  768, 29},  // XGA @ 60Hz
        {38, 112, 1280, 248,  1, 3, 1024, 38}   // 1280x1024 @ 60Hz
 };
 const Uint16   caVIAVideo_CardIDs[][2] = {
index 5eb476f..33df847 100644 (file)
@@ -1,27 +1,23 @@
 /*
- * Acess OS
- * Ext2 Driver Version 1
+ * Acess2 Ext2 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * dir.c
+ * - Directory Handling
  */
-/**
- * \file dir.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG  1
+#define DEBUG  0
 #define VERBOSE        0
 #include "ext2_common.h"
 
 // === MACROS ===
-#define BLOCK_DIR_OFS(_data, _block)   ((Uint16*)(_data)[(_block)])
+#define BLOCK_DIR_OFS(_data, _block)   (((Uint16*)(_data))[(_block)])
 
 // === PROTOTYPES ===
-char   *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+ int   Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
- int   Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int   Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
- int   Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
-// --- Helpers ---
-tVFS_Node      *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+tVFS_Node      *Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   Ext2_Unlink(tVFS_Node *Node, const char *OldName);
+ int   Ext2_Link(tVFS_Node *Parent, const char *Name, tVFS_Node *Node);
 
 // === GLOBALS ===
 tVFS_NodeType  gExt2_DirType = {
@@ -29,7 +25,7 @@ tVFS_NodeType gExt2_DirType = {
        .ReadDir = Ext2_ReadDir,
        .FindDir = Ext2_FindDir,
        .MkNod = Ext2_MkNod,
-       .Relink = Ext2_Relink,
+       .Unlink = Ext2_Unlink,
        .Link = Ext2_Link,
        .Close = Ext2_CloseFile
        };
@@ -46,7 +42,7 @@ tVFS_NodeType gExt2_FileType = {
  * \param Node Directory node
  * \param Pos  Position of desired element
  */
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tExt2_Inode     inode;
        tExt2_DirEnt    dirent;
@@ -63,14 +59,14 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
        Ext2_int_ReadInode(disk, Node->Inode, &inode);
        size = inode.i_size;
        
-       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
+       LOG("inode={.i_block[0]= 0x%x, .i_size=0x%x}", inode.i_block[0], inode.i_size);
        
        // Find Entry
        // Get First Block
        // - Do this ourselves as it is a simple operation
        Base = inode.i_block[0] * disk->BlockSize;
        // Scan directory
-       while(Pos -- && size > 0)
+       while(Pos -- && size > 0 && size <= inode.i_size)
        {
                VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
                ofs += dirent.rec_len;
@@ -85,33 +81,41 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
                        }
                        ofs = 0;
                        Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+                       if( Base == 0 ) {
+                               size = 0;
+                               break;
+                       }
                }
        }
        
        // Check for the end of the list
-       if(size <= 0) {
-               LEAVE('n');
-               return NULL;
+       if(size <= 0 || size > inode.i_size) {
+               LEAVE('i', -ENOENT);
+               return -ENOENT;
        }
        
        // Read Entry
        VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
-       //LOG("dirent.inode = %i", dirent.inode);
-       //LOG("dirent.rec_len = %i", dirent.rec_len);
-       //LOG("dirent.name_len = %i", dirent.name_len);
+       LOG("dirent={.rec_len=%i,.inode=0x%x,.name_len=%i}",
+               dirent.rec_len, dirent.inode, dirent.name_len);
        dirent.name[ dirent.name_len ] = '\0';  // Cap off string
        
+       if( dirent.name_len == 0 ) {
+               LEAVE('i', 1);
+               return 1;
+       }
        
        // Ignore . and .. (these are done in the VFS)
        if( (dirent.name[0] == '.' && dirent.name[1] == '\0')
        ||  (dirent.name[0] == '.' && dirent.name[1] == '.' && dirent.name[2]=='\0')) {
-               LEAVE('p', VFS_SKIP);
-               return VFS_SKIP;        // Skip
+               LEAVE('i', 1);
+               return 1;       // Skip
        }
        
-       LEAVE('s', dirent.name);
-       // Create new node
-       return strdup(dirent.name);
+       LOG("Name '%s'", dirent.name);
+       strncpy(Dest, dirent.name, FILENAME_MAX);
+       LEAVE('i', 0);
+       return 0;
 }
 
 /**
@@ -143,6 +147,7 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename)
        while(size > 0)
        {
                VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+               // TODO: Possible overrun if name_len == 255?
                dirent.name[ dirent.name_len ] = '\0';  // Cap off string
                // If it matches, create a node and return it
                if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0)
@@ -171,36 +176,38 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename)
  * \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
  * \brief Create a new node
  */
-int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
+tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
 {
-       #if 0
-       tVFS_Node       *child;
-       Uint64  inodeNum;
-       tExt2_Inode     inode;
-       inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
-       
-       memset(&inode, 0, sizeof(tExt2_Inode));
+       ENTER("pParent sName xFlags", Parent, Name, Flags);
        
-       // File type
-       inode.i_mode = 0664;
-       if( Flags & VFS_FFLAG_READONLY )
-               inode.i_mode &= ~0222;
-       if( Flags & VFS_FFLAG_SYMLINK )
-               inode.i_mode |= EXT2_S_IFLNK;
-       else if( Flags & VFS_FFLAG_DIRECTORY )
-               inode.i_mode |= EXT2_S_IFDIR | 0111;
-       
-       inode.i_uid = Threads_GetUID();
-       inode.i_gid = Threads_GetGID();
-       inode.i_ctime =
-               inode.i_mtime =
-               inode.i_atime = now() / 1000;
-       
-       child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
-       return Ext2_Link(Parent, child, Name);
-       #else
-       return 1;
-       #endif
+       Uint64 inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
+       if( inodeNum == 0 ) {
+               LOG("Inode allocation failed");
+               LEAVE_RET('n', NULL);
+       }
+       tVFS_Node *child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
+       if( !child ) {
+               Ext2_int_DereferenceInode(Parent->ImplPtr, inodeNum);
+               Log_Warning("Ext2", "Ext2_MkNod - Node creation failed");
+               LEAVE_RET('n', NULL);
+       }
+
+       child->Flags = Flags & (VFS_FFLAG_DIRECTORY|VFS_FFLAG_SYMLINK|VFS_FFLAG_READONLY);
+       child->UID = Threads_GetUID();
+       child->GID = Threads_GetGID();
+       child->CTime =
+               child->MTime =
+               child->ATime =
+               now();
+       child->ImplInt = 0;     // ImplInt is the link count
+       // TODO: Set up ACLs
+
+       int rv = Ext2_Link(Parent, Name, child);
+       if( rv ) {
+               Ext2_CloseFile(child);
+               return NULL;
+       }
+       LEAVE_RET('p', child);
 }
 
 /**
@@ -208,33 +215,37 @@ int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
  * \param Node This (directory) node
  * \param OldName      Old name of file
  * \param NewName      New name for file
- * \return Boolean Failure - See ::tVFS_Node.Relink for info
+ * \return Boolean Failure - See ::tVFS_Node.Unlink for info
  */
-int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int Ext2_Unlink(tVFS_Node *Node, const char *OldName)
 {
+       Log_Warning("Ext2", "TODO: Impliment Ext2_Unlink");
        return 1;
 }
 
 /**
  * \brief Links an existing node to a new name
  * \param Parent       Parent (directory) node
- * \param Node Node to link
  * \param Name New name for the node
+ * \param Node Node to link
  * \return Boolean Failure - See ::tVFS_Node.Link for info
  */
-int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
+int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child)
 {      
-       #if 0
        tExt2_Disk      *disk = Node->ImplPtr;
        tExt2_Inode     inode;
-       tExt2_DirEnt    dirent;
+       tExt2_DirEnt    *dirent;
        tExt2_DirEnt    newEntry;
-       Uint64  Base;   // Block's Base Address
+       Uint64  base;   // Block's Base Address
         int    block = 0, ofs = 0;
        Uint    size;
        void    *blockData;
-        int    bestMatch = -1, bestSize, bestBlock, bestOfs;
+        int    bestMatch = -1;
+        int    bestSize=0, bestBlock=0, bestOfs=0, bestNeedsSplit=0;
         int    nEntries;
+
+       ENTER("pNode sName pChild",
+               Node, Name, Child);
        
        blockData = malloc(disk->BlockSize);
        
@@ -244,7 +255,7 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
        // Create a stub entry
        newEntry.inode = Child->Inode;
        newEntry.name_len = strlen(Name);
-       newEntry.rec_len = (newEntry.name_len+3+8)&~3;
+       newEntry.rec_len = ((newEntry.name_len+3)&~3) + EXT2_DIRENT_SIZE;
        newEntry.type = inode.i_mode >> 12;
        memcpy(newEntry.name, Name, newEntry.name_len);
        
@@ -253,13 +264,18 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
        size = inode.i_size;
        
        // Get a lock on the inode
-       Ext2_int_LockInode(disk, Node->Inode);
-       
+       //Ext2_int_LockInode(disk, Node->Inode);
+       Mutex_Acquire(&Node->Lock);
+
+//     if( !Node->Data ) {
+//     }
+
        // Get First Block
        // - Do this ourselves as it is a simple operation
        base = inode.i_block[0] * disk->BlockSize;
        VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
        block = 0;
+       nEntries = 0;
        // Find File
        while(size > 0)
        {
@@ -270,10 +286,12 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
                                "Directory entry %i of inode 0x%x extends over a block boundary",
                                nEntries, (Uint)Node->Inode);
                }
-               else {
-               
+               else
+               {
+                       LOG("Entry %i: %x %i bytes", nEntries, dirent->type, dirent->rec_len);
                        // Free entry
-                       if(dirent->type == 0) {
+                       if(dirent->type == 0)
+                       {
                                if( dirent->rec_len >= newEntry.rec_len
                                 && (bestMatch == -1 || bestSize > dirent->rec_len) )
                                {
@@ -281,23 +299,40 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
                                        bestSize = dirent->rec_len;
                                        bestBlock = block;
                                        bestOfs = ofs;
+                                       bestNeedsSplit = 0;
                                }
                        }
                        // Non free - check name to avoid duplicates
-                       else {
+                       else
+                       {
+                               LOG(" name='%.*s'", dirent->name_len, dirent->name);
                                if(strncmp(Name, dirent->name, dirent->name_len) == 0) {
-                                       Ext2_int_UnlockInode(disk, Node->Inode);
+                                       //Ext2_int_UnlockInode(disk, Node->Inode);
+                                       Mutex_Release(&Node->Lock);
+                                       LEAVE('i', 1);
                                        return 1;       // ERR_???
                                }
+                               
+                                int    spare_space = dirent->rec_len - (dirent->name_len + EXT2_DIRENT_SIZE);
+                               if( spare_space > newEntry.rec_len
+                                && (bestMatch == -1 || bestSize > spare_space) )
+                               {
+                                       bestMatch = nEntries;
+                                       bestSize = spare_space;
+                                       bestBlock = block;
+                                       bestOfs = ofs;
+                                       bestNeedsSplit = 1;
+                               }
                        }
                }
                
                // Increment the pointer
                nEntries ++;
                ofs += dirent->rec_len;
-               if( ofs >= disk->BlockSize ) {
+               size -= dirent->rec_len;
+               if( size > 0 && ofs >= disk->BlockSize ) {
                        // Read the next block if needed
-                       BLOCK_DIR_OFS(Node->Data, block) = nEntries;
+               //      BLOCK_DIR_OFS(Node->Data, block) = nEntries;
                        block ++;
                        ofs = 0;
                        base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
@@ -305,93 +340,63 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
                }
        }
        
+       LOG("bestMatch = %i", bestMatch);
+       // If EOF was reached with no space, check if we can fit one on the end
+       if( bestMatch < 0 && ofs + newEntry.rec_len < disk->BlockSize ) {
+               Node->Size += newEntry.rec_len;
+               Node->Flags |= VFS_FFLAG_DIRTY;
+               bestBlock = block;
+               bestOfs = ofs;
+               bestSize = newEntry.rec_len;
+               bestNeedsSplit = 0;
+       }
        // Check if a free slot was found
-       if( bestMatch >= 0 ) {
+       if( bestMatch >= 0 )
+       {
                // Read-Modify-Write
-               bestBlock = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
-               if( block > 0 )
-                       bestMatch = BLOCK_DIR_OFS(Node->Data, bestBlock);
+               base = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
                VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
                dirent = blockData + bestOfs;
-               memcpy(dirent, newEntry, newEntry.rec_len);
+               // Shorten a pre-existing entry
+               if(bestNeedsSplit)
+               {
+                       dirent->rec_len = EXT2_DIRENT_SIZE + dirent->name_len;
+                       bestOfs += dirent->rec_len;
+                       //bestSize -= dirent->rec_len; // (not needed, bestSize is the spare space after)
+                       dirent = blockData + bestOfs;
+               }
+               // Insert new file entry
+               memcpy(dirent, &newEntry, newEntry.rec_len);
+               // Create a new blank entry
+               if( bestSize != newEntry.rec_len )
+               {
+                       bestOfs += newEntry.rec_len;
+                       dirent = blockData + bestOfs;
+
+                       dirent->rec_len = bestSize - newEntry.rec_len;                  
+                       dirent->type = 0;
+               }
+               // Save changes
                VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
        }
        else {
                // Allocate block, Write
-               block = Ext2_int_AllocateBlock(Disk, block);
-               Log_Warning("EXT2", "");
+               Uint32 newblock = Ext2_int_AllocateBlock(disk, base / disk->BlockSize);
+               Ext2_int_AppendBlock(disk, &inode, newblock);
+               base = newblock * disk->BlockSize;
+               Node->Size += newEntry.rec_len;
+               Node->Flags |= VFS_FFLAG_DIRTY;
+               memcpy(blockData, &newEntry, newEntry.rec_len);
+               memset(blockData + newEntry.rec_len, 0, disk->BlockSize - newEntry.rec_len);
+               VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
        }
 
-       Ext2_int_UnlockInode(disk, Node->Inode);
+       Child->ImplInt ++;
+       Child->Flags |= VFS_FFLAG_DIRTY;
+
+       //Ext2_int_UnlockInode(disk, Node->Inode);
+       Mutex_Release(&Node->Lock);
+       LEAVE('i', 0);
        return 0;
-       #else
-       return 1;
-       #endif
 }
 
-// ---- INTERNAL FUNCTIONS ----
-/**
- * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
- * \brief Create a new VFS Node
- */
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
-{
-       tExt2_Inode     inode;
-       tVFS_Node       retNode;
-       tVFS_Node       *tmpNode;
-       
-       if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
-               return NULL;
-       
-       if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
-               return tmpNode;
-       
-       
-       // Set identifiers
-       retNode.Inode = InodeID;
-       retNode.ImplPtr = Disk;
-       
-       // Set file length
-       retNode.Size = inode.i_size;
-       retNode.Data = NULL;
-       
-       // Set Access Permissions
-       retNode.UID = inode.i_uid;
-       retNode.GID = inode.i_gid;
-       retNode.NumACLs = 3;
-       retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
-       
-       //  Set Function Pointers
-       retNode.Type = &gExt2_FileType;
-       
-       switch(inode.i_mode & EXT2_S_IFMT)
-       {
-       // Symbolic Link
-       case EXT2_S_IFLNK:
-               retNode.Flags = VFS_FFLAG_SYMLINK;
-               break;
-       // Regular File
-       case EXT2_S_IFREG:
-               retNode.Flags = 0;
-               retNode.Size |= (Uint64)inode.i_dir_acl << 32;
-               break;
-       // Directory
-       case EXT2_S_IFDIR:
-               retNode.Type = &gExt2_DirType;
-               retNode.Flags = VFS_FFLAG_DIRECTORY;
-               retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
-               break;
-       // Unknown, Write protect it to be safe 
-       default:
-               retNode.Flags = VFS_FFLAG_READONLY;
-               break;
-       }
-       
-       // Set Timestamps
-       retNode.ATime = inode.i_atime * 1000;
-       retNode.MTime = inode.i_mtime * 1000;
-       retNode.CTime = inode.i_ctime * 1000;
-       
-       // Save in node cache and return saved node
-       return Inode_CacheNode(Disk->CacheID, &retNode);
-}
index 7c4bf97..4d13f1e 100644 (file)
@@ -1,38 +1,43 @@
 /*\r
- * Acess OS\r
- * Ext2 Driver Version 1\r
+ * Acess2 Ext2 Driver\r
+ * - By John Hodge (thePowersGang)\r
+ *\r
+ * ext2.c\r
+ * - Driver core\r
  */\r
-/**\r
- * \file fs/ext2.c\r
- * \brief Second Extended Filesystem Driver\r
- * \todo Implement file full write support\r
- */\r
-#define DEBUG  1\r
-#define VERBOSE        0\r
+#define DEBUG  0\r
+#define VERSION        VER2(0,90)\r
 #include "ext2_common.h"\r
 #include <modules.h>\r
 \r
-// === IMPORTS ===\r
-extern tVFS_NodeType   gExt2_DirType;\r
+#define MIN_BLOCKS_PER_GROUP   2\r
+#define MAX_BLOCK_LOG_SIZE     10      // 1024 << 10 = 1MiB\r
 \r
 // === PROTOTYPES ===\r
  int   Ext2_Install(char **Arguments);\r
-// Interface Functions\r
+ int   Ext2_Cleanup(void);\r
+// - Interface Functions\r
+ int    Ext2_Detect(int FD);\r
 tVFS_Node      *Ext2_InitDevice(const char *Device, const char **Options);\r
-void           Ext2_Unmount(tVFS_Node *Node);\r
-void           Ext2_CloseFile(tVFS_Node *Node);\r
-// Internal Helpers\r
- int           Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
-Uint64         Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
-Uint32         Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
-void           Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
+void   Ext2_Unmount(tVFS_Node *Node);\r
+void   Ext2_CloseFile(tVFS_Node *Node);\r
+// - Internal Helpers\r
+ int   Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
+void   Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode);\r
+void   Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
 \r
 // === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
+MODULE_DEFINE(0, VERSION, FS_Ext2, Ext2_Install, Ext2_Cleanup);\r
 tExt2_Disk     gExt2_disks[6];\r
  int   giExt2_count = 0;\r
 tVFS_Driver    gExt2_FSInfo = {\r
-       "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
+       .Name = "ext2",\r
+       .Detect = Ext2_Detect,\r
+       .InitDevice = Ext2_InitDevice,\r
+       .Unmount = Ext2_Unmount,\r
+       .GetNodeFromINode = NULL\r
        };\r
 \r
 // === CODE ===\r
@@ -46,6 +51,39 @@ int Ext2_Install(char **Arguments)
        return MODULE_ERR_OK;\r
 }\r
 \r
+/**\r
+ * \brief Clean up driver state before unload\r
+ */\r
+int Ext2_Cleanup(void)\r
+{\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * Detect if a volume is Ext2 formatted\r
+ */\r
+int Ext2_Detect(int FD)\r
+{\r
+       tExt2_SuperBlock        sb;\r
+       size_t  len;\r
+       \r
+       len = VFS_ReadAt(FD, 1024, 1024, &sb);\r
+\r
+       if( len != 1024 ) {\r
+               Log_Debug("Ext2", "_Detect: Read failed? (0x%x != 1024)", len);\r
+               return 0;\r
+       }\r
+       \r
+       switch(sb.s_magic)\r
+       {\r
+       case 0xEF53:\r
+               return 2;\r
+       default:\r
+               Log_Debug("Ext2", "_Detect: s_magic = 0x%x", sb.s_magic);\r
+               return 0;\r
+       }\r
+}\r
+\r
 /**\r
  \brief Initializes a device to be read by by the driver\r
  \param Device String - Device to read from\r
@@ -54,7 +92,7 @@ int Ext2_Install(char **Arguments)
 */\r
 tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
 {\r
-       tExt2_Disk      *disk;\r
+       tExt2_Disk      *disk = NULL;\r
         int    fd;\r
         int    groupCount;\r
        tExt2_SuperBlock        sb;\r
@@ -77,11 +115,15 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        if(sb.s_magic != 0xEF53) {\r
                Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
                        Device, sb.s_magic);\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
+               goto _error;\r
        }\r
-       \r
+\r
+       if( sb.s_blocks_per_group < MIN_BLOCKS_PER_GROUP ) {\r
+               Log_Warning("Ext2", "Blocks per group is too small (%i < %i)",\r
+                       sb.s_blocks_per_group, MIN_BLOCKS_PER_GROUP);\r
+               goto _error;\r
+       }       \r
+\r
        // Get Group count\r
        groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
        LOG("groupCount = %i", groupCount);\r
@@ -90,9 +132,7 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
        if(!disk) {\r
                Log_Warning("EXT2", "Unable to allocate disk structure");\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
+               goto _error;\r
        }\r
        disk->FD = fd;\r
        memcpy(&disk->SuperBlock, &sb, 1024);\r
@@ -102,10 +142,16 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        disk->CacheID = Inode_GetHandle();\r
        \r
        // Get Block Size\r
-       LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
+       if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) {\r
+               Log_Warning("Ext2", "Block size (log2) too large (%i > %i)",\r
+                       sb.s_log_block_size, MAX_BLOCK_LOG_SIZE);\r
+               goto _error;\r
+       }\r
        disk->BlockSize = 1024 << sb.s_log_block_size;\r
+       LOG("Disk->BlockSie = 0x%x (1024 << %i)", disk->BlockSize, sb.s_log_block_size);\r
        \r
        // Read Group Information\r
+       LOG("sb,s_first_data_block = %x", sb.s_first_data_block);\r
        VFS_ReadAt(\r
                disk->FD,\r
                sb.s_first_data_block * disk->BlockSize + 1024,\r
@@ -113,7 +159,6 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
                disk->Groups\r
                );\r
        \r
-       #if VERBOSE\r
        LOG("Block Group 0");\r
        LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
        LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
@@ -122,7 +167,6 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
        LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
        LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
-       #endif\r
        \r
        // Get root Inode\r
        Ext2_int_ReadInode(disk, 2, &inode);\r
@@ -149,6 +193,12 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        \r
        LEAVE('p', &disk->RootNode);\r
        return &disk->RootNode;\r
+_error:\r
+       if( disk )\r
+               free(disk);\r
+       VFS_Close(fd);\r
+       LEAVE('n');\r
+       return NULL;\r
 }\r
 \r
 /**\r
@@ -172,7 +222,41 @@ void Ext2_Unmount(tVFS_Node *Node)
 void Ext2_CloseFile(tVFS_Node *Node)\r
 {\r
        tExt2_Disk      *disk = Node->ImplPtr;\r
-       Inode_UncacheNode(disk->CacheID, Node->Inode);\r
+       ENTER("pNode", Node);\r
+\r
+       if( Mutex_Acquire(&Node->Lock) != 0 )\r
+       {\r
+               LEAVE('-');\r
+               return ;\r
+       }\r
+\r
+       if( Node->Flags & VFS_FFLAG_DIRTY )\r
+       {\r
+               // Commit changes\r
+               Ext2_int_WritebackNode(disk, Node);\r
+               Node->Flags &= ~VFS_FFLAG_DIRTY;\r
+       }\r
+\r
+       int was_not_referenced = (Node->ImplInt == 0);\r
+       tVFS_ACL        *acls = Node->ACLs;\r
+       if( Inode_UncacheNode(disk->CacheID, Node->Inode) == 1 )\r
+       {\r
+               if( was_not_referenced )\r
+               {\r
+                       LOG("Removng inode");\r
+                       // Remove inode\r
+                       Log_Warning("Ext2", "TODO: Remove inode when not referenced (%x)", (Uint32)Node->Inode);\r
+               }\r
+               if( acls != &gVFS_ACL_EveryoneRW ) {\r
+                       free(acls);\r
+               }\r
+               LOG("Node cleaned");\r
+       }\r
+       else {\r
+               LOG("Still referenced, releasing lock");\r
+               Mutex_Release(&Node->Lock);\r
+       }\r
+       LEAVE('-');\r
        return ;\r
 }\r
 \r
@@ -239,6 +323,118 @@ int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)
        return 1;\r
 }\r
 \r
+/**\r
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
+ * \brief Create a new VFS Node\r
+ */\r
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
+{\r
+       tExt2_Inode     inode;\r
+       tVFS_Node       retNode;\r
+       tVFS_Node       *tmpNode;\r
+       \r
+       if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )\r
+               return NULL;\r
+       \r
+       if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )\r
+               return tmpNode;\r
+\r
+       memset(&retNode, 0, sizeof(retNode));   \r
+       \r
+       // Set identifiers\r
+       retNode.Inode = InodeID;\r
+       retNode.ImplPtr = Disk;\r
+       retNode.ImplInt = inode.i_links_count;\r
+       if( inode.i_links_count == 0 ) {\r
+               Log_Notice("Ext2", "Inode %p:%x is not referenced, bug?", Disk, InodeID);\r
+       }\r
+       \r
+       // Set file length\r
+       retNode.Size = inode.i_size;\r
+       \r
+       // Set Access Permissions\r
+       retNode.UID = inode.i_uid;\r
+       retNode.GID = inode.i_gid;\r
+       retNode.NumACLs = 3;\r
+       retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);\r
+       \r
+       //  Set Function Pointers\r
+       retNode.Type = &gExt2_FileType;\r
+       \r
+       switch(inode.i_mode & EXT2_S_IFMT)\r
+       {\r
+       // Symbolic Link\r
+       case EXT2_S_IFLNK:\r
+               retNode.Flags = VFS_FFLAG_SYMLINK;\r
+               break;\r
+       // Regular File\r
+       case EXT2_S_IFREG:\r
+               retNode.Flags = 0;\r
+               retNode.Size |= (Uint64)inode.i_dir_acl << 32;\r
+               break;\r
+       // Directory\r
+       case EXT2_S_IFDIR:\r
+               retNode.Type = &gExt2_DirType;\r
+               retNode.Flags = VFS_FFLAG_DIRECTORY;\r
+               retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );\r
+               break;\r
+       // Unknown, Write protect it to be safe \r
+       default:\r
+               retNode.Flags = VFS_FFLAG_READONLY;\r
+               break;\r
+       }\r
+       \r
+       // Set Timestamps\r
+       retNode.ATime = inode.i_atime * 1000;\r
+       retNode.MTime = inode.i_mtime * 1000;\r
+       retNode.CTime = inode.i_ctime * 1000;\r
+       \r
+       // Save in node cache and return saved node\r
+       return Inode_CacheNode(Disk->CacheID, &retNode);\r
+}\r
+\r
+int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node)\r
+{\r
+       tExt2_Inode     inode;\r
+\r
+       if( Disk != Node->ImplPtr ) {\r
+               Log_Error("Ext2", "Ext2_int_WritebackNode - Disk != Node->ImplPtr");\r
+               return -1;\r
+       }\r
+       \r
+       if( Node->Flags & VFS_FFLAG_SYMLINK ) {\r
+               inode.i_mode = EXT2_S_IFLNK;\r
+       }\r
+       else if( Node->Flags & VFS_FFLAG_DIRECTORY ) {\r
+               inode.i_mode = EXT2_S_IFDIR;\r
+       }\r
+       else if( Node->Flags & VFS_FFLAG_READONLY ) {\r
+               Log_Notice("Ext2", "Not writing back readonly inode %p:%x", Disk, Node->Inode);\r
+               return 1;\r
+       }\r
+       else {\r
+               inode.i_mode = EXT2_S_IFREG;\r
+               inode.i_dir_acl = Node->Size >> 32;\r
+       }\r
+\r
+       inode.i_size = Node->Size & 0xFFFFFFFF;\r
+       inode.i_links_count = Node->ImplInt;\r
+\r
+       inode.i_uid = Node->UID;\r
+       inode.i_gid = Node->GID;\r
+\r
+       inode.i_atime = Node->ATime / 1000;\r
+       inode.i_mtime = Node->MTime / 1000;\r
+       inode.i_ctime = Node->CTime / 1000;\r
+\r
+       // TODO: Compact ACLs into unix mode\r
+       Log_Warning("Ext2", "TODO: Support converting Acess ACLs into unix modes");\r
+\r
+       Ext2_int_WriteInode(Disk, Node->Inode, &inode);\r
+\r
+       return 0;\r
+}\r
+\r
 /**\r
  * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
  * \brief Get the address of a block from an inode's list\r
@@ -296,11 +492,78 @@ Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
  */\r
 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
 {\r
-//     Uint    block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
-       Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
+       Uint    start_group = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+       Uint    group = start_group;\r
+\r
+       if( Disk->SuperBlock.s_free_inodes_count == 0 ) \r
+       {\r
+               Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p", Disk);\r
+               return 0;\r
+       }\r
+\r
+       while( group < Disk->GroupCount && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+               group ++;\r
+       if( group == Disk->GroupCount )\r
+       {\r
+               group = 0;\r
+               while( group < start_group && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+                       group ++;\r
+       }\r
+       \r
+       if( Disk->Groups[group].bg_free_inodes_count == 0 )\r
+       {\r
+               Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p, but superblock says some free", Disk);\r
+               return 0;\r
+       }\r
+\r
+       // Load bitmap for group\r
+       //  (s_inodes_per_group / 8) bytes worth\r
+       // - Allocate a buffer the size of a sector/block\r
+       // - Read in part of the bitmap\r
+       // - Search for a free inode\r
+       tExt2_Group     *bg = &Disk->Groups[group];\r
+        int    ofs = 0;\r
+       do {\r
+               const int sector_size = 512;\r
+               Uint8 buf[sector_size];\r
+               VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+               int byte, bit;\r
+               for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )\r
+                       ;\r
+               if( byte < sector_size )\r
+               {\r
+                       for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)\r
+                               ;\r
+                       ASSERT(bit != 8);\r
+                       buf[byte] |= 1 << bit;\r
+                       VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+                       bg->bg_free_inodes_count --;\r
+                       Disk->SuperBlock.s_free_inodes_count --;\r
+\r
+                       Uint32  ret = group * Disk->SuperBlock.s_inodes_per_group + byte * 8 + bit + 1;\r
+                       Log_Debug("Ext2", "Ext2_int_AllocateInode - Allocated 0x%x", ret);\r
+                       return ret;\r
+               }\r
+\r
+               ofs += sector_size;\r
+       } while(ofs < Disk->SuperBlock.s_inodes_per_group / 8);\r
+\r
+       Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes in group %p:%i but header reported free",\r
+               Disk, group);\r
+\r
        return 0;\r
 }\r
 \r
+/**\r
+ * \brief Reduce the reference count on an inode\r
+ */\r
+void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode)\r
+{\r
+       Log_Warning("Ext2", "TODO: Impliment Ext2_int_DereferenceInode");\r
+}\r
+\r
 /**\r
  * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
  * \brief Updates the superblock\r
index f151f2c..4c8c45e 100644 (file)
@@ -2,10 +2,6 @@
  * Acess OS
  * Ext2 Driver Version 1
  */
-/**
- * \file ext2_common.h
- * \brief Second Extended Filesystem Driver
- */
 #ifndef _EXT2_COMMON_H
 #define _EXT2_COMMON_H
 #include <acess.h>
@@ -27,21 +23,32 @@ typedef struct {
        tExt2_Group             Groups[];
 } tExt2_Disk;
 
+// === GLOBALS ===
+extern tVFS_NodeType   gExt2_FileType;
+extern tVFS_NodeType   gExt2_DirType;
+
 // === FUNCTIONS ===
 // --- Common ---
 extern void    Ext2_CloseFile(tVFS_Node *Node);
 extern Uint64  Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
 extern void    Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
+extern Uint32  Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);
+extern void    Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode);
 extern int     Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
 extern int     Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
 // --- Dir ---
-extern char    *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+extern int     Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 extern tVFS_Node       *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
-extern int     Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
-extern int     Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
+extern tVFS_Node       *Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int     Ext2_Link(tVFS_Node *Parent, const char *Name, tVFS_Node *Node);
+extern tVFS_Node       *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+extern int     Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node);
 // --- Read ---
 extern size_t  Ext2_Read(tVFS_Node *node, off_t offset, size_t length, void *buffer);
 // --- Write ---
 extern size_t  Ext2_Write(tVFS_Node *node, off_t offset, size_t length, const void *buffer);
+extern Uint32  Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 LastBlock);
+extern void    Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
+extern int     Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
 
 #endif
index a3aa301..4f9210e 100644 (file)
@@ -157,6 +157,6 @@ struct ext2_dir_entry_s {
        Uint8   type;           //!< File Type (Duplicate of ext2_inode_s.i_mode)\r
        char    name[EXT2_NAME_LEN+1];          //!< File name\r
 };\r
-#define EXT2_DIRENT_SIZE       (sizeof(struct ext2_dir_entry_s)-EXT2_NAME_LEN+1)\r
+#define EXT2_DIRENT_SIZE       (sizeof(struct ext2_dir_entry_s)-(EXT2_NAME_LEN+1))\r
 \r
 #endif\r
index 60b176c..766a0e6 100644 (file)
@@ -98,7 +98,9 @@ addBlocks:
                block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
                if(!block)      return Length - retLen;
                // Add it to this inode
-               if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+               if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+                       Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+                               block, disk, Node->Inode);
                        Ext2_int_DeallocateBlock(disk, block);
                        goto ret;
                }
@@ -113,13 +115,20 @@ addBlocks:
        // Last block :D
        block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
        if(!block)      goto ret;
-       if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+       if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+               Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+                       block, disk, Node->Inode);
                Ext2_int_DeallocateBlock(disk, block);
                goto ret;
        }
        base = block * disk->BlockSize;
        VFS_WriteAt(disk->FD, base, retLen, Buffer);
+       
+       // TODO: When should the size update be committed?
        inode.i_size += retLen;
+       Node->Size += retLen;
+       Node->Flags |= VFS_FFLAG_DIRTY;
+       
        retLen = 0;
 
 ret:   // Makes sure the changes to the inode are committed
@@ -136,80 +145,96 @@ ret:      // Makes sure the changes to the inode are committed
 Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
 {
         int    bpg = Disk->SuperBlock.s_blocks_per_group;
-       Uint    blockgroup = PrevBlock / bpg;
-       Uint    bitmap[Disk->BlockSize/sizeof(Uint)];
-       Uint    bitsperblock = 8*Disk->BlockSize;
-        int    i, j = 0;
-       Uint    block;
-       
+       Uint    firstgroup = PrevBlock / bpg;
+       Uint    blockgroup = firstgroup;
+       tExt2_Group     *bg;
+
+       // TODO: Need to do locking on the bitmaps      
+
        // Are there any free blocks?
-       if(Disk->SuperBlock.s_free_blocks_count == 0)   return 0;
-       
-       if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
+       if(Disk->SuperBlock.s_free_blocks_count == 0)
+               return 0;
+
+       // First: Check the next block after \a PrevBlock
+       if( (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group != 0
+        && Disk->Groups[blockgroup].bg_free_blocks_count > 0 )
        {
-               // Search block group's bitmap
-               for(i = 0; i < bpg; i++)
+               bg = &Disk->Groups[blockgroup];
+               const int sector_size = 512;
+               Uint8 buf[sector_size];
+                int    iblock = (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group;
+                int    byte = iblock / 8;
+                int    ofs = byte / sector_size * sector_size;
+               byte %= sector_size;
+               VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+               
+               if( (buf[byte] & (1 << (iblock%8))) == 0 )
                {
-                       // Get the block in the bitmap block
-                       j = i & (bitsperblock-1);
-                       
-                       // Read in if needed
-                       if(j == 0) {
-                               VFS_ReadAt(
-                                       Disk->FD,
-                                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
-                                       Disk->BlockSize,
-                                       bitmap
-                                       );
-                       }
-                       
-                       // Fast Check
-                       if( bitmap[j/32] == 0xFFFFFFFF ) {
-                               j = (j + 31) & ~31;
-                               continue;
-                       }
-                       
-                       // Is the bit set?
-                       if( bitmap[j/32] & (1 << (j%32)) )
-                               continue;
-                       
-                       // Ooh! We found one
-                       break;
-               }
-               if( i < bpg ) {
-                       Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
-                       goto    checkAll;       // Search the entire filesystem for a free block
-                       // Goto needed for neatness
+                       // Free block - nice and contig allocation
+                       buf[byte] |= (1 << (iblock%8));
+                       VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+                       bg->bg_free_blocks_count --;
+                       Disk->SuperBlock.s_free_blocks_count --;
+                       #if EXT2_UPDATE_WRITEBACK
+                       Ext2_int_UpdateSuperblock(Disk);
+                       #endif
+                       return PrevBlock + 1;
                }
-               
-               // Mark as used
-               bitmap[j/32] |= (1 << (j%32));
-               VFS_WriteAt(
-                       Disk->FD,
-                       (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
-                       Disk->BlockSize,
-                       bitmap
-                       );
-               block = i;
-               Disk->Groups[blockgroup].bg_free_blocks_count --;
-               #if EXT2_UPDATE_WRITEBACK
-               //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
-               #endif
+               // Used... darnit
+               // Fall through and search further
        }
-       else
+
+       // Second: Search for a group with free blocks
+       while( blockgroup < Disk->GroupCount && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+               blockgroup ++;
+       if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
        {
-       checkAll:
-               Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
+               blockgroup = 0;
+               while( blockgroup < firstgroup && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+                       blockgroup ++;
+       }
+       if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 ) {
+               Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of blockss on %p, but superblock says some free",
+                       Disk);
                return 0;
        }
+
+       // Search the bitmap for a free block
+       bg = &Disk->Groups[blockgroup]; 
+        int    ofs = 0;
+       do {
+               const int sector_size = 512;
+               Uint8 buf[sector_size];
+               VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+               int byte, bit;
+               for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )
+                       ;
+               if( byte < sector_size )
+               {
+                       for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)
+                               ;
+                       ASSERT(bit != 8);
+                       buf[byte] |= 1 << bit;
+                       VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+                       bg->bg_free_blocks_count --;
+                       Disk->SuperBlock.s_free_blocks_count --;
+
+                       #if EXT2_UPDATE_WRITEBACK
+                       Ext2_int_UpdateSuperblock(Disk);
+                       #endif
+
+                       Uint32  ret = blockgroup * Disk->SuperBlock.s_blocks_per_group + byte * 8 + bit;
+                       Log_Debug("Ext2", "Ext2_int_AllocateBlock - Allocated 0x%x", ret);
+                       return ret;
+               }
+       } while(ofs < Disk->SuperBlock.s_blocks_per_group / 8);
        
-       // Reduce global count
-       Disk->SuperBlock.s_free_blocks_count --;
-       #if EXT2_UPDATE_WRITEBACK
-       Ext2_int_UpdateSuperblock(Disk);
-       #endif
-       
-       return block;
+       Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of block in group %p:%i but header reported free",
+               Disk, blockgroup);
+       return 0;
 }
 
 /**
@@ -217,6 +242,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
  */
 void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
 {
+       Log_Warning("Ext2", "TODO: Impliment Ext2_int_DeallocateBlock");
 }
 
 /**
@@ -248,6 +274,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                if( nBlocks == 0 ) {
                        Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
                        if( !Inode->i_block[12] ) {
+                               Log_Warning("Ext2", "Allocating indirect block failed");
                                free(blocks);
                                return 1;
                        }
@@ -271,6 +298,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                if( nBlocks == 0 ) {
                        Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
                        if( !Inode->i_block[13] ) {
+                               Log_Warning("Ext2", "Allocating double indirect block failed");
                                free(blocks);
                                return 1;
                        }
@@ -284,6 +312,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                        id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
                        if( !id1 ) {
                                free(blocks);
+                               Log_Warning("Ext2", "Allocating double indirect block (l2) failed");
                                return 1;
                        }
                        blocks[nBlocks/dwPerBlock] = id1;
@@ -311,6 +340,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                if( nBlocks == 0 ) {
                        Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
                        if( !Inode->i_block[14] ) {
+                               Log_Warning("Ext2", "Allocating triple indirect block failed");
                                free(blocks);
                                return 1;
                        }
@@ -324,6 +354,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                {
                        id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
                        if( !id1 ) {
+                               Log_Warning("Ext2", "Allocating triple indirect block (l2) failed");
                                free(blocks);
                                return 1;
                        }
@@ -341,6 +372,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                if( nBlocks % dwPerBlock == 0 ) {
                        id2 = Ext2_int_AllocateBlock(Disk, id1);
                        if( !id2 ) {
+                               Log_Warning("Ext2", "Allocating triple indirect block (l3) failed");
                                free(blocks);
                                return 1;
                        }
@@ -361,7 +393,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
                return 0;
        }
        
-       Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
+       Log_Warning("Ext2", "Inode ?? cannot have a block appended to it, all indirects used");
        free(blocks);
        return 1;
 }
index dfa290b..cde4c72 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-OBJ = fat.o
+OBJ = fat.o dir.o fatio.o nodecache.o
 NAME = FAT
 
 -include ../Makefile.tpl
diff --git a/KernelLand/Modules/Filesystems/FAT/common.h b/KernelLand/Modules/Filesystems/FAT/common.h
new file mode 100644 (file)
index 0000000..3983b93
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Acess2 FAT Filesystem Driver
+ * - By John Hodge (thePowersGang)
+ * 
+ * common.h
+ * - FAT internal common header
+ */
+#ifndef _FS__FAT__COMMON_H_
+#define _FS__FAT__COMMON_H_
+
+#include "fs_fat.h"
+#include <vfs.h>
+
+#define CACHE_FAT      0       //!< Caches the FAT in memory
+#define USE_LFN                1       //!< Enables the use of Long File Names
+#define        SUPPORT_WRITE   1       //!< Enables write support
+
+#define FAT_FLAG_DIRTY 0x10000
+#define FAT_FLAG_DELETE        0x20000
+
+typedef struct sFAT_VolInfo tFAT_VolInfo;
+#if USE_LFN
+typedef struct sFAT_LFNCacheEnt        tFAT_LFNCacheEnt;
+typedef struct sFAT_LFNCache   tFAT_LFNCache;
+#endif
+typedef struct sFAT_CachedNode tFAT_CachedNode;
+
+/**
+ * \brief Internal IDs for FAT types
+ */
+enum eFatType
+{
+       FAT12,  //!< FAT12 Volume
+       FAT16,  //!< FAT16 Volume
+       FAT32,  //!< FAT32 Volume
+};
+
+// === TYPES ===
+struct sFAT_VolInfo
+{
+        int    fileHandle;     //!< File Handle
+       enum eFatType   type;   //!< FAT Variant
+       char    name[12];       //!< Volume Name (With NULL Terminator)
+       Uint32  firstDataSect;  //!< First data sector
+       Uint32  rootOffset;     //!< Root Offset (clusters)
+       Uint32  ClusterCount;   //!< Total Cluster Count
+       fat_bootsect    bootsect;       //!< Boot Sector
+       tVFS_Node       rootNode;       //!< Root Node
+       size_t  BytesPerCluster;
+       
+       tMutex  lNodeCache;
+       tFAT_CachedNode *NodeCache;
+       
+       tMutex  lFAT;           //!< Lock to prevent double-writing to the FAT
+       #if CACHE_FAT
+       Uint32  *FATCache;      //!< FAT Cache
+       #endif
+};
+
+#if USE_LFN
+/**
+ * \brief Long-Filename cache entry
+ */
+struct sFAT_LFNCacheEnt
+{
+        int    ID;
+       Uint16  Data[256];
+};
+/**
+ * \brief Long-Filename cache
+ */
+struct sFAT_LFNCache
+{
+        int    NumEntries;
+       tFAT_LFNCacheEnt        Entries[];
+};
+#endif
+
+struct sFAT_CachedNode
+{
+       struct sFAT_CachedNode  *Next;
+       tVFS_Node       Node;
+};
+
+// --- General Helpers ---
+extern int     FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);
+extern tTime   FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS);
+extern void    FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS);
+
+// --- Node Caching ---
+// NOTE: FAT uses its own node cache that references by cluster (not the inode value that the Inode_* cache uses)
+//       because tVFS_Node.Inode contains the parent directory inode
+extern tVFS_Node       *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry);
+extern tVFS_Node       *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern tVFS_Node       *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern int     FAT_int_DerefNode(tVFS_Node *Node);
+extern void    FAT_int_ClearNodeCache(tFAT_VolInfo *Disk);
+
+// --- FAT Access ---
+#define GETFATVALUE_EOC        0xFFFFFFFF
+extern Uint32  FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);
+#if SUPPORT_WRITE
+extern Uint32  FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);
+extern Uint32  FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);
+#endif
+extern void    FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);
+extern void    FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer);
+
+// --- Directory Access ---
+extern int     FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
+extern tVFS_Node       *FAT_FindDir(tVFS_Node *Node, const char *Name);
+extern tVFS_Node       *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+extern int     FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+#if SUPPORT_WRITE
+extern int     FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+extern tVFS_Node       *FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int     FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+extern int     FAT_Unlink(tVFS_Node *DirNode, const char *OldName);
+#endif
+extern void    FAT_CloseFile(tVFS_Node *node);
+
+// === GLOBALS ===
+extern tVFS_NodeType   gFAT_DirType;
+extern tVFS_NodeType   gFAT_FileType;
+
+#endif
+
diff --git a/KernelLand/Modules/Filesystems/FAT/dir.c b/KernelLand/Modules/Filesystems/FAT/dir.c
new file mode 100644 (file)
index 0000000..c7268d7
--- /dev/null
@@ -0,0 +1,1135 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * dir.c
+ * - Directory access/manipulation code
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+void   FAT_int_ProperFilename(char *dest, const char *src);
+ int   FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName, char *Dest);
+ int   FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source);
+ int   FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source);
+
+ int   FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry);
+ int   FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+ int   FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer);
+#if SUPPORT_WRITE
+ int   FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+#endif
+#if USE_LFN
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID);
+void   FAT_int_DelLFN(tVFS_Node *Node, int ID);
+#endif
+ int   FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
+tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+#if SUPPORT_WRITE
+tVFS_Node      *FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   FAT_int_IsValid83Filename(const char *Name);
+ int   FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+ int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);
+#endif
+
+// === CODE ===
+
+/**
+ * \brief Converts a FAT directory entry name into a proper filename
+ * \param dest Destination array (must be at least 13 bytes in size)
+ * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')
+ */
+void FAT_int_ProperFilename(char *dest, const char *src)
+{
+        int    inpos, outpos;
+       
+       // Name
+       outpos = 0;
+       for( inpos = 0; inpos < 8; inpos++ ) {
+               if(src[inpos] == ' ')   break;
+               dest[outpos++] = src[inpos];
+       }
+       inpos = 8;
+       // Check for empty extensions
+       if(src[8] != ' ')
+       {
+               dest[outpos++] = '.';
+               for( ; inpos < 11; inpos++)     {
+                       if(src[inpos] == ' ')   break;
+                       dest[outpos++] = src[inpos];
+               }
+       }
+       dest[outpos++] = '\0';
+       
+       //LOG("dest='%s'", dest);
+}
+
+/**
+ * \fn char *FAT_int_CreateName(fat_filetable *ft, Uint8 *LongFileName)
+ * \brief Converts either a LFN or a 8.3 Name into a proper name
+ * \param ft   Pointer to the file's entry in the parent directory
+ * \param LongFileName Long file name pointer
+ * \return Filename as a heap string
+ */
+int FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName, char *Dest)
+{
+       ENTER("pft sLongFileName", ft, LongFileName);
+       #if USE_LFN
+       if(LongFileName && LongFileName[0] != 0)
+       {
+                int    len = FAT_int_ConvertUTF16_to_UTF8(NULL, LongFileName);
+               if( len > FILENAME_MAX ) {
+                       return -1;
+               }
+               FAT_int_ConvertUTF16_to_UTF8((Uint8*)Dest, LongFileName);
+       }
+       else
+       {
+       #endif
+               FAT_int_ProperFilename(Dest, ft->name);
+       #if USE_LFN
+       }
+       #endif
+       return 0;
+}
+
+#if USE_LFN
+int FAT_int_CompareUTF16_UTF8(const Uint16 *Str16, const char *Str8)
+{
+        int    pos16 = 0, pos8 = 0;
+       const Uint8     *str8 = (const Uint8 *)Str8;
+       
+       while( Str16[pos16] && str8[pos8] )
+       {
+               Uint32  cp8, cp16;
+               if( Str16[pos16] & 0x8000 ) {
+                       // Do something!
+                       cp16 = 0;
+               }
+               else {
+                       cp16 = Str16[pos16];
+                       pos16 ++;
+               }
+               pos8 += ReadUTF8(str8 + pos8, &cp8);
+       
+               if(cp16 == cp8) continue ;
+               
+               if(cp16 < cp8)
+                       return -1;
+               else
+                       return 1;
+       }
+       if(Str16[pos16] == str8[pos8])
+               return 0;
+       if(Str16[pos16] < str8[pos8])
+               return -1;
+       else
+               return 1;
+}
+
+int FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source)
+{
+        int    len = 0;
+       for( ; *Source; Source ++ )
+       {
+               // TODO: Decode/Reencode
+               if( Dest )
+                       Dest[len] = *Source;
+               len += 1;
+       }
+       if( Dest )
+               Dest[len] = 0;
+       return len;
+}
+
+int FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source)
+{
+        int    len = 0;
+       while( *Source )
+       {
+               Uint32  cp;
+               int cpl;
+               
+               cpl = ReadUTF8(Source, &cp);
+               if(cp < 0x8000) {
+                       if( Dest )
+                               Dest[len] = cp;
+                       len ++;
+               }
+               else {
+                       // TODO!
+               }
+               Source += cpl;
+       }
+       Dest[len] = 0;
+       return len;
+}
+
+int FAT_int_ParseLFN(const fat_filetable *Entry, Uint16 *Buffer)
+{
+       const fat_longfilename  *lfnInfo;
+        int    ofs;
+       
+       lfnInfo = (const void*)Entry;
+       
+       if(lfnInfo->id & 0x40) {
+               memset(Buffer, 0, 256*2);
+       }
+       ofs = (lfnInfo->id & 0x3F) * 13 - 1;
+       if( ofs >= 255 )
+               return -1;
+       
+       Buffer[ofs--] = lfnInfo->name3[1];      Buffer[ofs--] = lfnInfo->name3[0];
+       Buffer[ofs--] = lfnInfo->name2[5];      Buffer[ofs--] = lfnInfo->name2[4];
+       Buffer[ofs--] = lfnInfo->name2[3];      Buffer[ofs--] = lfnInfo->name2[2];
+       Buffer[ofs--] = lfnInfo->name2[1];      Buffer[ofs--] = lfnInfo->name2[0];
+       Buffer[ofs--] = lfnInfo->name1[4];      Buffer[ofs--] = lfnInfo->name1[3];
+       Buffer[ofs--] = lfnInfo->name1[2];      Buffer[ofs--] = lfnInfo->name1[1];
+       Buffer[ofs--] = lfnInfo->name1[0];
+       
+       if((lfnInfo->id&0x3F) == 1)
+               return 1;
+       return 0;
+}
+#endif
+
+int FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry)
+{
+       fat_filetable   fileinfo[16];
+       char    tmpName[13];
+       #if USE_LFN
+       Uint16  lfn[256];
+        int    lfnId = -1;
+       #endif
+
+       ENTER("pDirNode sName pEntry", DirNode, Name, Entry);
+
+       for( int i = 0; ; i++ )
+       {
+               if((i & 0xF) == 0) {
+                       if(FAT_int_ReadDirSector(DirNode, i/16, fileinfo))
+                       {
+                               LEAVE('i', -1);
+                               return -1;
+                       }
+               }
+               
+               //Check if the files are free
+               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker
+               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry
+               
+               
+               #if USE_LFN
+               // Long File Name Entry
+               if(fileinfo[i & 0xF].attrib == ATTR_LFN)
+               {
+                       if( FAT_int_ParseLFN(&fileinfo[i&0xF], lfn) )
+                               lfnId = i+1;
+                       continue ;
+               }
+               // Remove LFN if it does not apply
+               if(lfnId != i)  lfn[0] = 0;
+               #else
+               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;
+               #endif
+
+               // Get Real Filename
+               FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);
+//             LOG("tmpName = '%s'", tmpName);
+//             #if DEBUG
+//             Debug_HexDump("FAT tmpName", tmpName, strlen(tmpName));
+//             #endif
+/*
+               #if DEBUG && USE_LFN
+               if(lfnId == i)
+               {
+                       Uint8 lfntmp[256*3+1];
+                       FAT_int_ConvertUTF16_to_UTF8(lfntmp, lfn);
+                       LOG("lfntmp = '%s'", lfntmp);
+               }
+               #endif
+*/
+       
+               // Only the long name is case sensitive, 8.3 is not
+               #if USE_LFN
+               if(strucmp(tmpName, Name) == 0 || FAT_int_CompareUTF16_UTF8(lfn, Name) == 0)
+               #else
+               if(strucmp(tmpName, Name) == 0)
+               #endif
+               {
+                       memcpy(Entry, fileinfo + (i&0xF), sizeof(*Entry));
+                       LOG("Found %s at %i", Name, i);
+                       LEAVE('i', i);
+                       return i;
+               }
+       }
+       
+       LEAVE('i', -1);
+       return -1;
+}
+
+int FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry)
+{
+        int    ents_per_sector = 512 / sizeof(fat_filetable); 
+       fat_filetable   fileinfo[ents_per_sector];
+        int    i, sector;
+
+       if( Mutex_Acquire(&DirNode->Lock) ) {
+               return -EINTR;
+       }
+       
+       sector = 0;
+       for( i = 0; ; i ++ )
+       {
+               if( i == 0 || i == ents_per_sector )
+               {
+                       if(FAT_int_ReadDirSector(DirNode, sector, fileinfo))
+                       {
+                               LOG("ReadDirSector failed");
+                               break ;
+                       }
+                       i = 0;
+                       sector ++;
+               }
+       
+               // Check for free/end of list
+               if(fileinfo[i].name[0] == '\0') break;  // End of List marker
+               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry
+               
+               if(fileinfo[i].attrib == ATTR_LFN)      continue;
+
+               LOG("fileinfo[i].cluster = %x:%04x", fileinfo[i].clusterHi, fileinfo[i].cluster);
+               #if DEBUG
+               {
+                       char    tmpName[13];
+                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);
+                       LOG("tmpName = '%s'", tmpName);
+               }
+               #endif
+               
+       
+               if(fileinfo[i].cluster != (Cluster & 0xFFFF))   continue;
+               if(fileinfo[i].clusterHi != ((Cluster >> 16) & 0xFFFF)) continue;
+       
+               memcpy(Entry, &fileinfo[i], sizeof(*Entry));
+               Mutex_Release(&DirNode->Lock);
+               return i;
+       }
+       
+       Mutex_Release(&DirNode->Lock);
+       return -ENOENT;
+}
+
+/* 
+ * ====================
+ *     Directory IO
+ * ====================
+ */
+
+/**
+ * \brief Reads a sector from the disk
+ * \param Node Directory node to read
+ * \param Sector       Sector number in the directory to read
+ * \param Buffer       Destination buffer for the read data
+ */
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)
+{
+       Uint64  addr;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+       
+       // Parse address
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LOG("addr = 0x%llx", addr);
+       // Read Sector
+       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a sector to the disk
+ * \param Node Directory node to write
+ * \param Sector       Sector number in the directory to write
+ * \param Buffer       Source data
+ */
+int FAT_int_WriteDirSector(tVFS_Node *Node, int Sector, const fat_filetable *Buffer)
+{
+       Uint64  addr;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+       
+       // Parse address
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       // Read Sector
+       if(VFS_WriteAt(disk->fileHandle, addr, 512, Buffer) != 512)
+       {
+               LEAVE('i', 1);
+               return 1;
+       }
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \brief Writes an entry to the disk
+ * \todo Support expanding a directory
+ * \param Node Directory node
+ * \param ID   ID of entry to update
+ * \param Entry        Entry data
+ * \return Zero on success, non-zero on error
+ */
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)
+{
+       Uint64  addr = 0;
+        int    tmp;
+       Uint32  cluster = 0;
+       tFAT_VolInfo    *disk = Node->ImplPtr;
+       
+       ENTER("pNode iID pEntry", Node, ID, Entry);
+       
+       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+       if( tmp )
+       {
+               //TODO: Allocate a cluster
+               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);
+               if(cluster == -1) {
+                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);
+                       LEAVE('i', 1);
+                       return 1;
+               }
+               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+       }
+       
+
+       LOG("addr = 0x%llx", addr);
+       
+       // Wriet data to disk
+       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);
+       
+       LEAVE('i', 0);
+       return 0;
+}
+#endif
+
+#if USE_LFN    
+/**
+ * \fn Uint16 *FAT_int_GetLFN(tVFS_Node *node)
+ * \brief Return pointer to LFN cache entry
+ * \param Node Directory node
+ * \param ID   ID of the short name
+ * \return Pointer to the LFN cache entry
+ */
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID)
+{
+       tFAT_LFNCache   *cache;
+        int    i, firstFree;
+       
+       if( Mutex_Acquire( &Node->Lock ) ) {
+               return NULL;
+       }
+       
+       // TODO: Thread Safety (Lock things)
+       cache = Node->Data;
+       
+       // Create a cache if it isn't there
+       if(!cache) {
+               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );
+               cache->NumEntries = 1;
+               cache->Entries[0].ID = ID;
+               cache->Entries[0].Data[0] = 0;
+               Mutex_Release( &Node->Lock );
+               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);
+               return cache->Entries[0].Data;
+       }
+       
+       // Scan for this entry
+       firstFree = -1;
+       for( i = 0; i < cache->NumEntries; i++ )
+       {
+               if( cache->Entries[i].ID == ID ) {
+                       Mutex_Release( &Node->Lock );
+                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);
+                       return cache->Entries[i].Data;
+               }
+               if( cache->Entries[i].ID == -1 && firstFree == -1 )
+                       firstFree = i;
+       }
+       
+       if(firstFree == -1) {
+               // Use `i` for temp length
+               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);
+               Node->Data = realloc( Node->Data, i );
+               if( !Node->Data ) {
+                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);
+                       Mutex_Release( &Node->Lock );
+                       return NULL;
+               }
+               //Log_Debug("FAT", "Realloc (%i)\n", i);
+               cache = Node->Data;
+               i = cache->NumEntries;
+               cache->NumEntries ++;
+       }
+       else {
+               i = firstFree;
+       }
+       
+       // Create new entry
+       cache->Entries[ i ].ID = ID;
+       cache->Entries[ i ].Data[0] = '\0';
+       
+       Mutex_Release( &Node->Lock );
+       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);
+       return cache->Entries[ i ].Data;
+}
+
+/**
+ * \fn void FAT_int_DelLFN(tVFS_Node *node)
+ * \brief Delete a LFN cache entry
+ * \param Node Directory node
+ * \param ID   File Entry ID
+ */
+void FAT_int_DelLFN(tVFS_Node *Node, int ID)
+{
+       tFAT_LFNCache   *cache = Node->Data;
+        int    i;
+       
+       // Fast return
+       if(!cache)      return;
+       
+       // Scan for a current entry
+       for( i = 0; i < cache->NumEntries; i++ )
+       {
+               if( cache->Entries[i].ID == ID )
+                       cache->Entries[i].ID = -1;
+       }
+       return ;
+}
+#endif
+
+/**
+ * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)
+ * \param Node Node structure of directory
+ * \param ID   Directory position
+ * \return Filename as a heap string, NULL or VFS_SKIP
+ */
+int FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
+{
+       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector
+        int    a;
+       #if USE_LFN
+       Uint16  *lfn = NULL;
+       #endif
+       
+       ENTER("pNode iID", Node, ID);
+       
+       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))
+       {
+               LOG("End of chain, end of dir");
+               LEAVE('i', -EIO);
+               return -EIO;
+       }
+       
+       // Offset in sector
+       a = ID % 16;
+
+       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);
+       
+       // Check if this is the last entry
+       if( fileinfo[a].name[0] == '\0' ) {
+               Node->Size = ID;
+               LOG("End of list");
+               LEAVE('i', -ENOENT);
+               return -ENOENT; // break
+       }
+       
+       // Check for empty entry
+       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {
+               LOG("Empty Entry");
+               LEAVE_RET('i', 1);      // Skip
+       }
+       
+       #if USE_LFN
+       // Get Long File Name Cache
+       if(fileinfo[a].attrib == ATTR_LFN)
+       {
+               fat_longfilename        *lfnInfo;
+               
+               lfnInfo = (fat_longfilename *) &fileinfo[a];
+               
+               // Get cache for corresponding file
+               // > ID + Index gets the corresponding short node
+               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );
+
+               a = FAT_int_ParseLFN(&fileinfo[a], lfn);
+               if( a < 0 ) {
+                       LOG("Invalid LFN, error");
+                       LEAVE_RET('i', -EIO);
+               }
+
+               LEAVE_RET('i', 1);      // Skip
+       }
+       #endif
+       
+       // Check if it is a volume entry
+       if(fileinfo[a].attrib & 0x08) {
+               LEAVE_RET('i', 1);      // Skip
+       }
+       // Ignore .
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {
+               LEAVE_RET('i', 1);      // Skip
+       }
+       // and ..
+       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {
+               LEAVE_RET('i', 1);      // Skip
+       }
+       
+       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",
+               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],
+               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],
+               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );
+       
+       #if USE_LFN
+       lfn = FAT_int_GetLFN(Node, ID);
+       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);
+       FAT_int_CreateName(&fileinfo[a], lfn, Dest);
+       #else
+       FAT_int_CreateName(&fileinfo[a], NULL, Dest);
+       #endif
+       
+       LEAVE('i', 0);
+       return 0;
+}
+
+/**
+ * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)
+ * \brief Finds an entry in the current directory
+ */
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)
+{
+       fat_filetable   fileent;
+       
+       ENTER("pNode sname", Node, Name);       
+
+       // Fast Returns
+       if(!Name || Name[0] == '\0') {
+               LEAVE('n');
+               return NULL;
+       }
+
+       if( FAT_int_GetEntryByName(Node, Name, &fileent) == -1 ) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+
+       tVFS_Node *ret = FAT_int_CreateNode(Node, &fileent);
+       LOG("Found %s as %p", Name, ret);
+       LEAVE('p', ret);
+       return ret;
+}
+
+tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)
+{
+       tFAT_VolInfo    *disk = Root->ImplPtr;
+       tVFS_Node       *dirnode, *ret;
+       fat_filetable   ft;
+
+       ENTER("pRoot XInode", Root, Inode);
+
+       ret = FAT_int_GetNode(disk, Inode & 0xFFFFFFFF);
+       if( ret ) {
+               if( (ret->Inode >> 32) != 0 ) {
+                       LOG("Node in cache, quick return");
+                       LEAVE('p', ret);
+                       return ret;
+               }
+               else {
+                       LOG("Node cached, but incomplete");
+                       // Fall on through
+               }
+               ret = NULL;
+       }
+       
+       dirnode = FAT_int_CreateIncompleteDirNode(disk, Inode >> 32);
+
+       int id = FAT_int_GetEntryByCluster(dirnode, Inode & 0xFFFFFFFF, &ft);
+       if( id != -1 ) {
+               ret = FAT_int_CreateNode(dirnode, &ft);
+       }
+
+       dirnode->Type->Close(dirnode);
+
+       LEAVE('p', ret);
+       return ret;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Create a new node
+ */
+tVFS_Node *FAT_Mknod(tVFS_Node *DirNode, const char *Name, Uint Flags)
+{
+       tFAT_VolInfo    *disk = DirNode->ImplPtr;
+        int    rv;
+       fat_filetable   ft;
+       memset(&ft, 0, sizeof(ft));
+
+       ENTER("pDirNode sName xFlags", DirNode, Name, Flags);
+       
+       // Allocate a cluster
+       Uint32 cluster = FAT_int_AllocateCluster(disk, -1);
+       LOG("Cluster 0x%07x allocated", cluster);
+       
+       // Create a temporary file table entry for an empty node
+       ft.cluster = cluster & 0xFFFF;
+       ft.clusterHi = cluster >> 16;
+       ft.size = 0;
+       if( Flags & VFS_FFLAG_DIRECTORY )
+               ft.attrib = ATTR_DIRECTORY;
+       else
+               ft.attrib = 0;
+       
+       tVFS_Node *newnode = FAT_int_CreateNode(DirNode, &ft);
+       if( !newnode ) {
+               errno = -EINTERNAL;
+               return NULL;
+       }
+       LOG("newnode = %p", newnode);
+
+       // Call link
+       if( (rv = FAT_Link(DirNode, Name, newnode)) ) {
+               newnode->ImplInt |= FAT_FLAG_DELETE;
+       }
+       LEAVE('p', newnode);
+       return newnode;
+}
+
+/**
+ * \brief Internal - Checks if a character is valid in an 8.3 filename
+ */
+static inline int is_valid_83_char(char ch)
+{
+       if( '0' <= ch && ch <= '9' )
+               return 1;
+       if( 'A' <= ch && ch <= 'Z' )
+               return 1;
+       if( 'a' <= ch && ch <= 'z' )
+               return 1;
+       if( strchr("$%'-_@~`#!(){}^#&", ch) )
+               return 1;
+       if( ch > 128 )
+               return 1;
+       return 0;
+}
+
+Uint8 FAT_int_UnicodeTo83(Uint32 Input)
+{
+       Input = toupper(Input);
+       // Input = unicode_to_oem(Input);
+       if( Input > 256 )
+               Input = '_';
+       if(!is_valid_83_char(Input))
+               Input = '_';
+       return Input;
+}
+
+/**
+ * \brief Internal - Determines if a filename is a valid 8.3 filename
+ */
+int FAT_int_IsValid83Filename(const char *Name)
+{
+        int    i, j;
+
+       if( !Name[0] || Name[0] == '.' )
+               return 0;
+
+       // Check filename portion
+       for( i = 0; Name[i] && i < 8; i ++ )
+       {
+               if( Name[i] == '.' )
+                       break;
+               if( !is_valid_83_char(Name[i]) )
+                       return 0;
+       }
+       // If the next char is not \0 or '.', it's not valid
+       if( Name[i] && Name[i++] != '.' )
+               return 0;
+       
+       // Check the extension portion
+       for( j = 0; Name[i+j] && j < 3; j ++ )
+       {
+               if( !is_valid_83_char(Name[i+j]) )
+                       return 0;
+       }
+       
+       // After the extension must be the end
+       if( Name[i+j] )
+               return 0;
+       
+       return 1;
+}
+
+Uint8 FAT_int_MakeLFNChecksum(const char *ShortName)
+{
+       Uint8 ret = 0;
+       for( int i = 0; i < 11; i++ )
+       {
+               // ret = (ret >>> 1) + ShortName[i]
+               // where >>> is rotate right
+               ret = ((ret & 1) ? 0x80 : 0x00) + (ret >> 1) + ShortName[i];
+       }
+       return ret;
+}
+
+/**
+ * \brief Create a new name for a file
+ * \note Since FAT doesn't support reference counting, this will cause double-references if
+ *       a file is hardlinked and not unlinked
+ */
+int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *NewNode)
+{
+       Uint16  lfn[256];
+       fat_filetable   ft;
+        int    nLFNEnt = 0;
+       const int eps = 512 / sizeof(fat_filetable);
+       fat_filetable   fileinfo[eps];
+       
+       if( Mutex_Acquire( &DirNode->Lock ) ) {
+               return EINTR;
+       }
+
+       // -- Ensure duplicates aren't created --
+       if( FAT_int_GetEntryByName(DirNode, NewName, &ft) >= 0 ) {
+               Mutex_Release( &DirNode->Lock );
+               return EEXIST;
+       }
+       
+       // -- Create filetable entry --
+       #if 0
+       {
+                int    bDirty = 0;
+                int    inofs = 0;
+               while( NewName[inofs] && NewName[inofs] == '.' )
+                       inofs ++, bDirty = 1;
+               for( int i = 0; i < 8 && NewName[inofs] && NewName[inofs] != '.'; i ++ )
+               {
+                       Uint32  cp;
+                       inofs += ReadUTF8(NewName + inofs, &cp);
+                       // Spaces are silently skipped
+                       if(isspace(cp)) {
+                               i --, bDirty = 1;
+                               continue ;
+                       }
+                       ft.name[i] = FAT_int_UnicodeTo83(cp);
+                       if(ft.name[i] != cp)
+                               bDirty = 1;
+               }
+               while( NewName[inofs] && NewName[inofs] != '.' )
+                       inofs ++, bDirty = 1;
+               for( ; i < 8+3 && NewName[inofs]; i ++ )
+               {
+                       Uint32  cp;
+                       inofs += ReadUTF8(NewName + inofs, &cp);
+                       // Spaces are silently skipped
+                       if(isspace(cp)) {
+                               i --, bDirty = 1;
+                               continue ;
+                       }
+                       ft.name[i] = FAT_int_UnicodeTo83(cp);
+                       if(ft.name[i] != cp)
+                               bDirty = 1;
+               }
+               if( !NewName[inofs] )   bDirty = 1;
+               
+               if( bDirty )
+               {
+                       int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+                       lfn[lfnlen] = 0;
+                       nLFNEnt = DivUp(lfnlen, 13);
+               }
+       }
+       #endif
+        int    bNeedsLFN = !FAT_int_IsValid83Filename(NewName);
+       if( bNeedsLFN )
+       {
+               int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+               lfn[lfnlen] = 0;
+               nLFNEnt = DivUp(lfnlen, 13);
+       
+               // Create a base mangled filetable entry
+               int i, j = 0;
+               while(NewName[j] == '.')        j ++;   // Eat leading dots
+               for( i = 0; i < 6 && NewName[j] && NewName[j] != '.'; i ++, j ++ )
+               {
+                       if( !isalpha(NewName[j]) && !is_valid_83_char(NewName[j]) )
+                               ft.name[i] = '_';
+                       else
+                               ft.name[i] = toupper(NewName[j]);
+               }
+               ft.name[i++] = '~';
+               ft.name[i++] = '1';
+               while(i < 8)    ft.name[i++] = ' ';
+               while(NewName[j] && NewName[j] != '.')  j ++;
+               for( ; i < 8+3 && NewName[j]; i ++, j ++ )
+               {
+                       if( NewName[j] == '.' )
+                               i --;
+                       else if( !is_valid_83_char(NewName[j]) )
+                               ft.name[i] = '_';
+                       else
+                               ft.name[i] = toupper(NewName[j]);
+               }
+               while(i < 8+3)  ft.name[i++] = ' ';
+               
+               // - Ensure there isn't a duplicate short-name
+                int    bIsDuplicate = 1;
+               while( bIsDuplicate )
+               {
+                       bIsDuplicate = 0;       // Assume none                  
+
+                       // Scan directory
+                       for( int id = 0; ; id ++ )
+                       {
+                               if( id % eps == 0 )
+                               {
+                                       if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+                                               break;  // end of cluster chain
+                               }
+                               
+                               // End of file list
+                               if( fileinfo[id%eps].name[0] == '\0' )  break;
+                               // Empty entry
+                               if( fileinfo[id%eps].name[0] == '\xE5' )        continue;
+                               // LFN entry
+                               if( fileinfo[id%eps].attrib == ATTR_LFN )       continue;
+                               
+                               // Is this a duplicate?
+                               if( memcmp(ft.name, fileinfo[id%eps].name, 8+3) == 0 ) {
+                                       bIsDuplicate = 1;
+                                       break;
+                               }
+                               
+                               // No - move a long
+                       }
+                       
+                       // If a duplicate was found, increment the suffix
+                       if( bIsDuplicate )
+                       {
+                               if( ft.name[7] == '9' ) {
+                                       // TODO: Expand into ~00
+                                       Log_Error("FAT", "TODO: Use two digit LFN suffixes");
+                                       Mutex_Release(&DirNode->Lock);
+                                       return ENOTIMPL;
+                               }
+                               
+                               ft.name[7] += 1;
+                       }
+               }
+       }
+       else
+       {
+               // Create pure filetable entry
+                int    i;
+               // - Copy filename
+               for( i = 0; i < 8 && *NewName && *NewName != '.'; i ++, NewName++ )
+                       ft.name[i] = *NewName;
+               // - Pad with spaces
+               for( ; i < 8; i ++ )
+                       ft.name[i] = ' ';
+               // - Eat '.'
+               if(*NewName)
+                       NewName ++;
+               // - Copy extension
+               for( ; i < 8+3 && *NewName; i ++, NewName++ )
+                       ft.name[i] = *NewName;
+               // - Pad with spaces
+               for( ; i < 8+3; i ++ )
+                       ft.name[i] = ' ';
+       }
+
+       ft.attrib = 0;
+       if(NewNode->Flags & VFS_FFLAG_DIRECTORY )
+               ft.attrib |= ATTR_DIRECTORY;    
+       ft.ntres     = 0;
+       FAT_int_GetFATTimestamp(NewNode->CTime, &ft.cdate, &ft.ctime, &ft.ctimems);
+//     ft.ctimems   = ft.ctimems;
+       ft.ctime     = LittleEndian16(ft.ctime);
+       ft.cdate     = LittleEndian16(ft.cdate);
+       FAT_int_GetFATTimestamp(NewNode->MTime, &ft.mdate, &ft.mtime, NULL);
+       ft.mtime     = LittleEndian16(ft.mtime);
+       ft.mdate     = LittleEndian16(ft.mdate);
+       FAT_int_GetFATTimestamp(NewNode->ATime, &ft.adate, NULL, NULL);
+       ft.adate     = LittleEndian16(ft.adate);
+       ft.clusterHi = LittleEndian16((NewNode->Inode >> 16) & 0xFFFF);
+       ft.cluster   = LittleEndian16(NewNode->Inode & 0xFFFF);
+       ft.size      = LittleEndian32(NewNode->Size);
+
+       LOG("ft.name = '%.11s'", ft.name);
+
+       // -- Add entry to the directory --
+       // Locate a range of nLFNEnt + 1 free entries
+        int    end_id = -1;
+        int    range_first = 0, range_last = -1;
+       for( int id = 0; ; id ++ )
+       {
+               if( id % eps == 0 )
+               {
+                       if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+                               break;  // end of cluster chain
+               }
+               
+               // End of file list, break out
+               if( fileinfo[id%eps].name[0] == '\0' ) {
+                       if( id - range_first == nLFNEnt )
+                               range_last = id;
+                       end_id = id;
+                       break;
+               }
+               
+               // If an entry is occupied, clear the range
+               if( fileinfo[id%eps].name[0] != '\xE5' ) {
+                       range_first = id + 1;
+                       continue ;
+               }
+               
+               // Free entry, check if we have enough
+               if( id - range_first == nLFNEnt ) {
+                       range_last = id;
+                       break;
+               }
+               // Check the next one
+       }
+       if( range_last == -1 )
+       {
+               // - If there are none, defragment the directory?
+               
+               // - Else, expand the directory
+               if( end_id == -1 ) {
+                       // End of cluster chain
+               }
+               else {
+                       // Just end of block
+               }
+               // - and if that fails, return an error
+               Log_Warning("FAT", "TODO: Impliment directory expansion / defragmenting");
+               Mutex_Release(&DirNode->Lock);
+               return ENOTIMPL;
+       }
+
+       // Calculate the checksum used for LFN
+       Uint8   lfn_checksum = 0;
+       if( nLFNEnt )
+       {
+               lfn_checksum = FAT_int_MakeLFNChecksum(ft.name);
+       }
+
+       // Insert entries       
+       if( range_first % eps != 0 )
+               FAT_int_ReadDirSector(DirNode, range_first/eps, fileinfo);
+       for( int id = range_first; id <= range_last; id ++ )
+       {
+               if( id % eps == 0 ) {
+                       if( id != range_first )
+                               FAT_int_WriteDirSector(DirNode, (id-1)/eps, fileinfo);
+                       FAT_int_ReadDirSector(DirNode, id/eps, fileinfo);
+               }
+               
+               if( id == range_last ) {
+                       // Actual entry
+                       memcpy(fileinfo + id % eps, &ft, sizeof(fat_filetable));
+               }
+               else {
+                       // Long filename
+                       int lfnid = (nLFNEnt - (id - range_first));
+                       int ofs = (lfnid-1) * 13;
+                        int    i=0, j=0;
+                       fat_longfilename *lfnent = (void*)( fileinfo + id%eps );
+                       
+                       lfnent->id = 0x40 | lfnid;
+                       lfnent->attrib = ATTR_LFN;
+                       lfnent->type = 0;
+                       lfnent->firstCluster = 0;
+                       lfnent->checksum = lfn_checksum;        // ???
+
+                       for( i = 0; i < 13; i ++ )
+                       {
+                               Uint16  wd;
+                               if( (wd = lfn[ofs+j]) ) j ++;
+                               wd = LittleEndian16(wd);
+                               if(i < 5)
+                                       lfnent->name1[i    ] = wd;
+                               else if( i < 5+6 )
+                                       lfnent->name2[i-5  ] = wd;
+                               else
+                                       lfnent->name3[i-5-6] = wd;
+                       }
+               }
+       }
+       FAT_int_WriteDirSector(DirNode, range_last/eps, fileinfo);
+
+       Mutex_Release( &DirNode->Lock );
+       return 0;
+}
+
+/**
+ * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)
+ * \brief Rename / Delete a file
+ */
+int FAT_Unlink(tVFS_Node *Node, const char *OldName)
+{
+       tVFS_Node       *child;
+       fat_filetable   ft;
+       
+       if( Mutex_Acquire(&Node->Lock) ) {
+               return EINTR;
+       }
+
+       int id = FAT_int_GetEntryByName(Node, OldName, &ft);
+       if(id == -1) {
+               Mutex_Release(&Node->Lock);
+               return ENOTFOUND;
+       }
+
+       child = FAT_int_CreateNode(Node->ImplPtr, &ft);
+       if( !child ) {
+               Mutex_Release(&Node->Lock);
+               return EINVAL;
+       }
+       child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close
+
+       // TODO: If it has a LFN, remove that too
+
+       // Delete from the directory
+       ft.name[0] = '\xE5';
+       FAT_int_WriteDirEntry(Node, id, &ft);
+
+       // Close child
+       child->Type->Close( child );
+       Mutex_Release( &Node->Lock );
+       return EOK;
+}
+#endif
index c69a063..c930497 100644 (file)
 #define DEBUG  0\r
 #define VERBOSE        1\r
 \r
-#define CACHE_FAT      0       //!< Caches the FAT in memory\r
-#define USE_LFN                1       //!< Enables the use of Long File Names\r
-#define        SUPPORT_WRITE   0       //!< Enables write support\r
-\r
 #include <acess.h>\r
 #include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-#define FAT_FLAG_DIRTY 0x10000\r
-#define FAT_FLAG_DELETE        0x20000\r
-\r
-// === TYPES ===\r
-#if USE_LFN\r
-/**\r
- * \brief Long-Filename cache entry\r
- */\r
-typedef struct sFAT_LFNCacheEnt\r
-{\r
-        int    ID;\r
-       // TODO: Handle UTF16 names correctly\r
-       char    Data[256];\r
-}      tFAT_LFNCacheEnt;\r
-/**\r
- * \brief Long-Filename cache\r
- */\r
-typedef struct sFAT_LFNCache\r
-{\r
-        int    NumEntries;\r
-       tFAT_LFNCacheEnt        Entries[];\r
-}      tFAT_LFNCache;\r
-#endif\r
+#include "common.h"\r
 \r
 // === PROTOTYPES ===\r
 // --- Driver Core\r
  int   FAT_Install(char **Arguments);\r
+ int   FAT_Detect(int FD);\r
 tVFS_Node      *FAT_InitDevice(const char *device, const char **options);\r
 void   FAT_Unmount(tVFS_Node *Node);\r
 // --- Helpers\r
  int   FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#if SUPPORT_WRITE\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#endif\r
-void   FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
 // --- File IO\r
 size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
 #if SUPPORT_WRITE\r
-void   FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
-#endif\r
-// --- Directory IO\r
-char   *FAT_ReadDir(tVFS_Node *Node, int ID);\r
-tVFS_Node      *FAT_FindDir(tVFS_Node *Node, const char *Name);\r
-tVFS_Node      *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);\r
-#if SUPPORT_WRITE\r
- int   FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);\r
- int   FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);\r
 #endif\r
 void   FAT_CloseFile(tVFS_Node *node);\r
 \r
+\r
 // === Options ===\r
  int   giFAT_MaxCachedClusters = 1024*512/4;\r
 \r
 // === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
+MODULE_DEFINE(0, VER2(0,80) /*v0.80*/, VFAT, FAT_Install, NULL, NULL);\r
 tFAT_VolInfo   gFAT_Disks[8];\r
  int   giFAT_PartCount = 0;\r
-tVFS_Driver    gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
+tVFS_Driver    gFAT_FSInfo = {\r
+       .Name = "fat",\r
+       .Detect = FAT_Detect,\r
+       .InitDevice = FAT_InitDevice,\r
+       .Unmount = FAT_Unmount,\r
+       .GetNodeFromINode = FAT_GetNodeFromINode\r
+};\r
 tVFS_NodeType  gFAT_DirType = {\r
        .TypeName = "FAT-Dir",\r
        .ReadDir = FAT_ReadDir,\r
        .FindDir = FAT_FindDir,\r
        #if SUPPORT_WRITE\r
        .MkNod = FAT_Mknod,\r
-       .Relink = FAT_Relink,\r
+       .Link = FAT_Link,\r
+       .Unlink = FAT_Unlink,\r
        #endif\r
        .Close = FAT_CloseFile\r
        };\r
@@ -120,6 +85,22 @@ int FAT_Install(char **Arguments)
        return MODULE_ERR_OK;\r
 }\r
 \r
+/**\r
+ * \brief Detect if a file is a FAT device\r
+ */\r
+int FAT_Detect(int FD)\r
+{\r
+       fat_bootsect bs;\r
+       \r
+       if( VFS_ReadAt(FD, 0, 512, &bs) != 512) {\r
+               return 0;\r
+       }\r
+\r
+       if(bs.bps == 0 || bs.spc == 0)\r
+               return 0;\r
+       \r
+       return 1;\r
+}\r
 /**\r
  * \brief Reads the boot sector of a disk and prepares the structures for it\r
  */\r
@@ -130,6 +111,8 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        Uint32  FATSz, RootDirSectors, TotSec;\r
        tVFS_Node       *node = NULL;\r
        tFAT_VolInfo    *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
+\r
+       memset(diskInfo, 0, sizeof(*diskInfo));\r
        \r
        // Temporary Pointer\r
        bs = &diskInfo->bootsect;\r
@@ -144,7 +127,8 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
        \r
        if(bs->bps == 0 || bs->spc == 0) {\r
-               Log_Notice("FAT", "Error in FAT Boot Sector");\r
+               Log_Notice("FAT", "Error in FAT Boot Sector (zero BPS/SPC)");\r
+               VFS_Close(diskInfo->fileHandle);\r
                return NULL;\r
        }\r
        \r
@@ -164,9 +148,9 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        \r
        diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
        \r
-       if(diskInfo->ClusterCount < 4085)\r
+       if(diskInfo->ClusterCount < FAT16_MIN_SECTORS)\r
                diskInfo->type = FAT12;\r
-       else if(diskInfo->ClusterCount < 65525)\r
+       else if(diskInfo->ClusterCount < FAT32_MIN_CLUSTERS)\r
                diskInfo->type = FAT16;\r
        else\r
                diskInfo->type = FAT32;\r
@@ -225,6 +209,7 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
                diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
                if(diskInfo->FATCache == NULL) {\r
                        Log_Warning("FAT", "Heap Exhausted");\r
+                       VFS_Cose(diskInfo->fileHandle);\r
                        return NULL;\r
                }\r
                Ofs = bs->resvSectCount*512;\r
@@ -272,10 +257,6 @@ tVFS_Node *FAT_InitDevice(const char *Device, const char **Options)
        \r
        diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
        \r
-       // Initalise inode cache for filesystem\r
-       diskInfo->inodeHandle = Inode_GetHandle();\r
-       LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
-       \r
        // == VFS Interface\r
        node = &diskInfo->rootNode;\r
        //node->Size = bs->files_in_root;\r
@@ -313,7 +294,7 @@ void FAT_Unmount(tVFS_Node *Node)
        // Close Disk Handle\r
        VFS_Close( disk->fileHandle );\r
        // Clear Node Cache\r
-       Inode_ClearCache(disk->inodeHandle);\r
+       FAT_int_ClearNodeCache(disk);\r
        // Mark as unused\r
        disk->fileHandle = -2;\r
        return;\r
@@ -331,15 +312,15 @@ void FAT_Unmount(tVFS_Node *Node)
  */\r
 int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
 {\r
-       Uint32  cluster;\r
+       Uint32  cluster, base_cluster;\r
        Uint64  addr;\r
         int    skip;\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        \r
        ENTER("pNode XOffset", Node, Offset);\r
        \r
-       cluster = Node->Inode & 0xFFFFFFF;      // Cluster ID\r
-       LOG("cluster = 0x%07x", cluster);\r
+       cluster = base_cluster = Node->Inode & 0xFFFFFFF;       // Cluster ID\r
+//     LOG("base cluster = 0x%07x", cluster);\r
        \r
        // Do Cluster Skip\r
        // - Pre FAT32 had a reserved area for the root.\r
@@ -353,16 +334,18 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
                        if(Cluster)     *Cluster = cluster;\r
                        cluster = FAT_int_GetFatValue(disk, cluster);\r
                        // Check for end of cluster chain\r
-                       if(cluster == 0xFFFFFFFF) {     LEAVE('i', 1);  return 1;}\r
+                       if(cluster == GETFATVALUE_EOC) { LEAVE('i', 1); return 1; }\r
                }\r
                if(Cluster)     *Cluster = cluster;\r
        }\r
        else {\r
+               // TODO: Bounds checking on root\r
+//             LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster);\r
                // Increment by clusters in offset\r
                cluster += Offset / disk->BytesPerCluster;\r
        }\r
        \r
-       LOG("cluster = %08x", cluster);\r
+//     LOG("cluster = 0x%07x", cluster);\r
        \r
        // Bounds Checking (Used to spot corruption)\r
        if(cluster > disk->ClusterCount + 2)\r
@@ -375,7 +358,7 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
        \r
        // Compute Offsets\r
        // - Pre FAT32 cluster base (in sectors)\r
-       if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+       if( base_cluster == disk->rootOffset && disk->type != FAT32 ) {\r
                addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
                addr += cluster * disk->BytesPerCluster;\r
        }\r
@@ -392,225 +375,6 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu
        return 0;\r
 }\r
 \r
-/*\r
- * ====================\r
- *   FAT Manipulation\r
- * ====================\r
- */\r
-/**\r
- * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
- * \brief Fetches a value from the FAT\r
- */\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
-{\r
-       Uint32  val = 0;\r
-       Uint32  ofs;\r
-       ENTER("pDisk xCluster", Disk, cluster);\r
-       Mutex_Acquire( &Disk->lFAT );\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               val = Disk->FATCache[cluster];\r
-               if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;\r
-               if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;\r
-               if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ofs = Disk->bootsect.resvSectCount*512;\r
-               if(Disk->type == FAT12) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);\r
-                       val = (cluster & 1 ? val>>12 : val & 0xFFF);\r
-                       if(val == EOC_FAT12)    val = -1;\r
-               } else if(Disk->type == FAT16) {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
-                       if(val == EOC_FAT16)    val = -1;\r
-               } else {\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
-                       if(val == EOC_FAT32)    val = -1;\r
-               }\r
-       #if CACHE_FAT\r
-       }\r
-       #endif /*CACHE_FAT*/\r
-       Mutex_Release( &Disk->lFAT );\r
-       LEAVE('x', val);\r
-       return val;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Allocate a new cluster\r
- */\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
-{\r
-       Uint32  ret = Previous;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               Uint32  eoc;\r
-               \r
-               LOCK(Disk->lFAT);\r
-               for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               for(ret = 0; ret < Previous; ret++)\r
-               {\r
-                       if(Disk->FATCache[ret] == 0)\r
-                               goto append;\r
-               }\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return 0;\r
-       \r
-       append:\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:     eoc = EOC_FAT12;        break;\r
-               case FAT16:     eoc = EOC_FAT16;        break;\r
-               case FAT32:     eoc = EOC_FAT32;        break;\r
-               default:        return 0;\r
-               }\r
-               \r
-               Disk->FATCache[ret] = eoc;\r
-               Disk->FATCache[Previous] = ret;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-               return ret;\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
-               return 0;\r
-               \r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       if( Previous & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= ret;\r
-                       }\r
-                       else {\r
-                               val &= 0xFFF;\r
-                               val |= ret<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       \r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               val &= 0xFFF000;\r
-                               val |= eoc;\r
-                       }\r
-                       else {\r
-                               val &= 0x000FFF;\r
-                               val |= eoc<<12;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
-                       break;\r
-               }\r
-               return ret;\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-}\r
-\r
-/**\r
- * \brief Free's a cluster\r
- * \return The original contents of the cluster\r
- */\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
-{\r
-       Uint32  ret;\r
-       #if CACHE_FAT\r
-       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
-       {\r
-               LOCK(Disk->lFAT);\r
-               \r
-               ret = Disk->FATCache[Cluster];\r
-               Disk->FATCache[Cluster] = 0;\r
-               \r
-               RELEASE(Disk->lFAT);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               Uint32  val;\r
-               Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
-               LOCK(Disk->lFAT);\r
-               switch(Disk->type)\r
-               {\r
-               case FAT12:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
-                       if( Cluster & 1 ) {\r
-                               ret = val & 0xFFF0000;\r
-                               val &= 0xFFF;\r
-                       }\r
-                       else {\r
-                               ret = val & 0xFFF;\r
-                               val &= 0xFFF000;\r
-                       }\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
-                       break;\r
-               case FAT16:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               case FAT32:\r
-                       VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-                       val = 0;\r
-                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
-                       break;\r
-               }\r
-               RELEASE(Disk->lFAT);\r
-       #if CACHE_FAT\r
-       }\r
-       #endif\r
-       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;\r
-       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;\r
-       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;\r
-       return ret;\r
-}\r
-#endif\r
-\r
-/*\r
- * ====================\r
- *      Cluster IO\r
- * ====================\r
- */\r
-/**\r
- * \brief Read a cluster\r
- * \param Disk Disk (Volume) to read from\r
- * \param Length       Length to read\r
- * \param Buffer       Destination for read data\r
- */\r
-void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Length,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
 /* ====================\r
  *       File IO\r
  * ====================\r
@@ -653,7 +417,7 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        for(i = preSkip; i--; )\r
        {\r
                cluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(cluster == -1) {\r
+               if(cluster == GETFATVALUE_EOC) {\r
                        Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
                        LEAVE('i', 0);\r
                        return 0;\r
@@ -679,7 +443,7 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                LOG("pos = %i, Reading the rest of the clusters");\r
                // Get next cluster in the chain\r
                cluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(cluster == -1) {\r
+               if(cluster == GETFATVALUE_EOC) {\r
                        Log_Warning("FAT", "Read past End of Cluster Chain (Align)");\r
                        LEAVE('X', pos);\r
                        return pos;\r
@@ -697,7 +461,7 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        // Read the rest of the cluster data\r
        for( ; count; count -- )\r
        {\r
-               if(cluster == -1) {\r
+               if(cluster == GETFATVALUE_EOC) {\r
                        Log_Warning("FAT", "Read past End of Cluster Chain (Bulk)");\r
                        LEAVE('X', pos);\r
                        return pos;\r
@@ -730,22 +494,6 @@ size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
 }\r
 \r
 #if SUPPORT_WRITE\r
-/**\r
- * \brief Write a cluster to disk\r
- */\r
-void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
-{\r
-       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
-       VFS_ReadAt(\r
-               Disk->fileHandle,\r
-               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
-                       * Disk->bootsect.bps,\r
-               Disk->BytesPerCluster,\r
-               Buffer\r
-               );\r
-       LEAVE('-');\r
-}\r
-\r
 /**\r
  * \brief Write to a file\r
  * \param Node File Node\r
@@ -753,23 +501,27 @@ void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)
  * \param Length       Size of data to write\r
  * \param Buffer       Data source\r
  */\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)\r
 {\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        char    tmpBuf[disk->BytesPerCluster];\r
         int    remLength = Length;\r
        Uint32  cluster, tmpCluster;\r
         int    bNewCluster = 0;\r
+       off_t   original_offset = Offset;\r
        \r
        if(Offset > Node->Size) return 0;\r
        \r
+       ENTER("pNode Xoffset xlength pbuffer", Node, Offset, Length, Buffer);\r
+       \r
        // Seek Clusters\r
        cluster = Node->Inode & 0xFFFFFFFF;\r
        while( Offset > disk->BytesPerCluster )\r
        {\r
                cluster = FAT_int_GetFatValue( disk, cluster );\r
-               if(cluster == -1) {\r
+               if(cluster == GETFATVALUE_EOC) {\r
                        Log_Warning("FAT", "EOC Unexpectedly Reached");\r
+                       LEAVE('i', 0);\r
                        return 0;\r
                }\r
                Offset -= disk->BytesPerCluster;\r
@@ -777,7 +529,10 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        if( Offset == disk->BytesPerCluster )\r
        {\r
                Uint32  tmp = FAT_int_AllocateCluster(disk, cluster);\r
-               if(!tmp)        return 0;\r
+               if(!tmp) {\r
+                       LEAVE('i', 0);\r
+                       return 0;\r
+               }\r
                cluster = tmp;\r
                Offset -= disk->BytesPerCluster;\r
        }\r
@@ -786,17 +541,20 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        {\r
                char    tmpBuf[disk->BytesPerCluster];\r
                \r
+               LOG("Read-Modify-Write single");\r
+               \r
                // Read-Modify-Write\r
                FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
                memcpy( tmpBuf + Offset, Buffer, Length );\r
                FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-               \r
-               return Length;\r
+               goto return_full;\r
        }\r
        \r
        // Clean up changes within a cluster\r
        if( Offset )\r
        {       \r
+               LOG("Read-Modify-Write first");\r
+\r
                // Read-Modify-Write\r
                FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
                memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
@@ -807,11 +565,10 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
                \r
                // Get next cluster (allocating if needed)\r
                tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(tmpCluster == -1) {\r
+               if(tmpCluster == GETFATVALUE_EOC) {\r
                        tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
+                       if( tmpCluster == 0 )\r
+                               goto ret_incomplete;\r
                }\r
                cluster = tmpCluster;\r
        }\r
@@ -820,674 +577,48 @@ size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
        {\r
                FAT_int_WriteCluster( disk, cluster, Buffer );\r
                Buffer += disk->BytesPerCluster;\r
+               remLength -= disk->BytesPerCluster;\r
                \r
                // Get next cluster (allocating if needed)\r
                tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
-               if(tmpCluster == -1) {\r
+               if(tmpCluster == GETFATVALUE_EOC) {\r
                        bNewCluster = 1;\r
                        tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
-                       if( tmpCluster == 0 ) {\r
-                               return Length - remLength;\r
-                       }\r
+                       if( tmpCluster == 0 )\r
+                               goto ret_incomplete;\r
                }\r
                cluster = tmpCluster;\r
        }\r
        \r
        // Finish off\r
-       tmpBuf = malloc( disk->BytesPerCluster );\r
-       if( bNewCluster )\r
-               memset(tmpBuf, 0, disk->BytesPerCluster);\r
-       else\r
-               FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
-       memcpy( tmpBuf, Buffer, remLength );\r
-       FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
-       free( tmpBuf );\r
-       \r
-       return Length;\r
-}\r
-#endif\r
-\r
-/* ====================\r
- *  File Names & Nodes\r
- * ====================\r
- */\r
-/**\r
- * \brief Converts a FAT directory entry name into a proper filename\r
- * \param dest Destination array (must be at least 13 bytes in size)\r
- * \param src  8.3 filename (concatenated, e.g 'FILE1   TXT')\r
- */\r
-void FAT_int_ProperFilename(char *dest, const char *src)\r
-{\r
-        int    inpos, outpos;\r
-       \r
-       // Name\r
-       outpos = 0;\r
-       for( inpos = 0; inpos < 8; inpos++ ) {\r
-               if(src[inpos] == ' ')   break;\r
-               dest[outpos++] = src[inpos];\r
-       }\r
-       inpos = 8;\r
-       // Check for empty extensions\r
-       if(src[8] != ' ')\r
-       {\r
-               dest[outpos++] = '.';\r
-               for( ; inpos < 11; inpos++)     {\r
-                       if(src[inpos] == ' ')   break;\r
-                       dest[outpos++] = src[inpos];\r
-               }\r
-       }\r
-       dest[outpos++] = '\0';\r
-       \r
-       //LOG("dest='%s'", dest);\r
-}\r
-\r
-/**\r
- * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
- * \brief Converts either a LFN or a 8.3 Name into a proper name\r
- * \param ft   Pointer to the file's entry in the parent directory\r
- * \param LongFileName Long file name pointer\r
- * \return Filename as a heap string\r
- */\r
-char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
-{\r
-       char    *ret;\r
-       ENTER("pft sLongFileName", ft, LongFileName);\r
-       //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);\r
-       #if USE_LFN\r
-       if(LongFileName && LongFileName[0] != '\0')\r
-       {       \r
-               ret = strdup(LongFileName);\r
-       }\r
-       else\r
-       {\r
-       #endif\r
-               ret = (char*) malloc(13);\r
-               if( !ret ) {\r
-                       Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");\r
-                       return NULL;\r
-               }\r
-               FAT_int_ProperFilename(ret, ft->name);\r
-       #if USE_LFN\r
-       }\r
-       #endif\r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \brief Creates a tVFS_Node structure for a given file entry\r
- * \param Parent       Parent directory VFS node\r
- * \param Entry        File table entry for the new node\r
- * \param Pos  Position in the parent of the new node\r
- */\r
-tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
-{\r
-       tVFS_Node       node;\r
-       tVFS_Node       *ret;\r
-       tFAT_VolInfo    *disk = Parent->ImplPtr;\r
-       \r
-       ENTER("pParent pFT", Parent, Entry);\r
-       LOG("disk = %p", disk);\r
-       \r
-       memset(&node, 0, sizeof(tVFS_Node));\r
-       \r
-       // Set Other Data\r
-       // 0-27: Cluster, 32-59: Parent Cluster\r
-       node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
-       LOG("node.Inode = %llx", node.Inode);\r
-       // Position in parent directory\r
-       node.ImplInt = Pos & 0xFFFF;\r
-       // Disk Pointer\r
-       node.ImplPtr = disk;\r
-       node.Size = Entry->size;\r
-       LOG("Entry->size = %i", Entry->size);\r
-       // root:root\r
-       node.UID = 0;   node.GID = 0;\r
-       node.NumACLs = 1;\r
-       \r
-       node.Flags = 0;\r
-       if(Entry->attrib & ATTR_DIRECTORY)      node.Flags |= VFS_FFLAG_DIRECTORY;\r
-       if(Entry->attrib & ATTR_READONLY) {\r
-               node.Flags |= VFS_FFLAG_READONLY;\r
-               node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X\r
-       }\r
-       else {\r
-               node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
-       }\r
-       \r
-       // Create timestamps\r
-       node.ATime = timestamp(0,0,0,\r
-                       ((Entry->adate&0x1F) - 1),      // Days\r
-                       ((Entry->adate&0x1E0) - 1),     // Months\r
-                       1980+((Entry->adate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       node.CTime = Entry->ctimems * 10;       // Miliseconds\r
-       node.CTime += timestamp(\r
-                       ((Entry->ctime&0x1F)<<1),       // Seconds\r
-                       ((Entry->ctime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->ctime&0xF800)>>11),    // Hours\r
-                       ((Entry->cdate&0x1F)-1),                // Days\r
-                       ((Entry->cdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->cdate&0xFF00)>>8) // Years\r
-                       );\r
-                       \r
-       node.MTime = timestamp(\r
-                       ((Entry->mtime&0x1F)<<1),       // Seconds\r
-                       ((Entry->mtime&0x3F0)>>5),      // Minutes\r
-                       ((Entry->mtime&0xF800)>>11),    // Hours\r
-                       ((Entry->mdate&0x1F)-1),                // Days\r
-                       ((Entry->mdate&0x1E0)-1),               // Months\r
-                       1980+((Entry->mdate&0xFF00)>>8) // Years\r
-                       );\r
-       \r
-       // Set pointers\r
-       if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
-               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
-               node.Type = &gFAT_DirType;      \r
-               node.Size = -1;\r
-       }\r
-       else {\r
-               node.Type = &gFAT_FileType;\r
-       }\r
-       \r
-       ret = Inode_CacheNode(disk->inodeHandle, &node);\r
-       LEAVE('p', ret);\r
-       return ret;\r
-}\r
-\r
-/* \r
- * ====================\r
- *     Directory IO\r
- * ====================\r
- */\r
-\r
-/**\r
- * \brief Reads a sector from the disk\r
- * \param Node Directory node to read\r
- * \param Sector       Sector number in the directory to read\r
- * \param Buffer       Destination buffer for the read data\r
- */\r
-int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
-{\r
-       Uint64  addr;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
-       \r
-       // Parse address\r
-       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LOG("addr = 0x%llx", addr);\r
-       // Read Sector\r
-       if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
-       {\r
-               LEAVE('i', 1);\r
-               return 1;\r
-       }\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Writes an entry to the disk\r
- * \todo Support expanding a directory\r
- * \param Node Directory node\r
- * \param ID   ID of entry to update\r
- * \param Entry        Entry data\r
- * \return Zero on success, non-zero on error\r
- */\r
-int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
-{\r
-       Uint64  addr = 0;\r
-        int    tmp;\r
-       Uint32  cluster = 0;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       \r
-       ENTER("pNode iID pEntry", Node, ID, Entry);\r
-       \r
-       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       if( tmp )\r
-       {\r
-               //TODO: Allocate a cluster\r
-               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
-               if(cluster == -1) {\r
-                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
-                       LEAVE('i', 1);\r
-                       return 1;\r
-               }\r
-               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
-       }\r
-       \r
-\r
-       LOG("addr = 0x%llx", addr);\r
-       \r
-       // Read Sector\r
-       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);      // Read Dir Data\r
-       \r
-       LEAVE('i', 0);\r
-       return 0;\r
-}\r
-#endif\r
-\r
-#if USE_LFN    \r
-/**\r
- * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- * \brief Return pointer to LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   ID of the short name\r
- * \return Pointer to the LFN cache entry\r
- */\r
-char *FAT_int_GetLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache;\r
-        int    i, firstFree;\r
-       \r
-       Mutex_Acquire( &Node->Lock );\r
-       \r
-       // TODO: Thread Safety (Lock things)\r
-       cache = Node->Data;\r
-       \r
-       // Create a cache if it isn't there\r
-       if(!cache) {\r
-               cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );\r
-               cache->NumEntries = 1;\r
-               cache->Entries[0].ID = ID;\r
-               cache->Entries[0].Data[0] = '\0';\r
-               Mutex_Release( &Node->Lock );\r
-               //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);\r
-               return cache->Entries[0].Data;\r
-       }\r
-       \r
-       // Scan for this entry\r
-       firstFree = -1;\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID ) {\r
-                       Mutex_Release( &Node->Lock );\r
-                       //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);\r
-                       return cache->Entries[i].Data;\r
-               }\r
-               if( cache->Entries[i].ID == -1 && firstFree == -1 )\r
-                       firstFree = i;\r
-       }\r
-       \r
-       if(firstFree == -1) {\r
-               // Use `i` for temp length\r
-               i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);\r
-               Node->Data = realloc( Node->Data, i );\r
-               if( !Node->Data ) {\r
-                       Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);\r
-                       Mutex_Release( &Node->Lock );\r
-                       return NULL;\r
-               }\r
-               //Log_Debug("FAT", "Realloc (%i)\n", i);\r
-               cache = Node->Data;\r
-               i = cache->NumEntries;\r
-               cache->NumEntries ++;\r
-       }\r
-       else {\r
-               i = firstFree;\r
-       }\r
-       \r
-       // Create new entry\r
-       cache->Entries[ i ].ID = ID;\r
-       cache->Entries[ i ].Data[0] = '\0';\r
-       \r
-       Mutex_Release( &Node->Lock );\r
-       //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);\r
-       return cache->Entries[ i ].Data;\r
-}\r
-\r
-/**\r
- * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- * \brief Delete a LFN cache entry\r
- * \param Node Directory node\r
- * \param ID   File Entry ID\r
- */\r
-void FAT_int_DelLFN(tVFS_Node *Node, int ID)\r
-{\r
-       tFAT_LFNCache   *cache = Node->Data;\r
-        int    i;\r
-       \r
-       // Fast return\r
-       if(!cache)      return;\r
-       \r
-       // Scan for a current entry\r
-       for( i = 0; i < cache->NumEntries; i++ )\r
-       {\r
-               if( cache->Entries[i].ID == ID )\r
-                       cache->Entries[i].ID = -1;\r
-       }\r
-       return ;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
- * \param Node Node structure of directory\r
- * \param ID   Directory position\r
- * \return Filename as a heap string, NULL or VFS_SKIP\r
- */\r
-char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
-{\r
-       fat_filetable   fileinfo[16];   // sizeof(fat_filetable)=32, so 16 per sector\r
-        int    a = 0;\r
-       char    *ret;\r
-       #if USE_LFN\r
-       char    *lfn = NULL;\r
-       #endif\r
-       \r
-       ENTER("pNode iID", Node, ID);\r
-       \r
-       if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
-       {\r
-               LOG("End of chain, end of dir");\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Offset in sector\r
-       a = ID % 16;\r
-\r
-       LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);\r
-       \r
-       // Check if this is the last entry\r
-       if( fileinfo[a].name[0] == '\0' ) {\r
-               Node->Size = ID;\r
-               LOG("End of list");\r
-               LEAVE('n');\r
-               return NULL;    // break\r
-       }\r
-       \r
-       // Check for empty entry\r
-       if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
-               LOG("Empty Entry");\r
-               #if 0   // Stop on empty entry?\r
-               LEAVE('n');\r
-               return NULL;    // Stop\r
-               #else\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;        // Skip\r
-               #endif\r
-       }\r
-       \r
-       #if USE_LFN\r
-       // Get Long File Name Cache\r
-       if(fileinfo[a].attrib == ATTR_LFN)\r
+       if( remLength )\r
        {\r
-               fat_longfilename        *lfnInfo;\r
-               \r
-               lfnInfo = (fat_longfilename *) &fileinfo[a];\r
-               \r
-               // Get cache for corresponding file\r
-               // > ID + Index gets the corresponding short node\r
-               lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );\r
-               \r
-               // Bit 6 indicates the start of an entry\r
-               if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
-               \r
-               a = ((lfnInfo->id & 0x3F) - 1) * 13;\r
-               //Log_Debug("FAT", "ID = 0x%02x, a = %i", lfnInfo->id, a);\r
-               \r
-               // Sanity Check (FAT implementations should not allow >255 character names)\r
-               if(a > 255)     return VFS_SKIP;\r
-               \r
-               // Append new bytes\r
-               lfn[a+ 0] = lfnInfo->name1[0];  lfn[a+ 1] = lfnInfo->name1[1];\r
-               lfn[a+ 2] = lfnInfo->name1[2];  lfn[a+ 3] = lfnInfo->name1[3];\r
-               lfn[a+ 4] = lfnInfo->name1[4];  \r
-               lfn[a+ 5] = lfnInfo->name2[0];  lfn[a+ 6] = lfnInfo->name2[1];\r
-               lfn[a+ 7] = lfnInfo->name2[2];  lfn[a+ 8] = lfnInfo->name2[3];\r
-               lfn[a+ 9] = lfnInfo->name2[4];  lfn[a+10] = lfnInfo->name2[5];\r
-               lfn[a+11] = lfnInfo->name3[0];  lfn[a+12] = lfnInfo->name3[1];\r
-               LOG("lfn = '%s'", lfn);\r
-               //Log_Debug("FAT", "lfn = '%s'", lfn);\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       #endif\r
-       \r
-       // Check if it is a volume entry\r
-       if(fileinfo[a].attrib & 0x08) {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // Ignore .\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       // and ..\r
-       if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {\r
-               LEAVE('p', VFS_SKIP);\r
-               return VFS_SKIP;\r
-       }\r
-       \r
-       LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
-               fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
-               fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
-               fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
-       \r
-       #if USE_LFN\r
-       lfn = FAT_int_GetLFN(Node, ID);\r
-       //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);\r
-       ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
-       #else\r
-       ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
-       #endif\r
-       \r
-       LEAVE('s', ret);\r
-       return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
- * \brief Finds an entry in the current directory\r
- */\r
-tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)\r
-{\r
-       fat_filetable   fileinfo[16];\r
-       char    tmpName[13];\r
-       #if USE_LFN\r
-       fat_longfilename        *lfnInfo;\r
-       char    lfn[256];\r
-        int    lfnPos=255, lfnId = -1;\r
-       #endif\r
-        int    i;\r
-       tVFS_Node       *tmpNode;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       Uint32  cluster;\r
-       \r
-       ENTER("pNode sname", Node, Name);       \r
-\r
-       // Fast Returns\r
-       if(!Name || Name[0] == '\0') {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       for( i = 0; ; i++ )\r
-       {\r
-               if((i & 0xF) == 0) {\r
-                       if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
-                       {\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-               }\r
-               \r
-               //Check if the files are free\r
-               if(fileinfo[i&0xF].name[0] == '\0')     break;  // End of List marker\r
-               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       // Free entry\r
-               \r
-               \r
-               #if USE_LFN\r
-               // Long File Name Entry\r
-               if(fileinfo[i & 0xF].attrib == ATTR_LFN)\r
-               {\r
-                       lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
-                       if(lfnInfo->id & 0x40) {\r
-                               memset(lfn, 0, 256);\r
-                               lfnPos = (lfnInfo->id & 0x3F) * 13 - 1;\r
-                       }\r
-                       // Sanity check the position so we don't overflow\r
-                       if( lfnPos < 12 )\r
-                               continue ;\r
-                       lfn[lfnPos--] = lfnInfo->name3[1];      lfn[lfnPos--] = lfnInfo->name3[0];\r
-                       lfn[lfnPos--] = lfnInfo->name2[5];      lfn[lfnPos--] = lfnInfo->name2[4];\r
-                       lfn[lfnPos--] = lfnInfo->name2[3];      lfn[lfnPos--] = lfnInfo->name2[2];\r
-                       lfn[lfnPos--] = lfnInfo->name2[1];      lfn[lfnPos--] = lfnInfo->name2[0];\r
-                       lfn[lfnPos--] = lfnInfo->name1[4];      lfn[lfnPos--] = lfnInfo->name1[3];\r
-                       lfn[lfnPos--] = lfnInfo->name1[2];      lfn[lfnPos--] = lfnInfo->name1[1];\r
-                       lfn[lfnPos--] = lfnInfo->name1[0];\r
-                       if((lfnInfo->id&0x3F) == 1)\r
-                       {\r
-                               lfnId = i+1;\r
-                       }\r
-               }\r
+               if( bNewCluster )\r
+                       memset(tmpBuf, 0, disk->BytesPerCluster);\r
                else\r
-               {\r
-                       // Remove LFN if it does not apply\r
-                       if(lfnId != i)  lfn[0] = '\0';\r
-               #else\r
-               if(fileinfo[i&0xF].attrib == ATTR_LFN)  continue;\r
-               #endif\r
-                       // Get Real Filename\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               \r
-                       // Only the long name is case sensitive, 8.3 is not\r
-                       #if USE_LFN\r
-                       if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
-                       #else\r
-                       if(strucmp(tmpName, Name) == 0)\r
-                       #endif\r
-                       {\r
-                               cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
-                               tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
-                               if(tmpNode == NULL)     // Node is not cached\r
-                               {\r
-                                       tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
-                               }\r
-                               LEAVE('p', tmpNode);\r
-                               return tmpNode;\r
-                       }\r
-               #if USE_LFN\r
-               }\r
-               #endif\r
+                       FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+               memcpy( tmpBuf, Buffer, remLength );\r
+               FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
        }\r
-       \r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
 \r
-tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)\r
-{\r
-       tFAT_VolInfo    *disk = Root->ImplPtr;\r
-        int    ents_per_sector = 512 / sizeof(fat_filetable); \r
-       fat_filetable   fileinfo[ents_per_sector];\r
-        int    sector = 0, i;\r
-       tVFS_Node       stub_node;\r
-\r
-       ENTER("pRoot XInode", Root, Inode);\r
-\r
-       stub_node.ImplPtr = disk;\r
-       stub_node.Size = -1;\r
-       stub_node.Inode = Inode >> 32;\r
-\r
-       for( i = 0; ; i ++ )\r
-       {\r
-               if( i == 0 || i == ents_per_sector )\r
-               {\r
-                       if(FAT_int_ReadDirSector(&stub_node, sector, fileinfo))\r
-                       {\r
-                               LOG("ReadDirSector failed");\r
-                               LEAVE('n');\r
-                               return NULL;\r
-                       }\r
-                       i = 0;\r
-                       sector ++;\r
-               }\r
-       \r
-               // Check for free/end of list\r
-               if(fileinfo[i].name[0] == '\0') break;  // End of List marker\r
-               if(fileinfo[i].name[0] == '\xE5')       continue;       // Free entry\r
-               \r
-               if(fileinfo[i].attrib == ATTR_LFN)      continue;\r
-\r
-               LOG("fileinfo[i].cluster = %x %04x", fileinfo[i].clusterHi, fileinfo[i].cluster);\r
-               #if DEBUG\r
-               {\r
-                       char    tmpName[13];\r
-                       FAT_int_ProperFilename(tmpName, fileinfo[i].name);\r
-                       LOG("tmpName = '%s'", tmpName);\r
-               }\r
-               #endif\r
-               \r
-       \r
-               if(fileinfo[i].cluster != (Inode & 0xFFFF))     continue;\r
-               if(fileinfo[i].clusterHi != ((Inode >> 16) & 0xFFFF))   continue;\r
-\r
-               LEAVE_RET('p', FAT_int_CreateNode(&stub_node, &fileinfo[i], sector*ents_per_sector+i));\r
+return_full:\r
+       if( original_offset + Length > Node->Size ) {\r
+               Node->Size = original_offset + Length;\r
+               LOG("Updated size to %x", Node->Size);\r
+               Node->ImplInt |= FAT_FLAG_DIRTY;\r
        }\r
-       LOG("sector = %i, i = %i", sector, i);\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
- * \brief Create a new node\r
- */\r
-int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
-{\r
-       return 0;\r
-}\r
 \r
-/**\r
- * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
- * \brief Rename / Delete a file\r
- */\r
-int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
-{\r
-       tVFS_Node       *child;\r
-       fat_filetable   ft = {0};\r
-        int    ret;\r
-       \r
-       child = FAT_FindDir(Node, OldName);\r
-       if(!child)      return ENOTFOUND;\r
-       \r
-       // Delete?\r
-       if( NewName == NULL )\r
-       {\r
-               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
-               \r
-               // Delete from the directory\r
-               ft.name[0] = '\xE9';\r
-               FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
-               \r
-               // Return success\r
-               ret = EOK;\r
-       }\r
-       // Rename\r
-       else\r
-       {\r
-               Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
-                       Node, OldName, NewName);\r
-               ret = ENOTIMPL;\r
-       }\r
-       \r
-       // Close child\r
-       child->Close( child );\r
-       return ret;\r
+       LEAVE('i', Length);\r
+       return Length;\r
+ret_incomplete:\r
+       LOG("Write incomplete");\r
+       Length -= remLength;\r
+       if( original_offset + Length > Node->Size ) {\r
+               Node->Size = original_offset + Length;  \r
+               Node->ImplInt |= FAT_FLAG_DIRTY;\r
+       }\r
+       LEAVE('i', Length);\r
+       return Length;\r
 }\r
 #endif\r
 \r
@@ -1499,39 +630,50 @@ void FAT_CloseFile(tVFS_Node *Node)
 {\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        if(Node == NULL)        return ;\r
-       \r
+\r
+       ENTER("pNode", Node);   \r
+\r
        #if SUPPORT_WRITE\r
        // Update the node if it's dirty (don't bother if it's marked for\r
        // deletion)\r
        if( (Node->ImplInt & FAT_FLAG_DIRTY) && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
        {\r
-               tFAT_VolInfo    buf[16];\r
-               tFAT_VolInfo    *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
-               \r
-               FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
-               ft->size = Node->Size;\r
+               fat_filetable   ft;\r
+               tVFS_Node       *dirnode;\r
+\r
+               dirnode = FAT_int_CreateIncompleteDirNode(disk, Node->Inode >> 32);\r
+               if( !dirnode ) {\r
+                       Log_Error("FAT", "Can't get node for directory cluster #0x%x", Node->Inode>>32);\r
+                       LEAVE('-');\r
+                       return ;\r
+               }\r
+\r
+               int id = FAT_int_GetEntryByCluster(dirnode, Node->Inode & 0xFFFFFFFF, &ft);\r
+               ft.size = Node->Size;\r
                // TODO: update adate, mtime, mdate\r
-               FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+               FAT_int_WriteDirEntry(dirnode, id, &ft);\r
+               \r
+               dirnode->Type->Close(dirnode);\r
                \r
                Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
        }\r
        #endif\r
+\r
+       Uint32  cluster = Node->Inode;\r
+       Uint32  implint = Node->ImplInt;\r
        \r
-       // TODO: Make this more thread safe somehow, probably by moving the\r
-       // Inode_UncacheNode higher up and saving the cluster value somewhere\r
-       if( Node->ReferenceCount == 1 )\r
-       {               \r
-               #if SUPPORT_WRITE\r
+       #if SUPPORT_WRITE\r
+       if( FAT_int_DerefNode(Node) == 1 )\r
+       {\r
+               LOG("implint = %x", implint);\r
                // Delete File\r
-               if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+               if( implint & FAT_FLAG_DELETE ) {\r
+                       Log_Debug("FAT", "Deallocating chain stating at 0x%07x", cluster);\r
                        // Since the node is marked, we only need to remove it's data\r
-                       Uint32  cluster = Node->Inode & 0xFFFFFFFF;\r
                        while( cluster != -1 )\r
-                               cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+                               cluster = FAT_int_FreeCluster(disk, cluster);\r
                }\r
-               #endif\r
        }\r
-       \r
-       Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
-       return ;\r
+       #endif\r
+       LEAVE('-');\r
 }\r
diff --git a/KernelLand/Modules/Filesystems/FAT/fatio.c b/KernelLand/Modules/Filesystems/FAT/fatio.c
new file mode 100644 (file)
index 0000000..7bf62ef
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * fatio.c
+ * - FAT Manipulation and Cluster IO
+ */
+#define DEBUG  0
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === CODE ===
+/**
+ * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+ * \brief Fetches a value from the FAT
+ */
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+{
+       Uint32  val = 0;
+       Uint32  ofs;
+       ENTER("pDisk xCluster", Disk, cluster);
+       
+       Mutex_Acquire( &Disk->lFAT );
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+               val = Disk->FATCache[cluster];
+               if(Disk->type == FAT12 && val == EOC_FAT12)     val = GETFATVALUE_EOC;
+               if(Disk->type == FAT16 && val == EOC_FAT16)     val = GETFATVALUE_EOC;
+               if(Disk->type == FAT32 && val == EOC_FAT32)     val = GETFATVALUE_EOC;
+       }
+       else
+       {
+       #endif
+               ofs = Disk->bootsect.resvSectCount*512;
+               if(Disk->type == FAT12) {
+                       VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);
+                       LOG("3 bytes at 0x%x are (Uint32)0x%x", ofs+(cluster/2)*3, val);
+                       val = (cluster & 1) ? (val>>12) : (val & 0xFFF);
+                       if(val == EOC_FAT12)    val = GETFATVALUE_EOC;
+               } else if(Disk->type == FAT16) {
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);
+                       if(val == EOC_FAT16)    val = GETFATVALUE_EOC;
+               } else {
+                       VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);
+                       if(val == EOC_FAT32)    val = GETFATVALUE_EOC;
+               }
+       #if CACHE_FAT
+       }
+       #endif /*CACHE_FAT*/
+       Mutex_Release( &Disk->lFAT );
+       LEAVE('x', val);
+       return val;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Allocate a new cluster
+ */
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)
+{
+       Uint32  ret = -1;
+       
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+                int    bFoundCluster = 0;
+               Uint32  eoc;
+
+               switch(Disk->type)
+               {
+               case FAT12:     eoc = EOC_FAT12;        break;
+               case FAT16:     eoc = EOC_FAT16;        break;
+               case FAT32:     eoc = EOC_FAT32;        break;
+                       default:        return 0;
+               }
+               
+               Mutex_Acquire(&Disk->lFAT);
+               if( Previous != -1 )
+               {
+                       for(ret = Previous; ret < Disk->ClusterCount; ret++)
+                       {
+                               if(Disk->FATCache[ret] != 0) {
+                                       bFoundCluster = 1;
+                                       break;
+                               }
+                       }
+               }
+               if( !bFoundCluster )
+               {
+                       for(ret = 0; ret < Previous; ret++)
+                       {
+                               if(Disk->FATCache[ret] == 0) {
+                                       bFoundCluster = 1;
+                                       break;
+                               }
+                       }
+               }
+               
+               if(bFoundCluster)
+               { 
+                       Disk->FATCache[ret] = eoc;
+                       if( Previous != -1 )
+                               Disk->FATCache[Previous] = ret;
+               }
+               else
+               {
+                       ret = 0;
+               }
+                       
+               Mutex_Release(&Disk->lFAT);
+               LOG("Allocated cluster %x", ret);
+               return ret;
+       }
+       else
+       {
+       #endif
+               Uint32  val = 0;
+               Uint32  base = Disk->bootsect.resvSectCount*512;
+                int    block = 0, block_ofs = 0;
+                int    first_block;
+               const int       block_size = 512*3;
+               const int       ents_per_block_12 = block_size * 2 / 3; // 1.5 bytes per entry
+//             const int       ents_per_block_16 = block_size / 2;     // 2 bytes per entry
+//             const int       ents_per_block_32 = block_size / 4;     // 4 bytes per entry
+                int    block_count_12 = DivUp(Disk->ClusterCount, ents_per_block_12);
+               Uint8   sector_data[block_size+1];
+               sector_data[block_size] = 0;
+               
+               Mutex_Acquire(&Disk->lFAT);
+               switch(Disk->type)
+               {
+               case FAT12:
+                       if( Previous != -1 )
+                               block = Previous / ents_per_block_12;
+                       else
+                               block = 0;
+                       first_block = block;
+                       
+                       // Search within the same block as the previous cluster first
+                       do {
+                               VFS_ReadAt(Disk->fileHandle, base + block*block_size, block_size, sector_data);
+                               for( block_ofs = 0; block_ofs < ents_per_block_12; block_ofs ++ )
+                               {
+                                       Uint32  *valptr = (void*)( sector_data + block_ofs / 2 * 3 );
+                                        int    bitofs = 12 * (block_ofs % 2);
+//                                     LOG("%i:%i - FAT Ent 0x%03x", block, block_ofs, (*valptr>>bitofs) & 0xFFF);
+                                       if( ((*valptr >> bitofs) & 0xFFF) == 0 ) {
+                                               // Found a free cluster
+                                               *valptr |= EOC_FAT12 << bitofs;
+                                               ret = block * ents_per_block_12 + block_ofs;
+                                               break;
+                                       }
+                               }
+                               // Check for early break from the above loop
+                               if( block_ofs != ents_per_block_12 )
+                                       break;
+
+                               // Next block please
+                               block ++;
+                               if( block == block_count_12 )
+                                       block = 0;
+                       } while( block != first_block );
+                       
+                       if( ret != 0 )  // TODO: Could cluster 0 be valid?
+                       {
+                               // Write back changes to this part of the FAT
+                               VFS_WriteAt(Disk->fileHandle, base + block, block_size, sector_data);
+       
+                               // Note the new cluster in the chain
+                               if( Previous != -1 )
+                               {
+                                       LOG("Updating cluster %x to point to %x (offset %x)", Previous, ret,
+                                               base + (Previous>>1)*3);
+                                       VFS_ReadAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val); 
+                                       if( Previous & 1 ) {
+                                               val &= 0x000FFF;
+                                               val |= ret << 12;
+                                       }
+                                       else {
+                                               val &= 0xFFF000;
+                                               val |= ret << 0;
+                                       }
+                                       VFS_WriteAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
+                               }
+                       }
+                       break;
+               case FAT16:
+                       Log_Warning("FAT", "TODO: Implement cluster allocation with FAT16");
+//                     VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);
+//                     VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);
+                       break;
+               case FAT32:
+                       Log_Warning("FAT", "TODO: Implement cluster allocation with FAT32");
+//                     VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);
+//                     VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);
+                       break;
+               }
+               Mutex_Release(&Disk->lFAT);
+               LOG("Allocated cluster %x", ret);
+               return ret;
+       #if CACHE_FAT
+       }
+       #endif
+}
+
+/**
+ * \brief Free's a cluster
+ * \return The original contents of the cluster
+ */
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       Uint32  ret;
+
+       if( Cluster < 2 || Cluster > Disk->ClusterCount )       // oops?
+       {
+               Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)", 
+                       Cluster, Disk->ClusterCount-1);
+               return -1;
+       }
+       
+       Mutex_Acquire(&Disk->lFAT);
+       #if CACHE_FAT
+       if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+       {
+               
+               ret = Disk->FATCache[Cluster];
+               Disk->FATCache[Cluster] = 0;
+       }
+       else
+       {
+       #endif
+               Uint32  val = 0;
+               Uint32  ofs = Disk->bootsect.resvSectCount*512;
+               switch(Disk->type)
+               {
+               case FAT12:
+                       VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+                       val = LittleEndian32(val);
+                       if( Cluster & 1 ) {
+                               ret = (val >> 12) & 0xFFF;
+                               val &= 0xFFF;
+                       }
+                       else {
+                               ret = val & 0xFFF;
+                               val &= 0xFFF000;
+                       }
+                       val = LittleEndian32(val);
+                       VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+                       break;
+               case FAT16:
+                       VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret);
+                       ret = LittleEndian16(ret);
+                       val = 0;
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);
+                       break;
+               case FAT32:
+                       VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret);
+                       ret = LittleEndian32(ret);
+                       val = 0;
+                       VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val);
+                       break;
+               }
+       #if CACHE_FAT
+       }
+       #endif
+       Mutex_Release(&Disk->lFAT);
+       LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12);
+       if(ret == 0) {
+               Log_Notice("FAT", "Cluster 0x%x was already free", Cluster);
+               return -1;
+       }
+       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;
+       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;
+       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;
+       LOG("ret = %07x", ret);
+       return ret;
+}
+#endif
+
+/*
+ * ====================
+ *      Cluster IO
+ * ====================
+ */
+/**
+ * \brief Read a cluster
+ * \param Disk Disk (Volume) to read from
+ * \param Length       Length to read
+ * \param Buffer       Destination for read data
+ */
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)
+{
+       ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);
+       VFS_ReadAt(
+               Disk->fileHandle,
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+                       * Disk->bootsect.bps,
+               Length,
+               Buffer
+               );
+       LEAVE('-');
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a cluster to disk
+ */
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer)
+{
+       ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);
+       VFS_WriteAt(
+               Disk->fileHandle,
+               (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+                       * Disk->bootsect.bps,
+               Disk->BytesPerCluster,
+               Buffer
+               );
+       LEAVE('-');
+}
+#endif
index 6896945..9911563 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef _FS_FAT_H_\r
 #define _FS_FAT_H_\r
 \r
+#define FAT16_MIN_SECTORS      4085\r
+#define FAT32_MIN_CLUSTERS     65525\r
+\r
 // === On Disk Structures ===\r
 /**\r
  * \struct fat_bootsect_s\r
@@ -116,16 +119,6 @@ struct fat_longfilename_s {
  * \}\r
  */\r
 \r
-/**\r
- * \brief Internal IDs for FAT types\r
- */\r
-enum eFatType\r
-{\r
-       FAT12,  //!< FAT12 Volume\r
-       FAT16,  //!< FAT16 Volume\r
-       FAT32,  //!< FAT32 Volume\r
-};\r
-\r
 /**\r
  * \name End of Cluster marks\r
  * \brief FAT values that indicate the end of a cluster chain in\r
@@ -143,29 +136,4 @@ typedef struct fat_bootsect_s fat_bootsect;
 typedef struct fat_filetable_s fat_filetable;\r
 typedef struct fat_longfilename_s fat_longfilename;\r
 \r
-// === Memory Structures ===\r
-/**\r
- * \struct drv_fat_volinfo_s\r
- * \brief Representation of a volume in memory\r
- */\r
-struct drv_fat_volinfo_s\r
-{\r
-        int    fileHandle;     //!< File Handle\r
-        int    type;   //!< FAT Type. See eFatType\r
-       char    name[12];       //!< Volume Name (With NULL Terminator)\r
-       tMutex  lFAT;   //!< Lock to prevent double-writing to the FAT\r
-       Uint32  firstDataSect;  //!< First data sector\r
-       Uint32  rootOffset;     //!< Root Offset (clusters)\r
-       Uint32  ClusterCount;   //!< Total Cluster Count\r
-       fat_bootsect    bootsect;       //!< Boot Sector\r
-       tVFS_Node       rootNode;       //!< Root Node\r
-        int    BytesPerCluster;\r
-        int    inodeHandle;    //!< Inode Cache Handle\r
-       #if CACHE_FAT\r
-       Uint32  *FATCache;      //!< FAT Cache\r
-       #endif\r
-};\r
-\r
-typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
-\r
 #endif\r
diff --git a/KernelLand/Modules/Filesystems/FAT/nodecache.c b/KernelLand/Modules/Filesystems/FAT/nodecache.c
new file mode 100644 (file)
index 0000000..1ad26e5
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * nodecache.c
+ * - FAT-Specific node caching
+ */
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+extern tVFS_Node       *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node);
+
+// === CODE ===
+tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS)
+{
+       return MS * 10 + timestamp(
+               // Seconds         Minutes              Hours
+               (Time & 0x1F) * 2, (Time >> 5) & 0x3F, (Time >> 11) & 0x1F,
+               // Day             Month                    Year
+               (Date & 0x1F) - 1, ((Date >> 5) & 0xF) - 1, 1980 + ((Date >> 9) & 0xFF)
+               );
+}
+
+void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS)
+{
+        int    y, m, d;
+        int    h, min, s, ms;
+       format_date(AcessTimestamp, &y, &m, &d, &h, &min, &s, &ms);
+       if(Date)
+               *Date = (d + 1) | ((m + 1) << 5) | ((y - 1980) << 9);
+       if(Time)
+               *Time = (s / 2) | (min << 5) | (h << 11);
+       if(MS)
+               *MS = (ms / 10) + (s & 1) * 100;
+}
+
+/**
+ * \brief Creates a tVFS_Node structure for a given file entry
+ * \param Parent       Parent directory VFS node
+ * \param Entry        File table entry for the new node
+ */
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry)
+{
+       tVFS_Node       node;
+       tVFS_Node       *ret;
+       tFAT_VolInfo    *disk = Parent->ImplPtr;
+
+       ENTER("pParent pEntry", Parent, Entry);
+       LOG("disk = %p", disk);
+       
+       if( (ret = FAT_int_GetNode(disk, Entry->cluster | (Entry->clusterHi<<16))) )
+       {
+               if( (ret->Inode >> 32) != 0 )
+               {
+                       LEAVE('p', ret);
+                       return ret;
+               }
+       }
+       else
+       {
+               ret = &node;
+               memset(ret, 0, sizeof(tVFS_Node));
+       }
+       
+       // Set Other Data
+       // 0-27: Cluster, 32-59: Parent Cluster
+       ret->Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);
+       LOG("node.Inode = %llx", ret->Inode);
+       ret->ImplInt = 0;
+       // Disk Pointer
+       ret->ImplPtr = disk;
+       ret->Size = Entry->size;
+       LOG("Entry->size = %i", Entry->size);
+       // root:root
+       ret->UID = 0;   ret->GID = 0;
+       ret->NumACLs = 1;
+       
+       ret->Flags = 0;
+       if(Entry->attrib & ATTR_DIRECTORY)
+               ret->Flags |= VFS_FFLAG_DIRECTORY;
+       if(Entry->attrib & ATTR_READONLY) {
+               ret->Flags |= VFS_FFLAG_READONLY;
+               ret->ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X
+       }
+       else {
+               ret->ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX
+       }
+       
+       // Create timestamps
+       ret->CTime = FAT_int_GetAcessTimestamp(Entry->cdate, Entry->ctime, Entry->ctimems);
+       ret->MTime = FAT_int_GetAcessTimestamp(Entry->mdate, Entry->mtime, 0);
+       ret->ATime = FAT_int_GetAcessTimestamp(Entry->adate, 0, 0);
+       
+       // Set pointers
+       if(ret->Flags & VFS_FFLAG_DIRECTORY) {
+               //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);
+               ret->Type = &gFAT_DirType;      
+               ret->Size = -1;
+       }
+       else {
+               ret->Type = &gFAT_FileType;
+       }
+
+       // Cache node only if we're not updating a cache
+       if( ret == &node ) {
+               ret = FAT_int_CacheNode(disk, &node);
+       }
+       
+       LEAVE('p', ret);
+       return ret;
+}
+
+tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       if( Cluster == Disk->rootOffset )
+               return &Disk->rootNode;
+       
+       // If the directory isn't in the cache, what do?
+       // - we want to lock it such that we don't collide, but don't want to put crap data in the cache
+       // - Put a temp node in with a flag that indicates it's incomplete?
+       
+       Mutex_Acquire(&Disk->lNodeCache);
+       tFAT_CachedNode *cnode, *prev = NULL;
+
+       for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next)
+       {
+               if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }       
+
+       // Create a temporary node?
+       cnode = calloc( sizeof(tFAT_CachedNode), 1 );
+       cnode->Node.Inode = Cluster;
+       cnode->Node.ReferenceCount = 1;
+       cnode->Node.ImplPtr = Disk;
+       cnode->Node.Type = &gFAT_DirType;       
+       cnode->Node.Size = -1;
+
+       if( prev )
+               prev->Next = cnode;
+       else
+               Disk->NodeCache = cnode;
+
+       Mutex_Release(&Disk->lNodeCache);
+       return &cnode->Node;
+}
+
+tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+       if( Cluster == Disk->rootOffset )
+               return &Disk->rootNode;
+       Mutex_Acquire(&Disk->lNodeCache);
+       tFAT_CachedNode *cnode;
+
+       for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
+       {
+               if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }
+
+       Mutex_Release(&Disk->lNodeCache);
+       return NULL;
+}
+
+tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
+{
+       tFAT_CachedNode *cnode, *prev = NULL;
+       Mutex_Acquire(&Disk->lNodeCache);
+       
+       for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+       {
+               if( cnode->Node.Inode == Node->Inode ) {
+                       cnode->Node.ReferenceCount ++;
+                       Mutex_Release(&Disk->lNodeCache);
+                       return &cnode->Node;
+               }
+       }
+       
+       cnode = malloc(sizeof(tFAT_CachedNode));
+       cnode->Next = NULL;
+       memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
+       cnode->Node.ReferenceCount = 1;
+       
+       if( prev )
+               prev->Next = cnode;
+       else
+               Disk->NodeCache = cnode;
+       
+       Mutex_Release(&Disk->lNodeCache);
+       return &cnode->Node;
+}
+
+int FAT_int_DerefNode(tVFS_Node *Node)
+{
+       tFAT_VolInfo    *Disk = Node->ImplPtr;
+       tFAT_CachedNode *cnode, *prev = NULL;
+        int    bFreed = 0;
+
+       if( Node == &Disk->rootNode )
+               return 0;
+
+       Mutex_Acquire(&Disk->lNodeCache);
+       Node->ReferenceCount --;
+       for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+       {
+               if(Node == &cnode->Node) {
+                       if(prev)
+                               prev->Next = cnode->Next;
+                       else
+                               Disk->NodeCache = cnode->Next;
+                       break;
+               }
+       }
+       if(Node->ReferenceCount == 0 && cnode) {
+               // Already out of the list :)
+               if(cnode->Node.Data)
+                       free(cnode->Node.Data);
+               VFS_CleanupNode(&cnode->Node);
+               free(cnode);
+               bFreed = 1;
+       }
+       Mutex_Release(&Disk->lNodeCache);
+       if( !cnode ) {
+               // Not here?
+               return -1;
+       }
+       
+       return bFreed;
+}
+
+void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
+{
+       // TODO: In theory when this is called, all handles will be closed
+}
index e7cd4f7..4a6635b 100644 (file)
@@ -28,6 +28,7 @@ $lStack = array( array("",array()) );
 foreach($lines as $line)
 {
        $line = trim($line);
+       if($line[0] == "#")     continue;
        // Directory
        if(preg_match('/^Dir\s+"([^"]+)"\s+{$/', $line, $matches))
        {
@@ -122,36 +123,9 @@ EOF;
                        }
                        $size = filesize($path);
        
-/*             
-                       $_sym = $prefix."_".$i."_data";
-                       $fp = fopen($path, "rb");
-                       
-                       $gOutput .= "Uint8 $_sym[] = {\n";
-                       for( $j = 0; $j + 16 < $size; $j += 16 ) {
-                               $gOutput .= "\t";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",";
-                               $gOutput .= hd8($fp).",".hd8($fp).",\n";
-                       }
-                       $gOutput .= "\t";
-                       for( ; $j < $size; $j ++ ) {
-                               if( $j & 15 )   $gOutput .= ",";
-                               $gOutput .= hd8($fp);
-                       }
-                       fclose($fp);
-                       $gOutput .= "\n};\n";
-*/
-                       
-//*
                        $_sym = "_binary_".str_replace(array("/","-","."), "_", $path)."_start";
                        $gOutput .= "extern Uint8 {$_sym}[];";
                        $gSymFiles[] = $path;
-//*/
                        $gOutput .= <<<EOF
 tVFS_Node {$prefix}_{$i} = {
        .NumACLs = 1,
index 941c025..fe2fc4d 100644 (file)
@@ -1,17 +1,19 @@
 Dir "SBin" {
        File "init" "__BIN__/SBin/init"
        File "login" "__BIN__/SBin/login"
-       File "dhcpc" "__BIN__/SBin/dhcpc"
+       File "telnetd" "__BIN__/SBin/telnetd"
 }
 Dir "Bin" {
        File "CLIShell" "__BIN__/Bin/CLIShell"
        File "ls" "__BIN__/Bin/ls"
        File "cat" "__BIN__/Bin/cat"
        File "mount" "__BIN__/Bin/mount"
-       File "ifconfig" "__BIN__/Bin/ifconfig"
+       File "lspci" "__BIN__/Bin/lspci"
+       File "ip" "__BIN__/Bin/ip"
        File "ping" "__BIN__/Bin/ping"
        File "telnet" "__BIN__/Bin/telnet"
        File "irc" "__BIN__/Bin/irc"
+       File "dhcpc" "__BIN__/SBin/dhcpc"
 }
 Dir "Libs" {
        File "ld-acess.so" "__BIN__/Libs/ld-acess.so"
@@ -36,3 +38,14 @@ Dir "Apps" {
                }
        }
 }
+#Dir "Keen5" {
+#      File "keen5e" "/home/tpg/Projects/AcessPorts/omnispeak/bin/keen5e"
+#      File "EGADICT.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGADICT.CK5"
+#      File "EGAGRAPH.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAGRAPH.CK5"
+#      File "EGAHEAD.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAHEAD.CK5"
+#      File "GAMEMAPS.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GAMEMAPS.CK5"
+#      File "GFXINFOE.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GFXINFOE.CK5"
+#      File "MAPHEAD.CK5"  "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/MAPHEAD.CK5"
+#      File "TILEINFO.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/TILEINFO.CK5"
+#      File "ACTION.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/ACTION.CK5"
+#}
index 92af114..1848613 100644 (file)
@@ -14,9 +14,9 @@ typedef struct sInitRD_File
 
 
 // === Functions ===
-extern size_t  InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
-extern char    *InitRD_ReadDir(tVFS_Node *Node, int ID);
-extern tVFS_Node       *InitRD_FindDir(tVFS_Node *Node, const char *Name);
+//extern size_t        InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
+//extern int   InitRD_ReadDir(tVFS_Node *Node, int ID);
+//extern tVFS_Node     *InitRD_FindDir(tVFS_Node *Node, const char *Name);
 
 // === Globals ===
 tVFS_NodeType  gInitRD_DirType;
index 3ee61ac..96f783e 100644 (file)
@@ -18,14 +18,17 @@ tVFS_Node   *InitRD_InitDevice(const char *Device, const char **Arguments);
 void   InitRD_Unmount(tVFS_Node *Node);
 tVFS_Node      *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
 size_t InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
-char   *InitRD_ReadDir(tVFS_Node *Node, int ID);
+ int   InitRD_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
 tVFS_Node      *InitRD_FindDir(tVFS_Node *Node, const char *Name);
 void   InitRD_DumpDir(tVFS_Node *Node, int Indent);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
 tVFS_Driver    gInitRD_FSInfo = {
-       "initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
+       .Name = "initrd",
+       .InitDevice = InitRD_InitDevice,
+       .Unmount = InitRD_Unmount,
+       .GetNodeFromINode = InitRD_GetNodeFromINode
        };
 tVFS_NodeType  gInitRD_DirType = {
        .ReadDir = InitRD_ReadDir,
@@ -40,7 +43,6 @@ tVFS_NodeType gInitRD_FileType = {
  */
 int InitRD_Install(char **Arguments)
 {
-       Log_Notice("InitRD", "Installed");
        VFS_AddDriver( &gInitRD_FSInfo );
        
        return MODULE_ERR_OK;
@@ -54,7 +56,6 @@ tVFS_Node *InitRD_InitDevice(const char *Device, const char **Arguments)
        #if DUMP_ON_MOUNT
        InitRD_DumpDir( &gInitRD_RootNode, 0 );
        #endif
-       Log_Notice("InitRD", "Mounted (%i files)", giInitRD_NumFiles);
        return &gInitRD_RootNode;
 }
 
@@ -91,14 +92,15 @@ size_t InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe
 /**
  * \brief Read from a directory
  */
-char *InitRD_ReadDir(tVFS_Node *Node, int ID)
+int InitRD_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
 {
        tInitRD_File    *dir = Node->ImplPtr;
        
        if(ID >= Node->Size)
-               return NULL;
+               return -EINVAL;
        
-       return strdup(dir[ID].Name);
+       strncpy(Dest, dir[ID].Name, FILENAME_MAX);
+       return 0;
 }
 
 /**
index 598120d..312bee7 100644 (file)
@@ -150,4 +150,7 @@ typedef struct sNTFS_FILE_Attrib
        };
 } PACKED       tNTFS_FILE_Attrib;
 
+extern int     NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
+extern tVFS_Node       *NTFS_FindDir(tVFS_Node *Node, const char *Name);
+
 #endif
index 37661e8..11cd241 100644 (file)
@@ -10,7 +10,7 @@
 #include "index.h"
 
 // === PROTOTYPES ===
-char   *NTFS_ReadDir(tVFS_Node *Node, int Pos);
+ int   NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *NTFS_FindDir(tVFS_Node *Node, const char *Name);
 Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str);
 
@@ -18,9 +18,9 @@ Uint64        NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str
 /**
  * \brief Get the name of an indexed directory entry
  */
-char *NTFS_ReadDir(tVFS_Node *Node, int Pos)
+int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       return NULL;
+       return -ENOTIMPL;
 }
 
 /**
index dbda06e..b9c4b8d 100644 (file)
 #include "common.h"
 #include <modules.h>
 
-// === IMPORTS ===
-extern char    *NTFS_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node       *NTFS_FindDir(tVFS_Node *Node, const char *Name);
-
 // === PROTOTYPES ===
  int   NTFS_Install(char **Arguments);
 tVFS_Node      *NTFS_InitDevice(const char *Devices, const char **Options);
@@ -23,7 +19,12 @@ void NTFS_DumpEntry(tNTFS_Disk *Disk, Uint32 Entry);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
-tVFS_Driver    gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
+tVFS_Driver    gNTFS_FSInfo = {
+       .Name = "ntfs",
+       .InitDevice = NTFS_InitDevice,
+       .Unmount = NTFS_Unmount,
+       .GetNodeFromINode = NULL
+};
 tVFS_NodeType  gNTFS_DirType = {
        .TypeName = "NTFS-File",
        .ReadDir = NTFS_ReadDir,
diff --git a/KernelLand/Modules/Filesystems/RAMDisk/Makefile b/KernelLand/Modules/Filesystems/RAMDisk/Makefile
new file mode 100644 (file)
index 0000000..b1f3980
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# RAMDisk Makfile
+#
+
+OBJ = ramdisk.o
+NAME = RAMDisk
+
+-include ../Makefile.tpl
+
diff --git a/KernelLand/Modules/Filesystems/RAMDisk/ramdisk.c b/KernelLand/Modules/Filesystems/RAMDisk/ramdisk.c
new file mode 100644 (file)
index 0000000..eeef8f6
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ * Acess2 Kernel - RAM Disk Support
+ * - By John Hodge (thePowersGang)
+ *
+ * ramdisk.c
+ * - Core File
+ */
+#define DEBUG  1
+#include <acess.h>
+#include <modules.h>
+#include "ramdisk.h"
+#define VERSION        VER2(0,1)
+
+#define MIN_RAMDISK_SIZE       (1*1024*1024)
+#define MAX_RAMDISK_SIZE       (64*1024*1024)
+
+// === PROTOTYPES ===
+ int   RAMFS_Install(char **Arguments);
+ int   RAMFS_Cleanup(void);
+// --- Mount/Unmount ---
+tVFS_Node      *RAMFS_InitDevice(const char *Device, const char **Options);
+void   RAMFS_Unmount(tVFS_Node *Node);
+// --- Directories ---
+ int   RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[256]);
+tVFS_Node      *RAMFS_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node      *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *Node);
+ int   RAMFS_Unlink(tVFS_Node *Node, const char *Name);
+// --- Files ---
+size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
+size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer);
+// --- Internals --
+void   RAMFS_int_RefFile(tRAMFS_Inode *Inode);
+void   RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
+void   *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc);
+void   RAMFS_int_DropPage(void *Page);
+Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk);
+void   RAMFS_int_RefFile(tRAMFS_Inode *Inode);
+void   RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, FS_RAMDisk, RAMFS_Install, RAMFS_Cleanup, NULL);
+tVFS_Driver    gRAMFS_Driver = {
+       .Name = "ramfs",
+       .InitDevice = RAMFS_InitDevice,
+       .Unmount = RAMFS_Unmount
+       // TODO: GetNodeFromInode
+       };
+tVFS_NodeType  gRAMFS_DirNodeType = {
+       .ReadDir = RAMFS_ReadDir,
+       .FindDir = RAMFS_FindDir,
+       .MkNod   = RAMFS_MkNod,
+       .Link    = RAMFS_Link,
+       .Unlink  = RAMFS_Unlink
+       };
+tVFS_NodeType  gRAMFS_FileNodeType = {
+       .Read  = RAMFS_Read,
+       .Write = RAMFS_Write
+       };
+
+// === CODE ===
+int RAMFS_Install(char **Arguments)
+{
+       VFS_AddDriver( &gRAMFS_Driver );
+       return 0;
+}
+
+int RAMFS_Cleanup(void)
+{
+       return 0;
+}
+
+
+// --- Mount/Unmount
+const char *_GetOption(const char *Data, const char *Option)
+{
+        int    len = strlen(Option);
+       if( strncmp(Data, Option, len) != 0 )
+               return NULL;
+       if( Data[len] != '=' )
+               return NULL;
+       return Data + len + 1;
+}
+
+tVFS_Node *RAMFS_InitDevice(const char *Device, const char **Options)
+{
+       size_t  size = 0;
+       tRAMDisk        *rd;
+
+       if( Options ) 
+       {
+               const char *v;
+               for( int i = 0; Options[i]; i ++ )
+               {
+                       LOG("Options[%i] = '%s'", i, Options[i]);
+                       if( (v = _GetOption(Options[i], "megs")) )
+                       {
+                               size = atoi(v) * 1024 * 1024;
+                               LOG("Size set to %iMiB", size>>20);
+                       }
+               }
+       }
+
+       LOG("Disk Size %iKiB", size>>10);
+
+       if( size > MAX_RAMDISK_SIZE || size < MIN_RAMDISK_SIZE )
+               return NULL;
+
+        int    n_pages = size / PAGE_SIZE;
+       
+       rd = calloc(1, sizeof(tRAMDisk) + n_pages * sizeof(tPAddr) + n_pages / 8);
+       rd->MaxPages = n_pages;
+       rd->RootDir.Inode.Disk = rd;
+       rd->RootDir.Inode.Node.ImplPtr = &rd->RootDir;
+       rd->RootDir.Inode.Node.Flags = VFS_FFLAG_DIRECTORY;
+       rd->RootDir.Inode.Node.Size = -1;
+       rd->RootDir.Inode.Node.Type = &gRAMFS_DirNodeType;
+       rd->Bitmap = (void*)&rd->PhysPages[ n_pages ];
+
+       for( int i = 0; i < n_pages; i ++ )
+       {
+               rd->PhysPages[i] = MM_AllocPhys();
+               if( !rd->PhysPages[i] ) {
+                       // Um... oops?
+                       break;
+               }
+       }
+
+       LOG("Mounted");
+       return &rd->RootDir.Inode.Node;
+}
+
+void RAMFS_Unmount(tVFS_Node *Node)
+{
+       Log_Warning("RAMDisk", "TODO: Impliment unmounting");
+}
+
+// --- Directories ---
+int RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[FILENAME_MAX])
+{
+       tRAMFS_Dir      *dir = Node->ImplPtr;
+       for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
+       {
+               if( Index -- == 0 ) {
+                       LOG("Return %s", d->Name);
+                       strncpy(Dest, d->Name, FILENAME_MAX);
+                       return 0;
+               }
+       }
+       LOG("Return -ENOENT");
+       return -ENOENT;
+}
+
+tVFS_Node *RAMFS_FindDir(tVFS_Node *Node, const char *Name)
+{
+       tRAMFS_Dir      *dir = Node->ImplPtr;
+
+       for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
+       {
+               if( strcmp(d->Name, Name) == 0 ) {
+                       LOG("Return %p", &d->Inode->Node);
+                       return &d->Inode->Node;
+               }
+       }
+       
+       LOG("Return NULL");
+       return NULL;
+}
+
+tVFS_Node *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+       tRAMFS_Dir      *dir = Node->ImplPtr;
+       if( RAMFS_FindDir(Node, Name) != NULL )
+               return NULL;
+       
+       tRAMFS_DirEnt   *de = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
+       de->Next = NULL;
+       de->NameLen = strlen(Name);
+       strcpy(de->Name, Name);
+
+       if( Flags & VFS_FFLAG_DIRECTORY ) {
+               tRAMFS_Dir      *newdir = calloc(1, sizeof(tRAMFS_Dir));
+               newdir->Inode.Node.Type = &gRAMFS_DirNodeType;
+               de->Inode = &newdir->Inode;
+       }
+       else {
+               tRAMFS_File     *newfile = calloc(1, sizeof(tRAMFS_File));
+               newfile->Inode.Node.Type = &gRAMFS_FileNodeType;
+               de->Inode = &newfile->Inode;
+       }
+       de->Inode->Disk = dir->Inode.Disk;
+       de->Inode->Node.Flags = Flags;
+       de->Inode->Node.ImplPtr = de->Inode;
+
+       RAMFS_int_RefFile(de->Inode);
+
+       // TODO: Lock?
+       if(dir->FirstEnt)
+               dir->LastEnt->Next = de;
+       else
+               dir->FirstEnt = de;
+       dir->LastEnt = de;
+
+       return &de->Inode->Node;
+}
+
+int RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *FileNode)
+{
+       tRAMFS_Dir      *dir = DirNode->ImplPtr;
+       tRAMFS_DirEnt   *dp;
+
+       for( dp = dir->FirstEnt; dp; dp = dp->Next )
+       {
+               if( strcmp(dp->Name, Name) == 0 )
+                       return -1;
+       }
+       
+       dp = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
+       dp->Next = NULL;
+       dp->Inode = FileNode->ImplPtr;
+       RAMFS_int_RefFile(dp->Inode);
+       strcpy(dp->Name, Name);
+
+       // TODO: Lock?  
+       if(dir->FirstEnt)
+               dir->LastEnt->Next = dp;
+       else
+               dir->FirstEnt = dp;
+       dir->LastEnt = dp;
+       
+       return 0;
+}
+
+int RAMFS_Unlink(tVFS_Node *Node, const char *Name)
+{
+       tRAMFS_Dir      *dir = Node->ImplPtr;
+       tRAMFS_DirEnt   *dp, *p = NULL;
+
+       // TODO: Is locking needed?
+
+       // Find the directory entry
+       for( dp = dir->FirstEnt; dp; p = dp, dp = dp->Next )
+       {
+               if( strcmp(dp->Name, Name) == 0 )
+                       break ;
+       }
+       if( !dp )       return -1;
+       
+       // Dereference the file
+       RAMFS_int_DerefFile( dp->Inode );
+
+       // Remove and free directory entry
+       if(!p)
+               dir->FirstEnt = dp->Next;
+       else
+               p->Next = dp->Next;
+       if( dir->LastEnt == dp )
+               dir->LastEnt = p;
+       free(dp);
+
+       return 0;
+}
+
+// --- Files ---
+size_t RAMFS_int_DoIO(tRAMFS_File *File, off_t Offset, size_t Size, void *Buffer, int bRead)
+{
+       size_t  rem;
+       Uint8   *page_virt;
+        int    page;
+
+       if( Offset >= File->Size )      return 0;
+       
+       if( Offset + Size > File->Size )        Size = File->Size - Size;
+
+       if( Size == 0 )         return 0;
+
+       page = Offset / PAGE_SIZE;
+       Offset %= PAGE_SIZE;
+       rem = Size;
+
+       page_virt = RAMFS_int_GetPage(File, page++, !bRead);
+       if(!page_virt)  return 0;
+       
+       if( Offset + Size <= PAGE_SIZE )
+       {
+               if( bRead )
+                       memcpy(Buffer, page_virt + Offset, Size);
+               else
+                       memcpy(page_virt + Offset, Buffer, Size);
+               return 0;
+       }
+       
+       if( bRead )
+               memcpy(Buffer, page_virt + Offset, PAGE_SIZE - Offset);
+       else
+               memcpy(page_virt + Offset, Buffer, PAGE_SIZE - Offset);
+       Buffer += PAGE_SIZE - Offset;
+       rem -= PAGE_SIZE - Offset;
+       
+       while( rem >= PAGE_SIZE )
+       {
+               RAMFS_int_DropPage(page_virt);
+               page_virt = RAMFS_int_GetPage(File, page++, !bRead);
+               if(!page_virt)  return Size - rem;
+               
+               if( bRead )
+                       memcpy(Buffer, page_virt, PAGE_SIZE);
+               else
+                       memcpy(page_virt, Buffer, PAGE_SIZE);
+               
+               Buffer += PAGE_SIZE;
+               rem -= PAGE_SIZE;
+       }
+
+       if( rem > 0 )
+       {
+               page_virt = RAMFS_int_GetPage(File, page, !bRead);
+               if(!page_virt)  return Size - rem;
+               if( bRead )
+                       memcpy(Buffer, page_virt, rem);
+               else
+                       memcpy(page_virt, Buffer, rem);
+       }
+
+       RAMFS_int_DropPage(page_virt);
+       
+       return Size;
+}
+
+size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer)
+{
+       tRAMFS_File     *file = Node->ImplPtr;
+       
+       return RAMFS_int_DoIO(file, Offset, Size, Buffer, 1);
+}
+
+size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer)
+{
+       tRAMFS_File     *file = Node->ImplPtr;
+       
+       // TODO: Limit checks?
+       if( Offset == file->Size )
+               file->Size += Size;
+
+       return RAMFS_int_DoIO(file, Offset, Size, (void*)Buffer, 0);
+}
+
+// --- Internals ---
+void *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc)
+{
+       Uint32  page_id = 0;
+       Uint32  *page_in_1 = NULL;
+       Uint32  *page_in_2 = NULL;
+
+        int    ofs = 0, block;
+
+       if( Page < 0 )  return NULL;
+       
+       if( Page < RAMFS_NDIRECT )
+       {
+               if( File->PagesDirect[Page] )
+                       page_id = File->PagesDirect[Page];
+       }
+       else if( Page - RAMFS_NDIRECT < PAGE_SIZE/4 )
+       {
+               ofs = Page - RAMFS_NDIRECT;
+               if( File->Indirect1Page == 0 ) {
+                       if( !bCanAlloc )
+                               return NULL;
+                       else
+                               File->Indirect1Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+               }
+               page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect1Page-1] );
+               page_id = page_in_1[ofs];
+       }
+       else if( Page - RAMFS_NDIRECT - PAGE_SIZE/4 < (PAGE_SIZE/4)*(PAGE_SIZE/4) )
+       {
+               block = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) / (PAGE_SIZE/4);
+               ofs   = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) % (PAGE_SIZE/4);
+               if( File->Indirect2Page == 0 ){
+                       if( !bCanAlloc )
+                               return NULL;
+                       else
+                               File->Indirect2Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+               }
+
+               page_in_2 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect2Page-1] );
+               if( page_in_2[block] == 0 ) {
+                       if( !bCanAlloc )
+                               return NULL;
+                       else
+                               page_in_2[block] = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+               }
+
+               page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[page_in_2[block] - 1] );
+               page_id = page_in_1[ofs];
+       }
+
+       if( page_id == 0 )
+       {
+               if( !bCanAlloc )
+                       return NULL;
+               
+               page_id = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+               if(page_in_1)
+                       page_in_1[ofs] = page_id;
+               else
+                       File->PagesDirect[Page] = page_id;
+       }
+       
+       MM_FreeTemp( page_in_1 );
+       MM_FreeTemp( page_in_2 );
+
+       return MM_MapTemp( File->Inode.Disk->PhysPages[page_id - 1] );
+}
+
+void RAMFS_int_DropPage(void *Page)
+{
+       MM_FreeTemp( Page );
+}
+
+Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk)
+{
+        int    i, j;
+
+       // Quick check
+       if( Disk->nUsedPages == Disk->MaxPages )
+               return 0;
+
+       // Find a chunk with at least one free page
+       for( i = 0; i < Disk->MaxPages / 32; i ++ )
+       {
+               if( Disk->Bitmap[i] != -1 )
+                       break;
+       }
+       if( i == Disk->MaxPages / 32 ) {
+               Log_Error("RAMFS", "Bookkeeping error, count and bitmap disagree");
+               return 0;
+       }
+
+       // Find the exact page
+       for( j = 0; j < 32; j ++ )
+       {
+               if( !(Disk->Bitmap[i] & (1U << j)) )
+                       break ;
+       }
+       ASSERT(j < 32);
+
+       return i * 32 + j;
+}
+
+void RAMFS_int_RefFile(tRAMFS_Inode *Inode)
+{
+       Inode->nLink ++;
+}
+
+void RAMFS_int_DerefFile(tRAMFS_Inode *Inode)
+{
+       Inode->nLink --;
+       if( Inode->nLink >= 0 )
+               return ;
+
+       Log_Error("RAMFS", "TODO: Clean up files when deleted");
+
+       // Need to delete file
+       switch( Inode->Type )
+       {
+       case 0: // File
+               break ;
+       case 1: // Directory
+               break ;
+       case 2: // Symlink
+               break ;
+       }
+       free(Inode);
+}
diff --git a/KernelLand/Modules/Filesystems/RAMDisk/ramdisk.h b/KernelLand/Modules/Filesystems/RAMDisk/ramdisk.h
new file mode 100644 (file)
index 0000000..4b0ce6c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Acess2 Kernel - RAM Disk Support
+ * - By John Hodge (thePowersGang)
+ *
+ * ramdisk.h
+ * - Core header
+ */
+#ifndef _RAMDISK_H_
+#define _RAMDISK_H_
+
+#include <vfs.h>
+
+#define RAMFS_NDIRECT  12
+
+typedef struct sRAMFS_Inode    tRAMFS_Inode;
+typedef struct sRAMFS_File     tRAMFS_File;
+typedef struct sRAMFS_DirEnt   tRAMFS_DirEnt;
+typedef struct sRAMFS_Dir      tRAMFS_Dir;
+typedef struct sRAMDisk        tRAMDisk;
+
+struct sRAMFS_Inode
+{
+       tRAMDisk        *Disk;
+       tVFS_Node       Node;
+        int    Type;   // 0: Normal, 1: Dir, 2: Symlink
+        int    nLink;
+};
+
+struct sRAMFS_File
+{
+       tRAMFS_Inode    Inode;
+       size_t  Size;
+        int    nAllocPageSlots;
+       Uint32  PagesDirect[RAMFS_NDIRECT];
+       Uint32  Indirect1Page;  // PAGE_SIZE/sizeof(Uint32) = 1024 on x86
+       Uint32  Indirect2Page;  // ~1 Million on x86
+};
+
+struct sRAMFS_DirEnt
+{
+       tRAMFS_DirEnt   *Next;
+       tRAMFS_Inode    *Inode;
+       Uint8   NameLen;
+       char    Name[];
+};
+
+struct sRAMFS_Dir
+{
+       tRAMFS_Inode    Inode;
+
+       tRAMFS_DirEnt   *FirstEnt;
+       tRAMFS_DirEnt   *LastEnt;
+};
+
+struct sRAMDisk
+{
+       tRAMFS_Dir      RootDir;
+       
+        int    MaxPages;
+       Uint32  *Bitmap;
+        int    nUsedPages;
+       tPAddr  PhysPages[];
+};
+
+#endif
+
index 8289455..deb0552 100644 (file)
@@ -20,7 +20,7 @@
 void   *IPStack_Adapter_Add(const tIPStack_AdapterType *Type, void *Ptr, const void *HWAddr);
 void   IPStack_Adapter_Del(void *Handle);
 // --- VFS API ---
-char   *Adapter_ReadDir(tVFS_Node *Node, int Pos);
+ int   Adapter_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
 tVFS_Node      *Adapter_FindDir(tVFS_Node *Node, const char *Name);
  int   Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data);
  int   Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data);
@@ -79,13 +79,14 @@ void *IPStack_Adapter_Add(const tIPStack_AdapterType *Type, void *Ptr, const voi
        ret->Node.Type = &gIP_AdapterType;
        ret->Node.ImplPtr = ret;
 
-       // TODO: Locking
+       Mutex_Acquire( &glIP_Adapters );
        gpIP_AdapterList_Last->Next = ret;
        gpIP_AdapterList_Last = ret;
+       Mutex_Release( &glIP_Adapters );
        
        // Watch the adapter for incoming packets
-       tTID tid = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
-       if(tid < 0) {
+       void *worker = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
+       if(!worker) {
                Log_Warning("IPStack", "Unable to create watcher thread for %p", ret);
        }
        
@@ -119,7 +120,7 @@ void *IPStack_Adapter_AddVFS(const char *Path)
        // Get MAC Address
        VFS_IOCtl(fd, NET_IOCTL_GETMAC, mac);
 
-       return IPStack_Adapter_Add(NULL, (void*)fd, mac);
+       return IPStack_Adapter_Add(NULL, (void*)(tVAddr)fd, mac);
 }
 
 void IPStack_Adapter_Del(void *Handle)
@@ -129,13 +130,14 @@ void IPStack_Adapter_Del(void *Handle)
 }
 
 // --- VFS API ---
-char *Adapter_ReadDir(tVFS_Node *Node, int Pos)
+int Adapter_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       if( Pos < 0 )   return NULL;
+       if( Pos < 0 )   return -EINVAL;
 
        // Loopback
        if( Pos == 0 ) {
-               return strdup("lo");
+               strcpy(Dest, "lo");
+               return 0;
        }
        Pos --;
        
@@ -143,7 +145,8 @@ char *Adapter_ReadDir(tVFS_Node *Node, int Pos)
                tAdapter *a;  int i;\
                for(i=0,a=list; i < Pos && a; i ++, a = a->Next ); \
                if( a ) { \
-                       return Adapter_GetName(a);\
+                       strncpy(Dest, Adapter_GetName(a), FILENAME_MAX);\
+                       return 0;\
                } \
                Pos -= i; \
        } while(0);
@@ -151,7 +154,7 @@ char *Adapter_ReadDir(tVFS_Node *Node, int Pos)
        CHECK_LIST(gpIP_AdapterList, "eth");
        // TODO: Support other types of adapters (wifi, tap, ...)
 
-       return NULL;
+       return -EINVAL;
 }
 
 tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name)
@@ -314,3 +317,85 @@ int Adapter_int_LoopbackSendPacket(void *Unused, tIPStackBuffer *Buffer)
        return 0;
 }
 
+// --- Broadcast Debugging ---
+extern Uint16  IPv4_Checksum(const void *Buf, size_t Length);
+void IPStack_SendDebugText(const char *Text)
+{
+       const Uint8     pkt_hdr[] = {
+               0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
+               0x00,0x00, 0x00,0x00, 0x00,0x00,
+               0x08,0x00,
+               
+               0x45,0x00,      // Version/Length, DiffServices
+               0xFF,0xFF,      // Total Length
+               0x00,0x00,      // Identifcation
+               0x00,0x00, 0xFF,0x11,   // Flags,Fragment, TTL=255,proto=UDP
+               0x00,0x00,      // Header checksum
+               0x00,0x00,0x00,0x00,    // Source
+               0xFF,0xFF,0xFF,0xFF,    // Destination
+               
+               0x80,0x00, 0x80,0x00,
+               0xFF,0xFF, 0xFF,0xFF,
+       };
+       static tShortSpinlock   lLock;
+
+       // Fast return if there's no avaliable adapters
+       if( !gpIP_AdapterList )
+               return ;
+
+       if( CPU_HAS_LOCK(&lLock) )
+               return ;        // Nested!
+       SHORTLOCK(&lLock);
+       #if ARCHDIR_is_x86
+       __asm__ __volatile__ ("sti");   // Start interrupts (x86 specific)
+       #endif
+
+       // Cache packets until a newline
+       static char     cache[1500 - (sizeof(pkt_hdr) + 4)];
+       static int      cache_len;
+       
+        int    len = strlen(Text);
+
+       // Append to cache
+       strncpy(cache + cache_len, Text, sizeof(cache) - cache_len);
+       cache_len += len;
+       // TODO: Detect overflows.
+       
+       // If there's no newline, only buffer
+       if( strpos(Text, '\n') == -1 ) {
+               SHORTREL(&lLock);
+               return ;
+       }
+
+       // Build packet
+        int    link_checksum_ofs = sizeof(pkt_hdr) + cache_len;
+       char    buffer[sizeof(pkt_hdr) + cache_len + 4];
+
+       memcpy(buffer, pkt_hdr, sizeof(pkt_hdr));
+       memcpy(buffer + sizeof(pkt_hdr), cache, cache_len);
+       
+       ((Uint16*)buffer)[(14+2)/2] = BigEndian16( sizeof(pkt_hdr)-14 + cache_len );    // IP Size
+       ((Uint16*)buffer)[(14+10)/2] = BigEndian16( 0 );        // IP Header
+       ((Uint16*)buffer)[(14+20+4)/2] = BigEndian16( 8+cache_len );    // UDP Size
+       ((Uint16*)buffer)[(14+20+6)/2] = BigEndian16( 0 );      // UDP Checksum
+//     *(Uint32*)&buffer[link_checksum_ofs] = BigEndian32( 0 );        // 802.3 checksum?
+       // TODO: Calculate checksums
+       ((Uint16*)buffer)[(14+10)/2] = BigEndian16( IPv4_Checksum(buffer+14,20) );      // IP Header
+       
+       // Create buffer
+       tIPStackBuffer  *buf = IPStack_Buffer_CreateBuffer(1);
+       IPStack_Buffer_AppendSubBuffer(buf, link_checksum_ofs+4, 0, buffer, NULL, NULL);
+
+       // Send 'er off
+       for( tAdapter *a = gpIP_AdapterList; a; a = a->Next )
+       {
+               a->Type->SendPacket( a->CardHandle, buf );
+       }
+
+       IPStack_Buffer_DestroyBuffer(buf);
+
+       cache_len = 0;
+
+       SHORTREL(&lLock);
+}
+
index b8462e6..0048420 100644 (file)
@@ -147,7 +147,7 @@ int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int Index, size_t *Length,
                return -1;
        }
 
-       if( Index > Buffer->nSubBuffers )
+       if( Index >= Buffer->nSubBuffers )
        {
                // Appended buffers
                Index -= Buffer->nSubBuffers;
@@ -166,11 +166,12 @@ int IPStack_Buffer_GetBuffer(tIPStackBuffer *Buffer, int Index, size_t *Length,
        }
        else
        {
-               Index = Buffer->nSubBuffers - Index;
+                int    rv = Index + 1;
+               Index = Buffer->nSubBuffers - Index - 1;
                // Prepended buffers
                *DataPtr = Buffer->SubBuffers[Index].Data;
                *Length = Buffer->SubBuffers[Index].PreLength;
-               return Buffer->nSubBuffers - (Index - 1);
+               return rv;
        }
 }
 
index 80974ef..66f0f96 100644 (file)
@@ -133,7 +133,7 @@ int ICMP_Ping(tInterface *Interface, tIPv4 Addr)
        end = ts + Interface->TimeoutDelay;
        while( !gICMP_PingSlots[i].bArrived && now() < end)     Threads_Yield();
        
-       if(now() >= end)
+       if( !gICMP_PingSlots[i].bArrived )
                return -1;
        
        return (int)( now() - ts );
index 0ecd847..7872998 100644 (file)
 
 #include "buffer.h"
 
+enum eIPStack_AdapterTypes
+{
+       ADAPTERTYPE_ETHERNET_10M,
+       ADAPTERTYPE_ETHERNET_100M,
+       ADAPTERTYPE_ETHERNET_1G
+};
+
+// Checksum offloading
+#define ADAPTERFLAG_OFFLOAD_MAC        (1 <<  0)
+#define ADAPTERFLAG_OFFLOAD_IP4        (1 <<  1)
+#define ADAPTERFLAG_OFFLOAD_IP6        (1 <<  2)
+#define ADAPTERFLAG_OFFLOAD_TCP        (1 <<  3)
+#define ADAPTERFLAG_OFFLOAD_UDP        (1 <<  4)
+
 typedef struct sIPStack_AdapterType tIPStack_AdapterType;
 
 struct sIPStack_AdapterType
diff --git a/KernelLand/Modules/IPStack/init.h b/KernelLand/Modules/IPStack/init.h
new file mode 100644 (file)
index 0000000..1f14bf1
--- /dev/null
@@ -0,0 +1,12 @@
+
+#ifndef _IPSTACK__INIT_H_
+#define _IPSTACK__INIT_H_
+
+extern int     ARP_Initialise();
+extern void    UDP_Initialise();
+extern void    TCP_Initialise();
+extern int     IPv4_Initialise();
+extern int     IPv6_Initialise();
+
+#endif
+
index 8fe0a43..9ab4b9a 100644 (file)
@@ -8,10 +8,11 @@
 #include "link.h"
 #include <api_drv_common.h>
 #include "include/adapters.h"
+#include "interface.h"
 
 // === CONSTANTS ===
-//! Default timeout value, 30 seconds
-#define DEFAULT_TIMEOUT        (30*1000)
+//! Default timeout value, 5 seconds
+#define DEFAULT_TIMEOUT        (5*1000)
 
 // === IMPORTS ===
 extern int     IPv4_Ping(tInterface *Iface, tIPv4 Addr);
@@ -20,18 +21,23 @@ extern tVFS_Node    gIP_RouteNode;
 extern tVFS_Node       gIP_AdaptersNode;
 
 // === PROTOTYPES ===
-char   *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
+ int   IPStack_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
  int   IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
 
  int   IPStack_AddFile(tSocketFile *File);
 tInterface     *IPStack_AddInterface(const char *Device, const char *Name);
 
-char   *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
+ int   IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
  int   IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
 
 // === GLOBALS ===
+tVFS_NodeType  gIP_RootNodeType = {
+       .ReadDir = IPStack_Root_ReadDir,
+       .FindDir = IPStack_Root_FindDir,
+       .IOCtl = IPStack_Root_IOCtl
+};
 tVFS_NodeType  gIP_InterfaceNodeType = {
                .ReadDir = IPStack_Iface_ReadDir,
                .FindDir = IPStack_Iface_FindDir,
@@ -62,27 +68,26 @@ tSocketFile *gIP_FileTemplates;
 /**
  * \brief Read from the IP Stack's Device Directory
  */
-char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tInterface      *iface;
-       char    *name;
        ENTER("pNode iPos", Node, Pos);
        
 
        // Routing Subdir
        if( Pos == 0 ) {
-               LEAVE('s', "routes");
-               return strdup("routes");
+               strcpy(Dest, "routes");
+               return 0;
        }
        // Adapters
        if( Pos == 1 ) {
-               LEAVE('s', "adapters");
-               return strdup("adapters");
+               strcpy(Dest, "adapters");
+               return 0;
        }
        // Pseudo Interfaces
        if( Pos == 2 ) {
-               LEAVE('s', "lo");
-               return strdup("lo");
+               strcpy(Dest, "lo");
+               return 0;
        }
        Pos -= 3;
        
@@ -91,38 +96,16 @@ char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
        
        // Did we run off the end?
        if(!iface) {
-               LEAVE('n');
-               return NULL;
-       }
-       
-       name = malloc(4);
-       if(!name) {
-               Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
-               LEAVE('n');
-               return NULL;
+               LEAVE('i', -EINTERNAL);
+               return -EINVAL;
        }
        
        // Create the name
        Pos = iface->Node.ImplInt;
-       if(Pos < 10) {
-               name[0] = '0' + Pos;
-               name[1] = '\0';
-       }
-       else if(Pos < 100) {
-               name[0] = '0' + Pos/10;
-               name[1] = '0' + Pos%10;
-               name[2] = '\0';
-       }
-       else {
-               name[0] = '0' + Pos/100;
-               name[1] = '0' + (Pos/10)%10;
-               name[2] = '0' + Pos%10;
-               name[3] = '\0';
-       }
+       snprintf(Dest, FILENAME_MAX, "%i", Pos);
        
-       LEAVE('s', name);
-       // Return the pre-generated name
-       return name;
+       LEAVE('i', 0);
+       return 0;
 }
 
 /**
@@ -237,6 +220,7 @@ tInterface *IPStack_AddInterface(const char *Device, const char *Name)
        iface->Next = NULL;
        iface->Type = 0;        // Unset type
        iface->Address = iface->Name + nameLen + 1;     // Address
+       memset(&iface->Route, 0, sizeof(iface->Route));
        iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
        iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
        
@@ -295,16 +279,18 @@ int IPStack_AddFile(tSocketFile *File)
 /**
  * \brief Read from an interface's directory
  */
-char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tSocketFile     *file = gIP_FileTemplates;
        while(Pos-- && file) {
                file = file->Next;
        }
        
-       if(!file)       return NULL;
+       if(!file)
+               return -EINVAL;
        
-       return strdup(file->Name);
+       strncpy(Dest, file->Name, FILENAME_MAX);
+       return 0;
 }
 
 /**
diff --git a/KernelLand/Modules/IPStack/interface.h b/KernelLand/Modules/IPStack/interface.h
new file mode 100644 (file)
index 0000000..60459a0
--- /dev/null
@@ -0,0 +1,10 @@
+
+#ifndef _IPSTACK__INTERFACE_H_
+#define _IPSTACK__INTERFACE_H_
+
+extern tInterface      gIP_LoopInterface;
+extern tVFS_NodeType   gIP_RootNodeType;
+extern tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
+
+#endif
+
index 3162301..36e2200 100644 (file)
@@ -181,7 +181,6 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
        
        // TODO: Handle packet fragmentation
        
-       
        Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
                hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
                hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
@@ -234,9 +233,12 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
        // Routing
        if(!iface)
        {
+               #if 0
                tMacAddr        to;
                tRoute  *rt;
-               
+       
+
+               // TODO: Put this in another thread to avoid delays in the RX thread    
                Log_Debug("IPv4", "Route the packet");
                // Drop the packet if the TTL is zero
                if( hdr->TTL == 0 ) {
@@ -261,6 +263,7 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
                        ((tIPv4*)rt->NextHop)->B[2], ((tIPv4*)rt->NextHop)->B[3]);
                Log_Warning("IPv4", "TODO: Implement forwarding with tIPStackBuffer");
 //             Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer);
+               #endif
                
                return ;
        }
@@ -283,7 +286,7 @@ void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
  */
 tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
 {
-       tInterface      *iface = NULL;
+       tInterface      *iface = NULL, *zero_iface = NULL;
        Uint32  netmask;
        Uint32  addr, this;
 
@@ -301,7 +304,20 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
                        LEAVE('p', iface);
                        return iface;
                }
-               
+
+               LOG("iface->Address = 0x%x", *(Uint32*)iface->Address);
+
+               if( *(Uint32*)iface->Address == 0 ) {
+                       if( zero_iface ) {
+                               Log_Notice("IPv4", "Multiple 0.0.0.0 interfaces on the same adapter, ignoring");
+                       }
+                       else {
+                               zero_iface = iface;
+                               LOG("Zero IF %p", iface);
+                       }
+                       continue ;
+               }               
+
                if( !Broadcast )        continue;
                
                // Check for broadcast
@@ -316,6 +332,17 @@ tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
                        return iface;
                }
        }
+
+       // Special case for intefaces that are being DHCP configured
+       // - If the interface address is 0.0.0.0, then if there is no match for the
+       //   destination the packet is treated as if it was addressed to 0.0.0.0
+       if( zero_iface && Broadcast )
+       {
+               LOG("Using 0.0.0.0 interface with magic!");
+               LEAVE('p', zero_iface);
+               return zero_iface;
+       }
+
        LEAVE('n');
        return NULL;
 }
index 7cb8e0a..090e4c0 100644 (file)
@@ -69,7 +69,7 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
 {
        tInterface      *iface;
        tIPv6Header     *hdr = Buffer;
-        int    ret, dataLength;
+        int    ret;
        char    *dataPtr;
        Uint8   nextHeader;
        
@@ -105,7 +105,6 @@ void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buff
        // Process Options
        nextHeader = hdr->NextHeader;
        dataPtr = hdr->Data;
-       dataLength = hdr->PayloadLength;
        for( ;; )
        {
                struct {
index 3dcd294..c4f716f 100644 (file)
@@ -114,8 +114,6 @@ int Link_HandlePacket(tAdapter *Adapter, tIPStackBuffer *Buffer)
        void    *data = IPStack_Buffer_CompactBuffer(Buffer, &len);
        
        tEthernetHeader *hdr = (void*)data;
-        int    i;
-       Uint32  checksum;
 
        if(len < sizeof(tEthernetHeader)) {
                Log_Log("Net Link", "Recieved an undersized packet (%i < %i)",
@@ -133,11 +131,12 @@ int Link_HandlePacket(tAdapter *Adapter, tIPStackBuffer *Buffer)
                hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5],
                ntohs(hdr->Type)
                );
-       checksum = *(Uint32*)&hdr->Data[len-sizeof(tEthernetHeader)-4];
+//     Uint32 checksum = *(Uint32*)(data + len + 4);
        //Log_Log("NET", "Checksum 0x%08x", checksum);
        // TODO: Check checksum
        
        // Check if there is a registered callback for this packet type
+        int    i;
        for( i = giRegisteredTypes; i--; )
        {
                if(gaRegisteredTypes[i].Type == ntohs(hdr->Type))       break;
index 5763e2d..bc920f1 100644 (file)
@@ -9,19 +9,10 @@
 #include <modules.h>
 #include <fs_devfs.h>
 #include "include/adapters.h"
+#include "interface.h"
+#include "init.h"
 
 // === IMPORTS ===
-extern int     ARP_Initialise();
-extern void    UDP_Initialise();
-extern void    TCP_Initialise();
-extern int     IPv4_Initialise();
-extern int     IPv6_Initialise();
-
-extern char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
-extern int     IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
-extern tInterface      gIP_LoopInterface;
-extern tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
 extern tRoute  *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
 
 // === PROTOTYPES ===
@@ -30,11 +21,6 @@ extern tRoute        *IPStack_AddRoute(const char *Interface, void *Network, int Subnet
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
-tVFS_NodeType  gIP_RootNodeType = {
-       .ReadDir = IPStack_Root_ReadDir,
-       .FindDir = IPStack_Root_FindDir,
-       .IOCtl = IPStack_Root_IOCtl
-};
 tDevFS_Driver  gIP_DriverInfo = {
        NULL, "ip",
        {
index c4b5392..d9efa99 100644 (file)
@@ -17,10 +17,10 @@ extern tVFS_Node    *IPStack_Root_FindDir(tVFS_Node *Node, const char *Filename);
 
 // === PROTOTYPES ===
 // - Routes directory
-char   *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
+ int   IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
- int   IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int   IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+tVFS_Node      *IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int   IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName);
 tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
  int   _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
  int   IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
@@ -43,7 +43,7 @@ tVFS_NodeType gIP_RouteDirNodeType = {
        .ReadDir = IPStack_RouteDir_ReadDir,
        .FindDir = IPStack_RouteDir_FindDir,
        .MkNod = IPStack_RouteDir_MkNod,
-       .Relink = IPStack_RouteDir_Relink,
+       .Unlink = IPStack_RouteDir_Unlink,
        .IOCtl = IPStack_RouteDir_IOCtl
 };
 tVFS_Node      gIP_RouteNode = {
@@ -58,22 +58,20 @@ tVFS_Node   gIP_RouteNode = {
 /**
  * \brief ReadDir for the /Devices/ip/routes/ directory
  */
-char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tRoute  *rt;
        
        for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
-       if( !rt )       return NULL;
+       if( !rt )       return -EINVAL;
        
        {
                 int    addrlen = IPStack_GetAddressSize(rt->AddressType);
-                int    len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
-               char    buf[len+1];
                 int    ofs;
-               ofs = sprintf(buf, "%i:", rt->AddressType);
-               ofs += Hex(buf+ofs, addrlen, rt->Network);
-               sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
-               return strdup(buf);
+               ofs = sprintf(Dest, "%i:", rt->AddressType);
+               ofs += Hex(Dest+ofs, addrlen, rt->Network);
+               sprintf(Dest+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
+               return 0;
        }
 }
 
@@ -169,13 +167,22 @@ tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name)
 /**
  * \brief Create a new route node
  */
-int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
 {
-       if( Flags )     return -EINVAL; 
-       if( Threads_GetUID() != 0 )     return -EACCES;
+       if( Flags ) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if( Threads_GetUID() != 0 ) {
+               errno = EACCES;
+               return NULL;
+       }
 
         int    type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
-       if( type <= 0 ) return -EINVAL;
+       if( type <= 0 ) {
+               errno = EINVAL;
+               return NULL;
+       }
 
         int    size = IPStack_GetAddressSize(type);
        Uint8   addrdata[size]; 
@@ -184,18 +191,21 @@ int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
        _Route_ParseRouteName(Name, addrdata, &subnet, &metric);
 
        // Check for duplicates
-       if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
-               return -EEXIST;
+       if( _Route_FindExactRoute(type, addrdata, subnet, metric) ) {
+               errno = EEXIST;
+               return NULL;
+       }
 
-       IPStack_Route_Create(type, addrdata, subnet, metric);
+       tRoute *rt = IPStack_Route_Create(type, addrdata, subnet, metric);
+       rt->Node.ReferenceCount ++;
 
-       return 0;
+       return &rt->Node;
 }
 
 /**
  * \brief Rename / Delete a route
  */
-int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName)
 {
        tRoute  *rt;
        
@@ -212,29 +222,15 @@ int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *Ne
                rt = _Route_FindExactRoute(type, addr, subnet, metric);
        }       
 
-       if( NewName == NULL )
-       {
-               // Delete the route
-               tRoute  *prev = NULL;
-               for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
-               
-               if(prev)
-                       prev->Next = rt->Next;
-               else
-                       gIP_Routes = rt->Next;
-               free(rt);
-       }
-       else
-       {
-               // Change the route
-                int    type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
-               if(type <= 0)   return -EINVAL;
-               Uint8   addr[IPStack_GetAddressSize(type)];
-                int    subnet, metric;
-               _Route_ParseRouteName(NewName, addr, &subnet, &metric);
+       // Delete the route
+       tRoute  *prev = NULL;
+       for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
        
-               return -ENOTIMPL;       
-       }
+       if(prev)
+               prev->Next = rt->Next;
+       else
+               gIP_Routes = rt->Next;
+       free(rt);
        return 0;
 }
 
index c8a5584..71dd4e5 100644 (file)
@@ -33,7 +33,7 @@ Uint16        TCP_GetUnusedPort();
  int   TCP_DeallocatePort(Uint16 Port);
 // --- Server
 tVFS_Node      *TCP_Server_Init(tInterface *Interface);
-char   *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
+ int   TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
 tVFS_Node      *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
  int   TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
 void   TCP_Server_Close(tVFS_Node *Node);
@@ -878,11 +878,10 @@ tVFS_Node *TCP_Server_Init(tInterface *Interface)
  * \param Node Server node
  * \param Pos  Position (ignored)
  */
-char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
+int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
        tTCPListener    *srv = Node->ImplPtr;
        tTCPConnection  *conn;
-       char    *ret;
        
        ENTER("pNode iPos", Node, Pos);
 
@@ -911,11 +910,10 @@ char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
        LOG("srv->NewConnections = %p", srv->NewConnections);
        LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
 
-       ret = malloc(9);
-       itoa(ret, conn->Node.ImplInt, 16, 8, '0');
-       Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
-       LEAVE('s', ret);
-       return ret;
+       itoa(Dest, conn->Node.ImplInt, 16, 8, '0');
+       Log_Log("TCP", "Thread %i got connection '%s'", Threads_GetTID(), Dest);
+       LEAVE('i', 0);
+       return 0;
 }
 
 /**
index 93d8c6a..9c2e20e 100644 (file)
@@ -16,6 +16,7 @@
 #include <Input/Keyboard/include/keyboard.h>
 #include "keymap_int.h"
 #include "layout_kbdus.h"
+#include <hal_proc.h>
 
 #define USE_KERNEL_MAGIC       1
 
@@ -28,7 +29,7 @@ extern void   Heap_Stats(void);
 
 // === PROTOTYPES ===
  int   Keyboard_Install(char **Arguments);
-void   Keyboard_Cleanup(void);
+ int   Keyboard_Cleanup(void);
 // - Internal
 tKeymap        *Keyboard_LoadMap(const char *Name);
 void   Keyboard_FreeMap(tKeymap *Keymap);
@@ -67,9 +68,10 @@ int Keyboard_Install(char **Arguments)
 /**
  * \brief Pre-unload cleanup function
  */
-void Keyboard_Cleanup(void)
+int Keyboard_Cleanup(void)
 {
        // TODO: Do I need this?
+       return 0;
 }
 
 // --- Map Management ---
@@ -162,6 +164,15 @@ void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
        Uint32  flag;
        Uint8   layer;
        
+       if( !Source ) {
+               Log_Error("Keyboard", "Passed NULL handle");
+               return ;
+       }
+       if( !Source->Node ) {
+               Log_Error("Keyboard", "Passed handle with NULL node");
+               return ;
+       }
+       
        bPressed = !(HIDKeySym & (1 << 31));
        HIDKeySym &= 0x7FFFFFFF;
 
@@ -279,6 +290,8 @@ void Keyboard_HandleKey(tKeyboard *Source, Uint32 HIDKeySym)
                case 'p':       Threads_Dump(); return;
                // Heap Statistics
                case 'h':       Heap_Stats();   return;
+               // PMem Statistics
+               case 'm':       MM_DumpStatistics();    return;
                // Dump Structure
                case 's':       return;
                }
index 5e6a9a2..25185a2 100644 (file)
@@ -15,9 +15,9 @@
 
 // === PROTOTYPES ===
  int   Mouse_Install(char **Arguments);
-void   Mouse_Cleanup(void);
+ int   Mouse_Cleanup(void);
 // - "User" side
-char   *Mouse_Root_ReadDir(tVFS_Node *Node, int Pos);
+ int   Mouse_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *Mouse_Root_FindDir(tVFS_Node *Node, const char *Name);
  int   Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data);
 size_t Mouse_Dev_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Data);
@@ -62,15 +62,18 @@ int Mouse_Install(char **Arguments)
 /**
  * \brief Pre-unload cleanup function
  */
-void Mouse_Cleanup(void)
+int Mouse_Cleanup(void)
 {
+       return 0;
 }
 
 // --- VFS Interface ---
-char *Mouse_Root_ReadDir(tVFS_Node *Node, int Pos)
+int Mouse_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       if( Pos != 0 )  return NULL;
-       return strdup("system");
+       if( Pos != 0 )
+               return -EINVAL;
+       strcpy(Dest, "system");
+       return 0;
 }
 
 tVFS_Node *Mouse_Root_FindDir(tVFS_Node *Node, const char *Name)
index e11bc74..f71fff7 100644 (file)
@@ -36,11 +36,7 @@ void KBC8042_Init(void)
 
 void KBC8042_KeyboardHandler(int IRQ, void *Ptr)
 {
-       Uint8   scancode;
-
-//     Log("KBC8042_KeyboardHandler: (IRQ=%i, Ptr=%p)", IRQ, Ptr);
-
-       scancode = inb(0x60);
+       Uint8   scancode = inb(0x60);
        KB_HandleScancode( scancode );
 }
 
index a8dd074..6e05bb4 100644 (file)
@@ -111,7 +111,7 @@ static inline void PL050_WriteKeyboardData(Uint8 Data)
                return ;
        }
 
-       while( --timeout && gpPL050_KeyboardBase[1] & PL050_TXBUSY );
+       while( --timeout && (gpPL050_KeyboardBase[1] & PL050_TXBUSY) );
        if(timeout)
                gpPL050_KeyboardBase[2] = Data;
        else
index e365e99..19fd77e 100644 (file)
@@ -13,7 +13,7 @@ CPPFLAGS := -I$(ACESSDIR)/KernelLand/Kernel/include -I$(ACESSDIR)/KernelLand/Ker
 CPPFLAGS += -I$(ACESSDIR)/KernelLand/Modules
 CPPFLAGS += -DARCH=$(ARCH) -DARCH_is_$(ARCH) -DARCHDIR_is_$(ARCHDIR)
 CPPFLAGS += $(_CPPFLAGS)
-CPPFLAGS += $(LIBINCLUDES)
+CPPFLAGS += $(LIBINCLUDES) -ffreestanding
 CFLAGS := -std=gnu99 -Wall -fno-stack-protector -g -O3
 CFLAGS += -Werror
 
@@ -51,9 +51,11 @@ clean:
 
 install: $(BIN)
 ifneq ($(BUILDTYPE),static)
-       @$(xMKDIR) $(DISTROOT)/Modules/$(ARCH); true
-       $(xCP) $(BIN) $(DISTROOT)/Modules/$(ARCH)/$(NAME).kmd
+       @$(xMKDIR) $(DISTROOT)/$(ARCH)/Modules; true
+       @gzip -c $(BIN) > $(BIN).gz
+       $(xCP) $(BIN).gz $(DISTROOT)/$(ARCH)/Modules/$(NAME).kmd.gz
 else
+       @true
 endif
 
 
diff --git a/KernelLand/Modules/Network/E1000/Makefile b/KernelLand/Modules/Network/E1000/Makefile
new file mode 100644 (file)
index 0000000..00a6e2c
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Acess2 Intel E1000 driver
+#
+
+OBJ = e1000.o
+NAME = E1000
+
+-include ../Makefile.tpl
+
diff --git a/KernelLand/Modules/Network/E1000/e1000.c b/KernelLand/Modules/Network/E1000/e1000.c
new file mode 100644 (file)
index 0000000..b225d3d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Acess2 E1000 Network Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * e1000.c
+ * - Intel E1000 Network Card Driver (core)
+ */
+#define DEBUG  1
+#define        VERSION VER2(0,1)
+#include <acess.h>
+#include "e1000.h"
+#include <modules.h>
+#include <drv_pci.h>
+#include <IPStack/include/adapters_api.h>
+
+// === PROTOTYPES ===
+ int   E1000_Install(char **Arguments);
+ int   E1000_Cleanup(void);
+tIPStackBuffer *E1000_WaitForPacket(void *Ptr);
+ int   E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
+void   E1000_IRQHandler(int Num, void *Ptr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, E1000, E1000_Install, E1000_Cleanup, NULL);
+tIPStack_AdapterType   gE1000_AdapterType = {
+       .Name = "E1000",
+       .Type = 0,      // TODO: Differentiate differnet wire protos and speeds
+       .Flags = 0,     // TODO: IP checksum offloading, MAC checksum offloading etc
+       .SendPacket = E1000_SendPacket,
+       .WaitForPacket = E1000_WaitForPacket
+       };
+
+// === CODE ===
+int E1000_Install(char **Arguments)
+{
+       for( int id = -1; (id = PCI_GetDevice(0x8086, 0x100E, id)) != -1; )
+       {
+               
+       }
+       return MODULE_ERR_NOTNEEDED;
+}
+
+int E1000_Cleanup(void)
+{
+       return 0;
+}
+
+tIPStackBuffer *E1000_WaitForPacket(void *Ptr)
+{
+       return NULL;
+}
+
+int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
+{
+       return -1;
+}
+
+void E1000_IRQHandler(int Num, void *Ptr)
+{
+}
diff --git a/KernelLand/Modules/Network/E1000/e1000.h b/KernelLand/Modules/Network/E1000/e1000.h
new file mode 100644 (file)
index 0000000..d8b864f
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Acess2 E1000 Network Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * e1000.h
+ * - Driver core header
+ */
+#ifndef _E1000_H_
+#define _E1000_H_
+
+
+
+#endif
+
index d8bbf88..f9f4d25 100644 (file)
@@ -2,7 +2,7 @@
  * Acess2 VIA Rhine II Driver (VT6102)
  * - By John Hodge (thePowersGang)
  */
-#define        DEBUG   0
+#define        DEBUG   1
 #define VERSION        ((0<<8)|10)
 #include <acess.h>
 #include <modules.h>
 #include "rhine2_hw.h"
 #include <IPStack/include/adapters_api.h>
 
+#define DESC_SIZE      16
+#define N_RX_DESCS     16
+#define RX_BUF_SIZE    1024
+#define N_RX_BUF_PER_PAGE      (PAGE_SIZE/RX_BUF_SIZE)
+#define N_RX_BUF_PAGES ((N_RX_DESCS*RX_BUF_SIZE)/PAGE_SIZE)
+#define N_TX_DESCS     ((PAGE_SIZE/DESC_SIZE)-N_RX_DESCS)
+
+#define CR0_BASEVAL    (CR0_STRT|CR0_TXON|CR0_RXON)
+
 // === CONSTANTS ===
 #define VENDOR_ID      0x1106
 #define DEVICE_ID      0x3065
@@ -22,18 +31,21 @@ typedef struct sCard
        Uint8   IRQ;
        
        tSemaphore      ReadSemaphore;
+       tSemaphore      SendSemaphore;
 
-       Uint32  RXBuffersPhys;
-       void    *RXBuffers;
+       struct {
+               Uint32  Phys;
+               void    *Virt;
+       } RXBuffers[N_RX_BUF_PAGES];
 
        Uint32  DescTablePhys;
        void    *DescTable;
+
+       struct sTXDesc  *TXDescs;
+        int    NextTX;
+        int    nFreeTX;
        
-       struct sTXDesc  *FirstTX;
-       struct sTXDesc  *LastTX;        // Most recent unsent packet
-       
-       struct sRXDesc  *FirstRX;       // Most recent unread packet
-       struct sRXDesc  *LastRX;        // End of RX descriptor queue
+       struct sRXDesc  *NextRX;        // Most recent unread packet
 
        void    *IPHandle;      
        Uint8   MacAddr[6];
@@ -41,16 +53,14 @@ typedef struct sCard
 
 // === PROTOTYPES ===
  int   Rhine2_Install(char **Options);
+void   Rhine2_int_InitialiseCard(tCard *Card);
 tIPStackBuffer *Rhine2_WaitPacket(void *Ptr);
  int   Rhine2_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
-void   Rhine2_IRQHandler(int Num);
+void   Rhine2_IRQHandler(int Num, void *Pt);
 // --- Helpers ---
 struct sRXDesc *Rhine2_int_GetDescFromPhys(tCard *Card, Uint32 Addr);
 void   *Rhine2_int_GetBufferFromPhys(tCard *Card, Uint32 Addr);
 void   Rhine2_int_FreeRXDesc(void *Desc, size_t, size_t, const void*);
-struct sTXDesc *Rhine2_int_AllocTXDesc(tCard *Card);
-// --- IO ---
-void   _WriteDWord(tCard *Card, int Offset, Uint32 Value);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, VIARhineII, Rhine2_Install, NULL, NULL);
@@ -74,8 +84,7 @@ int Rhine2_Install(char **Options)
        tCard   *card;
        
        giRhine2_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
-       Log_Debug("Rhine2", "%i cards", giRhine2_CardCount);
-       
+       Log_Debug("Rhine2", "giRhine2_CardCount = %i", giRhine2_CardCount);
        if( giRhine2_CardCount == 0 )   return MODULE_ERR_NOTNEEDED;
        
        gaRhine2_Cards = calloc( giRhine2_CardCount, sizeof(tCard) );
@@ -91,19 +100,27 @@ int Rhine2_Install(char **Options)
                LOG("BAR4 = 0x%08x", PCI_GetBAR(id, 4));
                LOG("BAR5 = 0x%08x", PCI_GetBAR(id, 5));
                
-//             card->IOBase = base;
+               card->IOBase = PCI_GetBAR(id, 0);
+               if( !(card->IOBase & 1) ) {
+                       // Oops?
+                       Log_Warning("Rhine2", "BAR0 is not in IO space");
+                       continue ;
+               }
+               card->IOBase &= ~1;
                card->IRQ = PCI_GetIRQ( id );
                
                // Install IRQ Handler
-//             IRQ_AddHandler(card->IRQ, Rhine2_IRQHandler);
-               
+               IRQ_AddHandler(card->IRQ, Rhine2_IRQHandler, card);
                
-               
-//             Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
-//                     i, card->IOBase, card->IRQ,
-//                     card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
-//                     card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
-//                     );
+               Rhine2_int_InitialiseCard(card);
+       
+               card->IPHandle = IPStack_Adapter_Add(&gRhine2_AdapterType, card, card->MacAddr);
+       
+               Log_Log("Rhine2", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
+                       i, card->IOBase, card->IRQ,
+                       card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
+                       card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
+                       );
                
                i ++;
        }
@@ -111,6 +128,77 @@ int Rhine2_Install(char **Options)
        return MODULE_ERR_OK;
 }
 
+void Rhine2_int_InitialiseCard(tCard *Card)
+{
+       tPAddr  phys;
+       
+       Card->MacAddr[0] = inb(Card->IOBase + REG_PAR0);
+       Card->MacAddr[1] = inb(Card->IOBase + REG_PAR1);
+       Card->MacAddr[2] = inb(Card->IOBase + REG_PAR2);
+       Card->MacAddr[3] = inb(Card->IOBase + REG_PAR3);
+       Card->MacAddr[4] = inb(Card->IOBase + REG_PAR4);
+       Card->MacAddr[5] = inb(Card->IOBase + REG_PAR5);
+
+       LOG("Resetting card");  
+       outb(Card->IOBase + REG_CR1, CR1_SFRST);
+       // TODO: Timeout
+       while( inb(Card->IOBase + REG_CR1) & CR1_SFRST ) ;
+       
+       LOG("Allocaating RX buffers");
+       // Allocate memory for things
+       for( int i = 0; i < N_RX_BUF_PAGES; i ++ )
+       {
+               Card->RXBuffers[i].Virt = (void*)MM_AllocDMA(1, 32, &phys);
+               Card->RXBuffers[i].Phys = phys;
+       }
+       
+       LOG("Allocating and filling RX/TX Descriptors");
+       Card->DescTable = (void*)MM_AllocDMA(1, 32, &phys);
+       Card->DescTablePhys = phys;
+
+       // Initialise RX Descriptors
+       struct sRXDesc  *rxdescs = Card->DescTable;
+       for( int i = 0; i < N_RX_DESCS; i ++ )
+       {
+               rxdescs[i].RSR = 0;
+               rxdescs[i].BufferSize = RX_BUF_SIZE;
+               rxdescs[i].RXBufferStart = Card->RXBuffers[i/N_RX_BUF_PER_PAGE].Phys
+                       + (i % N_RX_BUF_PER_PAGE) * RX_BUF_SIZE;
+               rxdescs[i].RDBranchAddress = Card->DescTablePhys + (i+1) * DESC_SIZE;
+               rxdescs[i].Length = (1 << 15);  // set OWN
+               LOG("RX Desc %p = {Buf:0x%8x, Next:0x%x}", rxdescs,
+                       rxdescs[i].RXBufferStart, rxdescs[i].RDBranchAddress
+                       );
+       }
+       rxdescs[ N_RX_DESCS - 1 ].RDBranchAddress = Card->DescTablePhys;
+       Card->NextRX = &rxdescs[0];
+
+       Card->TXDescs = (void*)(rxdescs + N_RX_DESCS);
+       memset(Card->TXDescs, 0, sizeof(struct sTXDesc)*N_TX_DESCS);
+       for( int i = 0; i < N_TX_DESCS; i ++ )
+       {
+               Card->TXDescs[i].TDBranchAddress = Card->DescTablePhys + (N_RX_DESCS + i + 1) * DESC_SIZE;
+       }
+       Card->TXDescs[N_TX_DESCS-1].TDBranchAddress = Card->DescTablePhys + N_RX_DESCS * DESC_SIZE;
+       Card->nFreeTX = N_TX_DESCS;
+       Card->NextTX = 0;
+       
+       // - Initialise card state
+       LOG("Initialising card state");
+       outb(Card->IOBase + REG_IMR0, 0xFF);
+       outb(Card->IOBase + REG_IMR1, 0xFF);
+       outd(Card->IOBase + REG_CUR_RX_DESC, Card->DescTablePhys);
+       outd(Card->IOBase + REG_CUR_TX_DESC, Card->DescTablePhys + N_RX_DESCS * DESC_SIZE);
+
+       outb(Card->IOBase + REG_TCR, TCR_TRSF(4));
+       
+       LOG("RX started");
+       outb(Card->IOBase + REG_CR0, CR0_BASEVAL);
+       outb(Card->IOBase + REG_CR1, 0);        // Disabled TX polling only?
+       
+       LOG("ISR state: %02x %02x", inb(Card->IOBase + REG_ISR0), inb(Card->IOBase + REG_ISR1));
+}
+
 // --- File Functions ---
 tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
 {
@@ -121,6 +209,7 @@ tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
        
        ENTER("pPtr", Ptr);
 
+       LOG("CR0 state: %02x", inb(card->IOBase + REG_CR0));
        if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
        {
                LEAVE('n');
@@ -128,9 +217,12 @@ tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
        }
        
        nDesc = 0;
-       desc = card->FirstRX;
-       while( desc->BufferSize & (1 << 15) )
+       desc = card->NextRX;
+       while( !(desc->Length & (1 << 15)) )
        {
+//             LOG("desc(%p) = {RSR:%04x,Length:%04x,BufferSize:%04x,RXBufferStart:%08x,RDBranchAddress:%08x}",
+//                     desc, desc->RSR, desc->Length, desc->BufferSize, desc->RXBufferStart, desc->RDBranchAddress);
+               // TODO: This kinda expensive call can be changed for an increment, but cbf
                desc = Rhine2_int_GetDescFromPhys(card, desc->RDBranchAddress);
                nDesc ++;
        }
@@ -138,8 +230,8 @@ tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
        LOG("%i descriptors in packet", nDesc);
 
        ret = IPStack_Buffer_CreateBuffer(nDesc);
-       desc = card->FirstRX;
-       while( desc->BufferSize & (1 << 15) )
+       desc = card->NextRX;
+       while( !(desc->Length & (1 << 15)) )
        {
                void    *data = Rhine2_int_GetBufferFromPhys(card, desc->RXBufferStart);
                IPStack_Buffer_AppendSubBuffer(ret,
@@ -148,7 +240,7 @@ tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
                        );
                desc = Rhine2_int_GetDescFromPhys(card, desc->RDBranchAddress);
        }       
-       card->FirstRX = desc;
+       card->NextRX = desc;
 
        LEAVE('p', ret);
        return ret;
@@ -159,86 +251,180 @@ int Rhine2_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
        tCard   *card = Ptr;
        size_t  len;
        const void      *data;
+        int    nDescs, first_desc_id;
+       struct sTXDesc  *desc = NULL;
        struct sTXDesc  *first_desc = NULL;
        struct sTXDesc  *last_desc = NULL;
 
        ENTER("pPtr pBuffer", Ptr, Buffer);     
 
+       #if 0
        // Iterate buffers
+       nDescs = 0;
+       for( int id = -1; -1 != (id = IPStack_Buffer_GetBuffer(Buffer, id, &len, &data)); )
+       {
+               if( ((tVAddr)data & (PAGE_SIZE-1)) + len > PAGE_SIZE )
+                       nDescs ++;
+               nDescs ++;
+       }
+       if( nDescs == 0 ) {
+               LEAVE('i', -1);
+               return -1;
+       }
+
+       LOG("%i descriptors needed", nDescs);
+       
+       if( card->nFreeTX < nDescs ) {
+               // Oops... wait?
+               // TODO: Semaphore instead?
+               LEAVE('i', 1);
+               return 1;
+       }
+
+       first_desc_id = card->NextTX;
+       card->NextTX = (card->NextTX + nDescs) % N_TX_DESCS;
+
+       desc = card->TXDescs + first_desc_id;
+       
+       nDescs = 0;
        for( int id = -1; -1 != (id = IPStack_Buffer_GetBuffer(Buffer, id, &len, &data)); )
        {
                tPAddr  pdata = MM_GetPhysAddr( (tVAddr)data );
-               struct sTXDesc  *desc;
                #if PHYS_BITS > 32
                if( pdata >> 32 ) {
                        // TODO: re-map
+                       Log_Warning("Rhine2", "TODO: Bounce-buffer >32 pbit buffers");
                } 
                #endif
+       
+               if( (pdata & (PAGE_SIZE-1)) + len > PAGE_SIZE )
+               {
+                       // Need to split into to descriptors
+                       Log_Warning("Rhine2", "TODO: Split cross-page buffers");
+               }
                
-               desc = Rhine2_int_AllocTXDesc(card);
-               if(!last_desc)
-                       first_desc = desc;
-               else
-                       last_desc->TDBranchAddress = MM_GetPhysAddr( (tVAddr)desc );
+               LOG("Buffer %i (%p+0x%x) placed in %p", id-1, data, len, desc);
 
+               // TODO: Rhine I requires 4-byte alignment (fsck that, I don't have one)
+       
                desc->TXBufferStart = pdata;
-               desc->BufferSize = len;
+               desc->BufferSize = len | (1 << 15);
                // TODO: TCR
                desc->TCR = 0;
-               desc->TDBranchAddress = 0;
+               if( nDescs == 0 )
+                       desc->TSR = 0;  // OWN will be set below
+               else
+                       desc->TSR = TD_TSR_OWN;
 
-               last_desc = desc;
+               nDescs ++;
+               if(first_desc_id + nDescs == N_TX_DESCS)
+                       desc = card->TXDescs;
+               else
+                       desc ++;
        }
+       #else
+       data = IPStack_Buffer_CompactBuffer(Buffer, &len);
        
-       if( !first_desc ) {
-               LEAVE('i', -1);
-               return -1;
-       }
-
-       first_desc->TCR |= TD_TCR_STP;
-       last_desc->TCR |= TD_TCR_EDP;
-
-       if( card->LastTX )
-               card->LastTX->TDBranchAddress = MM_GetPhysAddr( (tVAddr)first_desc );
-       else {
-               card->FirstTX = first_desc;
-               card->LastTX = first_desc;
-               _WriteDWord(card, REG_CUR_TX_DESC, MM_GetPhysAddr( (tVAddr)first_desc ));
-       }
+       nDescs = 1;
+       first_desc_id = card->NextTX;
+       card->NextTX = (card->NextTX + nDescs) % N_TX_DESCS;
+       desc = card->TXDescs + first_desc_id;
+       
+       desc->TXBufferStart = MM_GetPhysAddr( data );
+       desc->BufferSize = len | (1 << 15);
+       desc->TSR = 0;
+       desc->TCR = 0;
+       #endif
+       
+       first_desc = card->TXDescs + first_desc_id;
+       last_desc = desc;
        
-       // TODO: Wait until the packet has sent, then clean up
+       first_desc->TCR |= TD_TCR_STP;
+       last_desc->TCR |= TD_TCR_EDP|TD_TCR_IC;
+//     last_desc->BufferSize &= ~(1 << 15);
+
+       first_desc->TSR |= TD_TSR_OWN;
+
+       LOG("%i descriptors allocated, first = %p, last = %p", nDescs, first_desc, last_desc);
+
+
+       LOG("Waiting for TX to complete");
+       outb(card->IOBase + REG_CR0, CR0_TDMD|CR0_BASEVAL);
+       Semaphore_Wait(&card->SendSemaphore, 1);
+
+       #if 1
+       free((void*)data);
+       #endif
 
+       LEAVE('i', 0);
        return 0;
 }
 
-void Rhine2_IRQHandler(int Num)
+void Rhine2_IRQHandler(int Num, void *Ptr)
 {
+       tCard   *card = Ptr;
+       Uint8   isr0 = inb(card->IOBase + REG_ISR0);
+       Uint8   isr1 = inb(card->IOBase + REG_ISR1);
+
+       if( isr0 == 0 ) return ;        
+
+       LOG("ISR0 = 0x%02x, ISR1 = 0x%02x", isr0, isr1);
+
+       if( isr0 & ISR0_PRX )
+       {
+               LOG("PRX");
+               Semaphore_Signal(&card->ReadSemaphore, 1);
+       }
+       
+       if( isr0 & ISR0_PTX )
+       {
+               LOG("PTX");
+               Semaphore_Signal(&card->SendSemaphore, 1);
+       }
        
+       if( isr0 & ISR0_TXE )
+       {
+               LOG("TX Error... oops");
+               Semaphore_Signal(&card->SendSemaphore, 1);
+       }
+       
+       if( isr0 & ISR0_TU )
+       {
+               LOG("Transmit buffer underflow");
+       }
+
+       LOG("Acking interrupts");
+       outb(card->IOBase + REG_ISR0, isr0);
+       outb(card->IOBase + REG_ISR1, isr1);
 }
 
 // --- Helpers ---
 struct sRXDesc *Rhine2_int_GetDescFromPhys(tCard *Card, Uint32 Addr)
 {
-       return NULL;
+       if( Card->DescTablePhys > Addr )        return NULL;
+       if( Card->DescTablePhys + PAGE_SIZE <= Addr )   return NULL;
+       if( Addr & 15 ) return NULL;
+       return (struct sRXDesc*)Card->DescTable + ((Addr & (PAGE_SIZE-1)) / 16);
 }
 
 void *Rhine2_int_GetBufferFromPhys(tCard *Card, Uint32 Addr)
 {
+       for( int i = 0; i < N_RX_BUF_PAGES; i ++ )
+       {
+               if( Card->RXBuffers[i].Phys > Addr )    continue;
+               if( Card->RXBuffers[i].Phys + PAGE_SIZE <= Addr )       continue;
+               return Card->RXBuffers[i].Virt + (Addr & (PAGE_SIZE-1));
+       }
        return NULL;
 }
 
-void Rhine2_int_FreeRXDesc(void *Desc, size_t u1, size_t u2, const void *u3)
-{
-       
-}
-
-struct sTXDesc *Rhine2_int_AllocTXDesc(tCard *Card)
+void Rhine2_int_FreeRXDesc(void *Ptr, size_t u1, size_t u2, const void *u3)
 {
-       return NULL;
-}
+       struct sRXDesc  *desc = Ptr;
 
-// --- IO ---
-void _WriteDWord(tCard *Card, int Offset, Uint32 Value)
-{
+       LOG("Descriptor %p returned to card", desc);
        
+       desc->RSR = 0;
+       desc->Length = (1 << 15);       // Reset OWN
 }
+
index afe9cc9..f6a92f4 100644 (file)
@@ -45,6 +45,42 @@ enum eRegs
 #define TCR_RSVD1      (1 << 4)        // reserved
 #define TCR_TRSF(v)    (((v)&7)<<5)    // Transmit FIFO threshold
 
+#define CR0_INIT       (1 << 0)
+#define CR0_STRT       (1 << 1)
+#define CR0_STOP       (1 << 2)
+#define CR0_RXON       (1 << 3)
+#define CR0_TXON       (1 << 4)
+#define CR0_TDMD       (1 << 5)
+#define CR0_RDMD       (1 << 6)
+#define CR0_RESV       (1 << 7)        // reserved
+
+#define CR1_EREN       (1 << 0)        // Early recieve enable
+#define CR1_RESV0      (1 << 1)
+#define CR1_FDX        (1 << 2)        // Full/Half-duplex selector
+#define CR1_DPOLL      (1 << 3)        // Disable automatic polling
+#define CR1_RESV1      (1 << 4)
+#define CR1_TDMD       (1 << 5)
+#define CR1_RDMD       (1 << 6)
+#define CR1_SFRST      (1 << 7)        // Software reset
+
+#define ISR0_PRX       (1 << 0)        // Packet recieved
+#define ISR0_PTX       (1 << 1)        // Packet transmitted successfully
+#define ISR0_RXE       (1 << 2)        // RX Error
+#define ISR0_TXE       (1 << 3)        // TX Error
+#define ISR0_TU        (1 << 4)        // Transmit buffer underflow
+#define ISR0_RU        (1 << 5)        // Recieve buffer link error
+#define ISR0_BE        (1 << 6)        // PCI Bus error
+#define ISR0_CNT       (1 << 7)        // CRC error / missed packet counter overflow
+
+#define ISR1_ERI       (1 << 0)        // Early recieve interrupt
+#define ISR1_UDFI      (1 << 1)        // TX FIFO underflow event
+#define ISR1_OVFI      (1 << 2)        // Recieve overflow
+#define ISR1_PKTR      (1 << 3)        // FIFO overflow (?"next packet race with current packet")
+#define ISR1_NORBF     (1 << 4)        // No more recieve buffers avaiable (overflow essentialy)
+#define ISR1_ABTI      (1 << 5)        // Transmission abort due to excessive collisions
+#define ISR1_SRCI      (1 << 6)        // Port state change
+#define ISR1_GENI      (1 << 7)        // General purpose interrupt
+
 // TODO: Other Regs?
 
 struct sRXDesc
@@ -55,7 +91,7 @@ struct sRXDesc
        Uint16  _resvd;
        Uint32  RXBufferStart;
        Uint32  RDBranchAddress;        // ? - I'm guessing it's the next descriptor in the chain
-};
+} PACKED;
 
 #define RSR_RERR       (1 << 0)        // Receiver error
 #define RSR_CRC        (1 << 1)        // CRC Error
@@ -82,12 +118,14 @@ struct sTXDesc
        Uint8   _resvd;
        Uint32  TXBufferStart;
        Uint32  TDBranchAddress;        // Bit 0: Disable interrupt
-};
+} PACKED;
 
 #define TD_TCR_CRC     (1 << 0)        // Disable CRC generation
 #define TD_TCR_STP     (1 << 5)        // First descriptor in packet
 #define TD_TCR_EDP     (1 << 6)        // Last descriptor in packet
 #define TD_TCR_IC      (1 << 7)        // Interrupt when transmitted
 
+#define TD_TSR_OWN     (1 << 31)
+
 #endif
 
index 2292342..5e62dd0 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-OBJ = main.o io.o mbr.o
+OBJ = main.o io.o
 NAME = ATA
 
 -include ../Makefile.tpl
index 891d2bb..f5ace2b 100644 (file)
 // Needed out of io.c because it's the max for Read/WriteDMA
 #define        MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
 
-// === STRUCTURES ===
-typedef struct
-{
-       Uint8   BootCode[0x1BE];
-       struct {
-               Uint8   Boot;
-               Uint8   Unused1;        // Also CHS Start
-               Uint16  StartHi;        // Also CHS Start
-               Uint8   SystemID;
-               Uint8   Unused2;        // Also CHS Length
-               Uint16  LengthHi;       // Also CHS Length
-               Uint32  LBAStart;
-               Uint32  LBALength;
-       } __attribute__ ((packed)) Parts[4];
-       Uint16  BootFlag;       // = 0xAA 55
-} __attribute__ ((packed))     tMBR;
-
-typedef struct
-{
-       Uint64  Start;
-       Uint64  Length;
-       char    Name[4];
-       tVFS_Node       Node;
-}      tATA_Partition;
-
-typedef struct
-{
-       Uint64  Sectors;
-       char    Name[2];
-       tVFS_Node       Node;
-        int    NumPartitions;
-       tATA_Partition  *Partitions;
-}      tATA_Disk;
-
-// === GLOBALS ===
-extern tATA_Disk       gATA_Disks[];
-
 // === FUNCTIONS ===
-// --- Common ---
-extern void    ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
-
-// --- MBR Parsing ---
-extern void    ATA_ParseMBR(int Disk, tMBR *MBR);
-
 // --- IO Functions ---
 extern int     ATA_SetupIO(void);
 extern Uint64  ATA_GetDiskSize(int Disk);
index b8a15d0..da0447a 100644 (file)
@@ -9,6 +9,8 @@
 #include <modules.h>   // Needed for error codes
 #include <drv_pci.h>
 #include "common.h"
+#include <events.h>
+#include <timers.h>
 
 // === MACROS ===
 #define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
@@ -95,10 +97,11 @@ Uint8       *gATA_BusMasterBasePtr; //!< Paging Mapped MMIO (If needed)
  int   gATA_IRQPri = 14;
  int   gATA_IRQSec = 15;
 volatile int   gaATA_IRQs[2] = {0};
+tThread        *gATA_WaitingThreads[2];
 // - Locks to avoid tripping
 tMutex glaATA_ControllerLock[2];
 // - Buffers!
-Uint8  gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
+void   *gATA_Buffers[2];
 // - PRDTs
 tPRDT_Ent      gATA_PRDTs[2] = {
        {0, 512, IDE_PRDT_LAST},
@@ -148,17 +151,27 @@ int ATA_SetupIO(void)
        IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri, NULL );
        IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec, NULL );
 
-       gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
-       gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
+       tPAddr  paddr;
+       gATA_Buffers[0] = (void*)MM_AllocDMA(1, 32, &paddr);
+       gATA_PRDTs[0].PBufAddr = paddr;
+       gATA_Buffers[1] = (void*)MM_AllocDMA(1, 32, &paddr);
+       gATA_PRDTs[1].PBufAddr = paddr;
 
        LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
 
-       gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
-       LOG("gaATA_PRDT_PAddrs[0] = 0x%x", gaATA_PRDT_PAddrs[0]);
+       // TODO: Ensure that this is within 32-bits
+       gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( &gATA_PRDTs[0] );
+       gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( &gATA_PRDTs[1] );
+       LOG("gaATA_PRDT_PAddrs = {0x%P, 0x%P}", gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+       #if PHYS_BITS > 32
+       if( gaATA_PRDT_PAddrs[0] >> 32 || gaATA_PRDT_PAddrs[1] >> 32 ) {
+               Log_Error("ATA", "Physical addresses of PRDTs are not in 32-bits (%P and %P)",
+                       gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+               LEAVE('i', MODULE_ERR_MISC);
+               return MODULE_ERR_MISC;
+       }
+       #endif
        ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
-       
-       gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
-       LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]);
        ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]);
 
        // Enable controllers
@@ -275,22 +288,18 @@ Uint16 ATA_GetBasePort(int Disk)
        return 0;
 }
 
-/**
- * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- * \return Boolean Failure
- */
-int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+int ATA_DoDMA(Uint8 Disk, Uint64 Address, Uint Count, int bWrite, void *Buffer)
 {
         int    cont = (Disk>>1)&1;     // Controller ID
         int    disk = Disk & 1;
        Uint16  base;
-       Sint64  timeoutTime;
+        int    bUseBounceBuffer;
 
-       ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
+       ENTER("iDisk XAddress iCount bbWrite pBuffer", Disk, Address, Count, bWrite, Buffer);
 
        // Check if the count is small enough
        if(Count > MAX_DMA_SECTORS) {
-               Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
+               Log_Warning("ATA", "Passed too many sectors for a bulk DMA (%i > %i)",
                        Count, MAX_DMA_SECTORS);
                LEAVE('i');
                return 1;
@@ -306,6 +315,35 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
 
        // Set Size
        gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+       
+       // Detemine if the transfer can be done directly
+       tPAddr  buf_ps = MM_GetPhysAddr(Buffer);
+       tPAddr  buf_pe = MM_GetPhysAddr((char*)Buffer + Count * SECTOR_SIZE - 1);
+       if( buf_pe == buf_ps + Count * SECTOR_SIZE - 1 ) {
+               // Contiguous, nice
+               #if PHYS_BITS > 32
+               if( buf_pe >> 32 ) {
+                       // Over 32-bits, need to copy anyway
+                       bUseBounceBuffer = 1;
+                       LOG("%P over 32-bit, using bounce buffer", buf_pe);
+               }
+               #endif
+       }
+       else {
+               // TODO: Handle splitting the read into two?
+               bUseBounceBuffer = 1;
+               LOG("%P + 0x%x != %P, using bounce buffer", buf_ps, Count * SECTOR_SIZE, buf_pe);
+       }
+
+       // Set up destination / source buffers
+       if( bUseBounceBuffer ) {
+               gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(gATA_Buffers[cont]);
+               if( bWrite )
+                       memcpy(gATA_Buffers[cont], Buffer, Count * SECTOR_SIZE);
+       }
+       else {
+               gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(Buffer);
+       }
 
        // Get Port Base
        base = ATA_GetBasePort(Disk);
@@ -313,6 +351,8 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        // Reset IRQ Flag
        gaATA_IRQs[cont] = 0;
 
+       
+       // TODO: What the ____ does this do?
        #if 1
        if( cont == 0 ) {
                outb(IDE_PRI_CTRL, 4);
@@ -358,22 +398,29 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
        
        LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
        if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
+               outb(base+0x07, bWrite ? HDD_DMA_W48 : HDD_DMA_R48);    // Command (LBA48)
        else
-               outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
+               outb(base+0x07, bWrite ? HDD_DMA_W28 : HDD_DMA_R28);    // Command (LBA28)
 
+       // Intialise timeout timer
+       Threads_ClearEvent(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+       tTimer *timeout = Time_AllocateTimer(NULL, NULL);
+       Time_ScheduleTimer(timeout, ATA_TIMEOUT);
+       gATA_WaitingThreads[cont] = Proc_GetCurThread();
+       
        // Start transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 9 );      // Read and start
+       ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) | 1 );   // Write(0)/Read(8) and start
 
        // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
+       Uint32 ev = Threads_WaitEvents(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+       Time_FreeTimer(timeout);
+
+       if( ev & THREAD_EVENT_TIMER ) {
+               Log_Notice("ATA", "Timeout of %i ms exceeded", ATA_TIMEOUT);
        }
 
        // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont * 8, 8 );      // Read and stop
+       ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) );       // Write/Read and stop
 
        #if DEBUG
        {
@@ -390,10 +437,7 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
                if( ATA_int_BusMasterReadByte(cont * 8 + 2) & 0x4 ) {
                        Log_Error("ATA", "BM Status reports an interrupt, but none recieved");
                        ATA_int_BusMasterWriteByte(cont*8 + 2, 4);      // Clear interrupt
-                       memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-                       Mutex_Release( &glaATA_ControllerLock[ cont ] );
-                       LEAVE('i', 0);
-                       return 0;
+                       goto _success;
                }
 
                #if 1
@@ -403,24 +447,35 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
                // Release controller lock
                Mutex_Release( &glaATA_ControllerLock[ cont ] );
                Log_Warning("ATA",
-                       "Read timeout on disk %i (Reading sector 0x%llx)",
-                       Disk, Address);
+                       "Timeout on disk %i (%s sector 0x%llx)",
+                       Disk, bWrite ? "Writing" : "Reading", Address);
                // Return error
                LEAVE('i', 1);
                return 1;
        }
-       else {
-               LOG("Transfer Completed & Acknowledged");
-               // Copy to destination buffer
+       
+       LOG("Transfer Completed & Acknowledged");
+_success:
+       // Copy to destination buffer (if bounce was used and it was a read)
+       if( bUseBounceBuffer && !bWrite )
                memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
+       // Release controller lock
+       Mutex_Release( &glaATA_ControllerLock[ cont ] );
 
-               LEAVE('i', 0);
-               return 0;
-       }
+       LEAVE('i', 0);
+       return 0;
 }
 
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \return Boolean Failure
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+       return ATA_DoDMA(Disk, Address, Count, 0, Buffer);
+}
+
+
 /**
  * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
  * \brief Write up to \a MAX_DMA_SECTORS to a disk
@@ -432,77 +487,7 @@ int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
  */
 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
 {
-        int    cont = (Disk>>1)&1;     // Controller ID
-        int    disk = Disk & 1;
-       Uint16  base;
-       Sint64  timeoutTime;
-
-       // Check if the count is small enough
-       if(Count > MAX_DMA_SECTORS)     return 1;
-
-       // Get exclusive access to the disk controller
-       Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
-
-       // Set Size
-       gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
-       // Get Port Base
-       base = ATA_GetBasePort(Disk);
-
-       // Reset IRQ Flag
-       gaATA_IRQs[cont] = 0;
-       
-       // Set up transfer
-       outb(base+0x01, 0x00);
-       if( Address > 0x0FFFFFFF )      // Use LBA48
-       {
-               outb(base+0x6, 0x40 | (disk << 4));
-               outb(base+0x2, 0 >> 8); // Upper Sector Count
-               outb(base+0x3, Address >> 24);  // Low 2 Addr
-               outb(base+0x3, Address >> 28);  // Mid 2 Addr
-               outb(base+0x3, Address >> 32);  // High 2 Addr
-       }
-       else
-       {
-               // Magic, Disk, High Address nibble
-               outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
-       }
-
-       outb(base+0x02, (Uint8) Count);         // Sector Count
-       outb(base+0x03, (Uint8) Address);               // Low Addr
-       outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
-       outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
-       if( Address > 0x0FFFFFFF )
-               outb(base+0x07, HDD_DMA_W48);   // Write Command (LBA48)
-       else
-               outb(base+0x07, HDD_DMA_W28);   // Write Command (LBA28)
-
-       // Copy to output buffer
-       memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
-
-       // Start transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
-
-       // Wait for transfer to complete
-       timeoutTime = now() + ATA_TIMEOUT;
-       while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
-       {
-               HALT();
-       }
-
-       // Complete Transfer
-       ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
-
-       // If the IRQ is unset, return error
-       if( gaATA_IRQs[cont] == 0 ) {
-               // Release controller lock
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 1;       // Error
-       }
-       else {
-               Mutex_Release( &glaATA_ControllerLock[ cont ] );
-               return 0;
-       }
+       return ATA_DoDMA(Disk, Address, Count, 1, (void*)Buffer);
 }
 
 /**
@@ -515,10 +500,12 @@ void ATA_IRQHandlerPri(int UNUSED(IRQ), void *UNUSED(Ptr))
        // IRQ bit set for Primary Controller
        val = ATA_int_BusMasterReadByte( 0x2 );
        LOG("IRQ val = 0x%x", val);
-       if(val & 4) {
+       if(val & 4)
+       {
                LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0x2, 4 );
                gaATA_IRQs[0] = 1;
+               Threads_PostEvent(gATA_WaitingThreads[0], THREAD_EVENT_SHORTWAIT);
                return ;
        }
 }
@@ -536,6 +523,7 @@ void ATA_IRQHandlerSec(int UNUSED(IRQ), void *UNUSED(Ptr))
                LOG("IRQ hit (val = 0x%x)", val);
                ATA_int_BusMasterWriteByte( 0xA, 4 );
                gaATA_IRQs[1] = 1;
+               Threads_PostEvent(gATA_WaitingThreads[1], THREAD_EVENT_SHORTWAIT);
                return ;
        }
 }
index cc1fe62..a131a44 100644 (file)
@@ -11,6 +11,7 @@
 #include <api_drv_common.h>
 #include <api_drv_disk.h>
 #include "common.h"
+#include <Storage/LVM/include/lvm.h>
 
 // === MACROS ===
 #define IO_DELAY()     do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
 // === PROTOTYPES ===
  int   ATA_Install(char **Arguments);
 void   ATA_SetupPartitions(void);
-void   ATA_SetupVFS(void);
  int   ATA_ScanDisk(int Disk);
 void   ATA_ParseGPT(int Disk);
-void   ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
 Uint16 ATA_GetBasePort(int Disk);
-// Filesystem Interface
-char   *ATA_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node      *ATA_FindDir(tVFS_Node *Node, const char *Name);
-size_t ATA_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
-size_t ATA_WriteFS(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
- int   ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
 // Read/Write Interface/Quantiser
-Uint   ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument);
-Uint   ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
+int    ATA_ReadRaw(void *Ptr, Uint64 Address, size_t Count, void *Buffer);
+int    ATA_WriteRaw(void *Ptr, Uint64 Address, size_t Count, const void *Buffer);
 
 // === GLOBALS ===
-MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
-tVFS_NodeType  gATA_RootNodeType = {
-       .TypeName = "ATA Root Node",
-       .ReadDir = ATA_ReadDir,
-       .FindDir = ATA_FindDir
+MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", "LVM", NULL);
+tLVM_VolType   gATA_VolType = {
+       .Name = "ATA",
+       .Read = ATA_ReadRaw,
+       .Write = ATA_WriteRaw
        };
-tVFS_NodeType  gATA_DiskNodeType = {
-       .TypeName = "ATA Volume",
-       .Read = ATA_ReadFS,
-       .Write = ATA_WriteFS,
-       .IOCtl = ATA_IOCtl
-       };
-tDevFS_Driver  gATA_DriverInfo = {
-       NULL, "ata",
-       {
-               .NumACLs = 1,
-               .Size = -1,
-               .Flags = VFS_FFLAG_DIRECTORY,
-               .ACLs = &gVFS_ACL_EveryoneRX,
-               .Type = &gATA_RootNodeType
-       }
-};
-tATA_Disk      gATA_Disks[MAX_ATA_DISKS];
- int   giATA_NumNodes;
-tVFS_Node      **gATA_Nodes;
 
 // === CODE ===
 /**
@@ -73,11 +47,6 @@ int ATA_Install(char **Arguments)
 
        ATA_SetupPartitions();
 
-       ATA_SetupVFS();
-
-       if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
-               return MODULE_ERR_MISC;
-
        return MODULE_ERR_OK;
 }
 
@@ -90,72 +59,31 @@ void ATA_SetupPartitions(void)
        for( i = 0; i < MAX_ATA_DISKS; i ++ )
        {
                if( !ATA_ScanDisk(i) ) {
-                       gATA_Disks[i].Name[0] = '\0';   // Mark as unused
                        continue;
                }
        }
 }
 
-/**
- * \brief Sets up the ATA drivers VFS information and registers with DevFS
- */
-void ATA_SetupVFS(void)
-{
-        int    i, j, k;
-
-       // Count number of nodes needed
-       giATA_NumNodes = 0;
-       for( i = 0; i < MAX_ATA_DISKS; i++ )
-       {
-               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
-               giATA_NumNodes ++;
-               giATA_NumNodes += gATA_Disks[i].NumPartitions;
-       }
-
-       // Allocate Node space
-       gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
-
-       // Set nodes
-       k = 0;
-       for( i = 0; i < MAX_ATA_DISKS; i++ )
-       {
-               if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
-               gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
-               for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
-                       gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
-       }
-
-       gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
-}
-
 /**
  * \brief Scan a disk, getting the size and any paritions
  * \param Disk Disk ID to scan
  */
 int ATA_ScanDisk(int Disk)
 {
-       tVFS_Node       *node;
-       tMBR    mbr;
-
+       Uint64  sector_count;
        ENTER("iDisk", Disk);
        
        // Get the disk size
-       gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
-       if(gATA_Disks[ Disk ].Sectors == 0)
+       sector_count = ATA_GetDiskSize(Disk);
+       if(sector_count == 0)
        {
                LEAVE('i', 0);
                return 0;
        }
 
-       LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
-
-       // Create Name
-       gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
-       gATA_Disks[ Disk ].Name[1] = '\0';
-
        #if 1
        {
-               Uint64  val = gATA_Disks[ Disk ].Sectors / 2;
+               Uint64  val = sector_count / 2;
                char    *units = "KiB";
                if( val > 4*1024 ) {
                        val /= 1024;
@@ -169,244 +97,45 @@ int ATA_ScanDisk(int Disk)
                        val /= 1024;
                        units = "TiB";
                }
-               Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
-                       gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
+               Log_Notice("ATA", "Disk %i: 0x%llx Sectors (%lli %s)",
+                       Disk, sector_count, val, units);
        }
        #endif
 
-       // Get pointer to vfs node and populate it
-       node = &gATA_Disks[ Disk ].Node;
-       node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
-       node->NumACLs = 0;      // Means Superuser only can access it
-       node->Inode = (Disk << 8) | 0xFF;
-       node->ImplPtr = gATA_Disks[ Disk ].Name;
-
-       node->ATime = node->MTime = node->CTime = now();
+       char name[] = "ata0";
+       sprintf(name, "ata%i", Disk);
+       LVM_AddVolume(&gATA_VolType, name, (void*)(Uint)Disk, 512, sector_count);
 
-       node->Type = &gATA_DiskNodeType;
-
-       // --- Scan Partitions ---
-       LOG("Reading MBR");
-       // Read Boot Sector
-       if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
-               Log_Warning("ATA", "Error in reading MBR on %i", Disk);
-               LEAVE('i', 0);
-               return 0;
-       }
-
-       // Check for a GPT table
-       if(mbr.Parts[0].SystemID == 0xEE)
-               ATA_ParseGPT(Disk);
-       else    // No? Just parse the MBR
-               ATA_ParseMBR(Disk, &mbr);
-       
        #if DEBUG >= 2
+       {
+       char    mbr[512];
        ATA_ReadDMA( Disk, 1, 1, &mbr );
        Debug_HexDump("ATA_ScanDisk", &mbr, 512);
+       }
        #endif
 
        LEAVE('i', 1);
        return 1;
 }
 
-/**
- * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
- * \brief Fills a parition's information structure
- */
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
-{
-       ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
-       Part->Start = Start;
-       Part->Length = Length;
-       Part->Name[0] = 'A'+Disk;
-       if(Num >= 10) {
-               Part->Name[1] = '1'+Num/10;
-               Part->Name[2] = '1'+Num%10;
-               Part->Name[3] = '\0';
-       } else {
-               Part->Name[1] = '1'+Num;
-               Part->Name[2] = '\0';
-       }
-       Part->Node.NumACLs = 0; // Only root can read/write raw block devices
-       Part->Node.Inode = (Disk << 8) | Num;
-       Part->Node.ImplPtr = Part->Name;
-
-       Part->Node.Type = &gATA_DiskNodeType;
-       Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
-       LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
-       LEAVE('-');
-}
-
-/**
- * \fn void ATA_ParseGPT(int Disk)
- * \brief Parses the GUID Partition Table
- */
-void ATA_ParseGPT(int Disk)
-{
-       ///\todo Support GPT Disks
-       Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
-}
-
-/**
- * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
-{
-       if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
-       return strdup( gATA_Nodes[Pos]->ImplPtr );
-}
-
-/**
- * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
- */
-tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
-{
-        int    part;
-       tATA_Disk       *disk;
-       
-       // Check first character
-       if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
-               return NULL;
-       disk = &gATA_Disks[Name[0]-'A'];
-       // Raw Disk
-       if(Name[1] == '\0') {
-               if( disk->Sectors == 0 && disk->Name[0] == '\0')
-                       return NULL;
-               return &disk->Node;
-       }
-
-       // Partitions
-       if(Name[1] < '0' || '9' < Name[1])      return NULL;
-       if(Name[2] == '\0') {   // <= 9
-               part = Name[1] - '0';
-               part --;
-               return &disk->Partitions[part].Node;
-       }
-       // > 9
-       if('0' > Name[2] || '9' < Name[2])      return NULL;
-       if(Name[3] != '\0')     return NULL;
-
-       part = (Name[1] - '0') * 10;
-       part += Name[2] - '0';
-       part --;
-       return &disk->Partitions[part].Node;
-
-}
-
-/**
- * \brief Read handler for VFS interface
- */
-size_t ATA_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
-{
-        int    disk = Node->Inode >> 8;
-        int    part = Node->Inode & 0xFF;
-
-       ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
-       // Raw Disk Access
-       if(part == 0xFF)
-       {
-               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
-       }
-       // Partition
-       else
-       {
-               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
-                       LEAVE('i', 0);
-                       return 0;
-               }
-               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
-               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
-       }
-
-       {
-               int ret = DrvUtil_ReadBlock(
-                       Offset, Length, Buffer,
-                       ATA_ReadRaw, SECTOR_SIZE, (void*)(Uint)disk
-                       );
-               //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
-               //Debug_HexDump("ATA_ReadFS", Buffer, Length);
-               LEAVE('i', ret);
-               return ret;
-       }
-}
-
-/**
- * \brief Write handler for VFS interface
- */
-size_t ATA_WriteFS(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
-{
-        int    disk = Node->Inode >> 8;
-        int    part = Node->Inode & 0xFF;
-
-       // Raw Disk Access
-       if(part == 0xFF)
-       {
-               if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
-                       return 0;
-               if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
-       }
-       // Partition
-       else
-       {
-               if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       return 0;
-               if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
-                       Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
-               Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
-       }
-
-       Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
-       Debug_HexDump("ATA_WriteFS", Buffer, Length);
-       return DrvUtil_WriteBlock(
-               Offset, Length, Buffer,
-               ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, (void*)(Uint)disk
-               );
-}
-
-const char     *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
-/**
- * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief IO Control Funtion
- */
-int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
-{
-       switch(Id)
-       {
-       BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
-       
-       case DISK_IOCTL_GETBLOCKSIZE:
-               return 512;     
-       
-       default:
-               return 0;
-       }
-       return 0;
-}
-
 // --- Disk Access ---
 /**
  * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
  */
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument)
+int ATA_ReadRaw(void *Ptr, Uint64 Address, Uint Count, void *Buffer)
 {
-        int    Disk = (tVAddr)Argument;
+        int    Disk = (tVAddr)Ptr;
         int    ret;
        Uint    offset;
        Uint    done = 0;
 
+       LOG("Reading %i sectors from 0x%llx of disk %i", Count, Address, Disk);
+
        // Pass straight on to ATA_ReadDMAPage if we can
        if(Count <= MAX_DMA_SECTORS)
        {
                ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
-               if(ret == 0)    return 0;
+               if(ret) return 0;
                return Count;
        }
 
@@ -423,17 +152,17 @@ Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument)
                offset += MAX_DMA_SECTORS*SECTOR_SIZE;
        }
 
-       ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
-       if(ret != 1)    return 0;
+       ret = ATA_ReadDMA(Disk, Address+done, Count, Buffer+offset);
+       if(ret) return 0;
        return done+Count;
 }
 
 /**
  * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
  */
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
+int ATA_WriteRaw(void *Ptr, Uint64 Address, Uint Count, const void *Buffer)
 {
-        int    Disk = (tVAddr)Argument;
+        int    Disk = (tVAddr)Ptr;
         int    ret;
        Uint    offset;
        Uint    done = 0;
diff --git a/KernelLand/Modules/Storage/ATA/mbr.c b/KernelLand/Modules/Storage/ATA/mbr.c
deleted file mode 100644 (file)
index eca8150..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Acess2 IDE Harddisk Driver
- * - MBR Parsing Code
- * mbr.c
- */
-#define DEBUG  0
-#include <acess.h>
-#include "common.h"
-
-// === PROTOTYPES ===
-void   ATA_ParseMBR(int Disk, tMBR *MBR);
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
-
-// === GLOBALS ===
-
-// === CODE ===
-/**
- * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
- */
-void ATA_ParseMBR(int Disk, tMBR *MBR)
-{
-        int    i, j = 0, k = 4;
-       Uint64  extendedLBA;
-       Uint64  base, len;
-       
-       ENTER("iDisk", Disk);
-       
-       // Count Partitions
-       gATA_Disks[Disk].NumPartitions = 0;
-       extendedLBA = 0;
-       for( i = 0; i < 4; i ++ )
-       {
-               if( MBR->Parts[i].SystemID == 0 )       continue;
-               
-               if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
-               {
-                       base = MBR->Parts[i].LBAStart;
-               }
-               else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
-               {
-                       base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
-               }
-               else
-                       continue;       // Invalid, don't count
-
-               if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
-                       LOG("Extended Partition at 0x%llx", base);
-                       if(extendedLBA != 0) {
-                               Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
-                               continue;
-                       }
-                       extendedLBA = base;
-               }
-               else {
-                       LOG("Primary Partition at 0x%llx", base);
-                       
-                       gATA_Disks[Disk].NumPartitions ++;
-               }
-       }
-       while(extendedLBA != 0)
-       {
-               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
-               if( extendedLBA == -1 ) break;
-               gATA_Disks[Disk].NumPartitions ++;
-       }
-       LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
-       
-       // Create patition array
-       gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
-       
-       // --- Fill Partition Info ---
-       extendedLBA = 0;
-       for( j = 0, i = 0; i < 4; i ++ )
-       {
-               LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
-               if( MBR->Parts[i].SystemID == 0 )       continue;
-               if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 )   // LBA 28
-               {
-                       base = MBR->Parts[i].LBAStart;
-                       len = MBR->Parts[i].LBALength;
-               }
-               else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 )      // LBA 48
-               {
-                       base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
-                       len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
-               }
-               else
-                       continue;
-               
-               if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
-                       if(extendedLBA != 0) {
-                               Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
-                               continue;
-                       }
-                       extendedLBA = base;
-                       continue;
-               }
-               // Create Partition
-               ATA_int_MakePartition(
-                       &gATA_Disks[Disk].Partitions[j], Disk, j,
-                       base, len
-                       );
-               j ++;
-               
-       }
-       // Scan extended partitions
-       while(extendedLBA != 0)
-       {
-               extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
-               if(extendedLBA == -1)   break;
-               ATA_int_MakePartition(
-                       &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
-                       );
-       }
-       
-       LEAVE('-');
-}
-
-/**
- * \brief Reads an extended partition
- * \return LBA of next Extended, -1 on error, 0 for last
- */
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
-{
-       Uint64  link = 0;
-        int    bFoundPart = 0;;
-        int    i;
-       tMBR    mbr;
-       Uint64  base, len;
-       
-       if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
-               return -1;      // Stop on Errors
-       
-       for( i = 0; i < 4; i ++ )
-       {
-               if( mbr.Parts[i].SystemID == 0 )        continue;
-               
-               // LBA 24
-               if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
-                       base = mbr.Parts[i].LBAStart;
-                       len = mbr.Parts[i].LBALength;
-               }
-               // LBA 48
-               else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
-                       base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
-                       len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
-               }
-               else {
-                       Log_Warning("ATA MBR",
-                               "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
-                               mbr.Parts[i].Boot, Disk, Addr, i
-                               );
-                       return -1;
-               }
-               base += Addr;   // Addresses are relative
-               
-               switch(mbr.Parts[i].SystemID)
-               {
-               case 0xF:
-               case 0x5:
-                       if(link != 0) {
-                               Log_Warning("ATA MBR",
-                                       "Disk %i has two forward links in the extended partition",
-                                       Disk
-                                       );
-                               return -1;
-                       }
-                       link = base;
-                       break;
-               default:
-                       if(bFoundPart) {
-                               Warning("ATA MBR",
-                                       "Disk %i has more than one partition in the extended partition at 0x%llx",
-                                       Disk, Addr
-                                       );
-                               return -1;
-                       }
-                       bFoundPart = 1;
-                       *Base = base;
-                       *Length = len;
-                       break;
-               }
-       }
-       
-       if(!bFoundPart) {
-               Log_Warning("ATA MBR",
-                       "No partition in extended partiton, Disk %i 0x%llx",
-                       Disk, Addr);
-               return -1;
-       }
-       
-       return link;
-}
index c33dcda..f6290d9 100644 (file)
@@ -21,7 +21,7 @@
  int   FDD_Install(char **Arguments);
  int   FDD_RegisterFS(void);
 // --- VFS
-char   *FDD_ReadDir(tVFS_Node *Node, int pos);
+ int   FDD_ReadDir(tVFS_Node *Node, int pos, char dest[FILENAME_MAX]);
 tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
  int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
 size_t FDD_ReadFS(tVFS_Node *node, off_t Offset, size_t Len, void *buffer);
@@ -111,17 +111,16 @@ int FDD_RegisterFS(void)
  * \param Pos  Position
  * \return Heap string of node name
  */
-char *FDD_ReadDir(tVFS_Node *Node, int Pos)
+int FDD_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       char    ret_tpl[2];
        if(Pos < 0 || Pos > MAX_DISKS )
-               return NULL;
+               return -ENOENT;
        if(gaFDD_Disks[Pos].bValid)
-               return VFS_SKIP;
+               return 1;
        
-       ret_tpl[0] = '0' + Pos;
-       ret_tpl[1] = '\0';
-       return strdup(ret_tpl);
+       Dest[0] = '0' + Pos;
+       Dest[1] = '\0';
+       return 0;
 }
 
 /**
index 3115b61..c106f77 100644 (file)
 
 #include <acess.h>
 
-typedef int (*tLVM_ReadFcn)(void *, Uint64, size_t, void *);
-typedef int (*tLVM_WriteFcn)(void *, Uint64, size_t, const void *);
+typedef struct sLVM_VolType    tLVM_VolType;
 
-extern int     LVM_AddVolume(const char *Name, void *Ptr, tLVM_ReadFcn Read, tLVM_WriteFcn Write);
+struct sLVM_VolType
+{
+       const char *Name;
+
+        int    (*Read)(void *, Uint64, size_t, void *);
+        int    (*Write)(void *, Uint64, size_t, const void *);
+       void    (*Cleanup)(void *);
+};
+
+
+extern int     LVM_AddVolume(const tLVM_VolType *Type, const char *Name, void *Ptr, size_t BlockSize, size_t BlockCount);
 
 #endif
 
index 0d0a252..e406a9b 100644 (file)
 
 // === TYPES ===
 typedef struct sLVM_Vol        tLVM_Vol;
+typedef struct sLVM_Format tLVM_Format;
+
+// === STRUCTURES ===
+struct sLVM_Format
+{
+       tLVM_Format     *Next;
+       const char      *Name;
+        int    (*CountSubvolumes)(tLVM_Vol *Volume, void *FirstBlockData);
+       void    (*PopulateSubvolumes)(tLVM_Vol *Volume, void *FirstBlockData);
+};
 
 // === FUNCTIONS ===
 extern size_t  LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest);
@@ -20,5 +30,8 @@ extern size_t LVM_int_WriteVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t Bloc
 // --- Subvolume Management ---
 extern void    LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, Uint64 LastBlock);
 
+// --- Global Fromats ---
+extern tLVM_Format     gLVM_MBRType;
+
 #endif
 
index f4ef3c1..5ef812d 100644 (file)
@@ -24,13 +24,14 @@ struct sLVM_Vol
 {
        tLVM_Vol        *Next;
        
-       tVFS_Node       Node;
+       tVFS_Node       DirNode;
+       tVFS_Node       VolNode;
 
        void    *Ptr;
-       tLVM_ReadFcn    Read;
-       tLVM_WriteFcn   Write;
+       const tLVM_VolType      *Type;
 
        size_t  BlockSize;
+       Uint64  BlockCount;
        
         int    nSubVolumes;
        tLVM_SubVolume  **SubVolumes;
@@ -52,6 +53,10 @@ struct sLVM_SubVolume
 };
 
 extern tVFS_NodeType   gLVM_SubVolNodeType;
+extern tVFS_NodeType   gLVM_VolNodeType;
+
+extern tLVM_Vol        *gpLVM_FirstVolume;
+extern tLVM_Vol        *gpLVM_LastVolume;
 
 #endif
 
index 587689e..8793d68 100644 (file)
 // === PROTOTYPES ===
 // ---
  int   LVM_Initialise(char **Arguments);
-void   LVM_Cleanup(void);
+ int   LVM_Cleanup(void);
 // ---
-char   *LVM_Root_ReadDir(tVFS_Node *Node, int ID);
+ int   LVM_Root_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
 tVFS_Node      *LVM_Root_FindDir(tVFS_Node *Node, const char *Name);
-char   *LVM_Vol_ReadDir(tVFS_Node *Node, int ID);
+ int   LVM_Vol_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
 tVFS_Node      *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name);
+size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
 size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
 size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+void   LVM_CloseNode(tVFS_Node *Node);
 
 Uint   LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument);
 Uint   LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
@@ -35,15 +38,19 @@ tVFS_NodeType       gLVM_RootNodeType = {
 };
 tVFS_NodeType  gLVM_VolNodeType = {
        .ReadDir = LVM_Vol_ReadDir,
-       .FindDir = LVM_Vol_FindDir
+       .FindDir = LVM_Vol_FindDir,
+       .Read = LVM_Vol_Read,
+       .Write = LVM_Vol_Write,
+       .Close = LVM_CloseNode
 };
 tVFS_NodeType  gLVM_SubVolNodeType = {
        .Read = LVM_SubVol_Read,
-       .Write = LVM_SubVol_Write
+       .Write = LVM_SubVol_Write,
+       .Close = LVM_CloseNode
 };
 tDevFS_Driver  gLVM_DevFS = {
        NULL, "LVM",
-       {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType}
+       {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType, .Size = -1}
 };
 
 tLVM_Vol       *gpLVM_FirstVolume;
@@ -56,26 +63,81 @@ int LVM_Initialise(char **Arguments)
        return 0;
 }
 
-void LVM_Cleanup(void)
+int LVM_Cleanup(void)
 {
+       // Attempt to destroy all volumes
+       tLVM_Vol        *vol, *prev = NULL, *next;
        
+       // TODO: Locks?
+       for( vol = gpLVM_FirstVolume; vol; prev = vol, vol = next )
+       {
+               next = vol->Next;
+                int    nFree = 0;
+               
+               for( int i = 0; i < vol->nSubVolumes; i ++ )
+               {
+                       tLVM_SubVolume  *sv;
+                       sv = vol->SubVolumes[i];
+                       if( sv == NULL ) {
+                               nFree ++;
+                               continue;
+                       }
+
+                       Mutex_Acquire(&sv->Node.Lock);
+                       if(sv->Node.ReferenceCount == 0) {
+                               nFree ++;
+                               vol->SubVolumes[i] = NULL;
+                               Mutex_Release(&sv->Node.Lock);
+                       }
+                       else {
+                               Mutex_Release(&sv->Node.Lock);
+                               continue ;
+                       }
+
+                       Mutex_Acquire(&sv->Node.Lock);
+                       LOG("Removed subvolume %s:%s", vol->Name, sv->Name);
+                       free(sv);
+               }
+               
+               if( nFree != vol->nSubVolumes )
+                       continue ;
+
+               if(prev)
+                       prev->Next = next;
+               else
+                       gpLVM_FirstVolume = next;
+
+               Mutex_Acquire(&vol->DirNode.Lock);
+               Mutex_Acquire(&vol->VolNode.Lock);
+               if( vol->Type->Cleanup )
+                       vol->Type->Cleanup( vol->Ptr );
+               LOG("Removed volume %s", vol->Name);
+               free(vol);
+       }
+
+       if( gpLVM_FirstVolume ) 
+               return EBUSY;
+       
+       return EOK;
 }
 
 // --------------------------------------------------------------------
 // VFS Inteface
 // --------------------------------------------------------------------
-char *LVM_Root_ReadDir(tVFS_Node *Node, int ID)
+int LVM_Root_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
 {
        tLVM_Vol        *vol;
        
-       if( ID < 0 )    return NULL;    
+       if( ID < 0 )    return -EINVAL;
 
        for( vol = gpLVM_FirstVolume; vol && ID --; vol = vol->Next );
        
-       if(vol)
-               return strdup(vol->Name);
+       if(vol) {
+               strncpy(Dest, vol->Name, FILENAME_MAX);
+               return 0;
+       }
        else
-               return NULL;
+               return -ENOENT;
 }
 tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name)
 {
@@ -84,29 +146,42 @@ tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name)
        {
                if( strcmp(vol->Name, Name) == 0 )
                {
-                       return &vol->Node;
+                       vol->DirNode.ReferenceCount ++;
+                       return &vol->DirNode;
                }
        }
        return NULL;
 }
 
-char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID)
+int LVM_Vol_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
 {
        tLVM_Vol        *vol = Node->ImplPtr;
+       const char *src;
        
-       if( ID < 0 || ID >= vol->nSubVolumes )
-               return NULL;
-       
-       return strdup( vol->SubVolumes[ID]->Name );
+       if( ID < 0 || ID >= vol->nSubVolumes+1 )
+               return -EINVAL;
+
+       if( ID == 0 ) {
+               src = "ROOT";
+       }
+       else {
+               src = vol->SubVolumes[ID-1]->Name;
+       }
+       strncpy(Dest, src, FILENAME_MAX);
+       return 0;
 }
 tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name)
 {
        tLVM_Vol        *vol = Node->ImplPtr;
+
+       if( strcmp("ROOT", Name) == 0 )
+               return &vol->VolNode;
        
        for( int i = 0; i < vol->nSubVolumes; i ++ )
        {
                if( strcmp(vol->SubVolumes[i]->Name, Name) == 0 )
                {
+                       vol->SubVolumes[i]->Node.ReferenceCount ++;
                        return &vol->SubVolumes[i]->Node;
                }
        }
@@ -114,6 +189,29 @@ tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name)
        return NULL;
 }
 
+size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+       tLVM_Vol        *vol = Node->ImplPtr;
+       Uint64  byte_size = vol->BlockCount * vol->BlockSize;   
+
+       if( Offset > byte_size )
+               return 0;
+       if( Length > byte_size )
+               Length = byte_size;
+       if( Offset + Length > byte_size )
+               Length = byte_size - Offset;
+
+       return DrvUtil_ReadBlock(
+               Offset, Length, Buffer, 
+               LVM_int_DrvUtil_ReadBlock, vol->BlockSize, vol
+               );
+}
+
+size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+{
+       return 0;
+}
+
 size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
 {
        tLVM_SubVolume  *sv = Node->ImplPtr;
@@ -126,8 +224,13 @@ size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffe
        if( Offset + Length > byte_size )
                Length = byte_size - Offset;
 
-       Offset += sv->FirstBlock * sv->Vol->BlockSize;  
+       LOG("Reading (0x%llx+0x%llx)+0x%x to %p",
+               (Uint64)(sv->FirstBlock * sv->Vol->BlockSize), Offset,
+               Length, Buffer
+               );
        
+       Offset += sv->FirstBlock * sv->Vol->BlockSize;  
+
        return DrvUtil_ReadBlock(
                Offset, Length, Buffer, 
                LVM_int_DrvUtil_ReadBlock, sv->Vol->BlockSize, sv->Vol
@@ -154,6 +257,11 @@ size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void
                );
 }
 
+void LVM_CloseNode(tVFS_Node *Node)
+{
+       Node->ReferenceCount --;
+}
+
 Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument)
 {
        return LVM_int_ReadVolume( Argument, Address, Count, Buffer );
index 169f6f3..67fdbce 100644 (file)
@@ -16,6 +16,11 @@ void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector);
 Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length);
 
 // === GLOBALS ===
+tLVM_Format    gLVM_MBRType = {
+       .Name = "MBR",
+       .CountSubvolumes = LVM_MBR_CountSubvolumes,
+       .PopulateSubvolumes = LVM_MBR_PopulateSubvolumes
+};
 
 // === CODE ===
 /**
@@ -71,7 +76,8 @@ int LVM_MBR_CountSubvolumes(tLVM_Vol *Volume, void *FirstSector)
        while(extendedLBA != 0)
        {
                extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
-               if( extendedLBA == -1 ) break;
+               if( extendedLBA == (Uint64)-1 )
+                       break;
                numPartitions ++;
        }
        LOG("numPartitions = %i", numPartitions);
@@ -122,7 +128,8 @@ void LVM_MBR_PopulateSubvolumes(tLVM_Vol *Volume, void *FirstSector)
        while(extendedLBA != 0)
        {
                extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
-               if(extendedLBA == -1)   break;
+               if(extendedLBA == (Uint64)-1)
+                       break;
                LVM_int_SetSubvolume_Anon( Volume, j, base, len );
                j ++ ;
        }
index 558a7aa..cf1a60d 100644 (file)
@@ -5,6 +5,7 @@
  * volumes.c
  * - Volume management
  */
+#define DEBUG  1
 #include "lvm_int.h"
 
 // === PROTOTYPES ===
 // --------------------------------------------------------------------
 int LVM_AddVolumeVFS(const char *Name, int FD)
 {
-       return LVM_AddVolume(Name, (void*)(Uint)FD, LVM_int_VFSReadEmul, LVM_int_VFSWriteEmul);
+       // Assuming 512-byte blocks, not a good idea
+//     return LVM_AddVolume(Name, (void*)(Uint)FD, 512, LVM_int_VFSReadEmul, LVM_int_VFSWriteEmul);
+       return 0;
 }
 
-int LVM_AddVolume(const char *Name, void *Ptr, tLVM_ReadFcn Read, tLVM_WriteFcn Write)
+int LVM_AddVolume(const tLVM_VolType *Type, const char *Name, void *Ptr, size_t BlockSize, size_t BlockCount)
 {
        tLVM_Vol        dummy_vol;
-//     tLVM_Vol        *real_vol;
+       tLVM_Vol        *real_vol;
+       tLVM_Format     *fmt;
+       void    *first_block;
+
+       if( BlockCount == 0 || BlockSize == 0 ) {
+               Log_Error("LVM", "BlockSize(0x%x)/BlockCount(0x%x) invalid in LVM_AddVolume",
+                       BlockSize, BlockCount);
+               return 1;
+       }
 
+       dummy_vol.Type = Type;
        dummy_vol.Ptr = Ptr;
-       dummy_vol.Read = Read;
-       dummy_vol.Write = Write;
+       dummy_vol.BlockCount = BlockCount;
+       dummy_vol.BlockSize = BlockSize;
+
+       // Read the first block of the volume   
+       first_block = malloc(BlockSize);
+       if( !first_block ) {
+               Log_Error("VLM", "LVM_AddVolume - malloc error on %i bytes", BlockSize);
+               return -1;
+       }
+       Type->Read(Ptr, 0, 1, first_block);
        
-       // Determine Type
+       // Determine Format
+       // TODO: Determine format
+       fmt = &gLVM_MBRType;
 
        // Type->CountSubvolumes
+       dummy_vol.nSubVolumes = fmt->CountSubvolumes(&dummy_vol, first_block);
        
        // Create real volume descriptor
+       // TODO: If this needs to be rescanned later, having the subvolume list separate might be an idea
+       real_vol = malloc( sizeof(tLVM_Vol) + strlen(Name) + 1 + sizeof(tLVM_SubVolume*) * dummy_vol.nSubVolumes );
+       real_vol->Next = NULL;
+       real_vol->Type = Type;
+       real_vol->Ptr = Ptr;
+       real_vol->BlockSize = BlockSize;
+       real_vol->BlockCount = BlockCount;
+       real_vol->nSubVolumes = dummy_vol.nSubVolumes;
+       real_vol->SubVolumes = (void*)( real_vol->Name + strlen(Name) + 1 );
+       real_vol->BlockSize = BlockSize;
+       strcpy(real_vol->Name, Name);
+       memset(real_vol->SubVolumes, 0, sizeof(tLVM_SubVolume*) * real_vol->nSubVolumes);
+       // - VFS Nodes
+       memset(&real_vol->DirNode, 0, sizeof(tVFS_Node));
+       real_vol->DirNode.Type = &gLVM_VolNodeType;
+       real_vol->DirNode.ImplPtr = real_vol;
+       real_vol->DirNode.Flags = VFS_FFLAG_DIRECTORY;
+       real_vol->DirNode.Size = -1;
+       memset(&real_vol->VolNode, 0, sizeof(tVFS_Node));
+       real_vol->VolNode.Type = &gLVM_VolNodeType;
+       real_vol->VolNode.ImplPtr = real_vol;
+       real_vol->VolNode.Size = BlockCount * BlockSize;
 
        // Type->PopulateSubvolumes
+       fmt->PopulateSubvolumes(real_vol, first_block);
+       free(first_block);
 
        // Add to volume list
+       gpLVM_LastVolume->Next = real_vol;
+       gpLVM_LastVolume = real_vol;
 
        return 0;
 }
@@ -75,6 +124,10 @@ void LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, U
        
        sv->Node.ImplPtr = sv;
        sv->Node.Type = &gLVM_SubVolNodeType;
+       sv->Node.Size = BlockCount * Volume->BlockSize;
+       
+       Log_Log("LVM", "Partition %s/%s - 0x%llx+0x%llx blocks",
+               Volume->Name, sv->Name, FirstBlock, BlockCount);
 }
 
 // --------------------------------------------------------------------
@@ -82,12 +135,12 @@ void LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, U
 // --------------------------------------------------------------------
 size_t LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest)
 {
-       return Volume->Read(Volume->Ptr, BlockNum, BlockCount, Dest);
+       return Volume->Type->Read(Volume->Ptr, BlockNum, BlockCount, Dest);
 }
 
 size_t LVM_int_WriteVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, const void *Src)
 {
-       return Volume->Write(Volume->Ptr, BlockNum, BlockCount, Src);   
+       return Volume->Type->Write(Volume->Ptr, BlockNum, BlockCount, Src);     
 }
 
 int LVM_int_VFSReadEmul(void *Arg, Uint64 BlockStart, size_t BlockCount, void *Dest)
index 4d6e684..8dbe04e 100644 (file)
@@ -2,8 +2,8 @@
 #
 
 OBJ  = main.o
-OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o
-OBJ += hub.o
+OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o usb_info.o
+OBJ += hub.o portctl.o
 CPPFLAGS = -Iinclude
 NAME = Core
 
index 7bc4dc2..23f3a36 100644 (file)
 // resvd
 #define SET_FEATURE    3
 
-#define PORT_CONNECTION        0
-#define PORT_ENABLE    1
-#define PORT_SUSPEND   2
-#define PORT_OVER_CURRENT      3
-#define PORT_RESET     4
-#define PORT_POWER     8
-#define PORT_LOW_SPEED 9
-#define C_PORT_CONNECTION      16
-#define C_PORT_ENABLE  17
-#define C_PORT_SUSPEND 18
-#define C_PORT_OVER_CURRENT    19
-#define C_PORT_RESET   20
-#define PORT_TEST      21
-#define PORT_INDICATOR 21
-
 struct sHubDescriptor
 {
        Uint8   DescLength;
@@ -56,6 +41,9 @@ void  Hub_Connected(tUSBInterface *Dev, void *Descriptors, size_t Length);
 void   Hub_Disconnected(tUSBInterface *Dev);
 void   Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
 void   Hub_int_HandleChange(tUSBInterface *Dev, int Port);
+void   Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat);
+void   Hub_ClearPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+int    Hub_GetPortStatus(tUSBInterface *HubDev, int Port, int Flag);
 
 // === GLOBALS ===
 tUSBDriver     gUSBHub_Driver = {
@@ -150,13 +138,8 @@ void Hub_int_HandleChange(tUSBInterface *Dev, int Port)
                        // - Power on port
                        USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_POWER, Port, 0, NULL);
                        Time_Delay(info->PowerOnDelay);
-                       // - Reset
-                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_RESET, Port, 0, NULL);
-                       Time_Delay(20); // Spec says 10ms after reset, but how long is reset?
-                       // - Enable
-                       USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_ENABLE, Port, 0, NULL);
-                       // - Poke USB Stack
-                       USB_DeviceConnected(info->HubPtr, Port);
+                       // - Start reset process
+                       USB_PortCtl_BeginReset(info->HubPtr, Port);
                }
                else {
                        // Disconnected
@@ -179,3 +162,20 @@ void Hub_int_HandleChange(tUSBInterface *Dev, int Port)
                USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_RESET, Port, 0, NULL);
        }
 }
+
+void Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat)
+{
+       USB_Request(Dev, 0, 0x23, SET_FEATURE, Feat, Port, 0, NULL);
+}
+
+void Hub_ClearPortFeature(tUSBInterface *Dev, int Port, int Feat)
+{
+       USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, Feat, Port, 0, NULL);
+}
+
+int Hub_GetPortStatus(tUSBInterface *Dev, int Port, int Flag)
+{
+       Uint16  status[2];      // Status, Change
+       USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
+       return !!(status[0] & (1 << Flag));
+}
index 0b03d75..04a6ab9 100644 (file)
@@ -53,16 +53,23 @@ struct sUSBDriver
 
 extern void    USB_RegisterDriver(tUSBDriver *Driver);
 
+// --- Driver Pointer ---
 extern void    *USB_GetDeviceDataPtr(tUSBInterface *Dev);
 extern void    USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
 
+// --- Device/Interface information ---
+extern Uint32  USB_GetInterfaceClass(tUSBInterface *Dev);
+extern void    USB_GetDeviceVendor(tUSBInterface *Dev, Uint16 *VendorID, Uint16 *DeviceID);
+extern char    *USB_GetSerialNumber(tUSBInterface *Dev);
+
+// --- Device IO ---
 extern void    USB_StartPollingEndpoint(tUSBInterface *Dev, int Endpoint);
 extern void    USB_ReadDescriptor(tUSBInterface *Dev, int Type, int Index, int Length, void *Data);
 extern void    USB_Request(tUSBInterface *Dev, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
 // TODO: Async
-extern void    USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void    USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void    USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback);
+extern void    USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data);
+extern void    USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data);
+extern void    USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBuf);
 
 #endif
 
index ab37279..7806e1b 100644 (file)
@@ -15,26 +15,46 @@ typedef struct sUSBHostDef  tUSBHostDef;
 
 typedef void   (*tUSBHostCb)(void *DataPtr, void *Data, size_t Length);
 
-typedef void   *(*tUSBHostOp)(void *Ptr, int Dest, int DataTgl, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
-typedef void   *(*tUSBIntOp)(void *Ptr, int Dest, int Period, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
+typedef void   *(*tUSBInitInt)(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len);
+typedef void   *(*tUSBInit)(void *Ptr, int Endpt, size_t MaxPacketSize);
+typedef void   *(*tUSBDataOp)(void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
+
+typedef void   *(*tUSBControlOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+       int bOutbound,  // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT
+       const void *SetupData, size_t SetupLength,
+       const void *OutData, size_t OutLength,
+       void *InData, size_t InLength
+       );
+typedef void   *(*tUSBBulkOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+       int bOutbound, void *Data, size_t Length
+       );
+typedef void   *(*tUSBIsochOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+       int bOutbound, void *Data, size_t Length, int When
+       );
 
 /**
  * \brief Defines a USB Host Controller type
  */
 struct sUSBHostDef
 {
-       tUSBIntOp       InterruptIN;
-       tUSBIntOp       InterruptOUT;
-       void    (*StopInterrupt)(void *Ptr, void *Handle);
-
-       void    *(*ControlSETUP)(void *Ptr, int Dest, int DataTgl, void *Data, size_t Length);
-       tUSBHostOp      ControlIN;
-       tUSBHostOp      ControlOUT;
+       tUSBInitInt     InitInterrupt;
+       tUSBInit        InitIsoch;
+       tUSBInit        InitControl;
+       tUSBInit        InitBulk;
+       void    (*RemEndpoint)(void *Ptr, void *Handle);
        
-       tUSBHostOp      BulkIN;
-       tUSBHostOp      BulkOUT;
-
+       // NOTE: If \a Cb is ERRPTR, the handle returned must be free'd by the calling code
+       //       otherwise the controller will free it once done
+       tUSBIsochOp     SendIsoch;
+       tUSBControlOp   SendControl;
+       tUSBBulkOp      SendBulk;
+       void    (*FreeOp)(void *Ptr, void *Handle);
+
+       // Root hub stuff
        void    (*CheckPorts)(void *Ptr);
+       void    (*SetPortFeature)(void *Ptr, int PortNum, int Feat);
+       void    (*ClearPortFeature)(void *Ptr, int PortNum, int Feat);
+        int    (*GetPortStatus)(void *Ptr, int PortNum, int Flag);
 };
 
 extern tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
index 6b32d49..b38b101 100644 (file)
@@ -23,5 +23,26 @@ extern void  USB_RemoveHub(tUSBHub *Hub);
 extern void    USB_DeviceConnected(tUSBHub *Hub, int Port);
 extern void    USB_DeviceDisconnected(tUSBHub *Hub, int Port);
 
+#define PORT_CONNECTION        0
+#define PORT_ENABLE    1
+#define PORT_SUSPEND   2
+#define PORT_OVER_CURRENT      3
+#define PORT_RESET     4
+#define PORT_POWER     8
+#define PORT_LOW_SPEED 9
+#define C_PORT_CONNECTION      16
+#define C_PORT_ENABLE  17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT    19
+#define C_PORT_RESET   20
+#define PORT_TEST      21
+#define PORT_INDICATOR 21
+
+extern void    Hub_SetPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+extern void    Hub_ClearPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+extern int     Hub_GetPortStatus(tUSBInterface *HubDev, int Port, int Flag);
+
+extern void    USB_PortCtl_BeginReset(tUSBHub *Hub, int Port);
+
 #endif
 
index 6ef7a2b..0464550 100644 (file)
 // === IMPORTS ===
 extern void    USB_PollThread(void *unused);
 extern void    USB_AsyncThread(void *Unused);
+extern void    USB_PortCtl_Init(void);
 
 // === PROTOTYPES ===
  int   USB_Install(char **Arguments);
 void   USB_Cleanup(void);
-char   *USB_ReadDir(tVFS_Node *Node, int Pos);
+ int   USB_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
 tVFS_Node      *USB_FindDir(tVFS_Node *Node, const char *Name);
  int   USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
 
@@ -43,8 +44,7 @@ tDevFS_Driver gUSB_DrvInfo = {
  */
 int USB_Install(char **Arguments)
 {
-       Log_Warning("USB", "Not Complete - Devel Only");
-       
+       USB_PortCtl_Init();
        Proc_SpawnWorker(USB_PollThread, NULL);
        Proc_SpawnWorker(USB_AsyncThread, NULL);
        
@@ -62,9 +62,9 @@ void USB_Cleanup()
  * \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
  * \brief Read from the USB root
  */
-char *USB_ReadDir(tVFS_Node *Node, int Pos)
+int USB_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
 {
-       return NULL;
+       return -ENOTIMPL;
 }
 
 /**
diff --git a/KernelLand/Modules/USB/Core/portctl.c b/KernelLand/Modules/USB/Core/portctl.c
new file mode 100644 (file)
index 0000000..1f6cf86
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * portctl.c
+ * - Port control code
+ */
+#define DEBUG  1
+#define SANITY 1
+#include <acess.h>
+#include "usb.h"
+#include <workqueue.h>
+#include <timers.h>
+#include <usb_hub.h>
+
+// === PROTOTYPES ===
+void   USB_PortCtl_Init(void);
+void   USB_PortCtl_Worker(void *Unused);
+void   USB_PortCtl_SetPortFeature(tUSBHub *Hub, int Port, int Feat);
+void   USB_PortCtl_ClearPortFeature(tUSBHub *Hub, int Port, int Feat);
+ int   USB_PortCtl_GetPortStatus(tUSBHub *Hub, int Port, int Flag);
+
+// === GLOBALS === 
+tWorkqueue     gUSB_PortCtl_WorkQueue;
+
+// === CODE ===
+void USB_PortCtl_Init(void)
+{
+       Workqueue_Init(&gUSB_PortCtl_WorkQueue, "USB Port Reset Work Queue", offsetof(tUSBHubPort, ListNext));
+       Proc_SpawnWorker(USB_PortCtl_Worker, NULL);
+}
+
+void USB_PortCtl_Worker(void *Unused)
+{
+       Threads_SetName("USB PortCtl Worker");
+       for(;;)
+       {
+               tUSBHubPort *port;
+               tUSBHub *hub;
+              
+               port = Workqueue_GetWork(&gUSB_PortCtl_WorkQueue);
+               if( !port ) {
+                       Log_Warning("USB", "PortCtl Workqueue returned NULL");
+                       break;
+               }
+               hub = (tUSBHub*)(port - port->PortNum) - 1;
+
+               LOG("port = %p, hub = %p", port, hub);
+
+               switch(port->Status)
+               {
+               case 1:
+                       // Assert reset
+                       USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_RESET);
+                       LOG("Port reset starting");
+                       // Wait 50 ms
+                       Time_Delay(50);
+                       USB_PortCtl_ClearPortFeature(hub, port->PortNum, PORT_RESET);
+                       Time_Delay(10); // May take up to 2ms for reset to clear
+                       // Enable port
+                       LOG("Port enabling");
+                       USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_ENABLE);
+                       // Begin connect processing
+                       port->Status = 2;
+                       USB_DeviceConnected(hub, port->PortNum);
+                       break;
+               }
+       }
+}
+
+void USB_PortCtl_BeginReset(tUSBHub *Hub, int Port)
+{
+       LOG("Starting %p %i", Hub, Port);
+       // Set status field in hub structure
+       Hub->Ports[Port].Status = 1;
+       Hub->Ports[Port].PortNum = Port;
+       // Add to the work queue
+       Workqueue_AddWork(&gUSB_PortCtl_WorkQueue, &Hub->Ports[Port]);
+}
+
+void USB_PortCtl_SetPortFeature(tUSBHub *Hub, int Port, int Feat)
+{
+       if( Hub->Interface->Driver == NULL ) {
+               // - Host Port
+               tUSBHost        *host = Hub->Interface->Dev->Host;
+               ASSERT(host->HostDef->SetPortFeature);
+               host->HostDef->SetPortFeature(host->Ptr, Port, Feat);
+       }
+       else {
+               // - Hub Port
+               Hub_SetPortFeature(Hub->Interface, Port, Feat);
+       }
+}
+
+void USB_PortCtl_ClearPortFeature(tUSBHub *Hub, int Port, int Feat)
+{
+       if( Hub->Interface->Driver == NULL ) {
+               // - Host Port
+               tUSBHost        *host = Hub->Interface->Dev->Host;
+               ASSERT(host->HostDef->ClearPortFeature);
+               host->HostDef->ClearPortFeature(host->Ptr, Port, Feat);
+       }
+       else {
+               // - Hub Port
+               Hub_ClearPortFeature(Hub->Interface, Port, Feat);
+       }
+}
+
+int USB_PortCtl_GetPortStatus(tUSBHub *Hub, int Port, int Flag)
+{
+       if( Hub->Interface->Driver == NULL ) {
+               // - Host Port
+               tUSBHost        *host = Hub->Interface->Dev->Host;
+               ASSERT(host->HostDef->GetPortStatus);
+               return host->HostDef->GetPortStatus(host->Ptr, Port, Flag);
+       }
+       else {
+               // - Hub Port
+               return Hub_GetPortStatus(Hub->Interface, Port, Flag);
+       }
+       return 0;
+}
+
index e20f53c..3234a77 100644 (file)
@@ -31,7 +31,7 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
 {
        tUSBHost        *host;
        
-       host = malloc(sizeof(tUSBHost) + nPorts*sizeof(void*));
+       host = malloc(sizeof(tUSBHost) + nPorts*sizeof(tUSBHubPort));
        if(!host) {
                // Oh, bugger.
                return NULL;
@@ -43,6 +43,8 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
        host->RootHubDev.ParentHub = NULL;
        host->RootHubDev.Host = host;
        host->RootHubDev.Address = 0;
+       ASSERT(HostDef->InitControl);
+       host->RootHubDev.EndpointHandles[0] = HostDef->InitControl(ControllerPtr, 0, 64);
 
 //     host->RootHubIf.Next = NULL;
        host->RootHubIf.Dev = &host->RootHubDev;
@@ -52,7 +54,7 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts)
 
        host->RootHub.Interface = &host->RootHubIf;
        host->RootHub.nPorts = nPorts;
-       memset(host->RootHub.Devices, 0, sizeof(void*)*nPorts);
+       memset(host->RootHub.Ports, 0, sizeof(tUSBHubPort)*nPorts);
 
        // Append to list
        Mutex_Acquire( &glUSB_Hosts );
@@ -97,10 +99,10 @@ tUSBHub *USB_RegisterHub(tUSBInterface *Device, int PortCount)
 {
        tUSBHub *ret;
        
-       ret = malloc(sizeof(tUSBHub) + sizeof(ret->Devices[0])*PortCount);
+       ret = malloc(sizeof(tUSBHub) + sizeof(ret->Ports[0])*PortCount);
        ret->Interface = Device;
        ret->nPorts = PortCount;
-       memset(ret->Devices, 0, sizeof(ret->Devices[0])*PortCount);
+       memset(ret->Ports, 0, sizeof(ret->Ports[0])*PortCount);
        return ret;
 }
 
@@ -108,7 +110,7 @@ void USB_RemoveHub(tUSBHub *Hub)
 {
        for( int i = 0; i < Hub->nPorts; i ++ )
        {
-               if( Hub->Devices[i] )
+               if( Hub->Ports[i].Dev )
                {
                        USB_DeviceDisconnected( Hub, i );
                }
index 5a13363..c5c8cad 100644 (file)
 #include <usb_core.h>
 #include <usb_hub.h>
 #include <usb_host.h>
+#include "usb_proto.h"
 
+typedef struct sUSBHubPort     tUSBHubPort;
 typedef struct sUSBHost        tUSBHost;
 typedef struct sUSBDevice      tUSBDevice;
 typedef struct sUSBEndpoint    tUSBEndpoint;
 
 // === STRUCTURES ===
+struct sUSBHubPort
+{
+       void    *ListNext;
+       char    Status;
+       char    PortNum;
+       tUSBDevice      *Dev;
+};
+
 /**
  * \brief USB Hub data
  */
@@ -25,7 +35,7 @@ struct sUSBHub
        tUSBInterface   *Interface;
        
         int    nPorts;
-       tUSBDevice      *Devices[];
+       struct sUSBHubPort      Ports[];
 };
 
 struct sUSBEndpoint
@@ -34,6 +44,7 @@ struct sUSBEndpoint
        tUSBInterface   *Interface;
         int    EndpointIdx;    // Interface endpoint index
         int    EndpointNum;    // Device endpoint num
+       void    *EndpointHandle;
        
         int    PollingPeriod;  // In 1ms intervals
         int    MaxPacketSize;  // In bytes
@@ -53,6 +64,8 @@ struct sUSBInterface
 
        tUSBDriver      *Driver;
        void    *Data;
+
+       struct sDescriptor_Interface    IfaceDesc;
        
         int    nEndpoints;
        tUSBEndpoint    Endpoints[];
@@ -71,6 +84,10 @@ struct sUSBDevice
        tUSBHost        *Host;
         int    Address;
 
+       void    *EndpointHandles[16];
+
+       struct sDescriptor_Device       DevDesc;
+
         int    nInterfaces;
        tUSBInterface   *Interfaces[];
 };
index 7b1b724..0da8c85 100644 (file)
@@ -5,7 +5,7 @@
  * usb_devinit.c
  * - USB Device Initialisation
  */
-#define DEBUG  1
+#define DEBUG  0
 #include <acess.h>
 #include <vfs.h>
 #include <drv_pci.h>
@@ -13,7 +13,7 @@
 #include "usb_proto.h"
 #include "usb_lowlevel.h"
 
-#define DUMP_DESCRIPTORS       0
+#define DUMP_DESCRIPTORS       1
 
 // === PROTOTYPES ===
 void   USB_DeviceConnected(tUSBHub *Hub, int Port);
@@ -21,6 +21,7 @@ void  USB_DeviceDisconnected(tUSBHub *Hub, int Port);
 void   *USB_GetDeviceDataPtr(tUSBInterface *Dev);
 void   USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
  int   USB_int_AllocateAddress(tUSBHost *Host);
+void   USB_int_DeallocateAddress(tUSBHost *Host, int Address);
 
 // === CODE ===
 void USB_DeviceConnected(tUSBHub *Hub, int Port)
@@ -28,7 +29,7 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
        tUSBDevice      tmpdev;
        tUSBDevice      *dev = &tmpdev;
        if( Port >= Hub->nPorts )       return ;
-       if( Hub->Devices[Port] )        return ;
+       if( Hub->Ports[Port].Dev )      return ;
 
        ENTER("pHub iPort", Hub, Port);
 
@@ -49,33 +50,51 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
        }
        USB_int_SendSetupSetAddress(dev->Host, dev->Address);
        LOG("Assigned address %i", dev->Address);
-       
+
+       dev->EndpointHandles[0] = dev->Host->HostDef->InitControl(dev->Host->Ptr, dev->Address << 4, 64);
+       for( int i = 1; i < 16; i ++ )
+               dev->EndpointHandles[i] = 0;
+
        // 2. Get device information
        {
                struct sDescriptor_Device       desc;
+               desc.Length = 0;
                LOG("Getting device descriptor");
                // Endpoint 0, Desc Type 1, Index 0
                USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc);
 
+               if( desc.Length < sizeof(desc) ) {
+                       Log_Error("USB", "Device descriptor undersized (%i<%i)", desc.Length, sizeof(desc));
+                       USB_int_DeallocateAddress(dev->Host, dev->Address);
+                       LEAVE('-');
+                       return;
+               }
+               if( desc.Type != 1 ) {
+                       Log_Error("USB", "Device descriptor type invalid (%i!=1)", desc.Type);
+                       USB_int_DeallocateAddress(dev->Host, dev->Address);
+                       LEAVE('-');
+                       return;
+               }
+
                #if DUMP_DESCRIPTORS            
                LOG("Device Descriptor = {");
                LOG(" .Length = %i", desc.Length);
                LOG(" .Type = %i", desc.Type);
-               LOG(" .USBVersion = 0x%04x", desc.USBVersion);
+               LOG(" .USBVersion = 0x%04x", LittleEndian16(desc.USBVersion));
                LOG(" .DeviceClass = 0x%02x", desc.DeviceClass);
                LOG(" .DeviceSubClass = 0x%02x", desc.DeviceSubClass);
                LOG(" .DeviceProtocol = 0x%02x", desc.DeviceProtocol);
                LOG(" .MaxPacketSize = 0x%02x", desc.MaxPacketSize);
-               LOG(" .VendorID = 0x%04x", desc.VendorID);
-               LOG(" .ProductID = 0x%04x", desc.ProductID);
-               LOG(" .DeviceID = 0x%04x", desc.DeviceID);
+               LOG(" .VendorID = 0x%04x",  LittleEndian16(desc.VendorID));
+               LOG(" .ProductID = 0x%04x", LittleEndian16(desc.ProductID));
+               LOG(" .DeviceID = 0x%04x",  LittleEndian16(desc.DeviceID));
                LOG(" .ManufacturerStr = Str %i", desc.ManufacturerStr);
                LOG(" .ProductStr = Str %i", desc.ProductStr);
                LOG(" .SerialNumberStr = Str %i", desc.SerialNumberStr);
-               LOG(" .NumConfigurations = %i", desc.SerialNumberStr);
+               LOG(" .NumConfigurations = %i", desc.NumConfigurations);
                LOG("}");
        
-               #if DEBUG       
+               #if DEBUG
                if( desc.ManufacturerStr )
                {
                        char    *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr);
@@ -102,11 +121,12 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                }
                #endif
                #endif
+               
+               memcpy(&dev->DevDesc, &desc, sizeof(desc));
        }
 
-       // TODO: Support alternate configurations
-       
        // 3. Get configurations
+       // TODO: Support alternate configurations
        for( int i = 0; i < 1; i ++ )
        {
                struct sDescriptor_Configuration        desc;
@@ -115,6 +135,13 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                size_t  total_length;
        
                USB_int_ReadDescriptor(dev, 0, 2, i, sizeof(desc), &desc);
+               if( desc.Length < sizeof(desc) ) {
+                       // ERROR: 
+               }
+               if( desc.Type != 2 ) {
+                       // ERROR: 
+               }
+               // TODO: Check return length? (Do we get a length?)
                #if DUMP_DESCRIPTORS
                LOG("Configuration Descriptor %i = {", i);
                LOG(" .Length = %i", desc.Length);
@@ -133,6 +160,11 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                }
                #endif
 
+               if( desc.NumInterfaces == 0 ) {
+                       Log_Notice("USB", "Device does not have any interfaces");
+                       continue ;
+               }
+
                // TODO: Split here and allow some method of selection
 
                // Allocate device now that we have the configuration
@@ -144,10 +176,10 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                total_length = LittleEndian16(desc.TotalLength);
                full_buf = malloc( total_length );
                USB_int_ReadDescriptor(dev, 0, 2, i, total_length, full_buf);
-
                ptr_ofs += desc.Length;
 
-               // TODO: Interfaces
+
+               // Interfaces!
                for( int j = 0; ptr_ofs < total_length && j < desc.NumInterfaces; j ++ )
                {
                        struct sDescriptor_Interface *iface;
@@ -179,21 +211,23 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                        LOG(" .InterfaceClass = 0x%x", iface->InterfaceClass);
                        LOG(" .InterfaceSubClass = 0x%x", iface->InterfaceSubClass);
                        LOG(" .InterfaceProcol = 0x%x", iface->InterfaceProtocol);
-                       # if DEBUG      
                        if( iface->InterfaceStr ) {
                                char    *tmp = USB_int_GetDeviceString(dev, 0, iface->InterfaceStr);
                                LOG(" .InterfaceStr = %i '%s'", iface->InterfaceStr, tmp);
                                free(tmp);
                        }
-                       # endif
                        LOG("}");
                        #endif
 
-                       dev_if = malloc(sizeof(tUSBInterface) + iface->NumEndpoints*sizeof(dev_if->Endpoints[0]));
+                       dev_if = malloc(
+                               sizeof(tUSBInterface)
+                               + iface->NumEndpoints*sizeof(dev_if->Endpoints[0])
+                               );
                        dev_if->Dev = dev;
                        dev_if->Driver = NULL;
                        dev_if->Data = NULL;
                        dev_if->nEndpoints = iface->NumEndpoints;
+                       memcpy(&dev_if->IfaceDesc, iface, sizeof(*iface));
                        dev->Interfaces[j] = dev_if;
 
                        // Copy interface data
@@ -222,7 +256,14 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                                LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize));
                                LOG(" .PollingInterval = %i", endpt->PollingInterval);
                                LOG("}");
-                               
+       
+                               // Make sure things don't break
+                               if( !((endpt->Address & 0x7F) < 15) ) {
+                                       Log_Error("USB", "Endpoint number %i>16", endpt->Address & 0x7F);
+                                       k --;
+                                       continue ;
+                               }
+
                                dev_if->Endpoints[k].Next = NULL;
                                dev_if->Endpoints[k].Interface = dev_if;
                                dev_if->Endpoints[k].EndpointIdx = k;
@@ -232,6 +273,33 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                                dev_if->Endpoints[k].Type = endpt->Attributes | (endpt->Address & 0x80);
                                dev_if->Endpoints[k].PollingAtoms = 0;
                                dev_if->Endpoints[k].InputData = NULL;
+                               
+                               // TODO: Register endpoint early
+                                int    ep_num = endpt->Address & 15;
+                               if( dev->EndpointHandles[ep_num] ) {
+                                       Log_Notice("USB", "Device %p:%i ep %i reused", dev->Host->Ptr, dev->Address, ep_num);
+                               }
+                               else {
+                                        int    addr = dev->Address*16+ep_num;
+                                        int    mps = dev_if->Endpoints[k].MaxPacketSize;
+                                       void *handle = NULL;
+                                       switch( endpt->Attributes & 3)
+                                       {
+                                       case 0: // Control
+                                               handle = dev->Host->HostDef->InitControl(dev->Host->Ptr, addr, mps);
+                                               break;
+                                       case 1: // Isochronous
+                                       //      handle = dev->Host->HostDef->InitIsoch(dev->Host->Ptr, addr, mps);
+                                               break;
+                                       case 2: // Bulk
+                                               handle = dev->Host->HostDef->InitBulk(dev->Host->Ptr, addr, mps);
+                                               break;
+                                       case 3: // Interrupt
+                                       //      handle = dev->Host->HostDef->InitInterrupt(dev->Host->Ptr, addr, ...);
+                                               break;
+                                       }
+                                       dev->EndpointHandles[ep_num] = handle;
+                               }
                        }
                        
                        // Initialise driver
@@ -246,24 +314,46 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port)
                                        );
                        }
                        else {
+                               LOG("Driver '%s' in use", dev_if->Driver->Name);
                                dev_if->Driver->Connected(
                                        dev_if,
                                        full_buf + iface_base_ofs, ptr_ofs - iface_base_ofs
                                        );
-                       //      dev_if->Driver->Connected( dev_if );
                        }
                }
                
                free(full_buf);
        }
-
+       
+       Hub->Ports[Port].Dev = dev;
+       
        // Done.
        LEAVE('-');
 }
 
 void USB_DeviceDisconnected(tUSBHub *Hub, int Port)
 {
-       
+       tUSBDevice      *dev;
+       if( !Hub->Ports[Port].Dev ) {
+               Log_Error("USB", "Non-registered device disconnected");
+               return;
+       }
+       dev = Hub->Ports[Port].Dev;
+
+       // TODO: Free related resources
+       // - Endpoint registrations
+       for( int i = 0; i < 16; i ++ )
+       {
+               if(dev->EndpointHandles[i])
+                       dev->Host->HostDef->RemEndpoint(dev->Host->Ptr, dev->EndpointHandles[i]);
+       }
+
+       // - Bus Address
+       USB_int_DeallocateAddress(dev->Host, dev->Address);
+       // - Inform handler
+       // - Release memory
+       free(dev);
+       Hub->Ports[Port].Dev = NULL;
 }
 
 void *USB_GetDeviceDataPtr(tUSBInterface *Dev) { return Dev->Data; }
diff --git a/KernelLand/Modules/USB/Core/usb_info.c b/KernelLand/Modules/USB/Core/usb_info.c
new file mode 100644 (file)
index 0000000..7a2bf82
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Acess 2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_info.c
+ * - USB Device Information Functions (helpers for drivers)
+ */
+#include <usb_core.h>
+#include "usb.h"
+#include "usb_lowlevel.h"
+
+// === CODE ===
+Uint32 USB_GetInterfaceClass(tUSBInterface *Dev)
+{
+       return ((Uint32)Dev->IfaceDesc.InterfaceClass << 16)
+               |((Uint32)Dev->IfaceDesc.InterfaceSubClass << 8)
+               |((Uint32)Dev->IfaceDesc.InterfaceProtocol << 0);
+}
+
+void USB_GetDeviceVendor(tUSBInterface *Dev, Uint16 *VendorID, Uint16 *DeviceID)
+{
+       *VendorID = LittleEndian16( Dev->Dev->DevDesc.VendorID );
+       *DeviceID = LittleEndian16( Dev->Dev->DevDesc.DeviceID );
+}
+char *USB_GetSerialNumber(tUSBInterface *Dev)
+{
+       return USB_int_GetDeviceString(Dev->Dev, 0, Dev->Dev->DevDesc.SerialNumberStr);
+}
+
index a1bf50b..de6f6f1 100644 (file)
 #include "usb.h"
 #include "usb_lowlevel.h"
 #include <workqueue.h>
+#include <events.h>
 #include "usb_async.h"
 
 // === PROTOTYPES ===
 void   USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data);
 void   USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
+void   USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data);
+void   USB_WakeCallback(void *Ptr, void *Buf, size_t Length);
 void   USB_AsyncCallback(void *Ptr, void *Buf, size_t Length);
 void   USB_AsyncThread(void *unused);
 
@@ -42,24 +45,63 @@ void USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Valu
        else
                endpt = 0;
        
-       USB_int_Request(Iface->Dev->Host, Iface->Dev->Address, endpt, Type, Req, Value, Index, Len, Data);
+       USB_int_Request(Iface->Dev, endpt, Type, Req, Value, Index, Len, Data);
 }
 
 
-void USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data)
 {
-       Log_Warning("USB", "TODO: Implement USB_SendData");
+       tUSBHost *host;
+       tUSBEndpoint    *ep;
+       void    *dest_hdl;
+       ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
+
+       host = Dev->Dev->Host;
+       ep = &Dev->Endpoints[Endpoint-1];
+       dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum];
+       LOG("dest_hdl = %p", dest_hdl);
+       if( !dest_hdl ) {
+               Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum);
+               LEAVE('-');
+               return;
+       }
+
+       Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
+       host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 1, (void*)Data, Length);
+       Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
+       
+       LEAVE('-');
 }
 
-void USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data)
 {
-       Log_Warning("USB", "TODO: Implement USB_RecvData");
+       tUSBHost *host;
+       tUSBEndpoint    *ep;
+       void    *dest_hdl;
+       ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
+
+       host = Dev->Dev->Host;
+       ep = &Dev->Endpoints[Endpoint-1];
+       dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum];
+       LOG("dest_hdl = %p", dest_hdl);
+       if( !dest_hdl ) {
+               Log_Notice("USB", "_RecvData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum);
+               LEAVE('-');
+               return;
+       }
+
+       Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
+       host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 0, Data, Length);
+       Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
+       
+       LEAVE('-');
 }
 
-void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback)
+void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBuf)
 {
        tAsyncOp *op;
        tUSBHost *host;
+       void    *dest_hdl;
 
        ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf); 
 
@@ -69,22 +111,27 @@ void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf,
        op->Length = Length;
        op->Data = DataBuf;
 
-       // TODO: Handle transfers that are larger than one packet
-       // TODO: Data toggle
-
        host = Dev->Dev->Host;
+       dest_hdl = Dev->Dev->EndpointHandles[op->Endpt->EndpointNum];
+       if( !dest_hdl ) {
+               Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, op->Endpt->EndpointNum);
+               LEAVE('-');
+               return;
+       }
+       
        LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum);
-       host->HostDef->BulkIN(
-               host->Ptr, Dev->Dev->Address*16 + op->Endpt->EndpointNum,
-               0, USB_AsyncCallback, op,
-               DataBuf, Length
-               );
+       host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_AsyncCallback, op, 0, DataBuf, Length);
        
        LEAVE('-');
 
 //     Log_Warning("USB", "TODO: Implement USB_RecvDataA");
 }
 
+void USB_WakeCallback(void *Ptr, void *Buf, size_t Length)
+{
+       Threads_PostEvent(Ptr, THREAD_EVENT_SHORTWAIT);
+}
+
 void USB_AsyncCallback(void *Ptr, void *Buf, size_t Length)
 {
        tAsyncOp *op = Ptr;
index 6b38e65..57948ce 100644 (file)
@@ -14,7 +14,7 @@
 #include <events.h>
 
 // === PROTOTYPES ===
-void   *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+void   *USB_int_Request(tUSBDevice *Dev, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
 void   USB_int_WakeThread(void *Thread, void *Data, size_t Length);
  int   USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
  int   USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
@@ -22,16 +22,28 @@ char        *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
  int   _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
 
 // === CODE ===
-void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
+void *USB_int_Request(tUSBDevice *Device, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
 {
+       tUSBHost        *Host = Device->Host;
        void    *hdl;
        // TODO: Sanity check (and check that Type is valid)
        struct sDeviceRequest   req;
-        int    dest = Addr * 16 + EndPt;       // TODO: Validate
        tThread *thisthread = Proc_GetCurThread();
+       void *dest_hdl;
+
+       ENTER("pDevice xEndPt iType iReq iVal iIndx iLen pData",
+               Device, EndPt, Type, Req, Val, Indx, Len, Data);
        
-       ENTER("pHost xdest iType iReq iVal iIndx iLen pData",
-               Host, dest, Type, Req, Val, Indx, Len, Data);
+       if( EndPt < 0 || EndPt >= 16 ) {
+               LEAVE('n');
+               return NULL;
+       }
+
+       dest_hdl = Device->EndpointHandles[EndPt];
+       if( !dest_hdl ) {
+               LEAVE('n');
+               return NULL;
+       }
        
        req.ReqType = Type;
        req.Request = Req;
@@ -41,36 +53,22 @@ void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, in
 
        Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
 
-       LOG("SETUP");   
-       hdl = Host->HostDef->ControlSETUP(Host->Ptr, dest, 0, &req, sizeof(req));
-
-       // TODO: Data toggle?
-       // TODO: Multi-packet transfers
-       if( Len > 0 )
-       {
-               if( Type & 0x80 )
-               {
-                       LOG("IN");
-                       hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, NULL, NULL, Data, Len);
-       
-                       LOG("OUT (Status)");
-                       hdl = Host->HostDef->ControlOUT(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
-               }
-               else
-               {
-                       LOG("OUT");
-                       Host->HostDef->ControlOUT(Host->Ptr, dest, 1, NULL, NULL, Data, Len);
-                       
-                       // Status phase (DataToggle=1)
-                       LOG("IN (Status)");
-                       hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
-               }
+       LOG("Send");
+       if( Type & 0x80 ) {
+               // Inbound data
+               hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 0,
+                       &req, sizeof(req),
+                       NULL, 0,
+                       Data, Len
+                       );
        }
-       else
-       {
-               // Zero length, IN status
-               LOG("IN (Status)");
-               hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
+       else {
+               // Outbound data
+               hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 1,
+                       &req, sizeof(req),
+                       Data, Len,
+                       NULL, 0
+                       );
        }
        LOG("Wait...");
        Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
@@ -86,20 +84,22 @@ void USB_int_WakeThread(void *Thread, void *Data, size_t Length)
 
 int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
 {
-       USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
+       USB_int_Request(&Host->RootHubDev, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
        return 0;
 }
 
 int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
 {
-       const int       ciMaxPacketSize = 0x400;
        struct sDeviceRequest   req;
-        int    bToggle = 0;
-       void    *final;
-        int    dest = Dev->Address*16 + Endpoint;
+       void    *dest_hdl;
+       
+       dest_hdl = Dev->EndpointHandles[Endpoint];
+       if( !dest_hdl ) {
+               return -1;
+       }
 
-       ENTER("pDev xdest iType iIndex iLength pDest",
-               Dev, dest, Type, Index, Length, Dest);
+       ENTER("pDev xEndpoint iType iIndex iLength pDest",
+               Dev, Endpoint, Type, Index, Length, Dest);
 
        req.ReqType = 0x80;
        req.ReqType |= ((Type >> 8) & 0x3) << 5;        // Bits 5/6
@@ -110,36 +110,19 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i
        req.Index = LittleEndian16( 0 );        // TODO: Language ID / Interface
        req.Length = LittleEndian16( Length );
 
-       LOG("SETUP");   
-       Dev->Host->HostDef->ControlSETUP(Dev->Host->Ptr, dest, 0, &req, sizeof(req));
-       
-       bToggle = 1;
-       while( Length > ciMaxPacketSize )
-       {
-               LOG("IN (%i rem)", Length - ciMaxPacketSize);
-               Dev->Host->HostDef->ControlIN(
-                       Dev->Host->Ptr, dest,
-                       bToggle, NULL, NULL,
-                       Dest, ciMaxPacketSize
-                       );
-               bToggle = !bToggle;
-               Length -= ciMaxPacketSize;
-       }
-
-       LOG("IN (final)");
-       Dev->Host->HostDef->ControlIN( Dev->Host->Ptr, dest, bToggle, NULL, NULL, Dest, Length );
-
        Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
-       LOG("OUT (Status)");
-       final = Dev->Host->HostDef->ControlOUT(
-               Dev->Host->Ptr, dest, 1,
-               USB_int_WakeThread, Proc_GetCurThread(),
-               NULL, 0
+       
+       LOG("Send");
+       Dev->Host->HostDef->SendControl(Dev->Host->Ptr, dest_hdl, USB_int_WakeThread, Proc_GetCurThread(), 0,
+               &req, sizeof(req),
+               NULL, 0,
+               Dest, Length
                );
 
        LOG("Waiting");
+       // TODO: Detect errors?
        Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
-
+       
        LEAVE('i', 0);
        return 0;
 }
index 9159cba..4282f28 100644 (file)
@@ -8,7 +8,7 @@
 #ifndef _USB_LOWLEVEL_H_
 #define _USB_LOWLEVEL_H_
 
-extern void    *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+extern void    *USB_int_Request(tUSBDevice *Dev, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
 extern int     USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
 extern int     USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
 extern char    *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
index 9cdd6b4..5a93269 100644 (file)
@@ -61,10 +61,9 @@ void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint)
 
        endpt->InputData = malloc(endpt->MaxPacketSize);
        LOG("Polling 0x%x at %i ms", Iface->Dev->Address * 16 + endpt->EndpointNum, endpt->PollingPeriod);
-       Iface->Dev->Host->HostDef->InterruptIN(
-               Iface->Dev->Host->Ptr,
-               Iface->Dev->Address * 16 + endpt->EndpointNum,
-               endpt->PollingPeriod,
+       Iface->Dev->Host->HostDef->InitInterrupt(
+               Iface->Dev->Host->Ptr, Iface->Dev->Address * 16 + endpt->EndpointNum,
+               0, endpt->PollingPeriod,
                USB_int_PollCallback, endpt,
                endpt->InputData, endpt->MaxPacketSize
                );
@@ -82,7 +81,8 @@ int USB_PollThread(void *unused)
                // Check hosts
                for( tUSBHost *host = gUSB_Hosts; host; host = host->Next )
                {
-                       host->HostDef->CheckPorts(host->Ptr);
+                       if( host->HostDef->CheckPorts )
+                               host->HostDef->CheckPorts(host->Ptr);
                }
 
                Time_Delay(100);
diff --git a/KernelLand/Modules/USB/EHCI/Makefile b/KernelLand/Modules/USB/EHCI/Makefile
new file mode 100644 (file)
index 0000000..069d030
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Acess2 EHCI Driver
+#
+
+OBJ = ehci.o
+CPPFLAGS = -I../Core/include
+NAME = EHCI
+
+-include ../Makefile.tpl
diff --git a/KernelLand/Modules/USB/EHCI/ehci.c b/KernelLand/Modules/USB/EHCI/ehci.c
new file mode 100644 (file)
index 0000000..50004c7
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * Acess2 EHCI Driver
+ * - By John Hodge (thePowersGang)
+ * 
+ * ehci.c
+ * - Driver Core
+ */
+#define DEBUG  1
+#define VERSION        VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include <usb_host.h>
+#include "ehci.h"
+#include <drv_pci.h>
+#include <limits.h>
+#include <events.h>
+#include <timers.h>
+
+// === CONSTANTS ===
+#define EHCI_MAX_CONTROLLERS   4
+#define EHCI_THREADEVENT_IOC   THREAD_EVENT_USER1
+#define EHCI_THREADEVENT_PORTSC        THREAD_EVENT_USER2
+
+// === PROTOTYPES ===
+ int   EHCI_Initialise(char **Arguments);
+ int   EHCI_Cleanup(void);
+ int   EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum);
+void   EHCI_InterruptHandler(int IRQ, void *Ptr);
+// -- API ---
+void   *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bInput, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void   *EHCI_InitIsoch  (void *Ptr, int Endpoint, size_t MaxPacketSize);
+void   *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize);
+void   *EHCI_InitBulk   (void *Ptr, int Endpoint, size_t MaxPacketSize);
+void   EHCI_RemEndpoint(void *Ptr, void *Handle);
+void   *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+       int isOutbound,
+       const void *SetupData, size_t SetupLength,
+       const void *OutData, size_t OutLength,
+       void *InData, size_t InLength
+       );
+void   *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length);
+void   EHCI_FreeOp(void *Ptr, void *Handle);
+Uint32 EHCI_int_RootHub_FeatToMask(int Feat);
+void   EHCI_RootHub_SetPortFeature(void *Ptr, int Port, int Feat);
+void   EHCI_RootHub_ClearPortFeature(void *Ptr, int Port, int Feat);
+ int   EHCI_RootHub_GetPortStatus(void *Ptr, int Port, int Flag);
+// --- Internals ---
+tEHCI_qTD      *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData);
+void   EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD);
+void   EHCI_int_AppendTD(tEHCI_Controller *Cont, tEHCI_QH *QH, tEHCI_qTD *TD);
+tEHCI_QH       *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize);
+void   EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH);
+void   EHCI_int_InterruptThread(void *ControllerPtr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_EHCI, EHCI_Initialise, NULL, "USB_Core", NULL);
+tEHCI_Controller       gaEHCI_Controllers[EHCI_MAX_CONTROLLERS];
+tUSBHostDef    gEHCI_HostDef = {
+       .InitInterrupt = EHCI_InitInterrupt,
+       .InitIsoch     = EHCI_InitIsoch,
+       .InitControl   = EHCI_InitControl,
+       .InitBulk      = EHCI_InitBulk,
+       .RemEndpoint   = EHCI_RemEndpoint,
+       .SendIsoch   = NULL,
+       .SendControl = EHCI_SendControl,
+       .SendBulk    = EHCI_SendBulk,
+       .FreeOp      = EHCI_FreeOp,
+       
+       .CheckPorts = NULL,     // No need
+       .SetPortFeature   = EHCI_RootHub_SetPortFeature,
+       .ClearPortFeature = EHCI_RootHub_ClearPortFeature,
+       .GetPortStatus    = EHCI_RootHub_GetPortStatus,
+       };
+
+// === CODE ===
+int EHCI_Initialise(char **Arguments)
+{
+       for( int id = -1; (id = PCI_GetDeviceByClass(0x0C0320, 0xFFFFFF, id)) >= 0;  )
+       {
+               Uint32  addr = PCI_GetBAR(id, 0);
+               if( addr == 0 ) {
+                       // Oops, PCI BIOS emulation time
+               }
+               Uint8   irq = PCI_GetIRQ(id);
+               if( irq == 0 ) {
+                       // TODO: The same
+               }
+
+               Log_Log("ECHI", "Controller at PCI %i 0x%x IRQ 0x%x",
+                       id, addr, irq);
+
+               if( EHCI_InitController(addr, irq) )
+               {
+                       // TODO: Detect other forms of failure than "out of slots"
+                       break ;
+               }
+
+               // TODO: Register with the USB stack
+       }
+       return 0;
+}
+
+int EHCI_Cleanup(void)
+{
+       return 0;
+}
+
+// --- Driver Init ---
+int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum)
+{
+       tEHCI_Controller        *cont = NULL;
+
+       for( int i = 0; i < EHCI_MAX_CONTROLLERS; i ++ )
+       {
+               if( gaEHCI_Controllers[i].PhysBase == 0 ) {
+                       cont = &gaEHCI_Controllers[i];
+                       cont->PhysBase = BaseAddress;
+                       break;
+               }
+       }
+       if(!cont) {
+               Log_Notice("EHCI", "Too many controllers (EHCI_MAX_CONTROLLERS=%i)",
+                       EHCI_MAX_CONTROLLERS);
+               return 1;
+       }
+
+       // - Nuke a couple of fields so error handling code doesn't derp
+       cont->CapRegs = NULL;
+       cont->PeriodicQueue = NULL;
+       cont->TDPool = NULL;
+
+       // -- Build up structure --
+       cont->CapRegs = (void*)MM_MapHWPages(BaseAddress, 1);
+       if( !cont->CapRegs ) {
+               Log_Warning("EHCI", "Can't map 1 page at %P into kernel space", BaseAddress);
+               goto _error;
+       }
+       // TODO: Error check
+       if( (cont->CapRegs->CapLength & 3) ) {
+               Log_Warning("EHCI", "Controller at %P non-aligned op regs", BaseAddress);
+               goto _error;
+       }
+       cont->OpRegs = (void*)( (Uint32*)cont->CapRegs + cont->CapRegs->CapLength / 4 );
+       // - Allocate periodic queue
+       tPAddr  unused;
+       cont->PeriodicQueue = (void*)MM_AllocDMA(1, 32, &unused);
+       if( !cont->PeriodicQueue ) {
+               Log_Warning("ECHI", "Can't allocate 1 32-bit page for periodic queue");
+               goto _error;
+       }
+       for( int i = 0; i < 1024; i ++ )
+               cont->PeriodicQueue[i] = 1;
+       // TODO: Error check
+       //  > Populate queue
+
+       // - Allocate TD pool
+       cont->TDPool = (void*)MM_AllocDMA(1, 32, &unused);
+       if( !cont->TDPool ) {
+               Log_Warning("ECHI", "Can't allocate 1 32-bit page for qTD pool");
+               goto _error;
+       }
+       for( int i = 0; i < TD_POOL_SIZE; i ++ ) {
+               cont->TDPool[i].Token = 3 << 8;
+       }
+
+       // Get port count
+       cont->nPorts = cont->CapRegs->HCSParams & 0xF;
+
+       // -- Bind IRQ --
+       IRQ_AddHandler(InterruptNum, EHCI_InterruptHandler, cont);
+       cont->InterruptThread = Proc_SpawnWorker(EHCI_int_InterruptThread, cont);
+       if( !cont->InterruptThread ) {
+               Log_Warning("EHCI", "Can't spawn interrupt worker thread");
+               goto _error;
+       }
+       LOG("cont->InterruptThread = %p", cont->InterruptThread);
+
+       // -- Initialisation procedure (from ehci-r10) --
+       // - Reset controller
+       cont->OpRegs->USBCmd = USBCMD_HCReset;
+       // - Set CTRLDSSEGMENT (TODO: 64-bit support)
+       // - Set USBINTR
+       cont->OpRegs->USBIntr = USBINTR_IOC|USBINTR_PortChange|USBINTR_FrameRollover;
+       // - Set PERIODICLIST BASE
+       cont->OpRegs->PeridocListBase = MM_GetPhysAddr( cont->PeriodicQueue );
+       // - Enable controller
+       cont->OpRegs->USBCmd = (0x40 << 16) | USBCMD_PeriodicEnable | USBCMD_Run;
+       // - Route all ports
+       cont->OpRegs->ConfigFlag = 1;
+
+       cont->DeadTD = EHCI_int_AllocateTD(cont, 0, NULL, 0, NULL, NULL);
+       cont->DeadTD->Link = 1;
+       cont->DeadTD->Link2 = 1;
+       cont->DeadTD->Token = 0;
+
+       // -- Register with USB Core --
+       cont->RootHub = USB_RegisterHost(&gEHCI_HostDef, cont, cont->nPorts);
+
+       return 0;
+_error:
+       cont->PhysBase = 0;
+       if( cont->CapRegs )
+               MM_Deallocate( (tVAddr)cont->CapRegs );
+       if( cont->PeriodicQueue )
+               MM_Deallocate( (tVAddr)cont->PeriodicQueue );
+       if( cont->TDPool )
+               MM_Deallocate( (tVAddr)cont->TDPool );
+       return 2;
+}
+
+void EHCI_InterruptHandler(int IRQ, void *Ptr)
+{
+       tEHCI_Controller *Cont = Ptr;
+       Uint32  sts = Cont->OpRegs->USBSts;
+       
+       // Clear interrupts
+       Cont->OpRegs->USBSts = sts;     
+
+       if( sts & 0xFFFF0FC0 ) {
+               LOG("Oops, reserved bits set (%08x), funny hardware?", sts);
+               sts &= ~0xFFFF0FFC0;
+       }
+
+       // Unmask read-only bits
+       sts &= ~(0xF000);
+
+       if( sts & USBINTR_IOC ) {
+               // IOC
+               Threads_PostEvent(Cont->InterruptThread, EHCI_THREADEVENT_IOC);
+               sts &= ~USBINTR_IOC;
+       }
+
+       if( sts & USBINTR_PortChange ) {
+               // Port change, determine what port and poke helper thread
+               LOG("Port status change");
+               Threads_PostEvent(Cont->InterruptThread, EHCI_THREADEVENT_PORTSC);
+               sts &= ~USBINTR_PortChange;
+       }
+       
+       if( sts & USBINTR_FrameRollover ) {
+               // Frame rollover, used to aid timing (trigger per-second operations)
+               LOG("Frame rollover");
+               sts &= ~USBINTR_FrameRollover;
+       }
+
+       if( sts ) {
+               // Unhandled interupt bits
+               // TODO: Warn
+               LOG("WARN - Bitmask %x unhandled", sts);
+       }
+
+
+}
+
+// --------------------------------------------------------------------
+// USB API
+// --------------------------------------------------------------------
+void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bOutbound, int Period,
+       tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+{
+       tEHCI_Controller        *Cont = Ptr;
+        int    pow2period, period_pow;
+       
+       if( Endpoint >= 256*16 )
+               return NULL;
+       if( Period <= 0 )
+               return NULL;
+       if( Period > 256 )
+               Period = 256;
+
+       // Round the period to the closest power of two
+       pow2period = 1;
+       period_pow = 0;
+       // - Find the first power above the period
+       while( pow2period < Period )
+       {
+               pow2period *= 2;
+               period_pow ++;
+       }
+       // - Check which is closest
+       if( Period - pow2period / 2 > pow2period - Period )
+               Period = pow2period;
+       else {
+               Period = pow2period/2;
+               period_pow --;
+       }
+       
+       // Allocate a QH
+       tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, Length);
+       qh->Impl.IntPeriodPow = period_pow;
+
+       Mutex_Acquire(&Cont->PeriodicListLock);
+
+       // Choose an interrupt slot to use      
+       int minslot = 0, minslot_load = INT_MAX;
+       for( int slot = 0; slot < Period; slot ++ )
+       {
+                int    load = 0;
+               for( int i = 0; i < PERIODIC_SIZE; i += Period )
+                       load += Cont->InterruptLoad[i+slot];
+               if( load == 0 ) break;
+               if( load < minslot_load ) {
+                       minslot = slot;
+                       minslot_load = load;
+               }
+       }
+       // Increase loading on the selected slot
+       for( int i = minslot; i < PERIODIC_SIZE; i += Period )
+               Cont->InterruptLoad[i] += Length;
+       qh->Impl.IntOfs = minslot;
+
+       // Allocate TD for the data
+       tEHCI_qTD *td = EHCI_int_AllocateTD(Cont, (bOutbound ? PID_OUT : PID_IN), Buf, Length, Cb, CbData);
+       EHCI_int_AppendTD(Cont, qh, td);
+
+       // Insert into the periodic list
+       for( int i = 0; i < PERIODIC_SIZE; i += Period )
+       {
+               // Walk list until
+               // - the end is reached
+               // - this QH is found
+               // - A QH with a lower period is encountered
+               tEHCI_QH        *pqh = NULL;
+               tEHCI_QH        *nqh;
+               for( nqh = Cont->PeriodicQueueV[i]; nqh; pqh = nqh, nqh = nqh->Impl.Next )
+               {
+                       if( nqh == qh )
+                               break;
+                       if( nqh->Impl.IntPeriodPow < period_pow )
+                               break;
+               }
+
+               // Somehow, we've already been added to this queue.
+               if( nqh && nqh == qh )
+                       continue ;
+
+               if( qh->Impl.Next && qh->Impl.Next != nqh ) {
+                       Log_Warning("EHCI", "Suspected bookkeeping error on %p - int list %i+%i overlap",
+                               Cont, period_pow, minslot);
+                       break;
+               }
+
+               if( nqh ) {
+                       qh->Impl.Next = nqh;
+                       qh->HLink = MM_GetPhysAddr(nqh) | 2;
+               }
+               else {
+                       qh->Impl.Next = NULL;
+                       qh->HLink = 2|1;        // QH, Terminate
+               }
+
+               if( pqh ) {
+                       pqh->Impl.Next = qh;
+                       pqh->HLink = MM_GetPhysAddr(qh) | 2;
+               }
+               else {
+                       Cont->PeriodicQueueV[i] = qh;
+                       Cont->PeriodicQueue[i] = MM_GetPhysAddr(qh) | 2;
+               }
+       }
+       Mutex_Release(&Cont->PeriodicListLock);
+
+       return qh;
+}
+
+void *EHCI_InitIsoch(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+       return (void*)(tVAddr)(Endpoint + 1);
+}
+void *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+       tEHCI_Controller *Cont = Ptr;
+       
+       // Allocate a QH
+       tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, MaxPacketSize);
+       qh->CurrentTD = MM_GetPhysAddr(Cont->DeadTD);
+
+       // Append to async list 
+       if( Cont->LastAsyncHead ) {
+               Cont->LastAsyncHead->HLink = MM_GetPhysAddr(qh)|2;
+               Cont->LastAsyncHead->Impl.Next = qh;
+               LOG("- Placed after %p", Cont->LastAsyncHead);
+       }
+       else {
+               Cont->OpRegs->AsyncListAddr = MM_GetPhysAddr(qh)|2;
+       }
+       qh->HLink = Cont->OpRegs->AsyncListAddr;
+       Cont->OpRegs->USBCmd |= USBCMD_AsyncEnable;
+       Cont->LastAsyncHead = qh;
+
+       LOG("Created %p for %p Ep 0x%x - %i bytes MPS", qh, Ptr, Endpoint, MaxPacketSize);
+
+       return qh;
+}
+void *EHCI_InitBulk(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+       return EHCI_InitControl(Ptr, Endpoint, MaxPacketSize);
+}
+void EHCI_RemEndpoint(void *Ptr, void *Handle)
+{
+       if( Handle == NULL )
+               return ;
+       else if( (tVAddr)Handle <= 256*16 )
+               return ;        // Isoch
+       else {
+               tEHCI_QH        *qh = Ptr;
+
+               // Remove QH from list
+               // - If it's a polling endpoint, need to remove from all periodic lists
+               if( qh->Impl.IntPeriodPow != 0xFF) {
+                       // Poll
+               }
+               else {
+                       // GP
+               }
+               
+               // Deallocate QH
+               EHCI_int_DeallocateQH(Ptr, Handle);
+       }
+}
+
+void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+       int isOutbound,
+       const void *SetupData, size_t SetupLength,
+       const void *OutData, size_t OutLength,
+       void *InData, size_t InLength
+       )
+{
+       tEHCI_Controller *Cont = Ptr;
+       tEHCI_qTD       *td_setup, *td_data, *td_status;
+
+       // Sanity checks
+       if( (tVAddr)Dest <= 256*16 )
+               return NULL;
+
+       // Check size of SETUP and status
+       
+       // Allocate TDs
+       td_setup = EHCI_int_AllocateTD(Cont, PID_SETUP, (void*)SetupData, SetupLength, NULL, NULL);
+       if( isOutbound )
+       {
+               td_data = OutData ? EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, NULL, NULL) : NULL;
+               td_status = EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, Cb, CbData);
+       }
+       else
+       {
+               td_data = InData ? EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, NULL, NULL) : NULL;
+               td_status = EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, Cb, CbData);
+               td_status->Token |= (1 << 15);  // IOC
+       }
+
+       // Append TDs
+       if( td_data ) {
+               td_setup->Link = MM_GetPhysAddr(td_data);
+               td_data->Link = MM_GetPhysAddr(td_status) | 1;
+               td_data->Token |= (1 << 8);     // Active
+       }
+       else {
+               td_setup->Link = MM_GetPhysAddr(td_status) | 1;
+       }
+       td_setup->Token |= (1 << 8);    // Active
+       td_status->Token |= (1 << 8);
+       EHCI_int_AppendTD(Cont, Dest, td_setup);
+
+       return td_status;
+}
+
+void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length)
+{
+       tEHCI_Controller        *Cont = Ptr;
+       
+       // Sanity check the pointer
+       // - Can't be NULL or an isoch
+       if( (tVAddr)Dest <= 256*16 )
+               return NULL;
+       
+       // Allocate single TD
+       tEHCI_qTD       *td = EHCI_int_AllocateTD(Cont, (Dir ? PID_OUT : PID_IN), Data, Length, Cb, CbData);
+       EHCI_int_AppendTD(Cont, Dest, td);      
+
+       return td;
+}
+
+void EHCI_FreeOp(void *Ptr, void *Handle)
+{
+       tEHCI_Controller        *Cont = Ptr;
+
+       EHCI_int_DeallocateTD(Cont, Handle);
+}
+
+Uint32 EHCI_int_RootHub_FeatToMask(int Feat)
+{
+       switch(Feat)
+       {
+       case PORT_RESET:        return PORTSC_PortReset;
+       case PORT_ENABLE:       return PORTSC_PortEnabled;
+       default:
+               Log_Warning("EHCI", "Unknown root hub port feature %i", Feat);
+               return 0;
+       }
+}
+
+void EHCI_RootHub_SetPortFeature(void *Ptr, int Port, int Feat)
+{
+       tEHCI_Controller        *Cont = Ptr;
+       if(Port >= Cont->nPorts)        return;
+
+       Cont->OpRegs->PortSC[Port] |= EHCI_int_RootHub_FeatToMask(Feat);
+}
+
+void EHCI_RootHub_ClearPortFeature(void *Ptr, int Port, int Feat)
+{
+       tEHCI_Controller        *Cont = Ptr;
+       if(Port >= Cont->nPorts)        return;
+
+       Cont->OpRegs->PortSC[Port] &= ~EHCI_int_RootHub_FeatToMask(Feat);
+}
+
+int EHCI_RootHub_GetPortStatus(void *Ptr, int Port, int Flag)
+{
+       tEHCI_Controller        *Cont = Ptr;
+       if(Port >= Cont->nPorts)        return 0;
+
+       return !!(Cont->OpRegs->PortSC[Port] & EHCI_int_RootHub_FeatToMask(Flag));
+}
+
+// --------------------------------------------------------------------
+// Internals
+// --------------------------------------------------------------------
+tEHCI_qTD *EHCI_int_GetTDFromPhys(tEHCI_Controller *Cont, Uint32 Addr)
+{
+       if( Addr == 0 ) return NULL;
+       LOG("%p + (%x - %x)", Cont->TDPool, Addr, MM_GetPhysAddr(Cont->TDPool));
+       return Cont->TDPool + (Addr - MM_GetPhysAddr(Cont->TDPool))/sizeof(tEHCI_qTD);
+}
+
+tEHCI_qTD *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData)
+{
+//     Semaphore_Wait(&Cont->TDSemaphore, 1);
+       Mutex_Acquire(&Cont->TDPoolMutex);
+       for( int i = 0; i < TD_POOL_SIZE; i ++ )
+       {
+               if( ((Cont->TDPool[i].Token >> 8) & 3) != 3 )
+                       continue ;
+               Cont->TDPool[i].Token = (PID << 8) | (Length << 16);
+               // NOTE: Assumes that `Length` is <= PAGE_SIZE
+               Cont->TDPool[i].Pages[0] = MM_GetPhysAddr(Data);
+               if( (Cont->TDPool[i].Pages[0] & (PAGE_SIZE-1)) + Length - 1 > PAGE_SIZE )
+                       Cont->TDPool[i].Pages[1] = MM_GetPhysAddr((char*)Data + Length - 1) & ~(PAGE_SIZE-1);
+               Mutex_Release(&Cont->TDPoolMutex);
+               LOG("Allocated %p for PID %i on %p", &Cont->TDPool[i], PID, Cont);
+               return &Cont->TDPool[i];
+       }
+
+       Mutex_Release(&Cont->TDPoolMutex);
+       return NULL;
+}
+
+void EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD)
+{
+       UNIMPLEMENTED();
+}
+
+void EHCI_int_AppendTD(tEHCI_Controller *Cont, tEHCI_QH *QH, tEHCI_qTD *TD)
+{
+       tEHCI_qTD       *ptd = NULL;
+       Uint32  link = QH->CurrentTD;
+
+       // TODO: Need locking and validation here
+       while( link && !(link & 1) )
+       {
+               ptd = EHCI_int_GetTDFromPhys(Cont, link);
+               link = ptd->Link;
+       }
+       // TODO: Figure out how to follow this properly
+       if( !ptd ) {
+               QH->CurrentTD = MM_GetPhysAddr(TD);
+               LOG("Appended %p to beginning of %p", TD, QH);
+       }
+       else {
+               ptd->Link = MM_GetPhysAddr(TD);
+               LOG("Appended %p to end of %p", TD, QH);
+       }
+}
+
+tEHCI_QH *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize)
+{
+       tEHCI_QH        *ret;
+       Mutex_Acquire(&Cont->QHPoolMutex);
+       for( int i = 0; i < QH_POOL_SIZE; i ++ )
+       {
+               if( !MM_GetPhysAddr( Cont->QHPools[i/QH_POOL_NPERPAGE] ) ) {
+                       tPAddr  tmp;
+                       Cont->QHPools[i/QH_POOL_NPERPAGE] = (void*)MM_AllocDMA(1, 32, &tmp);
+                       memset(Cont->QHPools[i/QH_POOL_NPERPAGE], 0, PAGE_SIZE);
+               }
+
+               ret = &Cont->QHPools[i/QH_POOL_NPERPAGE][i%QH_POOL_NPERPAGE];
+               if( ret->HLink == 0 ) {
+                       ret->HLink = 1;
+                       ret->Overlay.Link = 1;
+                       ret->Endpoint = (Endpoint >> 4) | 0x80 | ((Endpoint & 0xF) << 8)
+                               | (MaxPacketSize << 16);
+                       // TODO: Endpoint speed (13:12) 0:Full, 1:Low, 2:High
+                       // TODO: Control Endpoint Flag (27) 0:*, 1:Full/Low Control
+                       Mutex_Release(&Cont->QHPoolMutex);
+                       return ret;
+               }
+       }
+       Mutex_Release(&Cont->QHPoolMutex);
+       return NULL;
+}
+
+void EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH)
+{
+       // TODO: Ensure it's unused (somehow)
+       QH->HLink = 0;
+}
+
+void EHCI_int_HandlePortConnectChange(tEHCI_Controller *Cont, int Port)
+{
+       // Connect Event
+       if( Cont->OpRegs->PortSC[Port] & PORTSC_CurrentConnectStatus )
+       {
+               // Is the device low-speed?
+               if( (Cont->OpRegs->PortSC[Port] & PORTSC_LineStatus_MASK) == PORTSC_LineStatus_Kstate )
+               {
+                       LOG("Low speed device on %p Port %i, giving to companion", Cont, Port);
+                       Cont->OpRegs->PortSC[Port] |= PORTSC_PortOwner;
+               }
+               // not a low-speed device, EHCI reset
+               else
+               {
+                       LOG("Device connected on %p #%i", Cont, Port);
+                       // Reset procedure.
+                       USB_PortCtl_BeginReset(Cont->RootHub, Port);
+               }
+       }
+       // Disconnect Event
+       else
+       {
+               if( Cont->OpRegs->PortSC[Port] & PORTSC_PortOwner ) {
+                       LOG("Companion port %i disconnected, taking it back", Port);
+                       Cont->OpRegs->PortSC[Port] &= ~PORTSC_PortOwner;
+               }
+               else {
+                       LOG("Port %i disconnected", Port);
+                       USB_DeviceDisconnected(Cont->RootHub, Port);
+               }
+       }
+}
+
+void EHCI_int_InterruptThread(void *ControllerPtr)
+{
+       tEHCI_Controller        *Cont = ControllerPtr;
+       while(Cont->OpRegs)
+       {
+               Uint32  events;
+               
+               LOG("sleeping for events");
+               events = Threads_WaitEvents(EHCI_THREADEVENT_IOC|EHCI_THREADEVENT_PORTSC);
+               if( !events ) {
+                       // TODO: Should this cause a termination?
+               }
+               LOG("events = 0x%x", events);
+
+               if( events & EHCI_THREADEVENT_IOC )
+               {
+                       // IOC, Do whatever it is you do
+               }
+
+               // Port status change interrupt
+               if( events & EHCI_THREADEVENT_PORTSC )
+               {
+                       // Check for port status changes
+                       for(int i = 0; i < Cont->nPorts; i ++ )
+                       {
+                               Uint32  sts = Cont->OpRegs->PortSC[i];
+                               LOG("Port %i: sts = %x", i, sts);
+                               Cont->OpRegs->PortSC[i] = sts;
+                               if( sts & PORTSC_ConnectStatusChange )
+                                       EHCI_int_HandlePortConnectChange(Cont, i);
+
+                               if( sts & PORTSC_PortEnableChange )
+                               {
+                                       // Handle enable/disable
+                               }
+
+                               if( sts & PORTSC_OvercurrentChange )
+                               {
+                                       // Handle over-current change
+                               }
+                       }
+               }
+
+               LOG("Going back to sleep");
+       }
+}
index 431b039..598c8d4 100644 (file)
@@ -8,6 +8,18 @@
 #ifndef _EHCI_H_
 #define _EHCI_H_
 
+#include <threads.h>
+
+#define PERIODIC_SIZE  1024
+
+typedef struct sEHCI_CapRegs   tEHCI_CapRegs;
+typedef struct sEHCI_OpRegs    tEHCI_OpRegs;
+typedef struct sEHCI_iTD       tEHCI_iTD;
+typedef struct sEHCI_siTD      tEHCI_siTD;
+typedef struct sEHCI_qTD       tEHCI_qTD;
+typedef struct sEHCI_QH        tEHCI_QH;
+typedef struct sEHCI_Controller        tEHCI_Controller;
+
 struct sEHCI_CapRegs
 {
        Uint8   CapLength;      // Byte offset of Operational registers
@@ -82,7 +94,7 @@ struct sEHCI_OpRegs
         * 15    = Asynchronous Schedule Status
         * 16:31 = Reserved ?(Zero)
         */
-       Uint32  USBSts;
+       volatile Uint32 USBSts;
        /**
         * USB Interrupt Enable Register
         *
@@ -100,7 +112,7 @@ struct sEHCI_OpRegs
         * 
         * Bits 14:3 are used as n index into PeridocListBase
         */
-       Uint32  FrIndex;
+       volatile Uint32 FrIndex;
        /**
         * Control Data Structure Segment Register
         *
@@ -149,7 +161,142 @@ struct sEHCI_OpRegs
         * 22    = Wake on Over-current Enable
         * 23:31 = Reserved (ZERO)
         */
-       Uint32  PortSC[15];
+       volatile Uint32 PortSC[15];
+};
+
+#define USBCMD_Run     0x0001
+#define USBCMD_HCReset 0x0002
+#define USBCMD_PeriodicEnable  0x0010
+#define USBCMD_AsyncEnable     0x0020
+
+#define USBINTR_IOC    0x0001
+#define USBINTR_Error  0x0002
+#define USBINTR_PortChange     0x0004
+#define USBINTR_FrameRollover  0x0008
+#define USBINTR_HostSystemError        0x0010
+#define USBINTR_AsyncAdvance   0x0020
+
+#define PORTSC_CurrentConnectStatus    0x0001
+#define PORTSC_ConnectStatusChange     0x0002
+#define PORTSC_PortEnabled     0x0004
+#define PORTSC_PortEnableChange        0x0008
+#define PORTSC_OvercurrentActive       0x0010
+#define PORTSC_OvercurrentChange       0x0020
+#define PORTSC_ForcePortResume 0x0040
+#define PORTSC_Suspend         0x0080
+#define PORTSC_PortReset       0x0100
+#define PORTSC_Reserved1       0x0200
+#define PORTSC_LineStatus_MASK 0x0C00
+#define PORTSC_LineStatus_SE0          0x0000
+#define PORTSC_LineStatus_Jstate       0x0400
+#define PORTSC_LineStatus_Kstate       0x0800
+#define PORTSC_LineStatus_Undef        0x0C00
+#define PORTSC_PortPower       0x1000
+#define PORTSC_PortOwner       0x2000
+#define PORTSC_PortIndicator_MASK      0xC000
+#define PORTSC_PortIndicator_Off       0x0000
+#define PORTSC_PortIndicator_Amber     0x4000
+#define PORTSC_PortIndicator_Green     0x800
+
+// Isochronous (High-Speed) Transfer Descriptor
+struct sEHCI_iTD
+{
+       Uint32  Link;
+       struct {
+               Uint16  Offset;
+               Uint16  LengthSts;
+       } Transactions[8];
+       // -- 0 --
+       // 0:6  - Device
+       // 7    - Reserved
+       // 8:11 - Endpoint
+       // -- 1 --
+       // 0:10 - Max packet size
+       // 11   - IN/OUT
+       Uint32  BufferPointers[8];      // Page aligned, low 12 bits are overloaded
+};
+
+// Split Transaction Isochronous Transfer Descriptor
+struct sEHCI_siTD
+{
+       Uint32  Link;
+       Uint32  Dest;
+       Uint32  uFrame;
+       Uint32  StatusLength;
+       Uint32  Page0;
+       Uint32  Page1;
+       Uint32  BackLink;
+};
+
+// Queue Element Transfer Descriptor
+struct sEHCI_qTD
+{
+       Uint32  Link;
+       Uint32  Link2;  // Used when there's a short packet
+       Uint32  Token;
+       Uint32  Pages[5];       //First has offset in low 12 bits
+       
+       // Internals (32 bytes = 4x 64-bit pointers)
+       tUSBHostCb      *Callback;
+       void    *CallbackData;
+       tEHCI_qTD       *Next;
+} __attribute__((aligned(32)));
+// sizeof = 64
+
+// Queue Head
+struct sEHCI_QH
+{
+       Uint32  HLink;  // Horizontal link
+       Uint32  Endpoint;
+       Uint32  EndpointExt;
+       Uint32  CurrentTD;
+       struct {
+               Uint32  Link;
+               Uint32  Link2;
+               Uint32  Token;
+               Uint32  Pages[5];
+       }       Overlay;
+       struct {
+               Uint8   IntOfs;
+               Uint8   IntPeriodPow;
+               tEHCI_QH        *Next;
+       } Impl;
+} __attribute__((aligned(32)));
+// sizeof = 48 (round up to 64)
+
+#define PID_OUT        0
+#define PID_IN         1
+#define PID_SETUP      2
+
+#define TD_POOL_SIZE   (PAGE_SIZE/sizeof(tEHCI_qTD))
+// - 256 addresses * 16 endpoints
+#define QH_POOL_SIZE   (256*16)
+#define QH_POOL_PAGES  (QH_POOL_SIZE*sizeof(tEHCI_QH)/PAGE_SIZE)
+#define QH_POOL_NPERPAGE       (PAGE_SIZE/sizeof(tEHCI_QH))
+
+struct sEHCI_Controller
+{
+       tUSBHub *RootHub;
+       tThread *InterruptThread;
+        int    nPorts;
+
+       tPAddr  PhysBase;
+       tEHCI_CapRegs   *CapRegs;
+       tEHCI_OpRegs    *OpRegs;
+
+       tEHCI_qTD       *DeadTD;
+
+        int    InterruptLoad[PERIODIC_SIZE];
+       tEHCI_QH        *LastAsyncHead;
+       
+       tMutex          PeriodicListLock;
+       Uint32          *PeriodicQueue;
+       tEHCI_QH        *PeriodicQueueV[PERIODIC_SIZE];
+       
+       tMutex  QHPoolMutex;
+       tEHCI_QH        *QHPools[QH_POOL_PAGES];        // [PAGE_SIZE/64]
+       tMutex  TDPoolMutex;
+       tEHCI_qTD       *TDPool;        // [TD_POOL_SIZE]
 };
 
 #endif
index 380518d..6a473c6 100644 (file)
@@ -137,7 +137,7 @@ void HID_Kb_Report_Input(tUSBInterface *Dev, tHID_ReportGlobalState *Global, tHI
                info->Info = NULL;
                info->CollectionDepth = 1;
                info->bIsBoot = 1;      // TODO: Detect non-boot keyboards and parse descriptor
-               Log_Warning("USB HID", "TODO: Handle non-boot keyboards!");
+               Log_Warning("USB HID", "TODO: Detect and handle non-boot keyboards!");
                info->Info = Keyboard_CreateInstance(0, "USBKeyboard");
        }
 }
index 6b36809..c280273 100644 (file)
@@ -149,7 +149,7 @@ void HID_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
        
        // --- Read and parse report descriptor ---
        // NOTE: Also does sub-driver selection and initialisation
-       Uint8   *report_data = alloca(report_len);
+       Uint8   report_data[report_len];
        USB_ReadDescriptor(Dev, 0x1022, 0, report_len, report_data);
        HID_int_ParseReport(Dev, report_data, report_len, &gHID_RootCallbacks);
        
diff --git a/KernelLand/Modules/USB/MSC/Makefile b/KernelLand/Modules/USB/MSC/Makefile
new file mode 100644 (file)
index 0000000..bb53fc9
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Acess2 USB MSC Driver
+#
+
+OBJ = main.o scsi.o
+CPPFLAGS = -I../Core/include
+NAME = MSC
+
+-include ../Makefile.tpl
+
diff --git a/KernelLand/Modules/USB/MSC/common.h b/KernelLand/Modules/USB/MSC/common.h
new file mode 100644 (file)
index 0000000..f459080
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * common.h
+ * - Common header
+ */
+#ifndef _MSC__COMMON_H_
+#define _MSC__COMMON_H_
+
+#include <usb_core.h>
+#include <Storage/LVM/include/lvm.h>
+
+typedef struct sMSCInfo        tMSCInfo;
+
+struct sMSCInfo
+{
+       Uint64  BlockCount;
+       size_t  BlockSize;
+};
+
+extern void    MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+extern void    MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+
+extern tLVM_VolType    gMSC_SCSI_VolType;
+extern Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
+#endif
+
diff --git a/KernelLand/Modules/USB/MSC/main.c b/KernelLand/Modules/USB/MSC/main.c
new file mode 100644 (file)
index 0000000..94d258a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ */
+#define DEBUG  1
+#define VERSION        VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include "common.h"
+#include "msc_proto.h"
+
+// === PROTOTYPES ===
+ int   MSC_Initialise(char **Arguments);
+ int   MSC_Cleanup(void);
+void   MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen);
+void   MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data);
+// --- Internal Helpers
+ int   MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen);
+void   MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+void   MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_MSC, MSC_Initialise, MSC_Cleanup, "USB_Core", NULL);
+tUSBDriver     gMSC_Driver_BulkOnly = {
+       .Name = "MSC_BulkOnly",
+       .Match = {.Class = {0x080050, 0xFF00FF}},
+       .Connected = MSC_DeviceConnected,
+       .MaxEndpoints = 2,
+       .Endpoints = {
+               {0x82, MSC_DataIn},
+               {0x02, NULL},
+               }
+       };
+int giMSC_NextTag;
+
+// === CODE ===
+int MSC_Initialise(char **Arguments)
+{
+       USB_RegisterDriver( &gMSC_Driver_BulkOnly );
+       return 0;
+}
+
+int MSC_Cleanup(void)
+{
+       return 0;
+}
+
+void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
+{
+       tMSCInfo        *info;
+       tLVM_VolType    *vt;
+       
+       info = malloc( sizeof(*info) );
+       USB_SetDeviceDataPtr(Dev, info);
+       
+       // Get the class code (and hence what command set is in use)
+       Uint8   sc = (USB_GetInterfaceClass(Dev) & 0x00FF00) >> 8;
+       switch( sc )
+       {
+       // SCSI Transparent Command Set
+       case 0x06:
+               info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
+               vt = &gMSC_SCSI_VolType;
+               break;
+       // Unknown, prepare to chuck sad
+       default:
+               Log_Error("USB MSC", "Unknown sub-class 0x%02x", sc);
+               USB_SetDeviceDataPtr(Dev, NULL);
+               free(info);
+               return ;
+       }
+
+       // Create device name from Vendor ID, Device ID and Serial Number
+       Uint16  vendor, devid;
+       char    *serial_number;
+       USB_GetDeviceVendor(Dev, &vendor, &devid);
+       serial_number = USB_GetSerialNumber(Dev);
+       if( !serial_number ) {
+               // No serial number - this breaks spec, but it's easy to handle
+               Log_Warning("USB MSC", "Device does not have a serial number, using a random one");
+               serial_number = malloc(4+8+1);
+               sprintf(serial_number, "rand%08x", rand());
+       }
+       char    name[4 + 4 + 1 + 4 + 1 + strlen(serial_number) + 1];
+       sprintf(name, "usb-%04x:%04x-%s", vendor, devid, serial_number);
+       free(serial_number);
+
+       // Pass the buck to LVM
+       LOG("Device '%s' has 0x%llx blocks of 0x%x bytes", name, info->BlockCount, info->BlockSize);
+       LVM_AddVolume(vt, name, Dev, info->BlockSize, info->BlockCount);
+}
+
+void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data)
+{
+       // Will this ever be needed?
+}
+
+/**
+ * \brief Create a CBW structure
+ */
+int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen)
+{
+       if( CmdLen == 0 ) {
+               Log_Error("MSC", "Zero length commands are invalid");
+               return -1;
+       }
+       
+       if( CmdLen > 16 ) {
+               Log_Error("MSC", "Command data >16 bytes (%i)", CmdLen);
+               return -1;
+       }
+       
+       Cbw->dCBWSignature = LittleEndian32(0x43425355);
+       Cbw->dCBWTag    = giMSC_NextTag ++;
+       Cbw->dCBWDataTransferLength = LittleEndian32(DataLen);
+       Cbw->bmCBWFlags = (bInput ? 0x80 : 0x00);
+       Cbw->bCBWLUN    = 0;    // TODO: Logical Unit Number (param from proto)
+       Cbw->bCBWLength = CmdLen;
+       memcpy(Cbw->CBWCB, CmdData, CmdLen);
+       
+       return 0;
+}
+
+void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
+{
+       tMSC_CBW        cbw;
+       tMSC_CSW        csw;
+       const int       endpoint_out = 2;
+       const int       endpoint_in = 1;
+       
+       if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) )
+               return ;
+       
+       // Send CBW
+       USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
+       
+       // Send Data
+       USB_SendData(Dev, endpoint_out, DataLen, Data);
+       
+       // Read CSW
+       USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
+       // TODO: Validate CSW
+}
+
+void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
+{
+       tMSC_CBW        cbw;
+       tMSC_CSW        csw;
+       const int       endpoint_out = 2;
+       const int       endpoint_in = 1;
+               
+       if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) )
+               return ;
+       
+       // Send CBW
+       USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
+       
+       // Read Data
+       // TODO: use async version and wait for the transaction to complete
+       USB_RecvData(Dev, endpoint_in, DataLen, Data);
+       
+       // Read CSW
+       USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
+       // TODO: Validate CSW
+}
+
diff --git a/KernelLand/Modules/USB/MSC/msc_proto.h b/KernelLand/Modules/USB/MSC/msc_proto.h
new file mode 100644 (file)
index 0000000..8cbd852
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ */
+#ifndef _MSC__MSC_PROTO_H_
+#define _MSC__MSC_PROTO_H_
+
+typedef struct sMSC_CBW        tMSC_CBW;
+typedef struct sMSC_CSW        tMSC_CSW;
+
+struct sMSC_CBW
+{
+       Uint32  dCBWSignature;  // = 0x43425355
+       Uint32  dCBWTag;
+       Uint32  dCBWDataTransferLength;
+       Uint8   bmCBWFlags;
+       Uint8   bCBWLUN;
+       Uint8   bCBWLength;
+       Uint8   CBWCB[16];
+} PACKED;
+
+struct sMSC_CSW
+{
+       Uint32  dCSWSignature;  // = 0x53425355
+       Uint32  dCSWTag;
+       Uint32  dCSWDataResidue;
+       Uint8   dCSWStatus;
+} PACKED;
+
+#endif
diff --git a/KernelLand/Modules/USB/MSC/scsi.c b/KernelLand/Modules/USB/MSC/scsi.c
new file mode 100644 (file)
index 0000000..c4220d8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * scsi.c
+ * - "SCSI Transparent Command Set" handling code
+ */
+#define DEBUG  0
+#include "common.h"
+#include "scsi.h"
+
+// === PROTOTYPES ===
+Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
+int    MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest);
+int    MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Dest);
+
+// === GLOBALS ===
+tLVM_VolType   gMSC_SCSI_VolType = {
+       .Name = "USB-MSC-SCSI",
+       .Read = MSC_SCSI_ReadData,
+       .Write = MSC_SCSI_WriteData
+       };
+
+// === CODE ===
+Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize)
+{
+       struct sSCSI_Cmd_ReadCapacity16 cmd;
+       struct sSCSI_Ret_ReadCapacity16 ret;
+       
+       cmd.Op   = 0x9E;
+       cmd.Svc  = 0x10;
+       cmd.LBA  = BigEndian64( 0 );
+       cmd.AllocationLength = BigEndian32(sizeof(ret));
+       cmd.Flags   = 0;
+       cmd.Control = 0;
+
+       ret.BlockSize = 0;
+       ret.BlockCount = 0;     
+       MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret);
+       
+       *BlockSize = BigEndian32(ret.BlockSize);
+       return BigEndian64(ret.BlockCount);
+}
+
+int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest)
+{
+       tUSBInterface   *Dev = Ptr;
+       tMSCInfo        *info = USB_GetDeviceDataPtr(Dev);
+       struct sSCSI_Cmd_Read16 cmd;
+
+       // TODO: Bounds checking?
+       
+       cmd.Op     = 0x88;
+       cmd.Flags  = 0;
+       cmd.LBA    = BigEndian64(Block);
+       cmd.Length = BigEndian32(Count);
+       cmd.GroupNumber = 0;
+       cmd.Control = 0;
+       
+       MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
+       // TODO: Error check    
+
+       return Count;
+}
+
+int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Data)
+{
+       Log_Warning("MSC_SCSI", "TODO: Impliment MSC_SCSI_WriteData");
+       return 0;
+}
+
diff --git a/KernelLand/Modules/USB/MSC/scsi.h b/KernelLand/Modules/USB/MSC/scsi.h
new file mode 100644 (file)
index 0000000..4795989
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * scsi.h
+ * - "SCSI Transparent Command Set" handling code
+ */
+#ifndef _MSC__SCSI_H_
+#define _MSC__SCSI_H_
+
+// NOTE: All commands are big-endian
+
+struct sSCSI_Cmd_ReadCapacity16
+{
+       Uint8   Op;     // 0x9E
+       Uint8   Svc;    // 0x10
+       Uint64  LBA;    //
+       Uint32  AllocationLength;
+       Uint8   Flags;
+       Uint8   Control;
+} PACKED;
+
+struct sSCSI_Ret_ReadCapacity16
+{
+       Uint64  BlockCount;
+       Uint32  BlockSize;
+       Uint8   Flags;
+       Uint8   _resvd[32-13];
+} PACKED;
+
+struct sSCSI_Cmd_Read16
+{
+       Uint8   Op;     // 0x88
+       Uint8   Flags;
+       Uint64  LBA;
+       Uint32  Length;
+       Uint8   GroupNumber;
+       Uint8   Control;
+} PACKED;
+
+#endif
+
index dd07210..0fe80dc 100644 (file)
@@ -35,14 +35,19 @@ tUHCI_TD    *UHCI_int_AllocateTD(tUHCI_Controller *Cont);
 void   UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD);
 tUHCI_TD       *UHCI_int_CreateTD(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
 // --- API
-void   *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void   *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void   UHCI_StopInterrupt(void *Ptr, void *Handle);
-void   *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length);
-void   *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void   *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void   *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void   *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void   *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len);
+void   *UHCI_InitIsoch(void *Ptr, int Endpt, size_t MaxPacketSize);
+void   *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize);
+void   *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize);
+void   UHCI_RemoveEndpoint(void *Ptr, void *EndptHandle);
+void   *UHCI_SendIsoch(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length, int When);
+void   *UHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+       int isOutbound,
+       const void *SetupData, size_t SetupLength,
+       const void *OutData, size_t OutLength,
+       void *InData, size_t InLength
+       );
+void   *UHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length);
 
 void   UHCI_CheckPortUpdate(void *Ptr);
 void   UHCI_int_InterruptThread(void *Unused);
@@ -58,18 +63,22 @@ MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL);
 tUHCI_TD       *gaUHCI_TDPool;
 tUHCI_Controller       gUHCI_Controllers[MAX_CONTROLLERS];
 tUSBHostDef    gUHCI_HostDef = {
-       .InterruptIN   = UHCI_InterruptIN,
-       .InterruptOUT  = UHCI_InterruptOUT,
-       .StopInterrupt = UHCI_StopInterrupt,
+       .InitInterrupt = UHCI_InitInterrupt,
+//     .InitIsoch     = UHCI_InitIsoch,
+       .InitControl   = UHCI_InitControl,
+       .InitBulk      = UHCI_InitBulk,
+       .RemEndpoint   = UHCI_RemoveEndpoint,
        
-       .ControlSETUP = UHCI_ControlSETUP,
-       .ControlIN    = UHCI_ControlIN,
-       .ControlOUT   = UHCI_ControlOUT,
-
-       .BulkOUT = UHCI_BulkOUT,
-       .BulkIN = UHCI_BulkIN,
+//     .SendIsoch   = UHCI_SendIsoch,
+       .SendControl = UHCI_SendControl,
+       .SendBulk    = UHCI_SendBulk,
+       .FreeOp      = NULL,
        
-       .CheckPorts = UHCI_CheckPortUpdate
+       .CheckPorts = UHCI_CheckPortUpdate,
+//     .ClearPortFeature = NULL,
+//     .GetBusState      = NULL,
+//     .GetPortStatus    = NULL,
+//     .SetPortFeature   = NULL
        };
 tSemaphore     gUHCI_InterruptSempahore;
 
@@ -191,7 +200,7 @@ int UHCI_int_InitHost(tUHCI_Controller *Host)
                1,17,9,25,5,21,13,29,3,19,11,27,7,23,15,31
                };
        for( int i = 0; i < 1024; i ++ ) {
-               Uint32  addr = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->ControlQH );
+               Uint32  addr = MM_GetPhysAddr( &Host->TDQHPage->ControlQH );
                Host->FrameList[i] = addr | 2;
        }
        for( int i = 0; i < 64; i ++ ) {
@@ -220,12 +229,12 @@ int UHCI_int_InitHost(tUHCI_Controller *Host)
                        dest += _count; destphys += _count * sizeof(tUHCI_QH);
                }
                // Skip padding, and move to control QH
-               dest->Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+               dest->Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
                dest->Child = 1;
        }
 
        // Set up control and bulk queues
-       Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+       Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
        Host->TDQHPage->ControlQH.Child = 1;
        Host->TDQHPage->BulkQH.Next = 1;
        Host->TDQHPage->BulkQH.Child = 1;
@@ -297,11 +306,11 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD)
        // Add
        TD->Link = 1;
        if( QH->Child & 1 ) {
-               QH->Child = MM_GetPhysAddr( (tVAddr)TD );
+               QH->Child = MM_GetPhysAddr( TD );
        }
        else {
                // Depth first
-               QH->_LastItem->Link = MM_GetPhysAddr( (tVAddr)TD ) | 4;
+               QH->_LastItem->Link = MM_GetPhysAddr( TD ) | 4;
        }
        QH->_LastItem = TD;
 
@@ -360,7 +369,7 @@ tUHCI_TD *UHCI_int_CreateTD(
        if(
                ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE
        #if PHYS_BITS > 32
-               || MM_GetPhysAddr( (tVAddr)Data ) >> 32
+               || MM_GetPhysAddr( Data ) >> 32
        #endif
                )
        {
@@ -373,14 +382,14 @@ tUHCI_TD *UHCI_int_CreateTD(
                        LOG("Relocated IN");
                        info = calloc( sizeof(tUHCI_ExtraTDInfo), 1 );
                        info->Offset = ((tVAddr)Data & (PAGE_SIZE-1));
-                       info->FirstPage = MM_GetPhysAddr( (tVAddr)Data );
-                       info->SecondPage = MM_GetPhysAddr( (tVAddr)Data + Length - 1 );
+                       info->FirstPage = MM_GetPhysAddr( Data );
+                       info->SecondPage = MM_GetPhysAddr( (const char *)Data + Length - 1 );
                }
                else
                {
                        LOG("Relocated OUT/SETUP");
-                       tVAddr  ptr = MM_MapTemp(td->BufferPointer);
-                       memcpy( (void*)ptr, Data, Length );
+                       void *ptr = MM_MapTemp(td->BufferPointer);
+                       memcpy( ptr, Data, Length );
                        MM_FreeTemp(ptr);
                        td->Control |= TD_CTL_IOC;
                }
@@ -388,7 +397,7 @@ tUHCI_TD *UHCI_int_CreateTD(
        }
        else
        {
-               td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
+               td->BufferPointer = MM_GetPhysAddr( Data );
                td->_info.bFreePointer = 0;
        }
 
@@ -481,149 +490,227 @@ void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period)
        UHCI_int_AppendTD(Cont, qh, TD);
 }
 
-void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+// --------------------------------------------------------------------
+// API
+// --------------------------------------------------------------------
+void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound,
+       int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len)
 {
        tUHCI_TD        *td;
-
-       if( Period < 0 )        return NULL;
-
-       ENTER("pPtr xDest iPeriod pCb pCbData pBuf iLength",
-               Ptr, Dest, Period, Cb, CbData, Buf, Length);
+       if( Period <= 0 )       return NULL;
+       
+       ENTER("pPtr xEndpt bbOutbound iPeriod pCb pCbData pBuf iLen",
+               Ptr, Endpt, bOutbound, Period, Cb, CbData, Buf, Len);
 
        // TODO: Data toggle?
-       td = UHCI_int_CreateTD(Ptr, Dest, PID_IN, 0, Cb, CbData, Buf, Length);
+       td = UHCI_int_CreateTD(Ptr, Endpt, (bOutbound ? PID_OUT : PID_IN), 0, Cb, CbData, Buf, Len);
        if( !td )       return NULL;
        
        UHCI_int_SetInterruptPoll(Ptr, td, Period);
-       
-       LEAVE('p', td); 
+
+       LEAVE('p', td);
        return td;
 }
-// TODO: Does interrupt OUT make sense?
-void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+
+void *UHCI_int_InitEndpt(tUHCI_Controller *Cont, int Type, int Endpt, size_t MaxPacketSize)
 {
-       tUHCI_TD        *td;
+       if( Endpt >= 256*16 )
+               return NULL;    
 
-       if( Period < 0 )        return NULL;
+       if( MaxPacketSize > MAX_PACKET_SIZE) {
+               Log_Warning("UHCI", "MaxPacketSize for %x greater than controller max (%i > %i)",
+                       Endpt, MaxPacketSize, MAX_PACKET_SIZE);
+               return NULL;
+       }
 
-       ENTER("pPtr xDest iPeriod pCb pCbData pBuf, iLength",
-               Ptr, Dest, Period, Cb, CbData, Buf, Length);
+       if( Cont->DevInfo[Endpt / 16] == NULL ) {
+               Cont->DevInfo[Endpt / 16] = calloc( 1, sizeof(*Cont->DevInfo[0]) );
+       }
+       tUHCI_EndpointInfo *epi = &Cont->DevInfo[Endpt/16]->EndpointInfo[Endpt%16];
+       if( epi->Type ) {
+               // oops, in use
+               Log_Warning("UHCI", "Endpoint %x reused?", Endpt);
+               return NULL;
+       }
 
-       // TODO: Data toggle?
-       td = UHCI_int_CreateTD(Ptr, Dest, PID_OUT, 0, Cb, CbData, Buf, Length);
-       if( !td )       return NULL;
-       
-       UHCI_int_SetInterruptPoll(Ptr, td, Period);
+       epi->MaxPacketSize = MaxPacketSize;
+       epi->Type = Type;
+       epi->Tgl = 0;
+
+       return (void*)(tVAddr)(Endpt+1);
 
-       LEAVE('p', td); 
-       return td;
 }
 
-void UHCI_StopInterrupt(void *Ptr, void *Handle)
+void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize)
 {
-       // TODO: Stop interrupt transaction
-       Log_Error("UHCI", "TODO: Implement UHCI_StopInterrupt");
+       return UHCI_int_InitEndpt(Ptr, 1, Endpt, MaxPacketSize);
 }
 
-void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length)
+void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize)
 {
-       tUHCI_Controller        *Cont = Ptr;
-       tUHCI_QH        *qh = &Cont->TDQHPage->ControlQH;
-       tUHCI_TD        *td;
+       return UHCI_int_InitEndpt(Ptr, 2, Endpt, MaxPacketSize);
+}
 
-       ENTER("pPtr xDest iTgl pData iLength", Ptr, Dest, Tgl, Data, Length);
+void UHCI_RemoveEndpoint(void *Ptr, void *Handle)
+{
+       tUHCI_Controller *Cont = Ptr;
+       if( Handle == NULL )
+               return ;
        
-       td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, Data, Length);
-       UHCI_int_AppendTD(Cont, qh, td);
-
-       LEAVE('p', td); 
-
-       return td;
+       if( (tVAddr)Handle <= 256*16 ) {
+                int    addr = (tVAddr)Handle;
+               Cont->DevInfo[addr/16]->EndpointInfo[addr%16].Type = 0;
+       }
+       else {
+               // TODO: Stop interrupt transaction
+               Log_Error("UHCI", "TODO: Implement stopping interrupt polling");
+       }
 }
-void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
+
+void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+       int bOutbound,  // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT
+       const void *SetupData, size_t SetupLength,
+       const void *OutData, size_t OutLength,
+       void *InData, size_t InLength
+       )
 {
+       ENTER("pPtr pEndpt ibOutbound", Ptr, Endpt, bOutbound);
+       
        tUHCI_Controller        *Cont = Ptr;
        tUHCI_QH        *qh = &Cont->TDQHPage->ControlQH;
        tUHCI_TD        *td;
+       tUHCI_EndpointInfo *epi;
+        int    dest, tgl;
+       size_t  mps;
 
-       ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
+       if( Endpt == NULL ) {
+               Log_Error("UHCI", "Passed a NULL Endpoint handle");
+               LEAVE('n');
+               return NULL;
+       }
 
-       td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, Tgl, Cb, CbData, Data, Length);
-       UHCI_int_AppendTD(Cont, qh, td);
+       // Sanity check Endpt
+       if( (tVAddr)Endpt > 0x800 ) {
+               LEAVE('n');
+               return NULL;
+       }
+       dest = (tVAddr)Endpt - 1;
+       if( Cont->DevInfo[dest/16] == NULL )    LEAVE_RET('n', NULL);
+       epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+       if( epi->Type != 1 )    LEAVE_RET('n', NULL);
+       mps = epi->MaxPacketSize;
+       tgl = epi->Tgl;
+
+       // TODO: Build up list and then append to QH in one operation
+
+       char    *data_ptr, *status_ptr;
+       size_t  data_len,   status_len;
+       Uint8   data_pid,   status_pid;
+       
+       if( bOutbound ) {
+               data_pid   = PID_OUT; data_ptr   = (void*)OutData; data_len   = OutLength;
+               status_pid = PID_IN;  status_ptr = InData;  status_len = InLength;
+       }
+       else {
+               data_pid   = PID_IN;  data_ptr   = InData;  data_len   = InLength;
+               status_pid = PID_OUT; status_ptr = (void*)OutData; status_len = OutLength;
+       }
 
-       LEAVE('p', td);
-       return td;
-}
-void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
-{
-       tUHCI_Controller        *Cont = Ptr;
-       tUHCI_QH        *qh = &Cont->TDQHPage->ControlQH;
-       tUHCI_TD        *td;
+       // Sanity check data lengths
+       if( SetupLength > mps ) LEAVE_RET('n', NULL);
+       if( status_len > mps )  LEAVE_RET('n', NULL);
 
-       ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
-       
-       td = UHCI_int_CreateTD(Cont, Dest, PID_IN, !!Tgl, Cb, CbData, Data, Length);
+       // Create and append SETUP packet
+       td = UHCI_int_CreateTD(Cont, dest, PID_SETUP, tgl, NULL, NULL, (void*)SetupData, SetupLength);
        UHCI_int_AppendTD(Cont, qh, td);
+       tgl = !tgl;
 
-       LEAVE('p', td);
+       // Send data packets
+       while( data_len > 0 )
+       {
+               size_t len = MIN(data_len, mps);
+               td = UHCI_int_CreateTD(Cont, dest, data_pid, tgl, NULL, NULL, data_ptr, len);
+               UHCI_int_AppendTD(Cont, qh, td);
+               tgl = !tgl;
+               
+               data_ptr += len;
+               data_len -= len;
+       }
+       
+       // Send status
+       td = UHCI_int_CreateTD(Cont, dest, status_pid, tgl, Cb, CbData, status_ptr, status_len);
+       UHCI_int_AppendTD(Cont, qh, td);
+       tgl = !tgl;
+       
+       // Update toggle value
+       epi->Tgl = tgl;
+       
+       LEAVE('p', td); 
        return td;
 }
 
-void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+void *UHCI_SendBulk(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, int bOutbound, void *Data, size_t Length)
 {
        tUHCI_Controller        *Cont = Ptr;
        tUHCI_QH        *qh = &Cont->TDQHPage->BulkQH;
-       tUHCI_TD        *td;
-       char    *src = Buf;
+       tUHCI_TD        *td = NULL;
+       tUHCI_EndpointInfo *epi;
+        int    dest, tgl;
+       size_t  mps;
 
-       ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
+       ENTER("pPtr pEndpt pCb pCbData bOutbound pData iLength", Ptr, Dest, Cb, CbData, bOutbound, Data, Length);
 
-       while( Length > MAX_PACKET_SIZE )
-       {
-               LOG("MaxPacket (rem = %i)", Length);
-               td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, MAX_PACKET_SIZE);
-               UHCI_int_AppendTD(Cont, qh, td);
-               
-               bToggle = !bToggle;
-               Length -= MAX_PACKET_SIZE;
-               src += MAX_PACKET_SIZE;
+       if( Endpt == NULL ) {
+               Log_Error("UHCI", "_SendBulk passed a NULL endpoint handle");
+               LEAVE('n');
+               return NULL;
        }
 
-       LOG("Final");
-       td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, Length);
-       UHCI_int_AppendTD(Cont, qh, td);
+       // Sanity check Endpt
+       if( (tVAddr)Endpt > 256*16 ) {
+               Log_Error("UHCI", "_SendBulk passed an interrupt endpoint handle");
+               LEAVE('n');
+               return NULL;
+       }
+       dest = (tVAddr)Endpt - 1;
+       if( Cont->DevInfo[dest/16] == NULL ) {
+               Log_Error("UHCI", "_SendBulk passed an uninitialised handle");
+               LEAVE('n');
+               return NULL;
+       }
+       epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+       if( epi->Type != 2 ) {
+               Log_Error("UHCI", "_SendBulk passed an invalid endpoint type (%i!=2)", epi->Type);
+               LEAVE('n');
+               return NULL;
+       }
+       tgl = epi->Tgl;
+       mps = epi->MaxPacketSize;
 
-       LEAVE('p', td);
-       return td;
-}
-void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
-       tUHCI_Controller        *Cont = Ptr;
-       tUHCI_QH        *qh = &Cont->TDQHPage->BulkQH;
-       tUHCI_TD        *td;
-       char    *dst = Buf;
+       Uint8   pid = (bOutbound ? PID_OUT : PID_IN);
 
-       ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
-       while( Length > MAX_PACKET_SIZE )
+       char *pos = Data;
+       while( Length > 0 )
        {
-               LOG("MaxPacket (rem = %i)", Length);
-               td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, MAX_PACKET_SIZE);
+               size_t len = MIN(mps, Length);
+
+               td = UHCI_int_CreateTD(Cont, dest, pid, tgl, Cb, (len == Length ? CbData : NULL), pos, len);
                UHCI_int_AppendTD(Cont, qh, td);
                
-               bToggle = !bToggle;
-               Length -= MAX_PACKET_SIZE;
-               dst += MAX_PACKET_SIZE;
+               pos += len;
+               Length -= len;
+               tgl = !tgl;
        }
-
-       LOG("Final");
-       td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, Length);
-       UHCI_int_AppendTD(Cont, qh, td);
+       
+       epi->Tgl = tgl;
 
        LEAVE('p', td);
        return td;
 }
 
+// ==========================
 // === INTERNAL FUNCTIONS ===
+// ==========================
 void UHCI_CheckPortUpdate(void *Ptr)
 {
        tUHCI_Controller        *Host = Ptr;
@@ -675,7 +762,7 @@ tUHCI_TD *UHCI_int_GetTDFromPhys(tUHCI_Controller *Controller, Uint32 PAddr)
        }
 
        
-       tPAddr  global_pool = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
+       tPAddr  global_pool = MM_GetPhysAddr( gaUHCI_TDPool );
        
        if( PAddr < global_pool || PAddr >= global_pool + PAGE_SIZE )   return NULL;
        
@@ -742,8 +829,8 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD)
        {
                char    *src, *dest;
                 int    src_ofs = TD->BufferPointer & (PAGE_SIZE-1);
-               src = (void *) MM_MapTemp(TD->BufferPointer);
-               dest = (void *) MM_MapTemp(info->FirstPage);
+               src = MM_MapTemp(TD->BufferPointer);
+               dest = MM_MapTemp(info->FirstPage);
                // Check for a single page transfer
                if( byte_count + info->Offset <= PAGE_SIZE )
                {
@@ -758,21 +845,21 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD)
                                TD->BufferPointer, info->FirstPage, info->SecondPage, TD);
                         int    part_len = PAGE_SIZE - info->Offset;
                        memcpy(dest + info->Offset, src + src_ofs, part_len);
-                       MM_FreeTemp( (tVAddr)dest );
-                       dest = (void *) MM_MapTemp(info->SecondPage);
+                       MM_FreeTemp( dest );
+                       dest = MM_MapTemp(info->SecondPage);
                        memcpy(dest, src + src_ofs + part_len, byte_count - part_len);
                }
-               MM_FreeTemp( (tVAddr)src );
-               MM_FreeTemp( (tVAddr)dest );
+               MM_FreeTemp( src );
+               MM_FreeTemp( dest );
        }
 
        // Callback
        if( info->Callback != NULL )
        {
                LOG("Calling cb %p (%i bytes)", info->Callback, byte_count);
-               void    *ptr = (void *) MM_MapTemp( TD->BufferPointer );
+               void    *ptr = MM_MapTemp( TD->BufferPointer );
                info->Callback( info->CallbackPtr, ptr, byte_count );
-               MM_FreeTemp( (tVAddr)ptr );
+               MM_FreeTemp( ptr );
        }
        
        // Clean up info
@@ -870,6 +957,7 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr)
        Uint16  status = _InWord(Host, USBSTS);
        
        LOG("%p: status = 0x%04x", Ptr, status);
+       
        // Interrupt-on-completion
        if( status & 1 )
        {
@@ -877,6 +965,31 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr)
                Semaphore_Signal(&gUHCI_InterruptSempahore, 1);
        }
 
+       // USB Error Interrupt
+       if( status & 2 )
+       {
+               
+       }
+
+       // Resume Detect
+       // - Fired if in suspend state and a USB device sends the RESUME signal
+       if( status & 4 )
+       {
+               
+       }
+
+       // Host System Error
+       if( status & 8 )
+       {
+               
+       }
+
+       // Host Controller Process Error
+       if( status & 0x10 )
+       {
+               Log_Error("UHCI", "Host controller process error on controller %p", Ptr);
+       }
+
        _OutWord(Host, USBSTS, status);
 }
 
index 6eff0eb..fbbeba3 100644 (file)
@@ -8,6 +8,7 @@
 
 // === TYPES ===
 typedef struct sUHCI_Controller        tUHCI_Controller;
+typedef struct sUHCI_EndpointInfo      tUHCI_EndpointInfo;
 typedef struct sUHCI_ExtraTDInfo       tUHCI_ExtraTDInfo;
 
 typedef struct sUHCI_TD        tUHCI_TD;
@@ -24,8 +25,14 @@ struct sUHCI_ExtraTDInfo
        void    *CallbackPtr;
 };
 
-#define TD_CTL_IOC     (1 << 24)
+struct sUHCI_EndpointInfo
+{
+       unsigned MaxPacketSize : 12;
+       unsigned Type : 3;
+       unsigned Tgl : 1;
+};
 
+#define TD_CTL_IOC     (1 << 24)
 #define TD_CTL_ACTIVE  (1 << 23)
 #define TD_CTL_STALLED (1 << 22)
 #define TD_CTL_DATABUFERR      (1 << 21)
@@ -113,7 +120,6 @@ struct sUHCI_QH
         */
        Uint32  Next;
 
-       
        /**
         * \brief Next Entry in list
         * 
@@ -200,6 +206,10 @@ struct sUHCI_Controller
                
                tUHCI_TD        LocalTDPool[ (4096-(128+2)*sizeof(tUHCI_QH)) / sizeof(tUHCI_TD) ];
        }       *TDQHPage;
+       
+       struct {
+               tUHCI_EndpointInfo EndpointInfo[16];
+       } *DevInfo[256];
 };
 
 // === ENUMERATIONS ===
index cc8fda3..d7ab474 100644 (file)
@@ -252,6 +252,7 @@ void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colou
        ch.BGCol  = (Colour & 0x0F0000) >> (16-8);
        ch.BGCol |= (Colour & 0x000F00) >> (8-4);
        ch.BGCol |= (Colour & 0x00000F);
+       ch.FGCol = 0;
        word = VGA_int_GetWord(&ch);
 
        Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
index 54d0e16..e16a7b2 100644 (file)
--- a/Makefile
+++ b/Makefile
 SUBMAKE = $(MAKE) --no-print-directory
 
 USRLIBS := crt0.o acess.ld ld-acess.so libgcc.so libc.so
-USRLIBS += libreadline.so libnet.so liburi.so
+USRLIBS += libreadline.so libnet.so liburi.so libpsocket.so
 USRLIBS += libimage_sif.so
 
 USRAPPS := init login CLIShell cat ls mount
-USRAPPS += bomb dhcpclient
-USRAPPS += ip ping telnet irc
+USRAPPS += bomb lspci
+USRAPPS += ip dhcpclient ping telnet irc wget telnetd
 USRAPPS += axwin3
 
 ALL_DYNMODS = $(addprefix all-,$(DYNMODS))
@@ -98,6 +98,10 @@ $(CLEAN_USRAPPS): clean-%:
        +@$(SUBMAKE) clean -C Usermode/Applications/$*_src
 
 # Install
+ifeq ($(ARCH),host)
+install-%:
+       
+else
 $(INSTALL_DYNMODS): install-%:
        @$(_build_dynmod)$* install
 $(INSTALL_MODULES): install-%:
@@ -110,3 +114,4 @@ $(INSTALL_USRLIBS): install-%:
        @$(SUBMAKE) install -C Usermode/Libraries/$*_src
 $(INSTALL_USRAPPS): install-%:
        @$(SUBMAKE) install -C Usermode/Applications/$*_src
+endif
index 53784d2..c030d47 100644 (file)
@@ -51,6 +51,7 @@ endif
 DRIVERS := 
 MODULES :=
 
+MODULES += Filesystems/RAMDisk
 MODULES += Filesystems/Ext2
 MODULES += Filesystems/FAT
 MODULES += Filesystems/NTFS
diff --git a/Notes/SIF.txt b/Notes/SIF.txt
new file mode 100644 (file)
index 0000000..57c1fa7
--- /dev/null
@@ -0,0 +1,28 @@
+=== Simple Image Format ===
+
+U16    Magic   0x51F0  - This determines the endianness of the file
+U16    Flags
+       > 0-2: Compression (0: Uncompressed, 1: RLE, 2: zlib, 3: RLE-Channel)
+       > 3-5: Format (0: ARGB, 1: RGB
+U16    Width
+U16    Height
+<DATA>
+
+
+=== Compression Formats ===
+0 - Uncompressed
+       The file data is a linear sequence of Width * Height 32-bit ARGB
+       words (in file endianness, determined by the magic)
+
+1 - RLE-4
+       7-bit length followed by a 32-bit value that is repeated `n` times
+       (if bit 7 of the length byte is set, the next `n` 32-bit words are
+       verbatim)
+
+2 - zlib
+       The image data is a zlib stream of 32-bit xRGB words
+
+3 - RLE-Channel
+       The data is the alpha values, followed by red, then green, then blue
+       encoded as RLE with a 7-bit length and a verbatim flag (same as mode
+       1, except with 8-bit values instead of 32-bit) 
diff --git a/Notes/VirtualPCI.txt b/Notes/VirtualPCI.txt
new file mode 100644 (file)
index 0000000..341af06
--- /dev/null
@@ -0,0 +1,5 @@
+Rationale:
+- Provides a method for ARM SoCs to use existing device drivers (e.g. USB ECHI) with minimal modifcation.
+
+Method possibilities
+# Hook in Kernel/drv/pci.c that enumerates the virtual bus using a fixed format.
diff --git a/RunQemu b/RunQemu
index aeb68c3..d2e9ec3 100755 (executable)
--- a/RunQemu
+++ b/RunQemu
@@ -3,8 +3,9 @@
 
 QEMU=qemu-system-x86_64
 USE_GDB=
+BOOTOPT="-fda DiskImage.img -boot a"
 
-QEMU_PARAMS="-fda DiskImage.img -boot a"
+QEMU_PARAMS=""
 QEMU_PARAMS=$QEMU_PARAMS" -hda AcessHDD.img"
 QEMU_PARAMS=$QEMU_PARAMS" -vga std"
 QEMU_PARAMS=$QEMU_PARAMS" -smp 2"
@@ -17,9 +18,28 @@ while [ $# -ne 0 ]; do
        -gdb)
                QEMU_PARAMS=$QEMU_PARAMS" -s -S"
                ;;
+       -dbin)
+               shift
+               if [ "x$2" = "xdefault" ] || [ "x$2" = "x" ]; then
+                       _kfile="KernelLand/Acess2.$1.bin"
+               else
+                       _kfile="KernelLand/Acess2.$1-$2.bin"
+               fi
+               BOOTOPT="-kernel $_kfile"
+               BOOTOPT=$BOOTOPT" -initrd KernelLand/Modules/Filesystems/FS_InitRD.kmd.$1 -append $3"
+               shift
+               shift
+               ;;
        -dbgbin)
                QEMU=/home/tpg/apps/bin/qemu-system-x86_64
                ;;
+       -bin)
+               shift
+               QEMU=$1
+               ;;
+       -dbgscript)
+               QEMU="echo $QEMU"
+               ;;
        -extramem)
                QEMU_PARAMS=$QEMU_PARAMS" -m 768"
                ;;
@@ -39,6 +59,9 @@ while [ $# -ne 0 ]; do
        -notee)
                _NOTEE="yes"
                ;;
+       -nographic)
+               _NOGRAPHIC="yes"
+               ;;
        esac
        shift
 done
@@ -46,6 +69,7 @@ QEMU_PARAMS=$QEMU_PARAMS" -net "$_NETTYPE
 
 if [ "x$_NOUSB" != "xyes" ] ; then
        QEMU_PARAMS=$QEMU_PARAMS" -usb"
+       QEMU_PARAMS=$QEMU_PARAMS" -device usb-ehci"
        QEMU_PARAMS=$QEMU_PARAMS" -drive id=test_usb_image,file=USB_Test_Image.img,if=none"
        QEMU_PARAMS=$QEMU_PARAMS" -device usb-storage,drive=test_usb_image"
        QEMU_PARAMS=$QEMU_PARAMS" -usbdevice mouse"
@@ -54,8 +78,15 @@ fi
 
 #      /home/tpg/apps/bin/qemu-system-x86_64 $QEMU_PARAMS -serial stdio -serial file:QemuLog.txt
 #      qemu-system-x86_64 $QEMU_PARAMS -serial stdio | tee QemuLog.txt
-if [ "x$_NOTEE" != "xyes" ] ; then
-       $QEMU $QEMU_PARAMS -serial stdio | tee QemuLog.txt
-else
-       $QEMU $QEMU_PARAMS -serial stdio
+#echo $QEMU $BOOTOPT $QEMU_PARAMS
+if [ "x$_NOGRAPHIC" = "xyes" ] ; then
+       $QEMU $BOOTOPT $QEMU_PARAMS -nographic
+       exit
 fi
+
+if [ "x$_NOTEE" = "xyes" ] ; then
+       $QEMU $BOOTOPT $QEMU_PARAMS -serial stdio
+       exit
+fi
+
+$QEMU $BOOTOPT $QEMU_PARAMS -serial stdio | tee QemuLog.txt
index f506599..e952a3a 100755 (executable)
@@ -12,6 +12,11 @@ _NETTYPE="user"
 
 while [ $# -ne 0 ]; do
        case $1 in
+       -raspberrypi)
+               _SYSTEM="versatilepb"
+               QEMU_PARAMS=$QEMU_PARAMS" -cpu arm1176 -m 192 -localtime"
+               _KERNEL=Acess2.armv6-raspberrypi.bin
+               ;;
        -gdb)
                QEMU_PARAMS=$QEMU_PARAMS" -s -S"
                ;;
@@ -31,7 +36,7 @@ while [ $# -ne 0 ]; do
        esac
        shift
 done
-QEMU_PARAMS="-M $_SYSTEM -kernel $_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
+QEMU_PARAMS="-M $_SYSTEM -kernel KernelLand/$_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
 
 #      /home/tpg/apps/bin/qemu-system-x86_64 $QEMU_PARAMS -serial stdio -serial file:QemuLog.txt
 #      qemu-system-x86_64 $QEMU_PARAMS -serial stdio | tee QemuLog.txt
diff --git a/TODO.txt b/TODO.txt
new file mode 100644 (file)
index 0000000..ad79fd6
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,70 @@
+TODO:
+
+=== Hardware ===
+- E1000 Driver (stubbed)
+ > Find specs
+   http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ > Use bochs/qemu only as a backup
+
+- Cirrus 64-bit VisualMedia Accelerator
+   PCI 1013:00B8 (Cirrus CLGD5446)
+ > Specs avail?
+   Qemu Suggests http://home.worldonline.dk/~finth/
+ > Bochs/Qemu
+
+- UniChrome Driver
+
+- Sound Stack
+ > Intel 82801AA AC97 Audio (qemu)
+
+
+=== General Features ===
+- Init Scripts
+ > With an argument to init passed from the kernel?
+
+- #!
+ > Pass as argument? or pass pointer like ld-acess?
+ > argc/argv - Definitely
+
+- Network Debugging + IPv6 Autoconf
+ > Should IPv6 RAs be done in kernel mode, or usermode?
+ > Wait until something like linux's net.conf.ipv6.accept_ra is set?
+ > Have a custom suffix for stateless IPs?
+
+- Signals
+ > Add return value to mutexs and semaphores, and add warn_unused_ret
+
+
+=== Kernel Core ===
+- Virtual PCI bus for system configuration
+ > Hook in drv_pci.c, with an arch-defined array of devices
+ > Allow hooks on PCI config accesses (to emulate power management etc)
+
+- VFS Path caching
+ > Is it needed?
+ > Use a trie of path elements
+  - Trie on path content (with '/' included)
+  - Prefixed to reduce load
+  - Able to split
+ > Maintain backwards cache of elements
+ > Support symlink caching too
+
+- USB Stack
+ > Check validity
+ > (DONE) Rework HC API to support structure used by OHCI/ECHI
+
+- LVM Usablity
+ > /Devices/LVM/by-id/ and /Devices/LVM/by-label
+
+=== Userland ===
+- AxWin3
+ > Text editor (with a GP formatted text field?)
+ > Maybe a basic web browser using the surface support?
+ > Configuration (via lib/server)
+
+- Omnispeak
+ > Debug speed issues (tracing agian)
+ > Port to AxWin3
+ > (DONE) Trace memory corruption
+
+- Port dropbear!
diff --git a/Tools/DiskTool/src/Makefile b/Tools/DiskTool/src/Makefile
new file mode 100644 (file)
index 0000000..e91bc7f
--- /dev/null
@@ -0,0 +1,103 @@
+
+TARGET := $(shell gcc -v 2>&1 | grep Targ | awk '{print $$2}')
+
+include ../../../Makefile.Version.cfg
+-include Makefile.BuildNum
+ifeq ($(BUILD_NUM),)
+BUILD_NUM = 1
+endif
+
+
+KERNEL_SRC = ../../../KernelLand/Kernel/
+MODULE_SRC = ../../../KernelLand/Modules/
+
+BIN = ../DiskTool
+# Kernel Sources (compiled with -ffreestanding)
+K_OBJ := lib.o
+K_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o
+K_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o # vfs/select.o
+K_OBJ += vfs/fs/root.o vfs/fs/devfs.o
+K_OBJ += drvutil_disk.o drv/proc.o
+# Modules
+MODULES := Storage/LVM Filesystems/FAT Filesystems/Ext2 Filesystems/NTFS
+# Local kernel soruces (same as above, but located in same directory as Makefile)
+L_OBJ = vfs_handles.o threads.o nativefs.o time.o actions.o
+# Native Sources (compiled as usual)
+N_OBJ = main.o script.o logging.o helpers.o
+
+# Compilation Options
+CFLAGS := -Wall -std=gnu99 -g -Werror
+CPPFLAGS := -I include/
+K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC)
+LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g
+
+BUILDINFO_OBJ := obj/$(TARGET)/buildinfo.o
+BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c)
+
+# ====================
+# == Start of Magic ==
+# ====================
+# -- Load modules ---
+$(foreach module,$(MODULES), $(eval include $(MODULE_SRC)$(module)/Makefile) $(eval M_OBJ += $(addprefix $(module)/,$(OBJ))) )
+
+# -- Apply Prefixes to object paths
+OBJ_PREFIX = obj/$(TARGET)/
+K_OBJ_PREFIX = $(OBJ_PREFIX)_Kernel/
+M_OBJ_PREFIX = $(OBJ_PREFIX)_Module/
+K_OBJ := $(addprefix $(K_OBJ_PREFIX),$(K_OBJ))
+M_OBJ := $(addprefix $(M_OBJ_PREFIX),$(M_OBJ))
+L_OBJ := $(addprefix $(OBJ_PREFIX),$(L_OBJ))
+N_OBJ := $(addprefix $(OBJ_PREFIX),$(N_OBJ))
+
+OBJ := $(N_OBJ) $(L_OBJ) $(K_OBJ) $(M_OBJ) $(BUILDINFO_OBJ)
+
+DEPFILES  = $(filter %.o,$(OBJ))
+DEPFILES := $(DEPFILES:%=%.dep)
+
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+       $(RM) -f $(OBJ) $(DEPFILES) $(BIN)
+
+$(BIN): $(OBJ)
+       @echo [CC Link] -o $(BIN)
+       @$(CC) -o $(BIN) $(OBJ) $(LDFLAGS)
+       @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum
+
+$(M_OBJ): $(M_OBJ_PREFIX)%.o: $(MODULE_SRC)%.c
+       @mkdir -p $(dir $@)
+       @echo [CC Module] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(K_OBJ): $(K_OBJ_PREFIX)%.o: $(KERNEL_SRC)%.c
+       @mkdir -p $(dir $@)
+       @echo [CC Kernel] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(L_OBJ): $(OBJ_PREFIX)%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo [CC Local] -o $@
+       @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF [email protected]
+
+$(N_OBJ): $(OBJ_PREFIX)%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo [CC Native] -o $@
+       @$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS) -MMD -MP -MF [email protected]
+
+# Hacky buildinfo.c file
+$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) Makefile
+       @echo "" > $@
+       @echo "const char gsKernelVersion[] = \"$(ACESS_VERSION)\";" >> $@
+       @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+       @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
+       @echo "const char gsBuildInfo[] = \"Acess2 DiskTool v$(ACESS_VERSION)\";" >> $@
+$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
+       @echo [CC] -o $@
+       @$(CC) -o $@ -c $< $(CFLAGS) $(CPPFLAGS)
+
+$(OBJ): Makefile
+
+-include $(DEPFILES)
diff --git a/Tools/DiskTool/src/actions.c b/Tools/DiskTool/src/actions.c
new file mode 100644 (file)
index 0000000..5cda588
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * actions.c
+ * - High level actions that call the VFS
+ * # Kernel-space compiled
+ */
+#include <acess.h>
+#include <disktool_common.h>
+#include <Storage/LVM/include/lvm.h>
+
+// === IMPORTS ===
+extern int     NativeFS_Install(char **Arguments);
+extern int     LVM_Cleanup(void);
+
+// === PROTOTYPES ===
+void   DiskTool_Initialise(void)       __attribute__((constructor(101)));
+void   DiskTool_Cleanup(void);
+ int   DiskTool_int_TranslateOpen(const char *File, int Mode);
+ int   DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest);
+ int   DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest);
+void   DiskTool_LVM_Cleanup(void *Handle);
+
+// === GLOBALS ===
+tLVM_VolType   gDiskTool_VolumeType = {
+       .Name = "DiskTool",
+       .Read  = DiskTool_LVM_Read,
+       .Write = DiskTool_LVM_Write,
+       .Cleanup = DiskTool_LVM_Cleanup
+};
+
+// === CODE ===
+void DiskTool_Initialise(void)
+{
+       VFS_Init();
+       NativeFS_Install(NULL);
+       VFS_MkDir("/Native");
+       VFS_Mount("/", "/Native", "nativefs", "");
+}
+
+void DiskTool_Cleanup(void)
+{
+        int    vfs_rv, lvm_rv;
+        int    nNochangeLoop = 0;
+       // Unmount all
+       do {
+               lvm_rv = LVM_Cleanup();
+               vfs_rv = VFS_UnmountAll();
+               Log_Debug("DiskTool", "Unmounted %i volumes", vfs_rv);
+               if( vfs_rv == 0 && lvm_rv == 0 ) {
+                       nNochangeLoop ++;
+                       if(nNochangeLoop == 2) {
+                               Log_Error("DiskTool", "Possible handle leak");
+                               break;
+                       }
+               }
+               else {
+                       nNochangeLoop = 0;
+               }
+       }
+       while( vfs_rv >= 0 || lvm_rv != 0 );
+}
+
+int DiskTool_RegisterLVM(const char *Identifier, const char *Path)
+{
+       int fd = DiskTool_int_TranslateOpen(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);
+       if(fd == -1) {
+               Log_Notice("DiskTool", "Can't open '%s' for LVM %s", Path, Identifier);
+               return -1;
+       }
+       VFS_Seek(fd, 0, SEEK_END);
+       LVM_AddVolume( &gDiskTool_VolumeType, Identifier, (void*)(tVAddr)fd, 512, VFS_Tell(fd)/512);
+       Log_Debug("DiskTool", "Registered '%s' for LVM %s", Path, Identifier);
+       return 0;
+}
+
+int DiskTool_MountImage(const char *Identifier, const char *Path)
+{
+       // Validate Identifier and make mountpoint string
+       char mountpoint[sizeof("/Mount/") + strlen(Identifier) + 1];
+       strcpy(mountpoint, "/Mount/");
+       strcat(mountpoint, Identifier);
+       
+       // Translate path       
+       size_t tpath_len = DiskTool_int_TranslatePath(NULL, Path);
+       char tpath[tpath_len-1];
+       DiskTool_int_TranslatePath(tpath, Path);
+       
+       // Call mount
+       VFS_MkDir(mountpoint);
+       // TODO: Detect filesystem?
+       return VFS_Mount(tpath, mountpoint, "", "");
+}
+
+int DiskTool_MkDir(const char *Directory)
+{
+       return -1;
+}
+
+int DiskTool_Copy(const char *Source, const char *Destination)
+{
+       int src = DiskTool_int_TranslateOpen(Source, VFS_OPENFLAG_READ);
+       if( src == -1 ) {
+               Log_Error("DiskTool", "Unable to open %s for reading", Source);
+               return -1;
+       }
+       int dst = DiskTool_int_TranslateOpen(Destination, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_CREATE);
+       if( dst == -1 ) {
+               Log_Error("DiskTool", "Unable to open %s for writing", Destination);
+               VFS_Close(src);
+               return -1;
+       }
+
+       char    buf[1024];
+       size_t  len, total = 0;
+       while( (len = VFS_Read(src, sizeof(buf), buf)) == sizeof(buf) ) {
+               VFS_Write(dst, len, buf);
+               total += len;
+       }
+       VFS_Write(dst, len, buf), total += len;
+
+       Log_Notice("DiskTool", "Copied %i from %s to %s", total, Source, Destination);
+
+       VFS_Close(dst);
+       VFS_Close(src);
+       
+       return 0;
+}
+
+int DiskTool_ListDirectory(const char *Directory)
+{
+       int fd = DiskTool_int_TranslateOpen(Directory, VFS_OPENFLAG_READ|VFS_OPENFLAG_DIRECTORY);
+       if(fd == -1) {
+//             fprintf(stderr, "Can't open '%s'\n", Directory);
+               return -1;
+       }
+
+       Log("Directory listing of '%s'", Directory);    
+
+       char    name[256];
+       while( VFS_ReadDir(fd, name) )
+       {
+               tFInfo  fi;
+               int child = VFS_OpenChild(fd, name, 0);
+               if( child != -1 )
+               {
+                       VFS_FInfo(child, &fi, 0);
+                       VFS_Close(child);
+               }
+               Log("- %02x %6lli %s", fi.flags, fi.size, name);
+       }
+       
+       VFS_Close(fd);
+       
+       return 0;
+}
+
+int DiskTool_Cat(const char *File)
+{
+       int src = DiskTool_int_TranslateOpen(File, VFS_OPENFLAG_READ);
+       if( src == -1 ) {
+               Log_Error("DiskTool", "Unable to open %s for reading", File);
+               return -1;
+       }
+       
+       char    buf[1024];
+       size_t  len, total = 0;
+       while( (len = VFS_Read(src, sizeof(buf), buf)) == sizeof(buf) ) {
+               _fwrite_stdout(len, buf);
+               total += len;
+       }
+       _fwrite_stdout(len, buf);
+       total += len;
+
+       Log_Notice("DiskTool", "%i bytes from %s", total, File);
+
+       VFS_Close(src);
+       return 0;
+}
+
+int DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest)
+{
+       return VFS_ReadAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest) / 512;
+}
+int DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest)
+{
+       return VFS_WriteAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest) / 512;
+}
+void DiskTool_LVM_Cleanup(void *Handle)
+{
+       VFS_Close( (int)(tVAddr)Handle );
+}
+
+// --- Internal helpers ---
+int DiskTool_int_TranslateOpen(const char *File, int Flags)
+{
+       size_t tpath_len = DiskTool_int_TranslatePath(NULL, File);
+       if(tpath_len == 0)
+               return -1;
+       char tpath[tpath_len-1];
+       DiskTool_int_TranslatePath(tpath, File);
+
+       return VFS_Open(tpath, Flags);
+}
+
diff --git a/Tools/DiskTool/src/helpers.c b/Tools/DiskTool/src/helpers.c
new file mode 100644 (file)
index 0000000..f9e3bc4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * helpers.c
+ */
+#include <stdlib.h>
+#include <acess_logging.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+// === GLOBALS ===
+char   gsWorkingDirectory[1024];
+
+
+// === CODE ===
+size_t DiskTool_int_TranslatePath(char *Buffer, const char *Path)
+{
+        int    len;
+       const char *colon = strchr(Path, ':');
+
+       if( Path[0] == '#' )
+       {
+               len = strlen(Path+1);
+               if(Buffer) {
+                       strcpy(Buffer, Path+1);
+               }
+       }
+       else if( Path[0] == ':' )
+       {
+               len = strlen("/Devices/LVM/");
+               len += strlen(Path+1);
+               if(Buffer) {
+                       strcpy(Buffer, "/Devices/LVM/");
+                       strcat(Buffer, Path+1);
+               }
+       }
+       else if( colon )
+       {
+               const char *pos;
+               for(pos = Path; pos < colon; pos ++)
+               {
+                       if( !isalpha(*pos) )
+                               goto native_path;
+               }
+               
+               len = strlen("/Mount/");
+               len += strlen(Path);
+               if( Buffer ) {
+                       strcpy(Buffer, "/Mount/");
+                       strncat(Buffer+strlen("/Mount/"), Path, colon - Path);
+                       strcat(Buffer, colon + 1);
+               }
+       }
+       else
+       {
+       native_path:
+               if( !gsWorkingDirectory[0] ) {  
+                       getcwd(gsWorkingDirectory, 1024);
+               }
+       
+               len = strlen("/Native");
+               len += strlen( gsWorkingDirectory ) + 1;
+               len += strlen(Path);
+               if( Buffer ) {
+                       strcpy(Buffer, "/Native");
+                       strcat(Buffer, gsWorkingDirectory);
+                       strcat(Buffer, "/");
+                       strcat(Buffer, Path);
+               }
+       }
+       return len;
+}
diff --git a/Tools/DiskTool/src/include/acess.h b/Tools/DiskTool/src/include/acess.h
new file mode 100644 (file)
index 0000000..7eff8c9
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Acess2 DiskTool utility
+ * - By John Hodge (thePowersGang)
+ *
+ * include/acess.h
+ * - Mock kernel core header
+ */
+#ifndef _DISKTOOL__ACESS_H_
+#define _DISKTOOL__ACESS_H_
+
+#define        CONCAT(x,y) x ## y
+#define EXPAND_CONCAT(x,y) CONCAT(x,y)
+#define STR(x) #x
+#define EXPAND_STR(x) STR(x)
+
+#define ASSERT(x)      do{}while(0)
+
+extern char    __buildnum[];
+#define BUILD_NUM      ((int)(Uint)&__buildnum)
+extern const char gsGitHash[];
+extern const char gsBuildInfo[];
+
+#define BITS   32
+#define NULL   ((void*)0)
+#include <stdint.h>
+
+typedef uintptr_t      Uint;
+//typedef unsigned int size_t;
+#include <stddef.h>
+typedef uint64_t       off_t;
+typedef char   BOOL;
+
+
+typedef uint8_t        Uint8;
+typedef uint16_t       Uint16;
+typedef uint32_t       Uint32;
+typedef uint64_t       Uint64;
+
+typedef int8_t Sint8;
+typedef int16_t        Sint16;
+typedef int32_t        Sint32;
+typedef int64_t        Sint64;
+
+typedef uintptr_t      tVAddr;
+typedef uint32_t       tPAddr;
+
+typedef uint32_t       tUID;
+typedef uint32_t       tGID;
+typedef uint32_t       tTID;
+
+// NOTE: Since this is single-threaded (for now) mutexes can be implimented as simple locks
+typedef char   tShortSpinlock;
+
+typedef int64_t        tTime;
+extern tTime   now(void);
+extern int64_t timestamp(int sec, int min, int hr, int day, int month, int year);
+extern void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+
+#define PACKED __attribute__((packed))
+#define DEPRECATED
+#define EXPORT(s)
+#define EXPORTV(s)
+
+#include <vfs_ext.h>
+
+// These are actually library functions, but they can't be included, so they're defined manually
+extern void    *malloc(size_t bytes);
+extern void    *calloc(size_t nmemb, size_t size);
+extern void    *realloc(void *oldptr, size_t bytes);
+extern void    free(void *buffer);
+
+#include <errno.h>
+#include <acess_logging.h>
+
+// Threads
+extern int     *Threads_GetErrno(void);
+//extern tPGID Threads_GetPGID(void);
+//extern tPID  Threads_GetPID(void);
+extern tTID    Threads_GetTID(void);
+extern tUID    Threads_GetUID(void);
+extern tGID    Threads_GetGID(void);
+
+// Kinda hacky way of not colliding with native errno
+#define errno  (*(Threads_GetErrno()))
+
+/**
+ * \name Endianness Swapping
+ * \{
+ */
+#ifdef __BIG_ENDIAN__
+#define        LittleEndian16(_val)    SwapEndian16(_val)
+#define        LittleEndian32(_val)    SwapEndian32(_val)
+#define        LittleEndian64(_val)    SwapEndian32(_val)
+#define        BigEndian16(_val)       (_val)
+#define        BigEndian32(_val)       (_val)
+#define        BigEndian64(_val)       (_val)
+#else
+#define        LittleEndian16(_val)    (_val)
+#define        LittleEndian32(_val)    (_val)
+#define        LittleEndian64(_val)    (_val)
+#define        BigEndian16(_val)       SwapEndian16(_val)
+#define        BigEndian32(_val)       SwapEndian32(_val)
+#define        BigEndian64(_val)       SwapEndian64(_val)
+#endif
+extern Uint16  SwapEndian16(Uint16 Val);
+extern Uint32  SwapEndian32(Uint32 Val);
+extern Uint64  SwapEndian64(Uint64 Val);
+/**
+ * \}
+ */
+
+
+#include <string.h>
+extern int     strucmp(const char *s1, const char *s2);
+extern int     strpos(const char *Str, char Ch);
+extern void    itoa(char *buf, uint64_t num, int base, int minLength, char pad);
+extern int     snprintf(char *buf, size_t len, const char *fmt, ...);
+extern int     sprintf(char *buf, const char *fmt, ...);
+extern int     ReadUTF8(const Uint8 *str, Uint32 *Val);
+extern int     WriteUTF8(Uint8 *str, Uint32 Val);
+#define CheckString(str)       (1)
+#define CheckMem(mem,sz)       (1)
+#include <ctype.h>
+
+// TODO: Move out?
+extern int     DivUp(int value, int divisor);
+extern uint64_t        DivMod64U(uint64_t Num, uint64_t Den, uint64_t *Rem);
+
+static inline void SHORTLOCK(tShortSpinlock *Lock) {
+       if(*Lock)       Log_KernelPanic("---", "Double short lock");
+       *Lock = 1;
+}
+static inline void SHORTREL(tShortSpinlock *m) { *m = 0; }
+
+static inline intptr_t MM_GetPhysAddr(void *Ptr) { return 1; }
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/acess_logging.h b/Tools/DiskTool/src/include/acess_logging.h
new file mode 100644 (file)
index 0000000..f8577dd
--- /dev/null
@@ -0,0 +1,34 @@
+
+#ifndef _DISKTOOL__ACESS_LOGGING_H_
+#define _DISKTOOL__ACESS_LOGGING_H_
+
+#if DEBUG
+# define ENTER(str, v...)      Debug_TraceEnter(__func__, str, ##v)
+# define LOG(fmt, v...)        Debug_TraceLog(__func__, fmt, ##v)
+# define LEAVE(t, v...)        Debug_TraceLeave(__func__, t, ##v)
+# define LEAVE_RET(t,v)        do{LEAVE('-');return v;}while(0)
+#else
+# define ENTER(...)    do{}while(0)
+# define LOG(...)      do{}while(0)
+# define LEAVE(...)    do{}while(0)
+# define LEAVE_RET(t,v)        return v;
+#endif
+
+extern void    Log_KernelPanic(const char *Ident, const char *Message, ...) __attribute__((noreturn));
+extern void    Log_Panic(const char *Ident, const char *Message, ...);
+extern void    Log_Error(const char *Ident, const char *Message, ...);
+extern void    Log_Warning(const char *Ident, const char *Message, ...);
+extern void    Log_Notice(const char *Ident, const char *Message, ...);
+extern void    Log_Log(const char *Ident, const char *Message, ...);
+extern void    Log_Debug(const char *Ident, const char *Message, ...);
+
+extern void    Warning(const char *Message, ...);
+extern void    Log(const char *Message, ...);
+extern void    Debug_HexDump(const char *Prefix, const void *Data, size_t Length);
+
+extern void    Debug_TraceEnter(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLog(const char *Function, const char *Format, ...);
+extern void    Debug_TraceLeave(const char *Function, char Type, ...);
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/arch.h b/Tools/DiskTool/src/include/arch.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tools/DiskTool/src/include/disktool_common.h b/Tools/DiskTool/src/include/disktool_common.h
new file mode 100644 (file)
index 0000000..38703c2
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ * 
+ * include/disktool_common.h
+ * - DiskTool internal API between native and kernel code
+ */
+#ifndef _INCLUDE__DISKTOOL_COMMON_H_
+#define _INCLUDE__DISKTOOL_COMMON_H_
+
+extern void    DiskTool_Cleanup(void);
+
+extern int     DiskTool_RegisterLVM(const char *Identifier, const char *Path);
+extern int     DiskTool_MountImage(const char *Identifier, const char *Path);
+extern int     DiskTool_Copy(const char *Source, const char *Destination);
+extern int     DiskTool_ListDirectory(const char *Directory);
+extern int     DiskTool_Cat(const char *File);
+
+extern size_t  DiskTool_int_TranslatePath(char *Buffer, const char *Path);
+
+extern size_t  _fwrite_stdout(size_t bytes, const void *data);
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/modules.h b/Tools/DiskTool/src/include/modules.h
new file mode 100644 (file)
index 0000000..c940c10
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * include/modules.h
+ * - Reimplimentation of kernel module interface for POSIX userland
+ */
+#ifndef _INCLUDE__MODULES_H_
+#define _INCLUDE__MODULES_H_
+
+enum
+{
+       MODULE_ERR_OK,
+};
+
+#define MODULE_DEFINE(flags, version, name, init, deinit, deps...) \
+void __init_##init(void) __attribute__((constructor(200))); void __init_##init(void){init(NULL);}
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/mutex.h b/Tools/DiskTool/src/include/mutex.h
new file mode 100644 (file)
index 0000000..9fe1c4f
--- /dev/null
@@ -0,0 +1,19 @@
+
+#ifndef _MUTEX_H_
+#define _MUTEX_H_
+
+typedef struct {
+       void    *LockerReturnAddr;
+}      tMutex;
+
+static inline int Mutex_Acquire(tMutex *m) {
+       if(m->LockerReturnAddr)
+               Log_KernelPanic("---", "Double mutex lock of %p by %p (was locked by %p)",
+                       m, __builtin_return_address(0), m->LockerReturnAddr);
+       m->LockerReturnAddr = __builtin_return_address(0);;
+       return 0;
+}
+static inline void Mutex_Release(tMutex *m) { m->LockerReturnAddr = 0; }
+
+#endif
+
diff --git a/Tools/DiskTool/src/include/rwlock.h b/Tools/DiskTool/src/include/rwlock.h
new file mode 100644 (file)
index 0000000..b9ff514
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Acess2 Disk Tool
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+typedef char   tRWLock;
+
+static inline int RWLock_AcquireRead(tRWLock *m) {
+       if(*m)  Log_KernelPanic("---", "Double mutex lock");
+       *m = 1;
+       return 0;
+}
+static inline int RWLock_AcquireWrite(tRWLock *m) {
+       if(*m)  Log_KernelPanic("---", "Double mutex lock");
+       *m = 1;
+       return 0;
+}
+static inline void RWLock_Release(tRWLock *m) { *m = 0; }
+
+#endif
+
diff --git a/Tools/DiskTool/src/logging.c b/Tools/DiskTool/src/logging.c
new file mode 100644 (file)
index 0000000..0cb3ed3
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * 
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <acess_logging.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#define LOGHDR(col,type)       fprintf(stderr, "\e["col"m[%-8.8s]"type" ", Ident)
+#define LOGTAIL()      fprintf(stderr, "\e[0m\n")
+
+#define PUTERR(col,type)       {\
+       LOGHDR(col,type);\
+       va_list args; va_start(args, Message);\
+       vfprintf(stderr, Message, args);\
+       va_end(args);\
+       LOGTAIL();\
+}
+
+// === CODE ===
+void Log_KernelPanic(const char *Ident, const char *Message, ...) {
+       PUTERR("35", "k")
+       abort();
+}
+void Log_Panic(const char *Ident, const char *Message, ...)
+       PUTERR("34", "p")
+void Log_Error(const char *Ident, const char *Message, ...)
+       PUTERR("31", "e")
+void Log_Warning(const char *Ident, const char *Message, ...)
+       PUTERR("33", "w")
+void Log_Notice(const char *Ident, const char *Message, ...)
+       PUTERR("32", "n")
+void Log_Log(const char *Ident, const char *Message, ...)
+       PUTERR("37", "l")
+void Log_Debug(const char *Ident, const char *Message, ...)
+       PUTERR("37", "d")
+
+void Warning(const char *Message, ...) {
+       const char *Ident = "";
+       PUTERR("33", "W")
+}
+void Log(const char *Message, ...) {
+       const char *Ident = "";
+       PUTERR("37", "L")
+}
+
+void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
+{
+       const uint8_t *data = Data;
+       size_t  ofs;
+       fprintf(stderr, "[HexDump ]d %s: %i bytes\n", Prefix, (int)Length);
+       for( ofs = 0; ofs + 16 <= Length; ofs += 16 )
+       {
+               fprintf(stderr, "[HexDump ]d %s:", Prefix);
+               fprintf(stderr, "  %02x %02x %02x %02x %02x %02x %02x %02x",
+                       data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+               data += 8;
+               fprintf(stderr, "  %02x %02x %02x %02x %02x %02x %02x %02x",
+                       data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+               data += 8;
+               fprintf(stderr, "\n");
+       }
+       
+       fprintf(stderr, "[HexDump ]d %s:", Prefix);
+       for( ; ofs < Length; ofs ++ )
+       {
+               if( ofs % 8 == 0 )      fprintf(stderr, " ");
+               fprintf(stderr, " %02x", data[ofs%16]);
+       }
+       fprintf(stderr, "\n");
+}
+
+ int   giDebug_TraceLevel = 0;
+
+void Debug_TraceEnter(const char *Function, const char *Format, ...)
+{
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       for( int i = 0; i < giDebug_TraceLevel; i ++ )
+               fprintf(stderr, " ");
+       fprintf(stderr, "%s: (", Function);
+
+       va_list args;
+       va_start(args, Format);
+       
+       int hasBeenPrev = 0;
+       while(*Format)
+       {
+               while( *Format && isblank(*Format) )
+                       Format ++;
+               if( !*Format )  break;
+               
+               char type = *Format++;
+               const char *start = Format;
+               while( *Format && !isblank(*Format) )
+                       Format ++;
+               
+               if(hasBeenPrev)
+                       fprintf(stderr, ",");
+               hasBeenPrev = 1;
+               
+               fprintf(stderr, "%.*s=", (int)(Format-start), start);
+               switch(type)
+               {
+               case 'p':
+                       fprintf(stderr, "%p", va_arg(args,const void *));
+                       break;
+               case 's':
+                       fprintf(stderr, "\"%s\"", va_arg(args,const char *));
+                       break;
+               case 'i':
+                       fprintf(stderr, "%i", va_arg(args,int));
+                       break;
+               case 'x':
+                       fprintf(stderr, "0x%x", va_arg(args,unsigned int));
+                       break;
+               case 'X':
+                       fprintf(stderr, "0x%"PRIx64, va_arg(args,uint64_t));
+                       break;
+               default:
+                       va_arg(args,uintptr_t);
+                       fprintf(stderr, "?");
+                       break;
+               }
+       }
+
+       va_end(args);
+
+       fprintf(stderr, ")");
+       LOGTAIL();
+       giDebug_TraceLevel ++;
+}
+
+void Debug_TraceLog(const char *Function, const char *Format, ...)
+{
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       
+       for( int i = 0; i < giDebug_TraceLevel; i ++ )
+               fprintf(stderr, " ");
+       fprintf(stderr, "%s: ", Function);
+       
+       va_list args;
+       va_start(args, Format);
+
+       vfprintf(stderr, Format, args);
+       
+       va_end(args);
+       LOGTAIL();
+}
+
+void Debug_TraceLeave(const char *Function, char Type, ...)
+{
+       if( giDebug_TraceLevel == 0 ) {
+               Log_Error("Debug", "Function %s called LEAVE without ENTER", Function);
+       }
+       
+       const char *Ident = "Trace";
+       LOGHDR("37","T");
+       
+       va_list args;
+       va_start(args, Type);
+
+       if( giDebug_TraceLevel > 0 )
+       {       
+               giDebug_TraceLevel --;
+               for( int i = 0; i < giDebug_TraceLevel; i ++ )
+                       fprintf(stderr, " ");
+       }
+       fprintf(stderr, "%s: RETURN", Function);
+       switch(Type)
+       {
+       case '-':
+               break;
+       case 'i':
+               fprintf(stderr, " %i", va_arg(args, int));
+               break;
+       case 'x':
+               fprintf(stderr, " 0x%x", va_arg(args, unsigned int));
+               break;
+       case 'X':
+               fprintf(stderr, " 0x%"PRIx64, va_arg(args,uint64_t));
+               break;
+       case 's':
+               fprintf(stderr, " \"%s\"", va_arg(args, const char *));
+               break;
+       case 'p':
+               fprintf(stderr, " %p", va_arg(args, const void *));
+               break;
+       case 'n':
+               fprintf(stderr, " NULL");
+               break;
+       default:
+               fprintf(stderr, " ?");
+               break;
+       }
+       
+       va_end(args);
+       LOGTAIL();
+}
+
diff --git a/Tools/DiskTool/src/main.c b/Tools/DiskTool/src/main.c
new file mode 100644 (file)
index 0000000..2de26a6
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <disktool_common.h>
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       // Parse arguments
+       for( int i = 1; i < argc; i ++ )
+       {
+               if( strcmp("mount", argv[i]) == 0 || strcmp("-i", argv[i]) == 0 ) {
+                       // Mount an image
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "mount takes 2 arguments (image and mountpoint)\n");
+                               exit(-1);
+                       }
+
+                       if( DiskTool_MountImage(argv[i+2], argv[i+1]) ) {
+                               fprintf(stderr, "Unable to mount '%s' as '%s'\n", argv[i+1], argv[i+2]);
+                               break;
+                       }
+
+                       i += 2;
+                       continue ;
+               }
+               
+               if( strcmp("mountlvm", argv[i]) == 0 || strcmp("lvm", argv[i]) == 0 ) {
+                       
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "lvm takes 2 arguments (iamge and ident)\n");
+                               exit(-1);
+                       }
+
+                       if( DiskTool_RegisterLVM(argv[i+2], argv[i+1]) ) {
+                               fprintf(stderr, "Unable to register '%s' as LVM '%s'\n", argv[i+1], argv[i+2]);
+                               break;
+                       }
+                       
+                       i += 2;
+                       continue ;
+               }
+               
+               if( strcmp("ls", argv[i]) == 0 ) {
+                       if( argc - i < 2 ) {
+                               fprintf(stderr, "ls takes 1 argument (path)\n");
+                               break;
+                       }
+
+                       DiskTool_ListDirectory(argv[i+1]);
+                       i += 1;
+                       continue ;
+               }
+               
+               if( strcmp("cp", argv[i]) == 0 ) {
+                       
+                       if( argc - i < 3 ) {
+                               fprintf(stderr, "cp takes 2 arguments (source and destination)\n");
+                               break;
+                       }
+
+                       DiskTool_Copy(argv[i+1], argv[i+2]);                    
+
+                       i += 2;
+                       continue ;
+               }
+
+               if( strcmp("cat", argv[i]) == 0 ) {
+
+                       if( argc - 1 < 2 ) {
+                               fprintf(stderr, "cat takes 1 argument (path)\n");
+                               break;
+                       }
+
+                       DiskTool_Cat(argv[i+1]);
+
+                       i += 1;
+                       continue;
+               }
+       
+               fprintf(stderr, "Unknown command '%s'\n", argv[i]);
+       }
+       
+       DiskTool_Cleanup();
+       
+       return 0;
+}
+
+// NOTE: This is in a native compiled file because it needs access to the real errno macro
+int *Threads_GetErrno(void)
+{
+       return &errno;
+}
+
+// TODO: Move into a helper lib?
+void itoa(char *buf, uint64_t num, int base, int minLength, char pad)
+{
+       char fmt[] = "%0ll*x";
+       switch(base)
+       {
+       case  8:        fmt[5] = 'o';   break;
+       case 10:        fmt[5] = 'd';   break;
+       case 16:        fmt[5] = 'x';   break;
+       }
+       if(pad != '0') {
+               fmt[1] = '%';
+               sprintf(buf, fmt+1, minLength, num);
+       }
+       else {
+               sprintf(buf, fmt, minLength, num);
+       }
+}
+
+int strpos(const char *Str, char Ch)
+{
+       const char *r = strchr(Str, Ch);
+       if(!r)  return -1;
+       return r - Str;
+}
+
+int strucmp(const char *s1, const char *s2)
+{
+       return strcasecmp(s1, s2);
+}
+
+uint64_t DivMod64U(uint64_t value, uint64_t divisor, uint64_t *remainder)
+{
+       if(remainder)
+               *remainder = value % divisor;
+       return value / divisor;
+}
+
+size_t _fwrite_stdout(size_t bytes, const void *data)
+{
+       return fwrite(data, bytes, 1, stdout);
+}
diff --git a/Tools/DiskTool/src/nativefs.c b/Tools/DiskTool/src/nativefs.c
new file mode 120000 (symlink)
index 0000000..164ccfc
--- /dev/null
@@ -0,0 +1 @@
+../../../AcessNative/acesskernel_src/nativefs.c
\ No newline at end of file
diff --git a/Tools/DiskTool/src/script.c b/Tools/DiskTool/src/script.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tools/DiskTool/src/threads.c b/Tools/DiskTool/src/threads.c
new file mode 100644 (file)
index 0000000..79ec4c6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 
+ */
+#include <acess.h>
+#include <threads.h>
+
+// === CODE ===
+tThread *Proc_GetCurThread(void)
+{
+       return NULL;
+}
+
+void Threads_PostEvent(tThread *Thread, Uint32 Events)
+{
+       
+}
+
+Uint32 Threads_WaitEvents(Uint32 Events)
+{
+       Log_KernelPanic("Threads", "Can't use _WaitEvents in DiskTool");
+       return 0;
+}
+
+void Threads_ClearEvent(Uint32 Mask)
+{
+       
+}
+
+tUID Threads_GetUID(void) { return 0; }
+tGID Threads_GetGID(void) { return 0; }
+
+int *Threads_GetMaxFD(void) { static int max_fd=32; return &max_fd; }
+char **Threads_GetCWD(void) { static char *cwd; return &cwd; }
+char **Threads_GetChroot(void) { static char *chroot; return &chroot; }
+
diff --git a/Tools/DiskTool/src/time.c b/Tools/DiskTool/src/time.c
new file mode 100644 (file)
index 0000000..445b04b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ * 
+ * time.c
+ * - Timing functions (emulated)
+ */
+#include <acess.h>
+#include <timers.h>
+
+// === CODE ===
+tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
+{
+       return NULL;
+}
+
+void Time_ScheduleTimer(tTimer *Timer, int Delta)
+{
+       
+}
+
+void Time_FreeTimer(tTimer *Timer)
+{
+       
+}
+
+Sint64 now(void)
+{
+       // TODO: Translate UNIX time into Acess time
+       return 0;
+}
+
diff --git a/Tools/DiskTool/src/vfs_handles.c b/Tools/DiskTool/src/vfs_handles.c
new file mode 100644 (file)
index 0000000..4f30151
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_int.h>
+
+#define MAX_KERNEL_FILES       32
+
+// === GLOBALS ===
+tVFS_Handle    gaKernelHandles[MAX_KERNEL_FILES];
+
+// === CODE ===
+int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
+{
+       for( int i = 0; i < MAX_KERNEL_FILES; i ++ )
+       {
+               if(gaKernelHandles[i].Node)     continue;
+               gaKernelHandles[i].Node = Node;
+               gaKernelHandles[i].Position = 0;
+               gaKernelHandles[i].Mode = Mode;
+               return i;
+       }       
+
+       return -1;
+}
+
+tVFS_Handle *VFS_GetHandle(int ID)
+{
+       if( ID < 0 || ID >= MAX_KERNEL_FILES )
+               return NULL;
+       return &gaKernelHandles[ID];
+}
diff --git a/Tools/GCCProxy/gccproxy.sh b/Tools/GCCProxy/gccproxy.sh
new file mode 100755 (executable)
index 0000000..8fb035b
--- /dev/null
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+# Get invocation path (which could be a symlink in $PATH)
+fullpath=`which "$0"`
+if [[ !$? ]]; then
+       fullpath="$0"
+fi
+
+# Resolve symlink
+fullpath=`readlink -f "$fullpath"`
+
+# Get base directory
+BASEDIR=`dirname "$fullpath"`
+
+cfgfile=`mktemp`
+make --no-print-directory -f $BASEDIR/getconfig.mk ARCH=x86 > $cfgfile
+#echo $cfgfile
+#cat $cfgfile
+. $cfgfile
+rm $cfgfile
+
+_miscargs=""
+_compile=0
+
+while [[ $# -gt 0 ]]; do
+       case "$1" in
+       -E)
+               _preproc=1
+               ;;
+       -c)
+               _compile=1
+               ;;
+       -o)
+               shift
+               _outfile="-o $1"
+               ;;
+       -I)
+               shift
+               _cflags=$_cflags" -I$1"
+               ;;
+       -I*|-D*|-O*)
+               _cflags=$_cflags" $1"
+               ;;
+       -Wl,*)
+               arg=$1
+               arg=${arg#-Wl}
+               arg=${arg/,/ }
+               _ldflags=$_ldflags" ${arg}"
+               ;;
+       -l)
+               shift
+               _libs=$_libs" -l$1"
+               ;;
+       -l*|-L*)
+               _libs=$_libs" $1"
+               ;;
+       *)
+               _miscargs=$_miscargs" $1"
+               ;;
+       esac
+       shift
+done
+
+run() {
+#      echo $*
+       $*
+}
+
+if [[ $_preproc -eq 1 ]]; then
+       run $_CC -E $CFLAGS $_cflags $_miscargs $_outfile
+       exit $?
+fi
+if [[ $_compile -eq 1 ]]; then
+       run $_CC $CFLAGS $_cflags $_miscargs -c $_outfile
+       exit $?
+fi
+
+if echo " $_miscargs" | grep '\.c' >/dev/null; then
+       tmpout=`mktemp acess_gccproxy.XXXXXXXXXX.o --tmpdir`
+       run $_CC $CFLAGS $_miscargs -c -o $tmpout
+       run $_LD $LDFLAGS $_ldflags $_libs $tmpout $_outfile
+       rm $tmpout
+else
+       run $_LD $LDFLAGS $_ldflags $_miscargs $_outfile $LIBGCC_PATH
+fi
+
diff --git a/Tools/GCCProxy/getconfig.mk b/Tools/GCCProxy/getconfig.mk
new file mode 100644 (file)
index 0000000..bd0ce0d
--- /dev/null
@@ -0,0 +1,10 @@
+include $(dir $(lastword $(MAKEFILE_LIST)))../../Usermode/Applications/Makefile.cfg
+
+.PHONY: shellvars
+
+shellvars:
+       @echo '_CC="$(CC)"'
+       @echo '_LD="$(LD)"'
+       @echo 'LDFLAGS="$(LDFLAGS)"'
+       @echo 'CFLAGS="$(CFLAGS)"'
+       @echo 'LIBGCC_PATH="$(LIBGCC_PATH)"'
index 7abed27..24889fa 100644 (file)
@@ -352,7 +352,7 @@ void Command_Dir(int argc, char **argv)
        \r
        fileName = (char*)(tmpPath+dirLen);\r
        // Read Directory Content\r
-       while( (fp = readdir(dp, fileName)) )\r
+       while( (fp = SysReadDir(dp, fileName)) )\r
        {\r
                if(fp < 0)\r
                {\r
index b4e4e51..0e89a7c 100644 (file)
@@ -5,9 +5,11 @@
 include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
 
 ASFLAGS = -felf
-CPPFLAGS = -I$(ACESSUSERDIR)/include/ -DARCHDIR_is_$(ARCHDIR)
+CPPFLAGS = -ffreestanding -I$(ACESSUSERDIR)/include/ -DARCHDIR_is_$(ARCHDIR)
+CPPFLAGS += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
 CFLAGS   = -fno-stack-protector $(CPPFLAGS)
 LDFLAGS  = -T $(OUTPUTDIR)Libs/acess.ld -rpath-link $(OUTPUTDIR)Libs -L $(OUTPUTDIR)Libs -I /Acess/Libs/ld-acess.so -lld-acess -lc $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o
+LIBGCC_PATH = $(shell $(CC) -print-libgcc-file-name)
 
 # Extra-verbose errors!
 #CFLAGS += -Wall -Wextra -Wwrite-strings -Wshadow -Wswitch-default -Wswitch-enum -Wstrict-overflow=5 -Wfloat-equal -Wundef -Wmissing-declarations -Wlogical-op
index 27cf9e5..c1245ae 100644 (file)
@@ -35,9 +35,9 @@ $(_BIN): $(OUTPUTDIR)Libs/acess.ld $(OUTPUTDIR)Libs/crt0.o $(_LIBS) $(OBJ)
        @mkdir -p $(dir $(_BIN))
        @echo [LD] -o $@
 ifneq ($(_DBGMAKEFILE),)
-       $(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt
+       $(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt $(LIBGCC_PATH)
 else
-       @$(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt
+       @$(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt $(LIBGCC_PATH)
 endif
        @$(DISASM) $(_BIN) > $(_OBJPREFIX)$(BIN).dsm
 
diff --git a/Usermode/Applications/axwin2_src/Makefile b/Usermode/Applications/axwin2_src/Makefile
deleted file mode 100644 (file)
index 89f1584..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-NAME = AxWin2
-DIRS = WM Shell_src
-
-SUBMAKE = $(MAKE) --no-print-directory
-
-all:
-       @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
-install:
-       @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
-
-clean:
-       @$(foreach DIR,$(DIRS), $(SUBMAKE) -C $(DIR) $@ &&) true
diff --git a/Usermode/Applications/axwin2_src/SIF.txt b/Usermode/Applications/axwin2_src/SIF.txt
deleted file mode 100644 (file)
index 57c1fa7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-=== Simple Image Format ===
-
-U16    Magic   0x51F0  - This determines the endianness of the file
-U16    Flags
-       > 0-2: Compression (0: Uncompressed, 1: RLE, 2: zlib, 3: RLE-Channel)
-       > 3-5: Format (0: ARGB, 1: RGB
-U16    Width
-U16    Height
-<DATA>
-
-
-=== Compression Formats ===
-0 - Uncompressed
-       The file data is a linear sequence of Width * Height 32-bit ARGB
-       words (in file endianness, determined by the magic)
-
-1 - RLE-4
-       7-bit length followed by a 32-bit value that is repeated `n` times
-       (if bit 7 of the length byte is set, the next `n` 32-bit words are
-       verbatim)
-
-2 - zlib
-       The image data is a zlib stream of 32-bit xRGB words
-
-3 - RLE-Channel
-       The data is the alpha values, followed by red, then green, then blue
-       encoded as RLE with a 7-bit length and a verbatim flag (same as mode
-       1, except with 8-bit values instead of 32-bit) 
diff --git a/Usermode/Applications/axwin2_src/Shell_src/Makefile b/Usermode/Applications/axwin2_src/Shell_src/Makefile
deleted file mode 100644 (file)
index 55744b9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Project: Acess GUI Default Shell
-
--include ../../Makefile.cfg
-
-CPPFLAGS +=
-LDFLAGS += -laxwin2
-
-DIR = Apps/AxWin/1.0
-BIN = Shell
-OBJ = main.o
-
--include ../../Makefile.tpl
diff --git a/Usermode/Applications/axwin2_src/Shell_src/main.c b/Usermode/Applications/axwin2_src/Shell_src/main.c
deleted file mode 100644 (file)
index f1c0416..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Acess2 GUI Test App
- * - By John Hodge (thePowersGang)
- */
-#include <axwin2/axwin.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-// === CONSTANTS ===
-enum eTerminal_Events
-{
-       EVENT_NULL,
-       EVENT_NEW_TAB,
-       EVENT_CLOSE_TAB,
-       EVENT_EXIT
-};
-
-// === PROTOTYPES ===
- int   main(int argc, char *argv[]);
- int   Global_HandleMessage(tAxWin_Message *Message);
- int   Shell_HandleMessage(tAxWin_Message *Message);
-
-// === GLOBALS ===
-tAxWin_Element *geConsole;
-
-// === CODE ===
-int main(int argc, char *argv[])
-{
-       tAxWin_Element  *menu, *tab;
-       
-       if(argc != 1)
-       {
-               fprintf(stderr, "Usage: %s\n", argv[0]);
-               fprintf(stderr, "\tThis application takes no arguments\n");
-               return 0;
-       }
-
-       AxWin_Register("Terminal", Global_HandleMessage);
-
-       menu = AxWin_AddMenuItem(NULL, "File", 0);
-       AxWin_AddMenuItem(menu, "&New Tab\tCtrl-Shift-N", EVENT_NEW_TAB);
-       AxWin_AddMenuItem(menu, NULL, 0);
-       AxWin_AddMenuItem(menu, "&Close Tab\tCtrl-Shift-W", EVENT_CLOSE_TAB);
-       AxWin_AddMenuItem(menu, "E&xit\tAlt-F4", EVENT_EXIT);
-
-       tab = AxWin_CreateWindow("root@acess: ~");
-       //geConsole = AxWin_CreateElement();
-       
-       AxWin_MessageLoop();
-       
-       return 0;
-}
-
-/**
- */
-int Global_HandleMessage(tAxWin_Message *Message)
-{
-       switch(Message->ID)
-       {
-       default:
-               return 0;
-       }
-}
-
-int Shell_HandleMessage(tAxWin_Message *Message)
-{
-       switch(Message->ID)
-       {
-       default:
-               return 0;
-       }
-}
diff --git a/Usermode/Applications/axwin2_src/WM/Makefile b/Usermode/Applications/axwin2_src/WM/Makefile
deleted file mode 100644 (file)
index 19687e1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Project: Acess GUI Window Manager
-
--include ../../Makefile.cfg
-
-CPPFLAGS += 
-
-DIR := Apps/AxWin/1.0
-BIN := AxWinWM
-OBJ := main.o helpers.o commandline.o video.o input.o video_text.o
-OBJ += messages.o interface.o wm.o decorator.o render.o
-OBJ += image.o
-
-LDFLAGS += -limage_sif -luri -lnet
-
--include ../../Makefile.tpl
-
-all: resources/LogoSmall.sif.res.h
-
-%.res.h: % Makefile
-       echo "#define RESOURCE_$(notdir $<) \\"| sed -e 's/\./_/g' > $@
-       base64 $< | sed -e 's/.*/"&"\\/' >> $@
-       echo "" >> $@
diff --git a/Usermode/Applications/axwin2_src/WM/commandline.c b/Usermode/Applications/axwin2_src/WM/commandline.c
deleted file mode 100644 (file)
index 67db574..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <string.h>
-
-// === PROTOTYPES ===
-void   ShowUsage(char *ProgName);
-void   ShowHelp(char *ProgName);
-
-// === CODE ===
-void ParseCommandline(int argc, char *argv[])
-{
-        int    i;
-       char    *arg;
-       
-       for( i = 1; i < argc; i++ )
-       {
-               arg = argv[i];
-               if(arg[0] == '-')
-               {
-                       if( arg[1] == '-' )
-                       {
-                               if( strcmp(&arg[2], "help") == 0 ) {
-                                       ShowHelp(argv[0]);
-                                       exit(EXIT_SUCCESS);
-                               }
-                               else {
-                                       ShowUsage(argv[0]);
-                                       exit(EXIT_FAILURE);
-                               }
-                       }
-                       else
-                       {
-                               while( *++arg )
-                               {
-                                       switch(*arg)
-                                       {
-                                       case 'h':
-                                       case '?':
-                                               ShowHelp(argv[0]);
-                                               exit(EXIT_SUCCESS);
-                                               break;
-                                       default:
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       }
-}
-
-void ShowUsage(char *ProgName)
-{
-       fprintf(stderr, "Usage: %s [-h|--help]\n", ProgName);
-}
-
-void ShowHelp(char *ProgName)
-{
-       ShowUsage(ProgName);
-       fprintf(stderr, "\n");
-       fprintf(stderr, "\t--help\tShow this message\n");
-}
diff --git a/Usermode/Applications/axwin2_src/WM/common.h b/Usermode/Applications/axwin2_src/WM/common.h
deleted file mode 100644 (file)
index b00d697..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <acess/sys.h> // _SysDebug
-
-// === TYPES ===
-typedef struct sIPC_Type       tIPC_Type;
-typedef struct sFont   tFont;
-
-struct sIPC_Type
-{
-        int    (*GetIdentSize)(void *Ident);
-        int    (*CompareIdent)(void *Ident1, void *Ident2);
-       void    (*SendMessage)(void *Ident, size_t, void *Data);
-};
-
-#include "wm.h"
-#include "image.h"
-//#include "font.h"
-
-// === MACROS ===
-static inline uint32_t Video_AlphaBlend(uint32_t _orig, uint32_t _new, uint8_t _alpha)
-{
-       uint16_t        ao,ro,go,bo;
-       uint16_t        an,rn,gn,bn;
-       if( _alpha == 0 )       return _orig;
-       if( _alpha == 255 )     return _new;
-       
-       ao = (_orig >> 24) & 0xFF;
-       ro = (_orig >> 16) & 0xFF;
-       go = (_orig >>  8) & 0xFF;
-       bo = (_orig >>  0) & 0xFF;
-       
-       an = (_new >> 24) & 0xFF;
-       rn = (_new >> 16) & 0xFF;
-       gn = (_new >>  8) & 0xFF;
-       bn = (_new >>  0) & 0xFF;
-
-       if( _alpha == 0x80 ) {
-               ao = (ao + an) / 2;
-               ro = (ro + rn) / 2;
-               go = (go + gn) / 2;
-               bo = (bo + bn) / 2;
-       }
-       else {
-               ao = ao*(255-_alpha) + an*_alpha;
-               ro = ro*(255-_alpha) + rn*_alpha;
-               go = go*(255-_alpha) + gn*_alpha;
-               bo = bo*(255-_alpha) + bn*_alpha;
-               ao /= 255*2;
-               ro /= 255*2;
-               go /= 255*2;
-               bo /= 255*2;
-       }
-
-       return (ao << 24) | (ro << 16) | (go << 8) | bo;
-}
-
-// === GLOBALS ===
-extern const char      *gsTerminalDevice;
-extern const char      *gsMouseDevice;
-
-extern int     giScreenWidth;
-extern int     giScreenHeight;
-extern uint32_t        *gpScreenBuffer;
-
-extern int     giTerminalFD;
-extern int     giMouseFD;
-
-// === Functions ===
-extern void    memset32(void *ptr, uint32_t val, size_t count);
-// --- Initialisation ---
-extern void    ParseCommandline(int argc, char *argv[]);
-// --- Messages / IPC ---
-extern void    IPC_Init(void);
-extern void    IPC_FillSelect(int *nfds, fd_set *set);
-extern void    IPC_HandleSelect(fd_set *set);
-// --- Input ---
-extern void    Input_FillSelect(int *nfds, fd_set *set);
-extern void    Input_HandleSelect(fd_set *set);
-// --- Local WM ---
-extern tApplication    *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name);
-extern void    AxWin_DeregisterClient(tApplication *App);
-extern tApplication    *AxWin_GetClient(tIPC_Type *Method, void *Ident);
-extern tElement        *AxWin_CreateAppWindow(tApplication *App, const char *Name);
-// --- Video ---
-extern void    Video_Setup(void);
-extern void    Video_SetCursorPos(short X, short Y);
-extern void    Video_Update(void);
-extern void    Video_FillRect(short X, short Y, short W, short H, uint32_t Color);
-extern void    Video_DrawRect(short X, short Y, short W, short H, uint32_t Color);
-extern int     Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
-extern void    Video_DrawImage(short X, short Y, short W, short H, tImage *Image);
-// --- Interface ---
-extern void    Interface_Init(void);
-extern void    Interface_Update(void);
-extern void    Interface_Render(void);
-// --- Decorator ---
-extern void    Decorator_RenderWidget(tElement *Element);
-
-#endif
diff --git a/Usermode/Applications/axwin2_src/WM/decorator.c b/Usermode/Applications/axwin2_src/WM/decorator.c
deleted file mode 100644 (file)
index 171b526..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- * 
- * Widget Decorator
- */
-#include "common.h"
-#include "wm.h"
-
-#define BORDER_EVERYTHING      1
-
-#define BOX_BGCOLOUR    0xC0C0C0
-#define BOX_BORDER      0xA0A0A0
-#define BUTTON_BGCOLOUR 0xD0D0D0
-#define BUTTON_BORDER   0xF0F0F0
-#define        TEXT_COLOUR     0x000000
-
-// === CODE ===
-void Decorator_RenderWidget(tElement *Element)
-{
-       _SysDebug("Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})",
-               Element->Type,
-               Element->CachedX, Element->CachedY,
-               Element->CachedW, Element->CachedH
-               );
-       
-       #if BORDER_EVERYTHING
-       Video_DrawRect(Element->CachedX, Element->CachedY,
-                       Element->CachedW, Element->CachedH,
-                       0
-                       );
-       #endif
-       
-       switch(Element->Type)
-       {
-       case ELETYPE_NONE:
-       case ELETYPE_BOX:       break;  // Box is a meta-element
-       
-       case ELETYPE_TABBAR:    // Tab Bar
-               Video_DrawRect(
-                       Element->CachedX, Element->CachedY,
-                       Element->CachedW, Element->CachedH,
-                       BOX_BORDER
-                       );
-               Video_FillRect(
-                       Element->CachedX+1, Element->CachedY+1,
-                       Element->CachedW-2, Element->CachedH-2,
-                       BOX_BGCOLOUR
-                       );
-               // Enumerate Items.
-               break;
-       case ELETYPE_TOOLBAR:   // Tool Bar
-               Video_DrawRect(
-                       Element->CachedX, Element->CachedY,
-                       Element->CachedW, Element->CachedH,
-                       BOX_BORDER
-                       );
-               Video_FillRect(
-                       Element->CachedX+1, Element->CachedY+1,
-                       Element->CachedW-2, Element->CachedH-2,
-                       BOX_BGCOLOUR
-                       );
-               break;
-       
-       case ELETYPE_SPACER:    // Spacer (subtle line)
-               Video_FillRect(
-                       Element->CachedX+3, Element->CachedY+3,
-                       Element->CachedW-6, Element->CachedH-6,
-                       BOX_BORDER
-                       );
-               break;
-       
-       case ELETYPE_BUTTON:    // Button
-               Video_FillRect(
-                       Element->CachedX+1, Element->CachedY+1,
-                       Element->CachedW-2, Element->CachedH-2,
-                       BUTTON_BGCOLOUR
-                       );
-               Video_DrawRect(
-                       Element->CachedX, Element->CachedY,
-                       Element->CachedW-1, Element->CachedH-1,
-                       BUTTON_BORDER
-                       );
-               break;
-       
-       case ELETYPE_TEXT:
-               Video_DrawText(
-                       Element->CachedX+1, Element->CachedY+1,
-                       Element->CachedW-2, Element->CachedH-2,
-                       NULL,
-                       TEXT_COLOUR,
-                       Element->Text
-                       );
-               break;
-       
-       case ELETYPE_IMAGE:
-               Video_DrawImage(
-                       Element->CachedX, Element->CachedY,
-                       Element->CachedW, Element->CachedH,
-                       Element->Data
-                       );
-               break;
-               
-       default:
-               _SysDebug(" ERROR: Unknown type %i", Element->Type);
-               break;
-       }
-}
diff --git a/Usermode/Applications/axwin2_src/WM/font_8x16.h b/Usermode/Applications/axwin2_src/WM/font_8x16.h
deleted file mode 100644 (file)
index b9bad5d..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
- * Altered for Acess2
- */
-#define FONT_WIDTH     8
-#define FONT_HEIGHT    16
-static uint8_t VTermFont[256*16]=
-{
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
-       0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-       0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
-       0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-       0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-       0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-       0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
-       0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
-       0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-       0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-       0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-       0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-       0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
diff --git a/Usermode/Applications/axwin2_src/WM/helpers.c b/Usermode/Applications/axwin2_src/WM/helpers.c
deleted file mode 100644 (file)
index 194c024..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-
-// === CODE ===
-void memset32(void *ptr, uint32_t val, size_t count)
-{
-       uint32_t *dst = ptr;
-       while(count --) *dst++ = val;
-}
diff --git a/Usermode/Applications/axwin2_src/WM/image.c b/Usermode/Applications/axwin2_src/WM/image.c
deleted file mode 100644 (file)
index 1d7d343..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- * 
- * Window Manager and Widget Control
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include <uri.h>
-
-// === IMPORTS ===
-extern tImage *Image_SIF_Parse(void *Buffer, size_t Size);
-
-// === PROTOTYPES ===
- int   UnBase64(uint8_t *Dest, char *Src, int BufSize);
-
-// === CODE ===
-/**
- * \brief Open an image from a URI
- */
-tImage *Image_Load(const char *URI)
-{
-       tURI    *uri;
-        int    filesize;
-       void    *buf;
-       tImage  *img;
-       
-       uri = URI_Parse(URI);
-       if( !uri ) {
-               _SysDebug("Image_Load: Unable parse as URI '%s'\n", URI);
-               return NULL;
-       }
-       
-       if( strcmp(uri->Proto, "file") == 0 )
-       {
-               FILE    *fp;
-               fp = fopen(uri->Path, "rb");
-               if(!fp) {
-                       _SysDebug("Image_Load: Unable to open '%s'\n", uri->Path);
-                       free(uri);
-                       return NULL;
-               }
-               
-               fseek(fp, 0, SEEK_END);
-               filesize = ftell(fp);
-               buf = malloc( filesize );
-               if(!buf) {
-                       _SysDebug("Image_Load: malloc() failed!\n");
-                       fclose(fp);
-                       free(uri);
-                       return NULL;
-               }
-               
-               fread(buf, filesize, 1, buf);
-               fclose(fp);
-       }
-       else if( strcmp(uri->Proto, "base64") == 0 )
-       {
-               // 4 bytes of base64 = 3 bytes of binary (base 256)
-               filesize = strlen( uri->Path ) * 3 / 4;
-               buf = malloc(filesize);
-               if(!buf) {
-                       _SysDebug("Image_Load: malloc() failed!\n");
-                       free(uri);
-                       return NULL;
-               }
-               
-               filesize = UnBase64(buf, uri->Path, filesize);
-       }
-       else
-       {
-               _SysDebug("Image_Load: Unknow protocol '%s'\n", uri->Proto);
-               free(uri);
-               return NULL;
-       }
-       
-       img = Image_SIF_Parse(buf, filesize);
-       free(buf);
-       free(uri);
-       if( !img ) {
-               _SysDebug("Image_Load: Unable to parse SIF from '%s'\n", URI);
-               return NULL;
-       }
-       
-       return img;
-}
-
-/**
- * \brief Decode a Base64 value
- */
-int UnBase64(uint8_t *Dest, char *Src, int BufSize)
-{
-       uint32_t        val;
-        int    i, j;
-       char    *start_src = Src;
-       
-       for( i = 0; i+2 < BufSize; i += 3 )
-       {
-               val = 0;
-               for( j = 0; j < 4; j++, Src ++ ) {
-                       if('A' <= *Src && *Src <= 'Z')
-                               val |= (*Src - 'A') << ((3-j)*6);
-                       else if('a' <= *Src && *Src <= 'z')
-                               val |= (*Src - 'a' + 26) << ((3-j)*6);
-                       else if('0' <= *Src && *Src <= '9')
-                               val |= (*Src - '0' + 52) << ((3-j)*6);
-                       else if(*Src == '+')
-                               val |= 62 << ((3-j)*6);
-                       else if(*Src == '/')
-                               val |= 63 << ((3-j)*6);
-                       else if(!*Src)
-                               break;
-                       else if(*Src != '=')
-                               j --;   // Ignore invalid characters
-               }
-               Dest[i  ] = (val >> 16) & 0xFF;
-               Dest[i+1] = (val >> 8) & 0xFF;
-               Dest[i+2] = val & 0xFF;
-               if(j != 4)      break;
-       }
-       
-       // Finish things off
-       if(i   < BufSize)
-               Dest[i] = (val >> 16) & 0xFF;
-       if(i+1 < BufSize)
-               Dest[i+1] = (val >> 8) & 0xFF;
-       
-       return Src - start_src;
-}
diff --git a/Usermode/Applications/axwin2_src/WM/image.h b/Usermode/Applications/axwin2_src/WM/image.h
deleted file mode 100644 (file)
index 6cda85b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#ifndef _IMAGE_H_
-#define _IMAGE_H_
-
-typedef struct sImage  tImage;
-
-struct sImage
-{
-       short   Width;
-       short   Height;
-        int    Format;
-       uint8_t Data[];
-};
-
-enum eImageFormats
-{
-       IMGFMT_BGRA,
-       IMGFMT_RGB,
-       NUM_IMGFMTS
-};
-
-// === PROTOTYPES ===
-extern tImage  *Image_Load(const char *URI);
-
-#endif
diff --git a/Usermode/Applications/axwin2_src/WM/input.c b/Usermode/Applications/axwin2_src/WM/input.c
deleted file mode 100644 (file)
index 9386932..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-
-#define JOY_IOCTL_GETSETAXISLIMIT      6
-#define JOY_IOCTL_GETSETAXISPOSITION   7
-
-// === CODE ===
-int Input_Init(void)
-{
-       struct {
-                int    Num, Value;
-       }       num_value;
-
-       // Open mouse for RW
-       giMouseFD = open(gsMouseDevice, 3);
-
-       // Set mouse limits
-       num_value.Num = 0;
-       num_value.Value = giScreenWidth;
-       ioctl(giMouseFD, JOY_IOCTL_GETSETAXISLIMIT, &num_value);
-       num_value.Value = giScreenWidth/2;
-       ioctl(giMouseFD, JOY_IOCTL_GETSETAXISPOSITION, &num_value);
-
-       num_value.Num = 1;
-       num_value.Value = giScreenHeight;
-       ioctl(giMouseFD, JOY_IOCTL_GETSETAXISLIMIT, &num_value);
-       num_value.Value = giScreenHeight/2;
-       ioctl(giMouseFD, JOY_IOCTL_GETSETAXISPOSITION, &num_value);
-
-       return 0;
-}
-
-void Input_FillSelect(int *nfds, fd_set *set)
-{
-       if(*nfds < giTerminalFD)        *nfds = giTerminalFD;
-       if(*nfds < giMouseFD)   *nfds = giMouseFD;
-       FD_SET(giTerminalFD, set);
-       FD_SET(giMouseFD, set);
-}
-
-void Input_HandleSelect(fd_set *set)
-{
-       if(FD_ISSET(giTerminalFD, set))
-       {
-               uint32_t        codepoint;
-               if( read(giTerminalFD, &codepoint, sizeof(codepoint)) != sizeof(codepoint) )
-               {
-                       // oops, error
-               }
-               // TODO: pass on to message handler
-               _SysDebug("Keypress 0x%x", codepoint);
-       }
-
-       if(FD_ISSET(giMouseFD, set))
-       {
-               struct sMouseInfo {
-                       uint16_t        NAxies;
-                       uint16_t        NButtons;
-                       struct sMouseAxis {
-                                int16_t        MinValue;
-                                int16_t        MaxValue;
-                                int16_t        CurValue;
-                               uint16_t        CursorPos;
-                       }       Axies[2];
-                       uint8_t Buttons[3];
-               }       mouseinfo;
-       
-               seek(giMouseFD, 0, SEEK_SET);
-               if( read(giMouseFD, &mouseinfo, sizeof(mouseinfo)) != sizeof(mouseinfo) )
-               {
-                       // Not a 3 button mouse, oops
-                       return ;
-               }
-
-//             _SysDebug("sizeof(uint16_t) = %i, sizeof(int16_t) = %i",
-//                     sizeof(uint16_t), sizeof(int16_t));
-//             _SysDebug("NAxies=%i,NButtons=%i", mouseinfo.NAxies, mouseinfo.NButtons);
-//             _SysDebug("offsetof(Axies[0].MinValue) = %i", offsetof(struct sMouseInfo, Axies[0].MinValue));
-//             _SysDebug("[0] = {MinValue=%i,MaxValue=%i,CurValue=%i}",
-//                     mouseinfo.Axies[0].MinValue, mouseinfo.Axies[0].MaxValue,
-//                     mouseinfo.Axies[0].CurValue
-//                     );
-               // Handle movement
-               Video_SetCursorPos( mouseinfo.Axies[0].CursorPos, mouseinfo.Axies[1].CursorPos );
-//             _SysDebug("Cursor to %i,%i", mouseinfo.Axies[0].CursorPos, mouseinfo.Axies[1].CursorPos);
-       }
-}
diff --git a/Usermode/Applications/axwin2_src/WM/interface.c b/Usermode/Applications/axwin2_src/WM/interface.c
deleted file mode 100644 (file)
index 91396ee..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- * 
- * interface.c
- * > Main Overarching UI
- */
-#include "common.h"
-#include "resources/LogoSmall.sif.res.h"
-
-// === GLOBALS ==
- int   giInterface_Width = 0;
- int   giInterface_HeaderBarSize = 20;
- int   giInterface_TabBarSize = 20;
-tElement       *gpInterface_Sidebar;
-tElement       *gpInterface_ProgramList;
-tElement       *gpInterface_MainArea;
-tElement       *gpInterface_HeaderBar;
-tElement       *gpInterface_TabBar;
-tElement       *gpInterface_TabContent;
-const char     csLogoSmall[] = "base64:///"RESOURCE_LogoSmall_sif;
-tApplication   *gpInterface_CurrentApp;
-
-typedef struct sApplicationLink        tApplicationLink;
-
-struct sApplicationLink {
-       tApplication    *App;
-       tElement        *Button;
-       char    Name[];
-};
-
-// === CODE ===
-/**
- * \brief Initialise the UI
- */
-void Interface_Init(void)
-{
-       tElement        *btn, *text;
-       tElement        *ele;
-
-       // Calculate sizes
-       giInterface_Width = giScreenWidth/16;
-       
-       // Set root window to no-border
-       AxWin_SetFlags(NULL, 0);
-       
-       // -- Create Sidebar (Menu and Window List) --
-       gpInterface_Sidebar = AxWin_CreateElement(NULL, ELETYPE_TOOLBAR, ELEFLAG_VERTICAL, "Sidebar");
-       AxWin_SetSize( gpInterface_Sidebar, giInterface_Width );
-       
-       // > System Menu Button
-       btn = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_BUTTON, ELEFLAG_NOSTRETCH, "SystemMenu");
-       AxWin_SetSize(btn, giInterface_Width-4);
-       //text = AxWin_CreateElement(btn, ELETYPE_IMAGE, ELEFLAG_SCALE, "MenuLogo");
-       text = AxWin_CreateElement(btn, ELETYPE_IMAGE, 0, "MenuLogo");
-       //AxWin_SetText(text, "file:///LogoSmall.sif");
-       AxWin_SetText(text, csLogoSmall);
-       
-       // > Plain <hr/> style spacer
-       ele = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_SPACER, ELEFLAG_NOSTRETCH, "SideBar Spacer Top");
-       AxWin_SetSize(ele, 4);
-       
-       // > Application List (Window list on most OSs)
-       gpInterface_ProgramList = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_BOX, ELEFLAG_VERTICAL, "ProgramList");
-       
-       // > Plain <hr/> style spacer
-       ele = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_SPACER, ELEFLAG_NOSTRETCH, "SideBar Spacer Bottom");
-       AxWin_SetSize(ele, 4);
-       
-       // > Version/Time
-       text = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_TEXT, ELEFLAG_NOSTRETCH, "Version String");
-       AxWin_SetSize(text, 20);
-       AxWin_SetText(text, "2.0");
-       
-       // --
-       // -- Create Main Area and regions within --
-       // --
-       // > Righthand Area
-       gpInterface_MainArea = AxWin_CreateElement(NULL, ELETYPE_BOX, ELEFLAG_VERTICAL, "MainArea");
-       //  > Header Bar (Title)
-       gpInterface_HeaderBar = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_BOX, 0, "HeaderBar");
-       AxWin_SetSize(gpInterface_HeaderBar, giInterface_HeaderBarSize);
-       text = AxWin_CreateElement(gpInterface_HeaderBar, ELETYPE_TEXT, 0, NULL);
-       AxWin_SetText(text, "Acess2 GUI - By thePowersGang (John Hodge)");
-       //  > Tab Bar (Current windows)
-       gpInterface_TabBar = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_TABBAR, 0, "TabBar");
-       AxWin_SetSize(gpInterface_TabBar, giInterface_TabBarSize);
-       //  > Application Space
-       gpInterface_TabContent = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_BOX, 0, "TabContent");
-}
-
-void Interface_Update(void)
-{
-//     tApplication    *app;
-//     tApplicationLink        *lnk;
-       giInterface_Width = giScreenWidth/16;
-       AxWin_SetSize( gpInterface_Sidebar, giInterface_Width );
-
-       // Scan application list for changes
-       // - HACK for now, just directly access it
-//     for( app = gWM_Applications; app; app = app->Next )
-//     {
-//             AxWin_CreateElement();
-//     }
-
-       // Update current tab list
-}
-
-void Interface_Render(void)
-{
-       Video_FillRect(
-               0, 0,
-               giInterface_Width, giScreenHeight,
-               0xDDDDDD);
-       
-       Video_Update();
-}
diff --git a/Usermode/Applications/axwin2_src/WM/main.c b/Usermode/Applications/axwin2_src/WM/main.c
deleted file mode 100644 (file)
index 48e47ff..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-
-// === IMPORTS ===
-extern void    WM_Update(void);
-extern int     Input_Init(void);
-
-// === GLOBALS ===
-const char     *gsTerminalDevice = NULL;
-const char     *gsMouseDevice = NULL;
-
- int   giScreenWidth = 640;
- int   giScreenHeight = 480;
-uint32_t       *gpScreenBuffer = NULL;
-
- int   giTerminalFD = -1;
- int   giMouseFD = -1;
-
-// === CODE ===
-/**
- * \brief Program Entrypoint
- */
-int main(int argc, char *argv[])
-{
-       ParseCommandline(argc, argv);
-       
-       if( gsTerminalDevice == NULL ) {
-               gsTerminalDevice = "/Devices/VTerm/6";
-       }
-       if( gsMouseDevice == NULL ) {
-               gsMouseDevice = "/Devices/PS2Mouse";
-       }
-       
-       Video_Setup();
-       Interface_Init();
-       IPC_Init();
-       Input_Init();
-       
-       WM_Update();
-       
-       // Main Loop
-       for(;;)
-       {
-               fd_set  fds;
-                int    nfds = 0;
-               FD_ZERO(&fds);
-       
-               Input_FillSelect(&nfds, &fds);
-               IPC_FillSelect(&nfds, &fds);
-               
-               nfds ++;
-               select(nfds, &fds, NULL, NULL, NULL);
-
-               Input_HandleSelect(&fds);
-               IPC_HandleSelect(&fds);
-       }
-       return 0;
-}
-
diff --git a/Usermode/Applications/axwin2_src/WM/messages.c b/Usermode/Applications/axwin2_src/WM/messages.c
deleted file mode 100644 (file)
index f25e1c4..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-#include <net.h>
-#include <axwin2/messages.h>
-#include <string.h>
-
-#define AXWIN_PORT     4101
-
-#define STATICBUF_SIZE 64
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-void   IPC_Init(void);
-void   IPC_FillSelect(int *nfds, fd_set *set);
-void   IPC_HandleSelect(fd_set *set);
-void   IPC_Handle(tIPC_Type *IPCType, void *Ident, size_t MsgLen, tAxWin_Message *Msg);
-void   IPC_ReturnValue(tIPC_Type *IPCType, void *Ident, int MessageID, uint32_t Value);
- int   IPC_Type_Datagram_GetSize(void *Ident);
- int   IPC_Type_Datagram_Compare(void *Ident1, void *Ident2);
-void   IPC_Type_Datagram_Send(void *Ident, size_t Length, void *Data);
- int   IPC_Type_Sys_GetSize(void *Ident);
- int   IPC_Type_Sys_Compare(void *Ident1, void *Ident2);
-void   IPC_Type_Sys_Send(void *Ident, size_t Length, void *Data);
-
-// === GLOBALS ===
- int   giNetworkFileHandle = -1;
- int   giMessagesFileHandle = -1;
-tIPC_Type      gIPC_Type_Datagram = {
-       IPC_Type_Datagram_GetSize,
-       IPC_Type_Datagram_Compare, 
-       IPC_Type_Datagram_Send
-};
-tIPC_Type      gIPC_Type_SysMessage = {
-       IPC_Type_Sys_GetSize,
-       IPC_Type_Sys_Compare,
-       IPC_Type_Sys_Send
-};
-
-// === CODE ===
-void IPC_Init(void)
-{
-        int    tmp;
-       // TODO: Check this
-       giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ);
-       tmp = AXWIN_PORT;       ioctl(giNetworkFileHandle, 4, &tmp);    // TODO: Don't hard-code IOCtl number
-}
-
-void IPC_FillSelect(int *nfds, fd_set *set)
-{
-       if( giNetworkFileHandle > *nfds )       *nfds = giNetworkFileHandle;
-       FD_SET(giNetworkFileHandle, set);
-}
-
-void IPC_HandleSelect(fd_set *set)
-{
-       if( FD_ISSET(giNetworkFileHandle, set) )
-       {
-               char    staticBuf[STATICBUF_SIZE];
-                int    readlen, identlen;
-               char    *msg;
-
-               readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
-               
-               identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
-               msg = staticBuf + identlen;
-
-               IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
-               _SysDebug("IPC_HandleSelect: UDP handled");
-       }
-
-       while(SysGetMessage(NULL, NULL))
-       {
-               pid_t   tid;
-                int    len = SysGetMessage(&tid, NULL);
-               char    data[len];
-               SysGetMessage(NULL, data);
-
-               IPC_Handle(&gIPC_Type_SysMessage, &tid, len, (void*)data);
-               _SysDebug("IPC_HandleSelect: Message handled");
-       }
-}
-
-void IPC_Handle(tIPC_Type *IPCType, void *Ident, size_t MsgLen, tAxWin_Message *Msg)
-{
-       tApplication    *app;
-       tElement        *ele;
-       
-       _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)",
-               IPCType, Ident, MsgLen, Msg);
-       
-       if( MsgLen < sizeof(tAxWin_Message) )
-               return ;
-       if( MsgLen < sizeof(tAxWin_Message) + Msg->Size )
-               return ;
-       
-       app = AxWin_GetClient(IPCType, Ident);
-
-       switch((enum eAxWin_Messages) Msg->ID)
-       {
-       // --- Ping message (reset timeout and get server version)
-       case MSG_SREQ_PING:
-               _SysDebug(" IPC_Handle: MSG_SREQ_PING");
-               if( MsgLen < sizeof(tAxWin_Message) + 4 )       return;
-               Msg->ID = MSG_SRSP_VERSION;
-               Msg->Size = 4;
-               Msg->Data[0] = 0;
-               Msg->Data[1] = 1;
-               *(uint16_t*)&Msg->Data[2] = -1;
-               IPCType->SendMessage(Ident, sizeof(Msg->ID), Msg);
-               break;
-
-
-       // --- Register an application
-       case MSG_SREQ_REGISTER:
-               _SysDebug(" IPC_Handle: MSG_SREQ_REGISTER");
-               if( Msg->Data[Msg->Size-1] != '\0' ) {
-                       // Invalid message
-                       _SysDebug("IPC_Handle: RETURN - Not NULL terminated");
-                       return ;
-               }
-               
-               if( app != NULL ) {
-                       _SysDebug("Notice: Duplicate registration (%s)\n", Msg->Data);
-                       return ;
-               }
-               
-               // TODO: Should this function be implemented here?
-               AxWin_RegisterClient(IPCType, Ident, Msg->Data);
-               break;
-       
-       // --- Create a window
-       case MSG_SREQ_ADDWIN:
-               _SysDebug(" IPC_Handle: MSG_SREQ_ADDWIN");
-               if( Msg->Data[Msg->Size-1] != '\0' ) {
-                       // Invalid message
-                       return ;
-               }
-               
-               ele = AxWin_CreateAppWindow(app, Msg->Data);
-               IPC_ReturnValue(IPCType, Ident, MSG_SREQ_ADDWIN, ele->ApplicationID);
-               break;
-       
-       // --- Set a window's icon
-       case MSG_SREQ_SETICON:
-               _SysDebug(" IPC_Handle: MSG_SREQ_SETICON");
-               // TODO: Find a good way of implementing this
-               break;
-       
-       // --- Create an element
-       case MSG_SREQ_INSERT: {
-               _SysDebug(" IPC_Handle: MSG_SREQ_INSERT");
-               struct sAxWin_SReq_NewElement   *info = (void *)Msg->Data;
-               
-               if( Msg->Size != sizeof(*info) )        return;
-               
-               if( !app || info->Parent > app->MaxElementIndex )       return ;
-               
-               ele = AxWin_CreateElement( app->EleIndex[info->Parent], info->Type, info->Flags, NULL );
-               IPC_ReturnValue(IPCType, Ident, MSG_SREQ_ADDWIN, ele->ApplicationID);
-               break; }
-       
-       // --- Unknown message
-       default:
-               fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
-               _SysDebug("WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
-               break;
-       }
-}
-
-void IPC_ReturnValue(tIPC_Type *IPCType, void *Ident, int MessageID, uint32_t Value)
-{
-       char    data[sizeof(tAxWin_Message) + sizeof(tAxWin_RetMsg)];
-       tAxWin_Message  *msg = (void *)data;
-       tAxWin_RetMsg   *ret_msg = (void *)msg->Data;
-       
-       msg->Source = 0;        // 0 = Server
-       msg->ID = MSG_SRSP_RETURN;
-       msg->Size = sizeof(tAxWin_RetMsg);
-       ret_msg->ReqID = MessageID;
-       ret_msg->Rsvd = 0;
-       ret_msg->Value = Value;
-       
-       IPCType->SendMessage(Ident, sizeof(data), data);
-}
-
-int IPC_Type_Datagram_GetSize(void *Ident)
-{
-       return 4 + Net_GetAddressSize( ((uint16_t*)Ident)[1] );
-}
-
-int IPC_Type_Datagram_Compare(void *Ident1, void *Ident2)
-{
-       // Pass the buck :)
-       // - No need to worry about mis-matching sizes, as the size is computed
-       //   from the 3rd/4th bytes, hence it will differ before the size is hit.
-       return memcmp(Ident1, Ident2, IPC_Type_Datagram_GetSize(Ident1));
-}
-
-void IPC_Type_Datagram_Send(void *Ident, size_t Length, void *Data)
-{
-        int    identlen = IPC_Type_Datagram_GetSize(Ident);
-       char    tmpbuf[ identlen + Length ];
-       memcpy(tmpbuf, Ident, identlen);        // Header
-       memcpy(tmpbuf + identlen, Data, Length);        // Data
-       // TODO: Handle fragmented packets
-       write(giNetworkFileHandle, tmpbuf, sizeof(tmpbuf));
-}
-
-int IPC_Type_Sys_GetSize(void *Ident)
-{
-       return sizeof(pid_t);
-}
-
-int IPC_Type_Sys_Compare(void *Ident1, void *Ident2)
-{
-       return *(int*)Ident1 - *(int*)Ident2;
-}
-
-void IPC_Type_Sys_Send(void *Ident, size_t Length, void *Data)
-{
-       SysSendMessage( *(tid_t*)Ident, Length, Data );
-}
diff --git a/Usermode/Applications/axwin2_src/WM/render.c b/Usermode/Applications/axwin2_src/WM/render.c
deleted file mode 100644 (file)
index 0ee9e80..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- * 
- * Rendering code
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include "wm.h"
-#include <acess/sys.h> // _SysDebug
-
-// === IMPORTS ===
-extern void    Decorator_RenderWidget(tElement *Element);
-extern tElement        gWM_RootElement;
-extern tApplication    *gWM_Applications;
-extern int     giWM_MaxAreaX;
-extern int     giWM_MaxAreaY;
-extern int     giWM_MaxAreaW;
-extern int     giWM_MaxAreaH;
-
-// === PROTOTYPES ===
-void   WM_UpdateMinDims(tElement *Element);
-void   WM_UpdateDimensions(tElement *Element, int Pass);
-void   WM_UpdatePosition(tElement *Element);
-void   WM_RenderWidget(tElement *Element);
-void   WM_Update(void);
-
-// === CODE ===
-/**
- * \brief Updates the dimensions of an element
- * \todo What is the \a Pass parameter for
- * 
- * The dimensions of an element are calculated from the parent's
- * cross dimension (the side at right angles to the alignment) sans some
- * padding.
- */
-void WM_UpdateDimensions(tElement *Element, int Pass)
-{
-       tElement        *child;
-        int    nChildren = 0;
-        int    nFixed = 0;
-        int    maxCross = 0;
-        int    fixedSize = 0;
-        int    fullCross, dynWith;
-       
-       _SysDebug("WM_UpdateDimensions %p'%s'", Element, Element->DebugName);
-       _SysDebug(" -> Flags = 0x%x", Element->Flags);
-       _SysDebug(" ->CachedH = %i, ->PaddingT = %i, ->PaddingB = %i",
-               Element->CachedH, Element->PaddingT, Element->PaddingB
-               );
-       _SysDebug(" ->CachedW = %i, ->PaddingL = %i, ->PaddingR = %i",
-               Element->CachedW, Element->PaddingL, Element->PaddingR
-               );
-       
-       // Pass 1
-       for( child = Element->FirstChild; child; child = child->NextSibling )
-       {
-               if( child->Flags & ELEFLAG_ABSOLUTEPOS )
-                       continue ;
-               
-               _SysDebug(" > %p'%s' ->FixedWith = %i", child, child->DebugName, child->FixedWith);
-               if( child->FixedWith )
-               {
-                       nFixed ++;
-                       fixedSize += child->FixedWith;
-               }
-               
-               if( child->FixedCross && maxCross < child->FixedCross )
-                       maxCross = child->FixedCross;
-               if( child->MinCross && maxCross < child->MinCross )
-                       maxCross = child->MinCross;
-               nChildren ++;
-       }
-       
-       _SysDebug(" - nChildren = %i, nFixed = %i", Element, nChildren, nFixed);
-       if( nChildren > nFixed ) {
-               if( Element->Flags & ELEFLAG_VERTICAL )
-                       dynWith = Element->CachedH - Element->PaddingT
-                               - Element->PaddingB;
-               else
-                       dynWith = Element->CachedW - Element->PaddingL
-                               - Element->PaddingR;
-               dynWith -= fixedSize;
-               if( dynWith < 0 )       return ;
-               dynWith /= nChildren - nFixed;
-               _SysDebug(" - dynWith = %i", dynWith);
-       }
-       
-       if( Element->Flags & ELEFLAG_VERTICAL )
-               fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
-       else
-               fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
-       
-       _SysDebug(" - fullCross = %i", Element, fullCross);
-       
-       // Pass 2 - Set sizes and recurse
-       for( child = Element->FirstChild; child; child = child->NextSibling )
-       {
-                int    cross, with;
-               
-               _SysDebug(" > %p'%s' ->MinCross = %i", child, child->DebugName, child->MinCross);
-
-               
-               // --- Cross Size ---
-               if( child->FixedCross )
-                       cross = child->FixedCross;
-               // Expand to fill?
-               // TODO: Extra flag so options are (Expand, Equal, Wrap)
-               else if( child->Flags & ELEFLAG_NOEXPAND )
-                       cross = child->MinCross;
-               else
-                       cross = fullCross;
-               _SysDebug(" > %p'%s' - cross = %i", child, child->DebugName, cross);
-               if( Element->Flags & ELEFLAG_VERTICAL )
-                       child->CachedW = cross;
-               else
-                       child->CachedH = cross;
-               
-               // --- With Size ---
-               if( child->FixedWith)
-                       with = child->FixedWith;
-               else if( child->Flags & ELEFLAG_NOSTRETCH )
-                       with = child->MinWith;
-               else
-                       with = dynWith;
-               _SysDebug(" > %p'%s' - with = %i", child, child->DebugName, with);
-               if( Element->Flags & ELEFLAG_VERTICAL )
-                       child->CachedH = with;
-               else
-                       child->CachedW = with;
-               
-               WM_UpdateDimensions(child, Pass);
-       }
-       
-       _SysDebug("%p'%s' Done", Element, Element->DebugName);
-}
-
-/**
- * \brief Updates the position of an element
- * 
- * The parent element sets the positions of its children
- */
-void WM_UpdatePosition(tElement *Element)
-{
-       tElement        *child;
-        int    x, y;
-       static int      depth = 0;
-       char    indent[depth+1];
-       
-       if( Element->Flags & ELEFLAG_NORENDER ) return ;
-       
-       memset(indent, ' ', depth);
-       indent[depth] = '\0';
-       depth ++;
-       
-       _SysDebug("%sWM_UpdatePosition %p'%s'{PaddingL:%i, PaddingT:%i}",
-               indent, Element, Element->DebugName, Element->PaddingL, Element->PaddingT);
-       
-       // Initialise
-       x = Element->CachedX + Element->PaddingL;
-       y = Element->CachedY + Element->PaddingT;
-       
-       _SysDebug("%s- Alignment = %s", indent,
-               (Element->Flags & ELEFLAG_VERTICAL) ? "vertical" : "horizontal");
-
-       // Update each child
-       for(child = Element->FirstChild; child; child = child->NextSibling)
-       {
-               _SysDebug("%s- x = %i, y = %i", indent, x, y);
-               child->CachedX = x;
-               child->CachedY = y;
-               
-               // Set Alignment
-               if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
-                       _SysDebug("%sChild being aligned to center", indent);
-                       if(Element->Flags & ELEFLAG_VERTICAL)
-                               child->CachedX += Element->CachedW/2 - child->CachedW/2;
-                       else
-                               child->CachedY += Element->CachedH/2 - child->CachedH/2;
-               }
-               else if( Element->Flags & ELEFLAG_ALIGN_END) {
-                       _SysDebug("%sChild being aligned to end", indent);
-                       if(Element->Flags & ELEFLAG_VERTICAL )
-                               child->CachedX += Element->CachedW
-                                       - Element->PaddingL - Element->PaddingR
-                                       - child->CachedW;
-                       else
-                               child->CachedY += Element->CachedH
-                                       - Element->PaddingT
-                                       - Element->PaddingB
-                                       - child->CachedH;
-               }
-               
-               _SysDebug("%s> %p'%s' at (%i,%i)", indent, child, child->DebugName,
-                       child->CachedX, child->CachedY);
-       
-               // Update child's children positions
-               WM_UpdatePosition(child);
-               
-               // Increment
-               if(Element->Flags & ELEFLAG_VERTICAL ) {
-                       y += child->CachedH + Element->GapSize;
-               }
-               else {
-                       x += child->CachedW + Element->GapSize;
-               }
-       }
-       
-       _SysDebug("%sElement %p'%s' (%i,%i)",
-               indent, Element, Element->DebugName, Element->CachedX, Element->CachedY
-               );
-       depth --;
-}
-
-/**
- * \brief Update the minimum dimensions of the element
- * \note Called after a child's minimum dimensions have changed
- */
-void WM_UpdateMinDims(tElement *Element)
-{
-       tElement        *child;
-       
-       if(!Element)    return;
-       
-       Element->MinCross = 0;
-       Element->MinWith = 0;
-       
-       for(child = Element->FirstChild; child; child = child->NextSibling)
-       {
-               if( Element->Parent &&
-                       (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL)
-                       )
-               {
-                       if(child->FixedCross)
-                               Element->MinCross += child->FixedCross;
-                       else
-                               Element->MinCross += child->MinCross;
-                       if(child->FixedWith)
-                               Element->MinWith += child->FixedWith;
-                       else
-                               Element->MinWith += child->MinWith;
-               }
-               else
-               {
-                       if(child->FixedCross)
-                               Element->MinWith += child->FixedCross;
-                       else
-                               Element->MinWith += child->MinCross;
-                       if(child->FixedWith)
-                               Element->MinCross += child->FixedWith;
-                       else
-                               Element->MinCross += child->MinWith;
-               }
-       }
-       
-       // Recurse upwards
-       WM_UpdateMinDims(Element->Parent);
-}
-
-// --- Render ---
-void WM_RenderWidget(tElement *Element)
-{
-       tElement        *child;
-       
-       if( Element->Flags & ELEFLAG_NORENDER ) return ;
-       if( Element->Flags & ELEFLAG_INVISIBLE )        return ;
-       
-       Decorator_RenderWidget(Element);
-       
-       for(child = Element->FirstChild; child; child = child->NextSibling)
-       {
-               WM_RenderWidget(child);
-       }
-}
-
-void WM_UpdateWindow(tElement *Ele)
-{      
-       WM_UpdateDimensions( Ele, 0 );
-       WM_UpdatePosition( Ele );
-       WM_RenderWidget( Ele );
-}
-
-void WM_Update(void)
-{
-       tApplication    *app;
-       tElement        *ele;
-       
-       for( app = gWM_Applications; app; app = app->Next )
-       {
-               for( ele = app->MetaElement.FirstChild; ele; ele = ele->NextSibling ) {
-                       if( ele->Flags & ELEFLAG_WINDOW_MAXIMISED ) {
-                               ele->CachedX = giWM_MaxAreaX;
-                               ele->CachedY = giWM_MaxAreaY;
-                               ele->CachedW = giWM_MaxAreaW;
-                               ele->CachedH = giWM_MaxAreaH;
-                       }
-                       ele->Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
-                       WM_UpdateWindow(ele);
-               }
-       }
-       
-       gWM_RootElement.CachedX = 0;
-       gWM_RootElement.CachedY = 0;
-       gWM_RootElement.CachedW = giScreenWidth;
-       gWM_RootElement.CachedH = giScreenHeight;
-       gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
-       
-       WM_UpdateWindow( &gWM_RootElement );
-       
-       Video_Update();
-}
diff --git a/Usermode/Applications/axwin2_src/WM/resources/LogoSmall.sif b/Usermode/Applications/axwin2_src/WM/resources/LogoSmall.sif
deleted file mode 100644 (file)
index 2064e48..0000000
Binary files a/Usermode/Applications/axwin2_src/WM/resources/LogoSmall.sif and /dev/null differ
diff --git a/Usermode/Applications/axwin2_src/WM/resources/cursor.h b/Usermode/Applications/axwin2_src/WM/resources/cursor.h
deleted file mode 100644 (file)
index 3cce1f2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- */
-#ifndef _RESORUCE_CURSOR_H
-#define _RESORUCE_CURSOR_H
-
-#include <stdint.h>
-
-static struct {
-       uint16_t        W, H, OfsX, OfsY;
-       uint32_t        Data[];
-} cCursorBitmap = {
-       8, 16, 0, 0,
-       {
-               0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000,
-               0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000,
-               0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000,
-               0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000,
-               0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000,
-               0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000,
-               0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000,
-               0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0x00000000,
-               0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
-       }
-};
-
-#endif
-
diff --git a/Usermode/Applications/axwin2_src/WM/video.c b/Usermode/Applications/axwin2_src/WM/video.c
deleted file mode 100644 (file)
index 4121fbe..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-#include <acess/devices/terminal.h>
-#include <image.h>
-#include "resources/cursor.h"
-
-// === PROTOTYPES ===
-void   Video_Setup(void);
-void   Video_SetCursorPos(short X, short Y);
-void   Video_Update(void);
-void   Video_FillRect(short X, short Y, short W, short H, uint32_t Color);
-void   Video_DrawRect(short X, short Y, short W, short H, uint32_t Color);
-
-// === GLOBALS ===
- int   giVideo_CursorX;
- int   giVideo_CursorY;
-
-// === CODE ===
-void Video_Setup(void)
-{
-        int    tmpInt;
-       
-       // Open terminal
-       giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
-       if( giTerminalFD == -1 )
-       {
-               fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
-               exit(-1);
-       }
-       
-       // Set width
-       tmpInt = giScreenWidth;
-       tmpInt = ioctl( giTerminalFD, TERM_IOCTL_WIDTH, &tmpInt );
-       if(tmpInt != giScreenWidth)
-       {
-               fprintf(stderr, "Warning: Selected width (%i) is invalid, clipped to %i\n",
-                       giScreenWidth, tmpInt);
-               giScreenWidth = tmpInt;
-       }
-       
-       // Set height
-       tmpInt = giScreenHeight;
-       tmpInt = ioctl( giTerminalFD, TERM_IOCTL_HEIGHT, &tmpInt );
-       if(tmpInt != giScreenHeight)
-       {
-               fprintf(stderr, "Warning: Selected height (%i) is invalid, clipped to %i\n",
-                       giScreenHeight, tmpInt);
-               giScreenHeight = tmpInt;
-       }
-       
-       // Set mode to video
-       tmpInt = TERM_MODE_FB;
-       ioctl( giTerminalFD, TERM_IOCTL_MODETYPE, &tmpInt );
-       
-       // Force VT to be shown
-       ioctl( giTerminalFD, TERM_IOCTL_FORCESHOW, NULL );
-       
-       // Create local framebuffer (back buffer)
-       gpScreenBuffer = malloc( giScreenWidth*giScreenHeight*4 );
-       memset32( gpScreenBuffer, 0x8888FF, giScreenWidth*giScreenHeight );
-
-       // Set cursor position and bitmap
-       ioctl(giTerminalFD, TERM_IOCTL_SETCURSORBITMAP, &cCursorBitmap);
-       Video_SetCursorPos( giScreenWidth/2, giScreenHeight/2 );
-
-       Video_Update();
-}
-
-void Video_Update(void)
-{
-       //seek(giTerminalFD, 0, SEEK_SET);
-       seek(giTerminalFD, 0, 1);
-       write(giTerminalFD, gpScreenBuffer, giScreenWidth*giScreenHeight*4);
-}
-
-void Video_SetCursorPos(short X, short Y)
-{
-       struct {
-               uint16_t        x;
-               uint16_t        y;
-       } pos;
-       pos.x = giVideo_CursorX = X;
-       pos.y = giVideo_CursorY = Y;
-       ioctl(giTerminalFD, TERM_IOCTL_GETSETCURSOR, &pos);
-}
-
-void Video_FillRect(short X, short Y, short W, short H, uint32_t Color)
-{
-       uint32_t        *buf = gpScreenBuffer + Y*giScreenWidth + X;
-       
-       _SysDebug("Video_FillRect: (X=%i, Y=%i, W=%i, H=%i, Color=%08x)",
-               X, Y, W, H, Color);
-       
-       if(W < 0 || X < 0 || X >= giScreenWidth)        return ;
-       if(X + W > giScreenWidth)       W = giScreenWidth - X;
-       
-       if(H < 0 || Y < 0 || Y >= giScreenHeight)       return ;
-       if(Y + H > giScreenHeight)      H = giScreenHeight - Y;
-       
-       while( H -- )
-       {
-               memset32( buf, Color, W );
-               buf += giScreenWidth;
-       }
-}
-
-void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color)
-{      
-       Video_FillRect(X, Y, W, 1, Color);
-       Video_FillRect(X, Y+H-1, W, 1, Color);
-       Video_FillRect(X, Y, 1, H, Color);
-       Video_FillRect(X+W-1, Y, 1, H, Color);
-}
-
-/**
- * \brief Draw an image to the screen
- * \todo Maybe have support for an offset in the image
- */
-void Video_DrawImage(short X, short Y, short W, short H, tImage *Image)
-{
-        int    x, y;
-       uint8_t *buf = (uint8_t *)(gpScreenBuffer + Y*giScreenWidth + X);
-       uint8_t *data;
-       
-       // Sanity please
-       if( !Image )
-               return ;
-       
-       // Bounds Check
-       if( X >= giScreenWidth )        return ;
-       if( Y >= giScreenHeight )       return ;
-       
-       // Wrap to image size
-       if( W > Image->Width )  W = Image->Width;
-       if( H > Image->Height ) H = Image->Height;
-       
-       // Wrap to screen size
-       if( X + W > giScreenWidth )     W = giScreenWidth - X;
-       if( Y + H > giScreenHeight )    H = giScreenHeight - Y;
-       
-       // Do the render
-       data = Image->Data;
-       switch( Image->Format )
-       {
-       case IMGFMT_BGRA:
-               for( y = 0; y < H; y ++ )
-               {
-                        int    r, g, b, a;     // New
-                        int    or, og, ob;     // Original
-                       for( x = 0; x < W; x ++ )
-                       {
-                               b = data[x*4+0]; g = data[x*4+1]; r = data[x*4+2]; a = data[x*4+3];
-                               if( a == 0 )    continue;       // 100% transparent
-                               ob = buf[x*4+0]; og = buf[x*4+1]; or = buf[x*4+2];
-                               // Handle Alpha
-                               switch(a)
-                               {
-                               // Transparent: Handled above
-                               // Solid
-                               case 0xFF:      break;
-                               // Half
-                               case 0x80:
-                                       r = (or + r) / 2;
-                                       g = (og + g) / 2;
-                                       b = (ob + b) / 2;
-                                       break;
-                               // General
-                               default:
-                                       r = (or * (255-a) + r * a) / 255;
-                                       g = (og * (255-a) + g * a) / 255;
-                                       b = (ob * (255-a) + b * a) / 255;
-                                       break;
-                               }
-                               buf[x*4+0] = b; buf[x*4+1] = g; buf[x*4+2] = r;
-                       }
-                       data += Image->Width * 4;
-                       buf += giScreenWidth * 4;
-               }
-               break;
-       
-       // RGB
-       case IMGFMT_RGB:
-               for( y = 0; y < H; y ++ )
-               {
-                       for( x = 0; x < W; x ++ )
-                       {
-                               buf[x*4+0] = data[x*3+2];       // Blue
-                               buf[x*4+1] = data[x*3+1];       // Green
-                               buf[x*4+2] = data[x*3+0];       // Red
-                       }
-                       data += W * 3;
-                       buf += giScreenWidth * 4;
-               }
-               break;
-       default:
-               _SysDebug("ERROR: Unknown image format %i\n", Image->Format);
-               break;
-       }
-}
diff --git a/Usermode/Applications/axwin2_src/WM/video_text.c b/Usermode/Applications/axwin2_src/WM/video_text.c
deleted file mode 100644 (file)
index 3d680d5..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include <acess/sys.h>
-#include "common.h"
-
-typedef struct sGlyph {
-       struct sGlyph   *Next;
-       struct sGlyph   *Prev;
-       
-       uint32_t        Codepoint;
-       
-       // Effective dimensions (distance to move 'cursor')
-       short   Width;
-       short   Height;
-       
-       // Distance from the current cursor position to render at
-       short   OffsetX;
-       short   OffsetY;
-       
-       // True dimensions (size of the bitmap
-       short   TrueWidth;
-       short   TrueHeight;
-       
-       // Bitmap Data
-       uint8_t Bitmap[];       // 8-bit alpha
-       
-}      tGlyph;
-
-struct sFont {
-       struct sFont    *Next;
-        int    ReferenceCount;
-       
-       tGlyph  *AsciiGlyphs[128];      // Glyphs 0-127
-       
-       tGlyph  *FirstGlyph;
-       tGlyph  *LastGlyph;
-       
-       tGlyph  *(*CacheGlyph)(struct sFont *this, uint32_t Codepoint);
-       
-};
-
-
-// === PROTOTYPES ===
- int   Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
-void   Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
-tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint);
-void   _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color);
-tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint);
- int   ReadUTF8(const char *Input, uint32_t *Output);
-
-// === GLOBALS ===
-tFont  gSystemFont = {
-       .CacheGlyph = _SystemFont_CacheGlyph
-};
-
-// === CODE ===
-/**
- * \brief Draw text to the screen
- */
-int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text)
-{
-        int    xOfs = 0;
-       tGlyph  *glyph;
-       uint32_t        ch = 0;
-
-       _SysDebug("Video_DrawText: (X=%i,Y=%i,W=%i,H=%i,Font=%p,", X, Y, W, H, Font);
-       _SysDebug("  Color=%08x,Text='%s')", Color, Text);
-       
-       // Check the bounds
-       if(W < 0 || X < 0 || X >= giScreenWidth)        return 0;
-       if(X + W > giScreenWidth)       W = giScreenWidth - X;
-       
-       if(H < 0 || Y < 0 || Y >= giScreenHeight)       return 0;
-       if(Y + H > giScreenHeight)      H = giScreenHeight - Y;
-       
-       // Handle NULL font (system default monospace)
-       if( !Font )     Font = &gSystemFont;
-       
-       while( *Text )
-       {
-               // Read character
-               Text += ReadUTF8(Text, &ch);
-               
-               // Find (or load) the glyph
-               glyph = _GetGlyph(Font, ch);
-               if( !glyph )    continue ;      // If not found, just don't render it
-               
-               // End render if it will overflow the perscribed range
-               if( xOfs + glyph->TrueWidth > W )
-                       break;
-               
-               xOfs += glyph->Width;
-               _RenderGlyph(X + xOfs, Y, glyph, Color);
-       }
-       
-       return xOfs;
-}
-
-void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H)
-{
-        int    w=0, h=0;
-       uint32_t        ch;
-       tGlyph  *glyph;
-       if( !Font )     Font = &gSystemFont;
-       
-       while( *Text )
-       {
-               Text += ReadUTF8(Text, &ch);
-               glyph = _GetGlyph(Font, ch);
-               if( !glyph )    continue;
-               
-               w += glyph->Width;
-               if( h < glyph->Height ) h = glyph->Height;
-       }
-       
-       if(W)   *W = w;
-       if(H)   *H = h;
-}
-
-tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint)
-{
-       tGlyph  *next = NULL, *prev = NULL;
-       tGlyph  *new;
-       
-       // Check for ASCII
-       if( Codepoint < 128 )
-       {
-               if( Font->AsciiGlyphs[Codepoint] == NULL ) {
-                       Font->AsciiGlyphs[Codepoint] = Font->CacheGlyph(Font, Codepoint);
-               }
-               
-               return Font->AsciiGlyphs[Codepoint];
-       }
-       
-       // If within the range
-       if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
-       {
-               // Find what end is "closest"
-               if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
-               {
-                       // Start from the bottom
-                       for( next = Font->FirstGlyph;
-                                next && next->Codepoint < Codepoint;
-                                prev = next, next = next->Next
-                                );
-                       
-                       if( next->Codepoint == Codepoint )
-                               return next;
-                       
-               }
-               else
-               {
-                       // Start at the top
-                       // NOTE: The roles of next and prev are reversed here to allow 
-                       //       the insert to be able to assume that `prev` is the
-                       //       previous entry, and `next` is the next.
-                       for( prev = Font->LastGlyph;
-                                prev && prev->Codepoint > Codepoint;
-                                next = prev, prev = prev->Prev
-                                );
-                       if( prev->Codepoint == Codepoint )
-                               return prev;
-               }
-       }
-       else
-       {
-               // If below first
-               if( !Font->FirstGlyph ||  Font->FirstGlyph->Codepoint > Codepoint ) {
-                       prev = NULL;
-                       next = Font->FirstGlyph;
-               }
-               // Above last
-               else {
-                       prev = Font->LastGlyph;
-                       next = NULL;
-               }
-       }
-       
-       // Load new
-       new = Font->CacheGlyph(Font, Codepoint);
-       if( !new )      return NULL;
-       
-       // Add to list
-       // - Forward link
-       if( prev ) {
-               new->Next = prev->Next;
-               prev->Next = new;
-       }
-       else {
-               new->Next = Font->FirstGlyph;
-               Font->FirstGlyph = new;
-       }
-       
-       // - Backlink
-       if( next ) {
-               new->Prev = next->Prev;
-               next->Prev = new;
-       }
-       else {
-               new->Prev = Font->LastGlyph;
-               Font->LastGlyph = new;
-       }
-       
-       // Return
-       return new;
-}
-
-/**
- */
-void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color)
-{
-        int    xStart = 0, yStart = 0;
-        int    x, y;
-       uint32_t        *outBuf;
-       uint8_t *inBuf;
-       // TODO: Implement
-
-       X += Glyph->OffsetX;
-       if( X < 0 ) {   // If -ve, skip the first -X collums
-               xStart = -X;
-               X = 0;
-       }
-
-       Y += Glyph->OffsetY;
-       if( Y < 0 ) {   // If -ve, skip the first -Y lines
-               yStart = -Y;
-               Y = 0;
-       }
-
-       outBuf = gpScreenBuffer + Y*giScreenWidth + X;
-       inBuf = Glyph->Bitmap + yStart*Glyph->TrueWidth;
-
-       for( y = yStart; y < Glyph->TrueHeight; y ++ )
-       {
-               for( x = xStart; x < Glyph->TrueWidth; x ++ )
-               {
-                       outBuf[x] = Video_AlphaBlend( outBuf[x], Color, inBuf[x] );
-               }
-               outBuf += giScreenWidth;
-               inBuf += Glyph->TrueWidth;
-
-       }
-}
-
-// Load system font (8x16 monospace)
-#include "font_8x16.h"
-
-/*
- */
-tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
-{
-        int    i;
-       uint8_t index = 0;
-       tGlyph  *ret;
-       uint8_t *data;
-
-       _SysDebug("_SystemFont_CacheGlyph: (Font=%p, Codepoint=0x%06x)", Font, Codepoint);
-       
-       if( Codepoint < 128 ) {
-               index = Codepoint;
-       }
-       else {
-               index = '?';    // Unknowns come out as a question mark
-       }
-
-       _SysDebug(" index = %i", index);
-
-       ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
-       if( !ret ) {
-               _SysDebug("ERROR: malloc(%i) failed", sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT);
-               return NULL;
-       }
-
-       ret->Codepoint = Codepoint;
-
-       ret->Width = FONT_WIDTH;
-       ret->Height = FONT_HEIGHT;
-       
-       ret->TrueWidth = FONT_WIDTH;
-       ret->TrueHeight = FONT_HEIGHT;
-
-       ret->OffsetX = 0;
-       ret->OffsetY = 0;
-       
-       data = &VTermFont[index * FONT_HEIGHT];
-
-       for( i = 0; i < FONT_HEIGHT; i ++ )
-       {
-               ret->Bitmap[ i * 8 + 0 ] = data[i] & (1 << 7) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 1 ] = data[i] & (1 << 6) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 2 ] = data[i] & (1 << 5) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 3 ] = data[i] & (1 << 4) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 4 ] = data[i] & (1 << 3) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 5 ] = data[i] & (1 << 2) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 6 ] = data[i] & (1 << 1) ? 255 : 0;
-               ret->Bitmap[ i * 8 + 7 ] = data[i] & (1 << 0) ? 255 : 0;
-       }
-
-       return ret;
-}
-
-
-/**
- * \fn int ReadUTF8(char *Input, uint32_t *Val)
- * \brief Read a UTF-8 character from a string
- */
-int ReadUTF8(const char *Input, uint32_t *Val)
-{
-       const uint8_t   *str = (const uint8_t *)Input;
-       *Val = 0xFFFD;  // Assume invalid character
-       
-       // ASCII
-       if( !(*str & 0x80) ) {
-               *Val = *str;
-               return 1;
-       }
-       
-       // Middle of a sequence
-       if( (*str & 0xC0) == 0x80 ) {
-               return 1;
-       }
-       
-       // Two Byte
-       if( (*str & 0xE0) == 0xC0 ) {
-               *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 2;
-       }
-       
-       // Three Byte
-       if( (*str & 0xF0) == 0xE0 ) {
-               *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 3;
-       }
-       
-       // Four Byte
-       if( (*str & 0xF1) == 0xF0 ) {
-               *Val = (*str & 0x07) << 18;     // Upper 3 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
-               str ++;
-               if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
-               *Val |= (*str & 0x3F);  // Lower 6 Bits
-               return 4;
-       }
-       
-       // UTF-8 Doesn't support more than four bytes
-       return 4;
-}
-
-
-
-
diff --git a/Usermode/Applications/axwin2_src/WM/wm.c b/Usermode/Applications/axwin2_src/WM/wm.c
deleted file mode 100644 (file)
index b073223..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- * 
- * Window Manager and Widget Control
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include "wm.h"
-#include <acess/sys.h> // _SysDebug
-
-// === IMPORTS ===
-extern void    Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
-
-// === PROTOTYPES ===
-tApplication   *AxWin_RegisterClient(tIPC_Type *IPCType, void *Ident, const char *Name);
-void   AxWin_DeregisterClient(tApplication *App);
-tApplication   *AxWin_GetClient(tIPC_Type *Method, void *Ident);
-tElement       *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
-void   AxWin_DeleteElement(tElement *Element);
-void   AxWin_SetFlags(tElement *Element, int Flags);
-void   AxWin_SetSize(tElement *Element, int Size);
-void   AxWin_SetText(tElement *Element, const char *Text);
-
-// === GLOBALS ===
-// - TODO: Handle windows by having multiple root elements
-tElement       gWM_RootElement = {
-       .DebugName = "ROOT"
-};
-tWindow        *gWM_WindowFirst;
-tWindow        *gWM_WindowLast;
-tApplication   *gWM_Applications;
- int   giWM_MaxAreaX = 0;
- int   giWM_MaxAreaY = 0;
- int   giWM_MaxAreaW = -1;
- int   giWM_MaxAreaH = -1;
-
-// --- Element type flags
-struct {
-       void    (*Init)(tElement *This);
-       void    (*Delete)(tElement *This);
-       void    (*UpdateFlags)(tElement *This);
-       void    (*UpdateSize)(tElement *This);
-       void    (*UpdateText)(tElement *This);
-}      gaWM_WidgetTypes[MAX_ELETYPES] = {
-       {NULL, NULL, NULL, NULL, NULL}, // NULL
-       {NULL, NULL, NULL, NULL, NULL}, // Window
-       {NULL, NULL, NULL, NULL, NULL}  // Box
-};
-const int      ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
-
-// === CODE ===
-tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name)
-{
-        int    identlen = Method->GetIdentSize(Ident);
-       // Structure, empty string, Name, Ident
-       tApplication    *ret = calloc( 1, sizeof(tApplication) + 1 + strlen(Name) + 1 + identlen );
-       
-       // DebugName is empty
-       
-       // Name/Title
-       ret->Name = &ret->MetaElement.DebugName[1];
-       strcpy(ret->Name, Name);
-       // Ident
-       ret->Ident = ret->Name + strlen(Name) + 1;
-       memcpy(ret->Ident, Ident, identlen);
-       // IPC Type
-       ret->IPCType = Method;
-
-       // Element index
-       ret->MaxElementIndex = DEFAULT_ELEMENTS_PER_APP;
-       ret->EleIndex = calloc( 1, ret->MaxElementIndex * sizeof(*ret->EleIndex) );
-
-       // Add to global list
-       ret->Next = gWM_Applications;
-       gWM_Applications = ret;
-
-       // TODO: Inform listeners of the new application
-
-       return ret;
-}
-
-void AxWin_DeregisterClient(tApplication *App)
-{
-       // TODO: Complete implementing DeregisterClient
-       tElement        *win, *next;
-
-       for( win = App->MetaElement.FirstChild; win; win = next )
-       {
-               next = win->NextSibling;
-               AxWin_DeleteElement(win);
-       }
-
-       // TODO: Inform listeners of deleted application
-       
-       // Remove from list
-       {
-               tApplication    *app, *prev = NULL;
-               for( app = gWM_Applications; app; app = app->Next )
-               {
-                       if( app == App )        break;
-                       prev = app;
-               }
-               
-               if( app )
-               {
-                       if(prev)
-                               prev->Next = App->Next;
-                       else
-                               gWM_Applications = App->Next;
-               }
-       }
-       
-       free(App);
-}
-
-/**
- * \brief Get an application handle from a client identifier
- */
-tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident)
-{
-       // TODO: Faster and smarter technique
-       tApplication    *app;
-       for( app = gWM_Applications; app; app = app->Next )
-       {
-               if( app->IPCType != Method )    continue;
-               if( Method->CompareIdent( app->Ident, Ident ) != 0 ) continue;
-               return app;
-       }
-       return NULL;
-}
-
-tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name)
-{
-       tElement        *ret;
-       tWindow *win;
-       
-       win = calloc(1, sizeof(tWindow) + 1);
-       if(!win)        return NULL;
-       
-       ret = &win->RootElement;
-       ret->Type = ELETYPE_WINDOW;
-       ret->Data = win;
-       ret->Parent = &App->MetaElement;
-       
-       // Add to parent list
-       if(ret->Parent->LastChild)
-               ret->Parent->LastChild->NextSibling = ret;
-       ret->Parent->LastChild = ret;
-       if(!ret->Parent->FirstChild)
-               ret->Parent->FirstChild = ret;
-       
-       ret->Text = strdup(Name);
-       
-       return ret;
-}
-
-// --- Widget Creation and Control ---
-tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
-{
-       tElement        *ret;
-       const char      *dbgName = DebugName ? DebugName : "";
-       
-       ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
-       if(!ret)        return NULL;
-       
-       // Prepare
-       ret->Type = Type;
-       strcpy(ret->DebugName, dbgName);
-       if(Parent == NULL)      Parent = &gWM_RootElement;
-       ret->Parent = Parent;
-       ret->Flags = Flags;
-       
-       // Append to parent's list
-       if(Parent->LastChild)
-               Parent->LastChild->NextSibling = ret;
-       Parent->LastChild = ret;
-       if(!Parent->FirstChild) Parent->FirstChild = ret;
-       
-       ret->PaddingL = 2;
-       ret->PaddingR = 2;
-       ret->PaddingT = 2;
-       ret->PaddingB = 2;
-       
-       if( Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Type].Init )
-               gaWM_WidgetTypes[Type].Init(ret);
-       
-       WM_UpdateMinDims(ret->Parent);
-       
-       return ret;
-}
-
-/**
- * \brief Delete an element
- */
-void AxWin_DeleteElement(tElement *Element)
-{
-       tElement        *child, *next;
-       
-       for(child = Element->FirstChild; child; child = next)
-       {
-               next = child->NextSibling;
-               AxWin_DeleteElement(child);
-       }
-
-       // TODO: Implement AxWin_DeleteElement
-       // TODO: Clean up related data.
-       if( Element->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Element->Type].Delete )
-               gaWM_WidgetTypes[Element->Type].Delete(Element);
-
-       if(Element->Owner)
-               Element->Owner->EleIndex[ Element->ApplicationID ] = NULL;
-
-       Element->Type = 0;
-       Element->Owner = 0;
-       Element->Flags = 0;
-
-       free(Element);
-}
-
-/**
- * \brief Alter an element's flags 
- */
-void AxWin_SetFlags(tElement *Element, int Flags)
-{
-       // Permissions are handled in the message handler
-       if(!Element) {
-               gWM_RootElement.Flags = Flags;
-               return ;
-       }
-       
-       Element->Flags = Flags;
-       return ;
-}
-
-/**
- * \brief Set the fixed lenghthways size of an element
- */
-void AxWin_SetSize(tElement *Element, int Size)
-{
-       if(!Element)    return ;
-       Element->FixedWith = Size;
-       return ;
-}
-
-/**
- * \brief Set the text field of an element
- * \note Used for the image path on ELETYPE_IMAGE
- */
-void AxWin_SetText(tElement *Element, const char *Text)
-{
-       if(!Element)    return ;
-       if(Element->Text)       free(Element->Text);
-       Element->Text = strdup(Text);
-       
-       switch(Element->Type)
-       {
-       case ELETYPE_IMAGE:
-               if(Element->Data)       free(Element->Data);
-               Element->Data = Image_Load( Element->Text );
-               if(!Element->Data) {
-                       Element->Flags &= ~ELEFLAG_FIXEDSIZE;
-                       return ;
-               }
-               
-               //Element->Flags |= ELEFLAG_FIXEDSIZE;
-               Element->CachedW = ((tImage*)Element->Data)->Width;
-               Element->CachedH = ((tImage*)Element->Data)->Height;
-               
-               if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
-                       Element->MinCross = ((tImage*)Element->Data)->Width;
-                       Element->MinWith = ((tImage*)Element->Data)->Height;
-               }
-               else {
-                       Element->MinWith = ((tImage*)Element->Data)->Width;
-                       Element->MinCross = ((tImage*)Element->Data)->Height;
-               }
-               break;
-       
-       case ELETYPE_TEXT:
-               {
-                int    w=0, h=0;
-               Video_GetTextDims(NULL, Element->Text, &w, &h);
-               if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
-                       Element->MinCross = w;
-                       Element->MinWith = h;
-               }
-               else {
-                       Element->MinWith = w;
-                       Element->MinCross = h;
-               }
-               }
-               break;
-       default:        // Any other, no special case
-               break ; 
-       }
-       
-       return ;
-}
diff --git a/Usermode/Applications/axwin2_src/WM/wm.h b/Usermode/Applications/axwin2_src/WM/wm.h
deleted file mode 100644 (file)
index 5977fd6..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Acess2 Window Manager (AxWin2)
- */
-#ifndef _WM_H_
-#define _WM_H_
-
-#include <axwin2/axwin.h>
-#include "common.h"
-
-/**
- * \brief Number of elements that can be owned by each application
- */
-// TODO: Fine tune these values
-#define MAX_ELEMENTS_PER_APP   1024
-#define DEFAULT_ELEMENTS_PER_APP       128
-
-typedef struct sAxWin_Element  tElement;
-typedef struct sMenuItem       tMenuItem;
-typedef struct sWindow tWindow;
-typedef struct sApplication    tApplication;
-
-struct sAxWin_Element
-{
-       enum eElementTypes      Type;
-       
-       // Element Tree
-       tElement        *Parent;
-       tElement        *FirstChild;
-       tElement        *LastChild;
-       tElement        *NextSibling;
-       
-       // Application
-       tApplication    *Owner; //!< Owning application
-       uint16_t        ApplicationID;  //!< Index into sApplication::EleIndex
-
-       // User modifiable attributes   
-       short   PaddingL, PaddingR;
-       short   PaddingT, PaddingB;
-       short   GapSize;
-       
-       uint32_t        Flags;
-       
-       short   FixedWith;      //!< Fixed lengthways Size attribute (height)
-       short   FixedCross;     //!< Fixed Cross Size attribute (width)
-       
-       char    *Text;
-       
-       // -- Attributes maitained by the element code
-       // Not touched by the user
-       short   MinWith;        //!< Minimum long size
-       short   MinCross;       //!< Minimum cross size
-       void    *Data;  //!< Per-type data
-       
-       // -- Render Cache
-       short   CachedX, CachedY;
-       short   CachedW, CachedH;
-       
-       char    DebugName[];
-};
-
-struct sMenuItem
-{
-       tMenuItem       *Next;
-        int    Flags;
-        int    ID;     //!< ID number sent to application
-       const char      *Label;
-       const char      *Right;
-       tMenuItem       *FirstChild;
-};
-
-struct sWindow
-{
-        int    X, Y, W, H;
-       void    *Icon;
-       
-       tApplication    *App;
-       
-       tWindow *OrderNext;     // Render order
-       
-       tMenuItem       *Menus;
-       
-       tElement        RootElement;
-};
-
-struct sApplication
-{
-       tApplication    *Next;
-
-       tIPC_Type       *IPCType;
-       void    *Ident; //!< Client Identifier
-       
-       char    *Name;  //!< Application name
-       
-        int    MaxElementIndex;        //!< Number of entries in \a EleIndex
-       tElement        **EleIndex;     //!< Array of pointers to elements owned by this application
-       
-       tElement        MetaElement;    //!< Tabs child off this
-};
-
-// === FUNCTIONS ===
-
-// --- Render
-extern void    WM_UpdateMinDims(tElement *Element);
-extern void    WM_UpdateDimensions(tElement *Element, int Pass);
-extern void    WM_UpdatePosition(tElement *Element);
-extern void    WM_RenderWidget(tElement *Element);
-extern void    WM_Update(void);
-
-#endif
diff --git a/Usermode/Applications/axwin2_src/notes.txt b/Usermode/Applications/axwin2_src/notes.txt
deleted file mode 100644 (file)
index d4090b9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Applications can have 0-* windows
-Windows can have 1-* tabs
-Each window has a menu based on a template from the application
index e34968c..fee178a 100644 (file)
@@ -19,6 +19,7 @@
 void   create_sidebar(void);
 void   create_mainmenu(void);
 void   create_run_dialog(void);
+void   mainmenu_run_dialog(void *unused);
 
 // === GLOBALS ===
 tHWND  gSidebar;
@@ -49,6 +50,10 @@ int main(int argc, char *argv[])
        create_mainmenu();
        create_run_dialog();
        
+       AxWin3_RegisterAction(gSidebar, "Interface>Run", (tAxWin3_HotkeyCallback)mainmenu_run_dialog);
+//     AxWin3_RegisterAction(gSidebar, "Interface>Terminal", mainmenu_app_terminal);
+//     AxWin3_RegisterAction(gSidebar, "Interface>TextEdit", mainmenu_app_textedit);
+
        // Idle loop
        AxWin3_MainLoop();
        
@@ -113,6 +118,7 @@ void mainmenu_app_terminal(void *unused)
 void mainmenu_run_dialog(void *unused)
 {
        AxWin3_ShowWindow(gRunDialog, 1);
+       AxWin3_FocusWindow(gRunDialog);
 }
 
 void create_mainmenu(void)
@@ -130,6 +136,7 @@ void create_mainmenu(void)
 // --------------------------------------------------------------------
 int run_dorun(tAxWin3_Widget *unused)
 {
+       _SysDebug("DoRun pressed");
        char *cmd = AxWin3_Widget_GetText(gRunInput);
        _SysDebug("Command string '%s'", cmd);
        AxWin3_ShowWindow(gRunDialog, 0);
index 33fa974..592f46b 100644 (file)
@@ -14,7 +14,7 @@ all:
 install:
        @$(xMKDIR) $(DISTROOT)/Apps ; true
        @$(xMKDIR) $(DISTROOT)/Apps/AxWin ; true
-       @$(xMKDIR) $(DISTROOT)/Apps/3.0 ; true
+       @$(xMKDIR) $(DISTROOT)/Apps/AxWin/3.0 ; true
        @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
        @$(foreach FILE,$(FILES), $(xCP) $(FILE:-%=%) $(DISTROOT)/Apps/AxWin/3.0/$(FILE:-%=%) &&) true
 
index f0f9321..fae6cbe 100644 (file)
@@ -3,11 +3,12 @@
 -include ../../Makefile.cfg
 
 CPPFLAGS += -I include/ -I ../include/
+CFLAGS += -std=gnu99
 
 DIR := Apps/AxWin/3.0
 BIN := AxWinWM
 OBJ := main.o input.o video.o ipc.o image.o utf-8.o
-OBJ += wm.o wm_input.o wm_render.o wm_render_text.o
+OBJ += wm.o wm_input.o wm_render.o wm_render_text.o wm_hotkeys.o
 OBJ += decorator.o
 OBJ += renderers/passthru.o
 OBJ += renderers/background.o
index 6239b76..14c0414 100644 (file)
@@ -64,14 +64,17 @@ void Decorator_Redraw(tWindow *Window)
        }
 
        // Draw title bar
+       // - Body
        WM_Render_FillRect(Window,
                0, -ciTitlebarHeight, Window->W, ciTitlebarHeight,
                (bActive ? cColourActive_Titlebar : cColourInactive_Titlebar)
                );
+       // - Top Border
        WM_Render_FillRect(Window,
                0, -ciTitlebarHeight, Window->W, 1,
                cColour_TitleTopBorder
                );
+       // - Sides
        WM_Render_FillRect(Window,
                0, -ciTitlebarHeight, 1, ciTitlebarHeight,
                cColour_SideBorder
@@ -81,11 +84,13 @@ void Decorator_Redraw(tWindow *Window)
                cColour_SideBorder
                );
 
+       // Get the font height
        WM_Render_GetTextDims(
                NULL,   // TODO: Select font
                Window->Title ? Window->Title : "jI", -1,
                &text_width, &text_height
                );
+       // - Use that to draw the window title on the left of the window
        WM_Render_DrawText(Window,
                ciTitlebarHeight + 4, -(ciTitlebarHeight - (ciTitlebarHeight/2 - text_height/2)),
                Window->W - ciTitlebarHeight - 4, text_height,
@@ -93,29 +98,32 @@ void Decorator_Redraw(tWindow *Window)
                (bActive ? cColourActive_TitleText : cColourInactive_TitleText),
                Window->Title ? Window->Title : "--", -1
                );
-       
+
+       // TODO: Minimise, Maximise and Close   
+
        // Maximized windows don't have any other borders
        if( Window->Flags & WINFLAG_MAXIMIZED )
                return ;
        
-       // Left
+       // Left Border
        WM_Render_FillRect(Window,
                -ciSideBorderWidth, -ciTitlebarHeight,
                ciSideBorderWidth, Window->H + ciTitlebarHeight + ciBottomBorderWidth,
                cColour_SideBorder
                );
-       // Right
+       // Right Border
        WM_Render_FillRect(Window,
                Window->W, -ciTitlebarHeight,
                ciSideBorderWidth, Window->H + ciTitlebarHeight + ciBottomBorderWidth,
                cColour_SideBorder
                );
-       // Bottom
+       // Bottom Border (hard line)
        WM_Render_FillRect(Window,
                -ciSideBorderWidth, Window->H,
                ciSideBorderWidth*2+Window->W, 1,
                0x000000
                );
+       // Bottom Border
        WM_Render_FillRect(Window,
                -ciSideBorderWidth, Window->H+1,
                ciSideBorderWidth*2+Window->W, ciBottomBorderWidth-1,
index 360f99a..1be86ff 100644 (file)
@@ -12,6 +12,8 @@
 
 #define TODO(str)      
 
+#define ASSERT(expr)   do{if(!(expr)){_SysDebug("%s:%i - ASSERTION FAILED: "#expr, __FILE__, __LINE__);exit(-1);}}while(0)
+
 #define UNIMPLEMENTED()        do{_SysDebug("TODO: Implement %s", __func__); for(;;);}while(0)
 
 #define        AXWIN_VERSION   0x300
diff --git a/Usermode/Applications/axwin3_src/WM/include/messages.h b/Usermode/Applications/axwin3_src/WM/include/messages.h
deleted file mode 100644 (file)
index 3219ea0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Acess2 GUI (AxWin3)
- */
-#ifndef _MESSAGES_H_
-#define _MESSAGES_H_
-
-struct sAxWin_Message
-{
-       uint16_t        ID;
-};
-
-typedef struct sAxWin_Message  tAxWin_Message;
-
-enum eMessages
-{
-       MSG_NULL,
-       MSG_CREATEWIN
-};
-
-#endif
-
diff --git a/Usermode/Applications/axwin3_src/WM/include/wm_hotkeys.h b/Usermode/Applications/axwin3_src/WM/include/wm_hotkeys.h
new file mode 100644 (file)
index 0000000..1a7ca7e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ * 
+ * wm_hotkeys.h
+ * - Hotkey and key shortcut code
+ */
+#ifndef _WM_HOTKEYS_H_
+#define _WM_HOTKEYS_H_
+
+typedef struct sHotkey tHotkey;
+typedef struct sHotkeyTarget   tHotkeyTarget;
+
+struct sHotkey
+{
+       tHotkey *Next;
+       
+       const char      *Target;
+
+        int    nKeys;
+       uint32_t        Keys[];
+};
+
+struct sHotkeyTarget
+{
+       struct sHotkeyTarget    *Next;
+
+       const char      *Name;
+       
+       tWindow *Window;
+        int    Index;
+};
+
+
+extern void    WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName);
+extern void    WM_Hotkey_RegisterAction(const char *ActionName, tWindow *Target, uint16_t Index);
+extern void    WM_Hotkey_KeyDown(uint32_t Scancode);
+extern void    WM_Hotkey_KeyUp(uint32_t Scancode);
+
+#endif
+
diff --git a/Usermode/Applications/axwin3_src/WM/include/wm_messages.h b/Usermode/Applications/axwin3_src/WM/include/wm_messages.h
deleted file mode 100644 (file)
index c7955f6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Acess2 Window Manager v3 (axwin3)
- * - By John Hodge (thePowersGang)
- *
- * include/wm_messages.h
- * - Core window messages
- */
-#ifndef _WM_MESSAGES_H_
-#define _WM_MESSAGES_H_
-
-/**
- * \brief Messages delivered to windows
- */
-enum eWM_WindowMessages
-{
-       WNDMSG_NULL,
-       
-       WNDMSG_CREATE,
-       WNDMSG_DESTROY,
-       WNDMSG_FOCUS,   // Called on change
-       WNDMSG_SHOW,    // Called on change
-
-       WNDMSG_RESIZE,
-       
-       WNDMSG_MOUSEMOVE,
-       WNDMSG_MOUSEBTN,
-       WNDMSG_KEYDOWN,
-       WNDMSG_KEYFIRE,
-       WNDMSG_KEYUP,
-       
-       WNDMSG_CLASS_MIN = 0x1000,
-       WNDMSG_CLASS_MAX = 0x2000,
-};
-
-struct sWndMsg_Bool
-{
-        uint8_t        Val;
-};
-
-struct sWndMsg_Resize
-{
-       uint16_t        W, H;
-};
-
-struct sWndMsg_MouseMove
-{
-        int16_t        X, Y;
-        int16_t        dX, dY;
-};
-
-struct sWndMsg_MouseButton
-{
-        int16_t        X, Y;
-       uint8_t         Button;
-       uint8_t         bPressed;
-};
-
-struct sWndMsg_KeyAction
-{
-       uint32_t        KeySym;
-       uint32_t        UCS32;
-};
-
-#endif
index bd23c0b..469c08e 100644 (file)
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <acess/sys.h>
 #include <wm_input.h>
+#include <stddef.h>
 
 // TODO: Move out to a common header
 typedef struct
@@ -21,7 +22,7 @@ typedef struct
 // === IMPORTS ===
 extern void    Video_SetCursorPos(short X, short Y);
 const char     *gsMouseDevice;
-extern int     giTerminalFD;
+extern int     giTerminalFD_Input;
 extern int     giScreenWidth;
 extern int     giScreenHeight;
 
@@ -57,24 +58,25 @@ int Input_Init(void)
 
 void Input_FillSelect(int *nfds, fd_set *set)
 {
-       if(*nfds < giTerminalFD)        *nfds = giTerminalFD;
+       if(*nfds < giTerminalFD_Input)  *nfds = giTerminalFD_Input;
        if(*nfds < giMouseFD)   *nfds = giMouseFD;
-       FD_SET(giTerminalFD, set);
+       FD_SET(giTerminalFD_Input, set);
        FD_SET(giMouseFD, set);
 }
 
 void Input_HandleSelect(fd_set *set)
 {
-       if(FD_ISSET(giTerminalFD, set))
+       if(FD_ISSET(giTerminalFD_Input, set))
        {
                uint32_t        codepoint;
                static uint32_t scancode;
                #define KEY_CODEPOINT_MASK      0x3FFFFFFF
                
-               if( read(giTerminalFD, &codepoint, sizeof(codepoint)) != sizeof(codepoint) )
+               size_t readlen = read(giTerminalFD_Input, &codepoint, sizeof(codepoint));
+               if( readlen != sizeof(codepoint) )
                {
                        // oops, error
-                       _SysDebug("Terminal read failed?");
+                       _SysDebug("Terminal read failed? (%i != %i)", readlen, sizeof(codepoint));
                }
        
 //             _SysDebug("Keypress 0x%x", codepoint);
index 46aff21..cbed7fd 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include <wm.h>
 #include <wm_internals.h>
+#include <wm_hotkeys.h>
 
 #define AXWIN_PORT     4101
 
@@ -75,30 +76,40 @@ void IPC_Init(void)
         int    tmp;
        // TODO: Check this
        giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ);
-       tmp = AXWIN_PORT;       ioctl(giNetworkFileHandle, 4, &tmp);    // TODO: Don't hard-code IOCtl number
+       if( giNetworkFileHandle != -1 )
+       {
+               tmp = AXWIN_PORT;
+               ioctl(giNetworkFileHandle, 4, &tmp);    // TODO: Don't hard-code IOCtl number
+       }
 }
 
 void IPC_FillSelect(int *nfds, fd_set *set)
 {
-       if( giNetworkFileHandle > *nfds )       *nfds = giNetworkFileHandle;
-       FD_SET(giNetworkFileHandle, set);
+       if( giNetworkFileHandle != -1 )
+       {
+               if( giNetworkFileHandle > *nfds )       *nfds = giNetworkFileHandle;
+               FD_SET(giNetworkFileHandle, set);
+       }
 }
 
 void IPC_HandleSelect(fd_set *set)
 {
-       if( FD_ISSET(giNetworkFileHandle, set) )
+       if( giNetworkFileHandle != -1 )
        {
-               char    staticBuf[STATICBUF_SIZE];
-                int    readlen, identlen;
-               char    *msg;
-
-               readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
-               
-               identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
-               msg = staticBuf + identlen;
-
-               IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
-//             _SysDebug("IPC_HandleSelect: UDP handled");
+               if( FD_ISSET(giNetworkFileHandle, set) )
+               {
+                       char    staticBuf[STATICBUF_SIZE];
+                        int    readlen, identlen;
+                       char    *msg;
+       
+                       readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
+                       
+                       identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
+                       msg = staticBuf + identlen;
+       
+                       IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
+//                     _SysDebug("IPC_HandleSelect: UDP handled");
+               }
        }
 
        while(SysGetMessage(NULL, NULL))
@@ -259,10 +270,88 @@ void IPC_int_SetWindow(tIPC_Client *Client, uint32_t WindowID, tWindow *WindowPt
 }
 
 // --- IPC Message Handlers ---
+int IPC_Msg_Ping(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+       ASSERT(Msg->ID == IPCMSG_PING);
+       
+       if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
+       
+       if( Msg->Size < 4 )     return -1;
+       
+       tIPCMsg_ReturnInt       *ret = (void*)Msg->Data;
+       Msg->ID = IPCMSG_PING;
+       Msg->Size = sizeof(*ret);
+       ret->Value = AXWIN_VERSION;
+       Client->IPCType->SendMessage(Client->Ident, sizeof(*Msg)+sizeof(*ret), Msg);
+       return 0;
+}
+
+int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+       tAxWin_IPCMessage       *ret_hdr;
+       tIPCMsg_ReturnInt       *ret;
+       char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
+       
+       ASSERT(Msg->ID == IPCMSG_GETDISPLAYCOUNT);
+
+       if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
+       
+       ret_hdr = (void*)buf;
+       ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
+       ret_hdr->Flags = 0;
+       ret_hdr->Window = -1;
+       ret_hdr->Size = sizeof(*ret);
+       ret = (void*)ret_hdr->Data;
+       ret->Value = 1; // HARD CODE - Current version only supports one display
+       
+       Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
+       return 0;
+}
+
+int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+       tIPCMsg_GetDisplayDims  *info;
+       tAxWin_IPCMessage       *ret_hdr;
+       tIPCMsg_RetDisplayDims  *ret;
+       char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
+       
+       ASSERT(Msg->ID == IPCMSG_GETDISPLAYDIMS);
+
+       if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
+
+       info = (void*)Msg->Data;        
+
+       ret_hdr = (void*)buf;
+       ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
+       ret_hdr->Flags = 0;
+       ret_hdr->Window = -1;
+       ret_hdr->Size = sizeof(*ret);
+       ret = (void*)ret_hdr->Data;
+       
+       // HARD CODE! Only one display supported
+       if( info->DisplayID == 0 )
+       {
+               ret->X = 0;
+               ret->Y = 0;
+               ret->W = giScreenWidth;
+               ret->H = giScreenHeight;
+       }
+       else
+       {
+               ret->X = 0;     ret->Y = 0;
+               ret->W = 0;     ret->H = 0;
+       }
+       
+       Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
+       return 0;
+}
+
 int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
 {
        tIPCMsg_SendMsg *info = (void*)Msg->Data;
        tWindow *src, *dest;
+
+       ASSERT(Msg->ID == IPCMSG_SENDMSG);
        
        // - Sanity checks
        if( Msg->Size < sizeof(tIPCMsg_SendMsg) )
@@ -280,27 +369,13 @@ int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
        return 0;
 }
 
-int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
-{
-       tWindow *win;
-
-       // Don't allow the focus to be changed unless the client has the focus
-       if(!gpWM_FocusedWindow) return 1;
-       if(gpWM_FocusedWindow->Client != Client)        return 1;
-
-       win = IPC_int_GetWindow(Client, Msg->Window);
-       if(!win)        return 1;
-
-       WM_FocusWindow(win);
-
-       return 0;
-}
-
 int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
 {
        tIPCMsg_CreateWin       *info = (void*)Msg->Data;
        tWindow *newwin, *parent;
 
+       ASSERT(Msg->ID == IPCMSG_CREATEWIN);
+
        // - Sanity checks
        //  > +1 is for NULL byte on string
        if( Msg->Size < sizeof(*info) + 1 ) {
@@ -335,6 +410,8 @@ int IPC_Msg_SetWindowTitle(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
 {
        tWindow *win;
 
+       ASSERT(Msg->ID == IPCMSG_SETWINTITLE);
+       
        if( Msg->Size < 1 )     return -1;
        if( Msg->Data[ Msg->Size-1 ] != '\0' )  return -1;      
 
@@ -351,6 +428,8 @@ int IPC_Msg_ShowWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
        tIPCMsg_Boolean *info = (void*)Msg->Data;
        tWindow *win;
        
+       ASSERT(Msg->ID == IPCMSG_SHOWWINDOW);
+       
        if( Msg->Size < sizeof(*info) ) return -1;
        
        win = IPC_int_GetWindow(Client, Msg->Window);
@@ -375,11 +454,31 @@ int IPC_Msg_DecorateWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
        return 0;
 }
 
+int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+       tWindow *win;
+
+       ASSERT(Msg->ID == IPCMSG_FOCUSWINDOW);
+       
+       // Don't allow the focus to be changed unless the client has the focus
+       if(!gpWM_FocusedWindow) return 1;
+       if(gpWM_FocusedWindow->Client != Client)        return 1;
+
+       win = IPC_int_GetWindow(Client, Msg->Window);
+       if(!win)        return 1;
+
+       WM_FocusWindow(win);
+
+       return 0;
+}
+
 int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
 {
        tIPCMsg_SetWindowPos    *info = (void*)Msg->Data;
        tWindow *win;
        
+       ASSERT(Msg->ID == IPCMSG_SETWINPOS);
+       
        if(Msg->Size < sizeof(*info))   return -1;
        
        win = IPC_int_GetWindow(Client, Msg->Window);
@@ -395,62 +494,47 @@ int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
        return 0;
 }
 
-int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+int IPC_Msg_RegisterAction(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
 {
-       tAxWin_IPCMessage       *ret_hdr;
-       tIPCMsg_ReturnInt       *ret;
-       char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
-       
-       if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
-       
-       ret_hdr = (void*)buf;
-       ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
-       ret_hdr->Flags = 0;
-       ret_hdr->Window = -1;
-       ret_hdr->Size = sizeof(*ret);
-       ret = (void*)ret_hdr->Data;
-       ret->Value = 1; // HARD CODE - Current version only supports one display
+       tIPCMsg_RegAction       *info = (void*)Msg->Data;
+       tWindow *win;
        
-       Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
-       return 0;
-}
+       ASSERT(Msg->ID == IPCMSG_REGACTION);
 
-int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
-{
-       tIPCMsg_GetDisplayDims  *info;
-       tAxWin_IPCMessage       *ret_hdr;
-       tIPCMsg_RetDisplayDims  *ret;
-       char    buf[sizeof(*ret_hdr)+sizeof(*ret)];
+       if( Msg->Size < sizeof(*info) + 1 )
+               return -1;
        
-       if( !(Msg->Flags & IPCMSG_FLAG_RETURN) )        return 0;
+       win = IPC_int_GetWindow(Client, Msg->Window);
+       if(!win)        return 1;
 
-       info = (void*)Msg->Data;        
+       if( strnlen(info->Action, Msg->Size - sizeof(*info)) == Msg->Size - sizeof(*info) )
+               return 1;
+
+       _SysDebug("RegisterAction %p:%i [%i]\"%s\"",
+               Client, Msg->Window, info->Index, info->Action
+               );
+
+       WM_Hotkey_RegisterAction(info->Action, win, info->Index);
 
-       ret_hdr = (void*)buf;
-       ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
-       ret_hdr->Flags = 0;
-       ret_hdr->Window = -1;
-       ret_hdr->Size = sizeof(*ret);
-       ret = (void*)ret_hdr->Data;
-       
-       // HARD CODE! Only one display supported
-       if( info->DisplayID == 0 )
-       {
-               ret->X = 0;
-               ret->Y = 0;
-               ret->W = giScreenWidth;
-               ret->H = giScreenHeight;
-       }
-       else
-       {
-               ret->X = 0;     ret->Y = 0;
-               ret->W = 0;     ret->H = 0;
-       }
-       
-       Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
        return 0;
 }
 
+int (*gIPC_MessageHandlers[])(tIPC_Client *Client, tAxWin_IPCMessage *Msg) = {
+       IPC_Msg_Ping,
+       IPC_Msg_GetDisplayCount,
+       IPC_Msg_GetDisplayDims,
+       IPC_Msg_SendMsg,
+       IPC_Msg_CreateWin,
+       NULL,   // Destroy window
+       IPC_Msg_SetWindowTitle,
+       IPC_Msg_ShowWindow,
+       IPC_Msg_DecorateWindow,
+       IPC_Msg_FocusWindow,
+       IPC_Msg_SetWinPos,
+       IPC_Msg_RegisterAction
+};
+const int giIPC_NumMessageHandlers = sizeof(gIPC_MessageHandlers)/sizeof(gIPC_MessageHandlers[0]);
+
 void IPC_Handle(const tIPC_Type *IPCType, const void *Ident, size_t MsgLen, tAxWin_IPCMessage *Msg)
 {
        tIPC_Client     *client;
@@ -466,79 +550,21 @@ void IPC_Handle(const tIPC_Type *IPCType, const void *Ident, size_t MsgLen, tAxW
        
        client = IPC_int_GetClient(IPCType, Ident);
 
-       switch((enum eAxWin_IPCMessageTypes) Msg->ID)
-       {
-       // --- Ping message (reset timeout and get server version)
-       case IPCMSG_PING:
-               _SysDebug(" IPC_Handle: IPCMSG_PING");
-               if( Msg->Size < 4 )     return;
-               if( Msg->Flags & IPCMSG_FLAG_RETURN )
-               {
-                       tIPCMsg_ReturnInt       *ret = (void*)Msg->Data;
-                       Msg->ID = IPCMSG_PING;
-                       Msg->Size = sizeof(*ret);
-                       ret->Value = AXWIN_VERSION;
-                       IPCType->SendMessage(Ident, sizeof(*Msg)+sizeof(*ret), Msg);
-               }
-               break;
-
-       // -- Get display count
-       case IPCMSG_GETDISPLAYCOUNT:
-               rv = IPC_Msg_GetDisplayCount(client, Msg);
-               break;
-       
-       // --- Get display dimensions
-       case IPCMSG_GETDISPLAYDIMS:
-               rv = IPC_Msg_GetDisplayDims(client, Msg);
-               break;
-
-       // --- Send a message
-       case IPCMSG_SENDMSG:
-               _SysDebug(" IPC_Handle: IPCMSG_SENDMSG %i", ((tIPCMsg_SendMsg*)Msg->Data)->ID);
-               rv = IPC_Msg_SendMsg(client, Msg);
-               break;
-
-       // --- Create window
-       case IPCMSG_CREATEWIN:
-               _SysDebug(" IPC_Handle: IPCMSG_CREATEWIN");
-               rv = IPC_Msg_CreateWin(client, Msg);
-               break;
-       // TODO: Destroy window
-       
-       // --- Set window title
-       case IPCMSG_SETWINTITLE:
-               _SysDebug(" IPC_Handle: IPCMSG_SETWINTITLE");
-               rv = IPC_Msg_SetWindowTitle(client, Msg);
-               break;
-
-       // --- Give a window focus
-       case IPCMSG_FOCUSWINDOW:
-               _SysDebug(" IPC_Handle: IPCMSG_FOCUSWINDOW");
-               rv = IPC_Msg_FocusWindow(client, Msg);
-               break;
-       // --- Show/Hide a window
-       case IPCMSG_SHOWWINDOW:
-               _SysDebug(" IPC_Handle: IPCMSG_SHOWWINDOW");
-               rv = IPC_Msg_ShowWindow(client, Msg);
-               break;
-       case IPCMSG_DECORATEWINDOW:
-               _SysDebug(" IPC_Handle: IPCMSG_DECORATEWINDOW");
-               rv = IPC_Msg_DecorateWindow(client, Msg);
-               break;
-       // --- Move/Resize a window
-       case IPCMSG_SETWINPOS:
-               _SysDebug(" IPC_Handle: IPCMSG_SETWINPOS");
-               rv = IPC_Msg_SetWinPos(client, Msg);
-               break;
-
-       // --- Unknown message
-       default:
+       if( Msg->ID >= giIPC_NumMessageHandlers ) {
                fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
                _SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, IPCType);
-               break;
+               return ;
        }
-       if(rv)
-               _SysDebug("IPC_Handle: rv = %i", rv);
+       
+       if( !gIPC_MessageHandlers[ Msg->ID ] ) {
+               fprintf(stderr, "WARNING: Message %i does not have a handler\n", Msg->ID);
+               _SysDebug("WARNING: Message %i does not have a handler", Msg->ID);
+               return ;
+       }
+
+       _SysDebug("IPC_Handle: Msg->ID = %i", Msg->ID);
+       rv = gIPC_MessageHandlers[Msg->ID](client, Msg);
+       _SysDebug("IPC_Handle: rv = %i", rv);
 }
 
 // --- Server->Client replies
index 0d15046..0996f90 100644 (file)
@@ -9,6 +9,7 @@
 #include <acess/sys.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <axwin3/keysyms.h>
 
 // === IMPORTS ===
 extern void    Video_Setup(void);
@@ -16,7 +17,9 @@ extern void   WM_Initialise(void);
 extern int     Renderer_Menu_Init(void);
 extern int     Renderer_Widget_Init(void);
 extern int     Renderer_Background_Init(void);
+extern int     Renderer_Framebuffer_Init(void);
 extern void    WM_Update(void);
+extern void    WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName);
 
 // === PROTOTYPES ===
 void   ParseCommandline(int argc, char **argv);
@@ -29,6 +32,7 @@ const char    *gsMouseDevice = NULL;
  int   giScreenHeight = 480;
 
  int   giTerminalFD = -1;
+ int   giTerminalFD_Input = 0;
  int   giMouseFD = -1;
 
 #define __INSTALL_ROOT "/Acess/Apps/AxWin/3.0"
@@ -59,7 +63,13 @@ int main(int argc, char *argv[])
        Renderer_Menu_Init();
        Renderer_Widget_Init();
        Renderer_Background_Init();
+       Renderer_Framebuffer_Init();
        WM_Initialise();
+
+       // TODO: Config
+       uint32_t        keys[4];
+       keys[0] = KEYSYM_LEFTGUI;       keys[1] = KEYSYM_r;
+       WM_Hotkey_Register(2, keys, "Interface>Run");
        
        // Spawn interface root
        if( clone(CLONE_VM, 0) == 0 )
index 9cd112c..c8d61cf 100644 (file)
  */
 #include <common.h>
 #include <wm_renderer.h>
+#include <string.h>
+#include <framebuffer_messages.h>
+#include <wm_messages.h>
+
+// === TYPES ===
+typedef struct
+{
+       short   W, H;
+       void    *Data;
+       char    _data[];
+} tFBBuffer;
+typedef struct
+{
+       tFBBuffer       BackBuffer;
+        int    MaxBufferCount;
+       tFBBuffer       *Buffers[];
+} tFBWin;
 
 // === PROTOTYPES ===
-tWindow        *Renderer_Passthru_Create(int Flags);
-void   Renderer_Passthru_Redraw(tWindow *Window);
- int   Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
+tWindow        *Renderer_Framebuffer_Create(int Flags);
+void   Renderer_Framebuffer_Redraw(tWindow *Window);
+ int   Renderer_Framebuffer_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
 
 // === GLOBALS ===
-tWMRenderer    gRenderer_Passthru = {
-       .Name = "Passthru",
-       .CreateWindow = Renderer_Passthru_Create,
-       .Redraw = Renderer_Passthru_Redraw,
-       .HandleMessage = Renderer_Passthru_HandleMessage
+tWMRenderer    gRenderer_Framebuffer = {
+       .Name = "FrameBuffer",
+       .CreateWindow = Renderer_Framebuffer_Create,
+       .Redraw = Renderer_Framebuffer_Redraw,
+       .HandleMessage = Renderer_Framebuffer_HandleMessage
 };
 
 // === CODE ===
-int Renderer_Passthru_Init(void)
+int Renderer_Framebuffer_Init(void)
 {
+       WM_RegisterRenderer(&gRenderer_Framebuffer);
        return 0;
 }
 
-tWindow        *Renderer_Passthru_Create(int Flags)
+tWindow        *Renderer_Framebuffer_Create(int Flags)
+{
+       tWindow *ret;
+       tFBWin  *info;
+       const int       max_buffers = 10;       // TODO: Have this be configurable
+       
+       ret = WM_CreateWindowStruct( sizeof(*info) + max_buffers*sizeof(tFBBuffer*) );
+       info = ret->RendererInfo;
+       
+       info->BackBuffer.W = 0;
+       info->BackBuffer.H = 0;
+       info->BackBuffer.Data = NULL;
+       info->MaxBufferCount = max_buffers;
+       memset( info->Buffers, 0, sizeof(tFBBuffer*) * max_buffers );
+       
+       return ret;
+}
+
+void Renderer_Framebuffer_Redraw(tWindow *Window)
+{
+       
+}
+
+// --- ---
+tFBBuffer *_GetBuffer(tWindow *Win, uint16_t ID)
+{
+       tFBWin  *info = Win->RendererInfo;
+       if( ID == 0xFFFF )
+               return &info->BackBuffer;
+       else if( ID >= info->MaxBufferCount )
+               return NULL;
+       else
+               return info->Buffers[ ID ];
+}
+
+void _Blit(
+       tFBBuffer *Dest, uint16_t DX, uint16_t DY,
+       const tFBBuffer *Src, uint16_t SX, uint16_t SY,
+       uint16_t W, uint16_t H
+       )
+{
+       uint32_t        *dest_data = Dest->Data;
+       const uint32_t  *src_data = Src->Data;
+       // First, some sanity
+       if( DX > Dest->W )      return ;
+       if( DY > Dest->H )      return ;
+       if( SX > Src->W )       return ;
+       if( SY > Src->H )       return ;
+       
+       if( DX + W > Dest->W )  W = Dest->W - DX;
+       if( SX + W > Src->W )   W = Src->W - SX;
+       if( DY + H > Dest->H )  H = Dest->H - DY;
+       if( SY + H > Src->H )   H = Src->H - SY;
+       
+       dest_data += (DY * Dest->W) + DX;
+       src_data  += (SY * Src->W ) + SX;
+       for( int i = 0; i < H; i ++ )
+       {
+               memcpy( dest_data, src_data, W * 4 );
+               dest_data += Dest->W;
+               src_data += Src->W;
+       }
+}
+
+void _Fill(tFBBuffer *Buf, uint16_t X, uint16_t Y, uint16_t W, uint16_t H, uint32_t Colour)
+{
+       uint32_t        *data = Buf->Data;
+       
+       if( X > Buf->W )        return ;
+       if( Y > Buf->H )        return ;
+       if( X + W > Buf->W )    W = Buf->W - X;
+       if( Y + H > Buf->H )    H = Buf->H - Y;
+       
+       data += (Y * Buf->W) + X;
+       for( int i = 0; i < H; i ++ )
+       {
+               for( int j = 0; j < W; j ++ )
+                       *data++ = Colour;
+               data += Buf->W - W;
+       }
+}
+
+// --- ---
+void _Handle_Commit(tWindow *Target, size_t Len, const void *Data)
+{
+       // Do a window invalidate
+}
+
+void _Handle_CreateBuf(tWindow *Target, size_t Len, const void *Data)
 {
-       return NULL;
+       const tFBMsg_NewBuf     *msg = Data;
+       tFBBuffer       *buf;
+       tFBWin  *info = Target->RendererInfo;
+       
+       if( Len < sizeof(*msg) )        return ;
+       
+       if( msg->Buffer == -1 || msg->Buffer >= info->MaxBufferCount ) {
+               // Can't reallocate -1
+               return ;
+       }
+       
+       if( info->Buffers[msg->Buffer] ) {
+               free(info->Buffers[msg->Buffer]);
+               info->Buffers[msg->Buffer] = NULL;
+       }
+       
+       buf = malloc(sizeof(tFBBuffer) + msg->W * msg->H * 4);
+       buf->W = msg->W;
+       buf->H = msg->H;
+       buf->Data = buf->_data;
+       
+       info->Buffers[msg->Buffer] = buf;
 }
 
-void Renderer_Passthru_Redraw(tWindow *Window)
+void _Handle_Upload(tWindow *Target, size_t Len, const void *Data)
 {
+       const tFBMsg_Transfer   *msg = Data;
+       tFBBuffer       *dest, src;
+       
+       if( Len < sizeof(*msg) )        return ;
+       if( Len < sizeof(*msg) + msg->W * msg->H * 4 )  return ;
+       
+       dest = _GetBuffer(Target, msg->Buffer);
+
+       src.W = msg->W; 
+       src.H = msg->H; 
+       src.Data = (void*)msg->ImageData;
+
+       _Blit( dest, msg->X, msg->Y,  &src, 0, 0,  msg->W, msg->H );
+}
+
+void _Handle_Download(tWindow *Target, size_t Len, const void *Data)
+{
+       #if 0
+       const tFBMsg_Transfer   *msg = Data;
+       tFBBuffer       dest, *src;
+       
+       if( Len < sizeof(*msg) )        return ;
+       if( Len < sizeof(*msg) + msg->W * msg->H * 4 )  return ;
+       
+       src = _GetBuffer(Target, msg->Buffer);
+
+       dest.W = msg->W;        
+       dest.H = msg->H;        
+       dest.Data = msg->ImageData;
        
+       _Blit( &dest, 0, 0,  src, msg->X, msg->Y,  msg->W, msg->H );
+       #endif
 }
 
-int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+void _Handle_LocalBlit(tWindow *Target, size_t Len, const void *Data)
 {
+       const tFBMsg_Blit       *msg = Data;
+       tFBBuffer       *dest, *src;
+       
+       if( Len < sizeof(*msg) )        return ;
+       
+       src = _GetBuffer(Target, msg->Source);
+       dest = _GetBuffer(Target, msg->Dest);
+
+       _Blit( dest, msg->DstX, msg->DstY,  src, msg->SrcX, msg->SrcY,  msg->W, msg->H );
+}
+
+void _Handle_FillRect(tWindow *Target, size_t Len, const void *Data)
+{
+       const tFBMsg_Fill       *msg = Data;
+       tFBBuffer       *dest;
+       
+       if( Len < sizeof(*msg) )        return ;
+       
+       dest = _GetBuffer(Target, msg->Buffer);
+       
+       _Fill( dest, msg->X, msg->Y, msg->W, msg->H, msg->Colour );
+}
+
+int Renderer_Framebuffer_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+{
+       switch(Msg)
+       {
+       case WNDMSG_RESIZE:
+               // Resize the framebuffer
+               return 1;       // Pass on
+       
+       // Messages that get passed on
+       case WNDMSG_MOUSEBTN:
+               return 1;
+       
+       // --- Local messages ---
+       // - Drawing completed, do an update
+       case MSG_FB_COMMIT:
+               _Handle_Commit(Target, Len, Data);
+               return 0;
+       // - New Buffer (create a new server-side buffer)
+       case MSG_FB_NEWBUF:
+               _Handle_CreateBuf(Target, Len, Data);
+               return 0;
+       // - Upload (Transfer data from client to server)
+       case MSG_FB_UPLOAD:
+               _Handle_Upload(Target, Len, Data);
+               return 0;
+       // - Download (Transfer image data from server to client)
+       case MSG_FB_DOWNLOAD:
+               _Handle_Download(Target, Len, Data);
+               return 0;
+       // - Local Blit (Transfer from server to server)
+       case MSG_FB_BLIT:
+               _Handle_LocalBlit(Target, Len, Data);
+               return 0;
+       // - Fill a rectangle
+       case MSG_FB_FILL:
+               _Handle_FillRect(Target, Len, Data);
+               return 0;
+       }
        return 1;
 }
 
index 7668cbd..46b3198 100644 (file)
@@ -552,6 +552,34 @@ void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
 //     }
 }
 
+int Widget_GetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
+{
+       if( Len < sizeof(*Msg) )
+               return 0;
+       if( Len > sizeof(*Msg) )
+               return 1;       // Pass to user
+       
+       const char      *text = NULL;
+       tElement *ele = Widget_GetElementById(Info, Msg->WidgetID);
+       if(ele)
+               text = ele->Text;
+       
+       char    buf[sizeof(tWidgetMsg_SetText) + strlen(text?text:"") + 1];
+       tWidgetMsg_SetText      *omsg = (void*)buf;
+       
+       if( text ) {
+               omsg->WidgetID = Msg->WidgetID;
+               strcpy(omsg->Text, text);
+       }
+       else {
+               omsg->WidgetID = -1;
+               omsg->Text[0] = 0;
+       }
+       
+       WM_SendMessage(Info->RootElement.Window, Info->RootElement.Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
+       return 0;
+}
+
 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
 {
        tWidgetWin      *info = Target->RendererInfo;
@@ -691,6 +719,8 @@ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void
        case MSG_WIDGET_SETTEXT:
                Widget_SetText(info, Len, Data);
                return 0;
+       case MSG_WIDGET_GETTEXT:
+               return Widget_GetText(info, Len, Data);
        
        // 
        default:
index a65ddf9..3adb17d 100644 (file)
@@ -15,6 +15,9 @@
 #include <wm.h>
 #include <string.h>
 
+// === IMPORTS ===
+extern int     giTerminalFD_Input;
+
 // === PROTOTYPES ===
 void   Video_Setup(void);
 void   Video_SetCursorPos(short X, short Y);
@@ -34,13 +37,25 @@ void Video_Setup(void)
         int    tmpInt;
        
        // Open terminal
+       #if 0
        giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
        if( giTerminalFD == -1 )
        {
                fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
                exit(-1);
        }
-       
+       #else
+       giTerminalFD = 1;
+       giTerminalFD_Input = 0;
+       // Check that the console is a VT
+       // - ioctl(..., 0, NULL) returns the type, which should be 2
+       if( ioctl(1, 0, NULL) != 2 )
+       {
+               fprintf(stderr, "stdout is not an Acess VT, can't start");
+               _SysDebug("stdout is not an Acess VT, can't start");
+               exit(-1);
+       }
+       #endif
        
        // Set mode to video
        tmpInt = TERM_MODE_FB;
@@ -73,6 +88,7 @@ void Video_Update(void)
        _SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
                giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
        seek(giTerminalFD, ofs*4, 1);
+       _SysDebug("Video_Update - Sending");
        write(giTerminalFD, gpScreenBuffer+ofs, size*4);
        _SysDebug("Video_Update - Done");
        giVideo_FirstDirtyLine = 0;
diff --git a/Usermode/Applications/axwin3_src/WM/wm_hotkeys.c b/Usermode/Applications/axwin3_src/WM/wm_hotkeys.c
new file mode 100644 (file)
index 0000000..bdea09c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ * 
+ * wm_hotkeys.c
+ * - Hotkey and key shortcut code
+ */
+#include <common.h>
+#include <wm_internals.h>
+#include <wm_messages.h>
+#include <wm_hotkeys.h>
+#include <string.h>
+
+#define true   1
+#define false  0
+
+#define MAX_STATE_SCANCODE     256
+
+// === GOBALS ===
+char   gbWM_HasBeenKeyDown = true;
+uint8_t        gWM_KeyStates[MAX_STATE_SCANCODE/8];
+tHotkey        *gpWM_Hotkeys;
+tHotkeyTarget  *gpWM_HotkeyTargets;
+tHotkeyTarget  *gpWM_HotkeyTargets_Last;
+
+// === PROTOTYPES ===
+static void    _SetKey(uint32_t sc);
+static void    _UnsetKey(uint32_t sc);
+static int     _IsKeySet(uint32_t sc);
+void   WM_Hotkey_FireEvent(const char *Target);
+
+// === CODE ===
+void WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName)
+{
+       // TODO: Duplicate detection
+       
+       // Create new structure
+       tHotkey *h = malloc(sizeof(tHotkey) + nKeys * sizeof(uint32_t) + strlen(ActionName) + 1);
+       h->nKeys = nKeys;
+       h->Target = (void*)( h->Keys + nKeys );
+       strcpy((char*)h->Target, ActionName);
+       memcpy(h->Keys, Keys, nKeys * sizeof(uint32_t));
+       
+       h->Next = NULL;
+       if( gpWM_Hotkeys )
+               gpWM_Hotkeys->Next = h;
+       gpWM_Hotkeys = h;
+}
+
+void WM_Hotkey_RegisterAction(const char *ActionName, tWindow *Target, uint16_t Index)
+{
+       // Check for a duplicate registration
+       for( tHotkeyTarget *t = gpWM_HotkeyTargets; t; t = t->Next )
+       {
+               if( strcmp(t->Name, ActionName) != 0 )
+                       continue ;
+               // Duplicate!
+               return ;
+       }
+
+       // Create new structure
+       tHotkeyTarget   *t = malloc(sizeof(tHotkeyTarget) + strlen(ActionName) + 1);
+       t->Name = (void*)(t + 1);
+       strcpy((char*)t->Name, ActionName);
+       t->Window = Target;
+       t->Index = Index;
+
+       // TODO: Register to be informed when the window dies/closes?
+
+       // Append to list
+       if( gpWM_HotkeyTargets ) {
+               gpWM_HotkeyTargets_Last->Next = t;
+       }
+       else {
+               gpWM_HotkeyTargets = t;
+       }
+       gpWM_HotkeyTargets_Last = t;
+}
+
+void WM_Hotkey_KeyDown(uint32_t Scancode)
+{
+       _SetKey(Scancode);
+       gbWM_HasBeenKeyDown = true;
+}
+
+void WM_Hotkey_KeyUp(uint32_t Scancode)
+{
+       _UnsetKey(Scancode);
+
+       // Ensure that hotkeys are triggered on the longest sequence
+       // (so Win-Shift-R doesn't trigger Win-R if shift is released)
+       if( !gbWM_HasBeenKeyDown )
+               return ;
+
+       for( tHotkey *hk = gpWM_Hotkeys; hk; hk = hk->Next )
+       {
+               int i;
+               for( i = 0; i < hk->nKeys; i ++ )
+               {
+                       if( hk->Keys[i] == Scancode )   continue ;
+                       if( _IsKeySet(hk->Keys[i]) )    continue ;
+                       break;
+               }
+               _SysDebug("%i/%i satisfied for %s", i, hk->nKeys, hk->Target);
+               if( i != hk->nKeys )
+                       continue ;
+               
+               // Fire shortcut
+               WM_Hotkey_FireEvent(hk->Target);
+
+               break;
+       }
+       
+       gbWM_HasBeenKeyDown = false;
+}
+
+void WM_Hotkey_FireEvent(const char *Target)
+{
+//     _SysDebug("WM_Hotkey_FireEvent: (%s)", Target);
+       // - Internal events (Alt-Tab, Close, Maximize, etc...)
+       // TODO: Internal event handling
+       
+       // - Application registered events
+       for( tHotkeyTarget *t = gpWM_HotkeyTargets, *prev=NULL; t; t = t->Next )
+       {
+               if( strcmp(t->Name, Target) != 0 )
+                       continue ;
+
+               struct sWndMsg_Hotkey   info = {.ID=t->Index};
+               WM_SendMessage(NULL, t->Window, WNDMSG_HOTKEY, sizeof(info), &info);
+
+               // Sort the list by most-recently-used
+               if(prev != NULL) {
+                       prev->Next = t->Next;
+                       t->Next = gpWM_HotkeyTargets;
+                       gpWM_HotkeyTargets = t;
+               }
+
+               return ;
+       }
+}
+
+static void _SetKey(uint32_t sc)
+{
+//     _SysDebug("_SetKey: (%x)", sc);
+       if( sc >= MAX_STATE_SCANCODE )  return;
+       gWM_KeyStates[sc/8] |= 1 << (sc % 8);
+}
+static void _UnsetKey(uint32_t sc)
+{
+//     _SysDebug("_UnsetKey: (%x)", sc);
+       if( sc >= MAX_STATE_SCANCODE )  return;
+       gWM_KeyStates[sc/8] &= ~(1 << (sc % 8));
+}
+static int _IsKeySet(uint32_t sc)
+{
+       if( sc >= MAX_STATE_SCANCODE )  return 0;
+
+       return !!(gWM_KeyStates[sc/8] & (1 << (sc % 8)));
+}
+
index 3220f77..5f6ef85 100644 (file)
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <wm_internals.h>
 #include <wm_messages.h>
+#include <wm_hotkeys.h>
 
 #define MAX_BUTTONS    3
 
@@ -33,8 +34,8 @@ tWindow *WM_int_GetWindowAtPos(int X, int Y)
                for(win = ret->FirstChild; win; win = win->NextSibling)
                {
                        if( !(win->Flags & WINFLAG_SHOW) )      continue ;
-                       if( X < win->X || X >= win->X + win->W )        continue;
-                       if( Y < win->Y || Y >= win->Y + win->H )        continue;
+                       if( X < win->X || X >= win->X + win->RealW )    continue;
+                       if( Y < win->Y || Y >= win->Y + win->RealH )    continue;
                        next_win = win; // Overwrite as we want the final rendered window
                }
        }
@@ -70,7 +71,7 @@ void WM_Input_MouseMoved(int OldX, int OldY, int NewX, int NewY)
        WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg);
 }
 
-inline void WM_Input_int_SendBtnMsg(tWindow *Win, int X, int Y, int Index, int Pressed)
+void WM_Input_int_SendBtnMsg(tWindow *Win, int X, int Y, int Index, int Pressed)
 {
        struct sWndMsg_MouseButton      msg;    
 
@@ -114,6 +115,9 @@ void WM_Input_MouseButton(int X, int Y, int ButtonIndex, int Pressed)
 void WM_Input_KeyDown(uint32_t Character, uint32_t Scancode)
 {
        struct sWndMsg_KeyAction        msg;
+
+       WM_Hotkey_KeyDown(Scancode);
+
        msg.KeySym = Scancode;
        msg.UCS32 = Character;
        WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_KEYDOWN, sizeof(msg), &msg);
@@ -133,6 +137,9 @@ void WM_Input_KeyFire(uint32_t Character, uint32_t Scancode)
 void WM_Input_KeyUp(uint32_t Character, uint32_t Scancode)
 {
        struct sWndMsg_KeyAction        msg;
+
+       WM_Hotkey_KeyUp(Scancode);
+
        msg.KeySym = Scancode;
        msg.UCS32 = Character;
        WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_KEYUP, sizeof(msg), &msg);
diff --git a/Usermode/Applications/axwin3_src/include/framebuffer_messages.h b/Usermode/Applications/axwin3_src/include/framebuffer_messages.h
new file mode 100644 (file)
index 0000000..034999b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * framebuffer_messages.h
+ * - Drawing Surface / Framebuffer Window Type
+ */
+#ifndef _AXWIN3__FRAMEBUFFER_MESSAGES_H_
+#define _AXWIN3__FRAMEBUFFER_MESSAGES_H_
+
+enum
+{
+       MSG_FB_COMMIT = 0x1000,
+       MSG_FB_NEWBUF,
+       MSG_FB_UPLOAD,
+       MSG_FB_DOWNLOAD,
+       MSG_FB_BLIT,
+       MSG_FB_FILL
+};
+
+typedef struct
+{
+       uint16_t        Buffer;
+       uint16_t        W, H;
+} tFBMsg_NewBuf;
+
+typedef struct
+{
+       uint16_t        Buffer;
+       uint16_t        W, H;
+       uint16_t        X, Y;
+       uint32_t        ImageData[];
+} tFBMsg_Transfer;
+
+typedef struct
+{
+       uint16_t        Source;
+       uint16_t        Dest;
+       uint16_t        SrcX, SrcY;
+       uint16_t        DstX, DstY;
+       uint16_t        W, H;
+} tFBMsg_Blit;
+
+typedef struct
+{
+       uint16_t        Buffer;
+       uint16_t        X, Y;
+       uint16_t        W, H;
+       uint32_t        Colour;
+} tFBMsg_Fill;
+
+#endif
+
index a752e36..6e61ba8 100644 (file)
@@ -17,6 +17,7 @@ typedef struct sIPCMsg_CreateWin      tIPCMsg_CreateWin;
 typedef struct sIPCMsg_Boolean tIPCMsg_Boolean;
 typedef struct sIPCMsg_SetWindowPos    tIPCMsg_SetWindowPos;
 typedef struct sIPCMsg_SendMsg tIPCMsg_SendMsg;
+typedef struct sIPCMsg_RegAction       tIPCMsg_RegAction;
 
 typedef struct sIPCMsg_GetDisplayDims  tIPCMsg_GetDisplayDims;
 typedef struct sIPCMsg_RetDisplayDims  tIPCMsg_RetDisplayDims;
@@ -73,6 +74,12 @@ struct sIPCMsg_SetWindowPos
        uint8_t         bSetDims;
 };
 
+struct sIPCMsg_RegAction
+{
+       uint16_t        Index;
+       char    Action[];
+};
+
 struct sIPCMsg_GetDisplayDims
 {
        uint16_t        DisplayID;
@@ -100,6 +107,7 @@ enum eAxWin_IPCMessageTypes
        IPCMSG_DECORATEWINDOW,  //!< Enable/Disable decorations
        IPCMSG_FOCUSWINDOW,     //!< Give a window focus (no data)
        IPCMSG_SETWINPOS,       //!< Set a window position
+       IPCMSG_REGACTION        //!< Register an action name
 };
 
 #endif
diff --git a/Usermode/Applications/axwin3_src/include/wm_messages.h b/Usermode/Applications/axwin3_src/include/wm_messages.h
new file mode 100644 (file)
index 0000000..2308c28
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Acess2 Window Manager v3 (axwin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * include/wm_messages.h
+ * - Core window messages
+ */
+#ifndef _WM_MESSAGES_H_
+#define _WM_MESSAGES_H_
+
+/**
+ * \brief Messages delivered to windows
+ */
+enum eWM_WindowMessages
+{
+       WNDMSG_NULL,
+       
+       WNDMSG_CREATE,
+       WNDMSG_DESTROY,
+       WNDMSG_FOCUS,   // Called on change
+       WNDMSG_SHOW,    // Called on change
+
+       WNDMSG_RESIZE,
+       
+       WNDMSG_MOUSEMOVE,
+       WNDMSG_MOUSEBTN,
+       WNDMSG_KEYDOWN,
+       WNDMSG_KEYFIRE,
+       WNDMSG_KEYUP,
+
+       WNDMSG_HOTKEY,
+       
+       WNDMSG_CLASS_MIN = 0x1000,
+       WNDMSG_CLASS_MAX = 0x2000,
+};
+
+struct sWndMsg_Bool
+{
+        uint8_t        Val;
+};
+
+struct sWndMsg_Resize
+{
+       uint16_t        W, H;
+};
+
+struct sWndMsg_MouseMove
+{
+        int16_t        X, Y;
+        int16_t        dX, dY;
+};
+
+struct sWndMsg_MouseButton
+{
+        int16_t        X, Y;
+       uint8_t         Button;
+       uint8_t         bPressed;
+};
+
+struct sWndMsg_KeyAction
+{
+       uint32_t        KeySym;
+       uint32_t        UCS32;
+};
+
+struct sWndMsg_Hotkey
+{
+       uint16_t        ID;
+};
+
+#endif
index 17d089f..2b50167 100644 (file)
@@ -16,6 +16,7 @@
 // === CONSTANTS ===
 enum eConnectionType
 {
+       CONNTYPE_NONE,
        CONNTYPE_SENDMESSAGE,
        CONNTYPE_UDP,
        CONNTYPE_TCP
@@ -121,11 +122,16 @@ tAxWin_IPCMessage *AxWin3_int_GetIPCMessage(void)
        switch(giConnectionType)
        {
        case CONNTYPE_SENDMESSAGE:
-               _SysWaitEvent(THREAD_EVENT_IPCMSG);
-               while(SysGetMessage(NULL, NULL))
+               for( ;; )
                {
                        pid_t   tid;
-                       len = SysGetMessage(&tid, NULL);
+               
+                       // Wait for a message to arrive 
+                       while( !(len = SysGetMessage(&tid, NULL)) )
+                       {
+                               _SysWaitEvent(THREAD_EVENT_IPCMSG);
+                       }
+                       
                        // Check if the message came from the server
                        if(tid != giConnectionNum)
                        {
index 875f14b..450e4b4 100644 (file)
@@ -8,7 +8,6 @@
 #include <axwin3/axwin.h>
 #include <axwin3/widget.h>
 #include "include/internal.h"
-#include "include/ipc.h"
 #include <stdlib.h>
 #include <widget_messages.h>
 #include <string.h>
@@ -232,23 +231,20 @@ char *AxWin3_Widget_GetText(tAxWin3_Widget *Widget)
 {
        char    buf[sizeof(tWidgetMsg_SetText)];
        tWidgetMsg_SetText      *msg = (void*)buf;
-       tAxWin_IPCMessage       *retmsg;
-       char    *ret;
+       size_t  retmsg_size;
        
        msg->WidgetID = Widget->ID;
 
        AxWin3_SendMessage(Widget->Window, Widget->Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
 
-       retmsg = AxWin3_int_WaitIPCMessage(MSG_WIDGET_GETTEXT);
-       msg = (void*)retmsg->Data;
-
-       if( retmsg->Size < sizeof(*msg) ) {
-               free(retmsg);
+       msg = AxWin3_WaitMessage(Widget->Window, MSG_WIDGET_GETTEXT, &retmsg_size);
+       if( retmsg_size < sizeof(*msg) ) {
+               free(msg);
                return NULL;
        }
 
-       ret = strndup(msg->Text, retmsg->Size - sizeof(*msg));
-       free(retmsg);
+       char    *ret = strndup(msg->Text, retmsg_size - sizeof(*msg));
+       free(msg);
        return ret;
 }
 
index 4a6242b..4a6d8d3 100644 (file)
 #include <string.h>
 #include "include/internal.h"
 #include "include/ipc.h"
+#include <wm_messages.h>
 
-#define WINDOWS_PER_ALLOC      (63)
+#define WINDOWS_PER_ALLOC      (64-1)  // -1 to make it 64 pointers (+ Next)
+#define MAX_HOTKEYS    32
 
 typedef struct sWindowBlock    tWindowBlock;
 
@@ -28,6 +30,7 @@ struct sWindowBlock
  int   giAxWin3_LowestFreeWinID;
  int   giAxWin3_HighestUsedWinID;
 tWindowBlock   gAxWin3_WindowList;
+tAxWin3_HotkeyCallback gAxWin3_Hotkeys[MAX_HOTKEYS];
 
 // === CODE ===
 tWindow *AxWin3_int_CreateWindowStruct(uint32_t ServerID, int ExtraBytes)
@@ -188,11 +191,40 @@ void AxWin3_int_HandleMessage(tAxWin_IPCMessage *Msg)
        {
        case IPCMSG_SENDMSG: {
                tIPCMsg_SendMsg *info = (void*)Msg->Data;
-               if(Msg->Size < sizeof(*info))   return ;
-               if(Msg->Size < sizeof(*info) + info->Length)    return ;
-               if(!dest || !dest->Handler)     return ;
-               dest->Handler(dest, info->ID, info->Length, info->Data);
+               if(Msg->Size < sizeof(*info) || Msg->Size < sizeof(*info) + info->Length) {
+                       _SysDebug("Message is undersized (%i < %i + %i)",
+                               Msg->Size < sizeof(*info), info->Length);
+                       return ;
+               }
+               if(!dest || !dest->Handler) {
+                       _SysDebug("No handler for destination %p", dest);
+                       return ;
+               }
+               _SysDebug("IPC Message 0x%x - %i bytes", info->ID, info->Length);
+
+               if( dest->Handler(dest, info->ID, info->Length, info->Data) )
+                       ;
+               else {
+                       switch( info->ID )
+                       {
+                       case WNDMSG_HOTKEY: {
+                               const struct sWndMsg_Hotkey *mi = (void*)info->Data;
+                               if( mi->ID >= MAX_HOTKEYS ) 
+                                       ;       // TODO: Error when hotkey is out of range
+                               else if( gAxWin3_Hotkeys[mi->ID] == 0 )
+                                       _SysDebug("--- Unmapped hotkey ID %i fired", mi->ID);
+                               else
+                                       gAxWin3_Hotkeys[mi->ID]();
+                               }break;
+                       default:
+                               _SysDebug("--- Unhandled SENDMSG %i", info->ID);
+                               break;
+                       }
+               }
                break; }
+       default:
+               _SysDebug("Unknow message ID %i", Msg->ID);
+               break;
        }
 }
 
@@ -225,6 +257,32 @@ void AxWin3_SendMessage(tHWND Window, tHWND Destination, int Message, int Length
        free(msg);
 }
 
+void *AxWin3_WaitMessage(tHWND Window, int MessageID, size_t *Length)
+{
+       tAxWin_IPCMessage       *msg;
+       
+       for( ;; )
+       {
+               msg = AxWin3_int_WaitIPCMessage(IPCMSG_SENDMSG);
+               if( msg->Window != AxWin3_int_GetWindowID(Window) ) {
+                       AxWin3_int_HandleMessage(msg);
+                       continue ;
+               }
+               tIPCMsg_SendMsg *info = (void*)msg->Data;
+               if( info->ID != MessageID ) {
+                       AxWin3_int_HandleMessage(msg);
+                       continue ;
+               }
+
+               *Length = info->Length;
+               void    *ret = malloc(info->Length);    
+               memcpy(ret, info->Data, info->Length);
+               free(msg);
+       
+               return ret;
+       }
+}
+
 void AxWin3_FocusWindow(tHWND Window)
 {
        tAxWin_IPCMessage       *msg;
@@ -316,3 +374,28 @@ void AxWin3_ResizeWindow(tHWND Window, short W, short H)
        free(msg);
 }
 
+int AxWin3_RegisterAction(tHWND Window, const char *Action, tAxWin3_HotkeyCallback cb)
+{
+        int    i;
+       for( i = 0; i < MAX_HOTKEYS; i ++ )
+       {
+               if( gAxWin3_Hotkeys[i] == NULL )
+               {
+                       tAxWin_IPCMessage       *msg;
+                       struct sIPCMsg_RegAction        *info;
+                       gAxWin3_Hotkeys[i] = cb;
+                       
+                       msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_REGACTION, 0, sizeof(*info)+strlen(Action)+1);
+                       info = (void*)msg->Data;
+               
+                       info->Index = i;
+                       strcpy(info->Action, Action);
+                       
+                       AxWin3_int_SendIPCMessage(msg);
+                       free(msg);
+                       return i;
+               }
+       }
+       return -1;
+}
+
index a389c10..443a5de 100644 (file)
@@ -15,7 +15,7 @@ int main(int argc, char *argv[])
 {
         int    fd;
         int    num;
-       char    buf[BUF_SIZE+1];
+       char    buf[BUF_SIZE];
 
        if(argc < 2) {
                printf("Usage: cat <file>\n");
@@ -31,8 +31,7 @@ int main(int argc, char *argv[])
        do {
                num = read(fd, buf, BUF_SIZE);
                if(num < 0)     break;
-               buf[num] = '\0';
-               printf("%s", buf);
+               write(1, buf, num);
        } while(num == BUF_SIZE);
 
        close(fd);
index 149bd0a..8831cd6 100644 (file)
@@ -1,9 +1,12 @@
 /*
+ * 
+ * http://www.ietf.org/rfc/rfc2131.txt
  */
 #include <unistd.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <net.h>
 
 #define FILENAME_MAX   255
@@ -63,6 +66,11 @@ typedef struct sInterface
         int    Num;
         int    SocketFD;
         int    IfaceFD;
+
+       uint32_t        TransactionID;
+       char    HWAddr[6];
+       
+       int64_t Timeout;
 } tInterface;
 
 // === PROTOTYPES ===
@@ -72,6 +80,8 @@ int   Start_Interface(tInterface *Iface);
 void   Send_DHCPDISCOVER(tInterface *Iface);
 void   Send_DHCPREQUEST(tInterface *Iface, void *OfferBuffer, int TypeOffset);
 int    Handle_Packet(tInterface *Iface);
+void   Handle_Timeout(tInterface *Iface);
+void   Update_State(tInterface *Iface, int newState);
 void   SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router);
 
 // === CODE ===
@@ -96,10 +106,10 @@ int main(int argc, char *argv[])
 
        for( i = ifaces; i; i = i->Next )
        {
-               i->State = STATE_PREINIT;
                if( Start_Interface(i) < 0 ) {
                        return -1;
                }
+               i->State = STATE_PREINIT;
                
                // Send request
                Send_DHCPDISCOVER(i);
@@ -110,6 +120,7 @@ int main(int argc, char *argv[])
                 int    maxfd;
                fd_set  fds;
                tInterface      *p;
+               int64_t timeout = 1000;
        
                maxfd = 0;
                FD_ZERO(&fds);
@@ -118,12 +129,15 @@ int main(int argc, char *argv[])
                        FD_SET(i->SocketFD, &fds);
                        if(maxfd < i->SocketFD) maxfd = i->SocketFD;
                }
-               if( select(maxfd+1, &fds, NULL, NULL, NULL) < 0 )
+               
+               if( select(maxfd+1, &fds, NULL, NULL, &timeout) < 0 )
                {
                        // TODO: Check error result
                        return -1;
                }
 
+               _SysDebug("select() returned");
+
                // Check for changes (with magic to allow inline deletion)
                for( p = (void*)&ifaces, i = ifaces; i; p=i,i = i->Next )
                {
@@ -138,6 +152,11 @@ int main(int argc, char *argv[])
                                        i = p;
                                }
                        }
+                       
+                       if( _SysTimestamp() > i->Timeout )
+                       {
+                               Handle_Timeout(i);
+                       }
                }
        }
        return 0;
@@ -148,7 +167,11 @@ void Scan_Dir(tInterface **IfaceList, const char *Directory)
        int dp = open(Directory, OPENFLAG_READ);
        char filename[FILENAME_MAX];
 
-       while( readdir(dp, filename) )
+       if( dp == -1 ) {
+               fprintf(stderr, "Unable to open directory '%s'\n", Directory);
+       }
+
+       while( SysReadDir(dp, filename) )
        {
                if( filename[0] == '.' )        continue ;              
                if( strcmp(filename, "lo") == 0 )       continue ;
@@ -171,6 +194,20 @@ int Start_Interface(tInterface *Iface)
        
        // TODO: Check that the adapter is not in use
        
+       // Request MAC address from network adapter
+       {
+               char    path[] = "/Devices/ip/adapters/ethXXXX";
+               sprintf(path, "/Devices/ip/adapters/%s", Iface->Adapter);
+               fd = open(path, 0);
+               if(fd == -1) {
+                       _SysDebug("Unable to open adapter %s", path);
+                       return -1;
+               }
+               ioctl(fd, 4, Iface->HWAddr);
+               // TODO: Check if ioctl() failed
+               close(fd);
+       }
+       
        // Initialise an interface, with a dummy IP address (zero)
        fd = open("/Devices/ip", 0);
        if( fd == -1 ) {
@@ -204,11 +241,15 @@ int Start_Interface(tInterface *Iface)
        }
        tmp = 68; ioctl(fd, 4, &tmp);   // Local port
        tmp = 67; ioctl(fd, 5, &tmp);   // Remote port
-       tmp = 0;        ioctl(fd, 7, &tmp);     // Remote addr mask - we don't care where the reply comes from
+       tmp = 0;        ioctl(fd, 7, &tmp);     // Remote addr mask bits - we don't care where the reply comes from
        addr[0] = addr[1] = addr[2] = addr[3] = 255;    // 255.255.255.255
        ioctl(fd, 8, addr);     // Remote address
        
-       return fd;
+       return 0;
+}
+
+void Send_DHCPRELEASE(tInterface *Iface)
+{
 }
 
 void Send_DHCPDISCOVER(tInterface *Iface)
@@ -218,7 +259,10 @@ void Send_DHCPDISCOVER(tInterface *Iface)
        char    data[8 + sizeof(struct sDHCP_Message) + 3 + 1];
        msg = (void*)data + 8;
        
+       _SysDebug("DHCPDISCOVER to %s", Iface->Adapter);
+
        transaction_id = rand();
+       Iface->TransactionID = transaction_id;
 
        msg->op    = htonb(1);  // BOOTREQUEST
        msg->htype = htonb(1);  // 10mb Ethernet
@@ -226,25 +270,13 @@ void Send_DHCPDISCOVER(tInterface *Iface)
        msg->hops  = htonb(0);  // Hop count so far
        msg->xid   = htonl(transaction_id);     // Transaction ID
        msg->secs  = htons(0);  // secs - No time has elapsed
-       msg->flags = htons(0);  // flags - TODO: Check if broadcast bit need be set
+       msg->flags = htons(0x0000);     // flags - Broadcast is unset
        msg->ciaddr = htonl(0); // ciaddr - Zero, as we don't have one yet
        msg->yiaddr = htonl(0); // yiaddr - Zero?
        msg->siaddr = htonl(0); // siaddr - Zero? maybe -1
        msg->giaddr = htonl(0); // giaddr - Zero?
-       // Request MAC address from network adapter
-       {
-               char    path[] = "/Devices/ip/adapters/ethXXXX";
-               sprintf(path, "/Devices/ip/adapters/%s", Iface->Adapter);
-               int fd = open(path, 0);
-               if(fd == -1) {
-                       _SysDebug("Unable to open adapter %s", path);
-               }
-               else {
-                       ioctl(fd, 4, msg->chaddr);
-                       // TODO: Check if ioctl() failed
-                       close(fd);
-               }
-       }
+       memcpy(msg->chaddr, Iface->HWAddr, 6);
+
        memset(msg->sname, 0, sizeof(msg->sname));      // Nuke the rest
        memset(msg->file, 0, sizeof(msg->file));        // Nuke the rest
        msg->dhcp_magic = htonl(DHCP_MAGIC);
@@ -261,21 +293,53 @@ void Send_DHCPDISCOVER(tInterface *Iface)
        data[4] = 255;  data[5] = 255;  data[6] = 255;  data[7] = 255;
 
        write(Iface->SocketFD, data, sizeof(data));
-       Iface->State = STATE_DISCOVER_SENT;
+       Update_State(Iface, STATE_DISCOVER_SENT);
 }
 
 void Send_DHCPREQUEST(tInterface *Iface, void *OfferPacket, int TypeOffset)
 {
        struct sDHCP_Message    *msg;
+        int    i;
        msg = (void*) ((char*)OfferPacket) + 8;
 
        // Reuses old data :)
-       msg->op = 1;
-       msg->options[TypeOffset+2] = 3; // DHCPREQUEST
-       msg->options[TypeOffset+3] = 255;
+       msg->op    = 1;
+       msg->htype = 1;
+       msg->hlen  = 6;
+       msg->hops  = 0;
+       msg->xid   = msg->xid;
+       msg->secs  = htons(0);  // TODO: Maintain times
+       msg->flags = htons(0);
+       memcpy(msg->chaddr, Iface->HWAddr, 6);
+       memset(msg->sname, 0, sizeof(msg->sname));      // Nuke the rest
+       memset(msg->file, 0, sizeof(msg->file));        // Nuke the rest
+
+       i = 0;
+       msg->options[i++] = 53; // Message type = DHCPREQUEST
+       msg->options[i++] = 1;
+       msg->options[i++] = 3;
+       msg->options[i++] = 50; // Requested Address
+       msg->options[i++] = 4;
+       memcpy(msg->options + i, &msg->yiaddr, 4);      i += 4;
+//     msg->options[i++] = 54; // Server identifier
+//     msg->options[i++] = 4;
+//     memcpy(msg->options + i, (char*)OfferPacket + 4, 4);    i += 4;
+       msg->options[i++] = 255;
        
-       write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + TypeOffset + 4);
-       Iface->State = STATE_REQUEST_SENT;
+       // Clear last because yiaddr is needed in option setup
+       msg->ciaddr = htonl(0);
+       msg->yiaddr = htonl(0);
+       msg->siaddr = htonl(0);
+       msg->giaddr = htonl(0);
+
+       // HACK
+       ((uint8_t*)OfferPacket)[4] = 255;
+       ((uint8_t*)OfferPacket)[5] = 255;
+       ((uint8_t*)OfferPacket)[6] = 255;
+       ((uint8_t*)OfferPacket)[7] = 255;
+       
+       write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + i);
+       Update_State(Iface, STATE_REQUEST_SENT);
 }
 
 int Handle_Packet(tInterface *Iface)
@@ -310,6 +374,19 @@ int Handle_Packet(tInterface *Iface)
                return 0;
        }       
 
+
+       // Check if the packet is related to our requests
+       if( ntohl(msg->xid) != Iface->TransactionID ) {
+               _SysDebug("Transaction ID mis-match, ignoring (0x%x != 0x%x)",
+                       ntohl(msg->xid), Iface->TransactionID);
+               return 0;
+       }
+       if( memcmp(msg->chaddr, Iface->HWAddr, 6) != 0 ) {
+               _SysDebug("Hardware address mis-match, ignoring");
+               return 0;
+       }
+
+       // Parse options
        i = 0;
        while( i < len - sizeof(*msg) - 8 && msg->options[i] != 255 )
        {
@@ -353,13 +430,41 @@ int Handle_Packet(tInterface *Iface)
        case 4: // DHCPDECLINE - ?
                break;
        case 5: // DHCPACK
-               // TODO: Apply address
                SetAddress(Iface, &msg->yiaddr, subnet_mask, router);
+               // Return 1 to remove from list
                return 1;
        }
        return 0;
 }
 
+void Handle_Timeout(tInterface *Iface)
+{
+       switch(Iface->State)
+       {
+       case STATE_DISCOVER_SENT:
+               Send_DHCPDISCOVER(Iface);
+               break;
+       default:
+               _SysDebug("Timeout with state = %i", Iface->State);
+               break;
+       }
+}
+
+void Update_State(tInterface *Iface, int newState)
+{
+       if( Iface->State != newState )
+       {
+               Iface->Timeout = _SysTimestamp() + 500;
+               Iface->State = newState;
+       }
+       else
+       {
+               // TODO: Exponential backoff
+               Iface->Timeout = _SysTimestamp() + 3000;
+               _SysDebug("State %i repeated, timeout is 3000ms now", newState);
+       }
+}
+
 void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router)
 {
         int    mask_bits = 0;  
index 579aa47..cf5d5dc 100644 (file)
@@ -131,7 +131,7 @@ void DumpInterfaces(void)
        
        dp = open(IPSTACK_ROOT, OPENFLAG_READ);
        
-       while( readdir(dp, filename) )
+       while( SysReadDir(dp, filename) )
        {
                if(filename[0] == '.')  continue;
                DumpInterface(filename);
index 1d60fbc..f074bff 100644 (file)
@@ -118,7 +118,7 @@ void DumpRoutes(void)
        
        printf("Type\tNetwork \tGateway \tMetric\tIFace\n");
        
-       while( readdir(dp, filename) )
+       while( SysReadDir(dp, filename) )
        {
                if(filename[0] == '.')  continue;
                DumpRoute(filename);
index f420eb8..4dff114 100644 (file)
@@ -3,7 +3,7 @@
 include $(BASE)header.mk
 
 # Variables
-SRCS := main.c
+SRCS := main.c addr.c routes.c
 BIN  := $(OUTPUTDIR)Bin/ifconfig
 
 LDFLAGS-$(DIR) += -lnet
index ab82a14..e859bfe 100644 (file)
@@ -47,8 +47,6 @@ int main(int argc, char *argv[])
                        return -1;
                }
                
-               printf("pid = %i\n", pid);
-               
                // Spawn shell in a child process
                if(pid == 0)
                {
index 4be8f0a..2394af6 100644 (file)
@@ -75,7 +75,7 @@ int main(int argc, char *argv[])
        }
 
        // Traverse Directory
-       while( (tmp = readdir(fd, buf)) > 0 )
+       while( (tmp = SysReadDir(fd, buf)) > 0 )
        {
                // Error check
                if(tmp < 0) {
diff --git a/Usermode/Applications/lspci_src/Makefile b/Usermode/Applications/lspci_src/Makefile
new file mode 100644 (file)
index 0000000..b0c5e4f
--- /dev/null
@@ -0,0 +1,10 @@
+# Project: PCI Device Listing
+
+-include ../Makefile.cfg
+
+LDFLAGS += 
+
+OBJ = main.o
+BIN = lspci
+
+-include ../Makefile.tpl
diff --git a/Usermode/Applications/lspci_src/main.c b/Usermode/Applications/lspci_src/main.c
new file mode 100644 (file)
index 0000000..c24fde9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Acess2 lspci
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <acess/sys.h>
+
+#define PCI_BASE       "/Devices/pci"
+// === PROTOTYPES ===
+ int   main(int argc, char *argv[]);
+void   show_device(int PFD, const char *File, int bVerbose);
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+       int fd = open(PCI_BASE, OPENFLAG_READ);
+
+       char name[256]; 
+
+       while( SysReadDir(fd, name) )
+       {
+               if(name[0] == '.')      continue ;
+               
+               show_device(fd, name, 0);
+       }
+
+       return 0;
+}
+
+void show_device(int PFD, const char *File, int bVerbose)
+{
+        int    fd;
+        int    rv;
+
+       struct {
+               uint16_t        vendor;
+               uint16_t        device;
+               uint32_t        _unused;
+               uint32_t        revclass;
+       } pciinfo;
+
+       fd = _SysOpenChild(PFD, File, OPENFLAG_READ);
+       if( fd == -1 ) {
+               printf("%s - ERR (open failure)\n", File);
+               return ;
+       }
+       rv = read(fd, &pciinfo, sizeof(pciinfo));
+       if( rv != sizeof(pciinfo) ) {
+               printf("%s - ERR (read %i < %i)\n", File, rv, sizeof(pciinfo));
+               close(fd);
+               return ;
+       }
+       uint32_t        class_if = pciinfo.revclass >> 8;
+       uint8_t         revision = pciinfo.revclass & 0xFF;
+       printf("%s - %04x:%04x %06x:%02x\n",
+               File,
+               pciinfo.vendor, pciinfo.device,
+               class_if, revision
+               );
+
+       if( bVerbose )
+       {
+               printf("\n");
+       }
+
+       close(fd);
+}
+
index 5bee7c6..7c401bd 100644 (file)
@@ -6,7 +6,7 @@
 #include <stdio.h>
 
 #define        MOUNTABLE_FILE  "/Acess/Conf/Mountable"
-#define        MOUNTED_FILE    "/Devices/System/VFS/Mounts"
+#define        MOUNTED_FILE    "/Devices/system/VFS/Mounts"
 
 // === PROTOTYPES ===
 void   ShowUsage(char *ProgName);
@@ -22,16 +22,18 @@ int main(int argc, char *argv[])
         int    fd;
         int    i;
        char    *arg;
+       
        char    *sType = NULL;
        char    *sDevice = NULL;
        char    *sDir = NULL;
        char    *sOptions = NULL;
+        int    bUnmount = 0;
 
        // List mounted filesystems
        // - This is cheating, isn't it?
        if(argc == 1) {
                // Dump the contents of /Devices/system/VFS/Mounts
-               FILE    *fp = fopen("/Devices/system/VFS/Mounts", "r");
+               FILE    *fp = fopen(MOUNTED_FILE, "r");
                char    buf[1024];
                 int    len;
                while( (len = fread(buf, 1024, 1, fp)) )
@@ -56,6 +58,10 @@ int main(int argc, char *argv[])
                        {
                        // -t <driver> :: Filesystem driver to use
                        case 't':       sType = argv[++i];      break;
+                       // -o option_list :: Options to pass the driver
+                       case 'o':       sOptions = argv[++i];   break;
+                       // -u :: Unmount
+                       case 'u':       bUnmount = 1;   break;
                        case '-':
                                //TODO: Long Arguments
                        default:
@@ -81,6 +87,22 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
+       if( bUnmount )
+       {
+               // TODO: Check for a match in the fstab
+               
+               if( sDir ) {
+                       fprintf(stderr, "`mount -u` takes one argument\n");
+               }
+               
+               sDir = sDevice;
+               if( _SysMount(NULL, sDir, NULL, NULL) ) // Unmount (Dev=NULL means unmount)
+               {
+                       fprintf(stderr, "Unmount failed\n");
+               }
+               return EXIT_SUCCESS;
+       }
+
        // Check if we even got a device/mountpoint
        if(sDevice == NULL) {
                ShowUsage(argv[0]);
@@ -113,10 +135,10 @@ int main(int argc, char *argv[])
        else
        {
                // Check that we were passed a filesystem type
-               if(sType == NULL) {
-                       fprintf(stderr, "Please pass a filesystem type\n");
-                       return EXIT_FAILURE;
-               }
+//             if(sType == NULL) {
+//                     fprintf(stderr, "Please pass a filesystem type\n");
+//                     return EXIT_FAILURE;
+//             }
        }
        
        // Check Device
@@ -139,7 +161,14 @@ int main(int argc, char *argv[])
        if(sOptions == NULL)    sOptions = "";
 
        // Let's Mount!
-       _SysMount(sDevice, sDir, sType, sOptions);
+       if( _SysMount(sDevice, sDir, sType, sOptions) ) {
+//             perror("_SysMount");
+               if( !sType )
+                       fprintf(stderr, "Filesystem autodetection failed, please pass a type\n");
+               else {
+                       fprintf(stderr, "Mount %s:'%s'=>'%s' failed\n", sType, sDevice, sDir);
+               }
+       }
 
        return 0;
 }
@@ -147,7 +176,7 @@ int main(int argc, char *argv[])
 void ShowUsage(char *ProgName)
 {
        fprintf(stderr, "Usage:\n");
-       fprintf(stderr, "    %s [-t <type>] <device> <directory>\n", ProgName);
+       fprintf(stderr, "    %s [-t <type>] <device> <directory> [-o <options>]\n", ProgName);
        fprintf(stderr, "or  %s <device>\n", ProgName);
        fprintf(stderr, "or  %s <directory>\n", ProgName);
        fprintf(stderr, "or  %s\n", ProgName);
index fb4d8eb..5779b3d 100644 (file)
@@ -2,7 +2,8 @@ include $(BASE)header.mk
 
 # Rules
 ASFLAGS-$(DIR)  := -felf -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS-$(DIR) := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
 CFLAGS-$(DIR)   := -g -Wall -fno-stack-protector -O3
 LDFLAGS-$(DIR)  := -T $(OUTPUTDIR)Libs/acess.ld -rpath-link $(OUTPUTDIR)Libs -L $(OUTPUTDIR)Libs -I /Acess/Libs/ld-acess.so -lld-acess -lc $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o
 
diff --git a/Usermode/Applications/wget_src/Makefile b/Usermode/Applications/wget_src/Makefile
new file mode 100644 (file)
index 0000000..e6f5a01
--- /dev/null
@@ -0,0 +1,11 @@
+# Project: wget clone
+
+-include ../Makefile.cfg
+
+CFLAGS += -std=gnu99
+LDFLAGS += -lnet -lpsocket -luri
+OBJ = main.o
+BIN = wget
+
+-include ../Makefile.tpl
+
diff --git a/Usermode/Applications/wget_src/main.c b/Usermode/Applications/wget_src/main.c
new file mode 100644 (file)
index 0000000..3410840
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Acess2 Command-line HTTP Client (wget)
+ * - By John Hodge
+ *
+ * main.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <net.h>
+#include <uri.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+enum eProcols
+{
+       PROTO_NONE,
+       PROTO_HTTP,
+       PROTO_HTTPS
+};
+
+const char     **gasURLs;
+ int   giNumURLs;
+
+ int   main(int argc, char *argv[]);
+ int   _ParseHeaderLine(char *Line, int State, size_t *Size);
+void   writef(int fd, const char *format, ...);
+
+int main(int argc, char *argv[])
+{
+        int    proto, rv;
+       gasURLs = malloc( (argc - 1) * sizeof(*gasURLs) );
+       
+       // Parse arguments
+       for(int i = 1; i < argc; i ++ )
+       {
+               char    *arg = argv[i];
+               if( arg[0] != '-' ) {
+                       // URL
+                       gasURLs[giNumURLs++] = arg;
+               }
+               else if( arg[1] != '-') {
+                       // Short arg
+               }
+               else {
+                       // Long arg
+               }
+       }
+
+       // Do the download
+       for( int i = 0; i < giNumURLs; i ++ )
+       {
+               char    *outfile = NULL;
+               tURI    *uri = URI_Parse(gasURLs[i]);
+               struct addrinfo *addrinfo;
+
+               if( !uri ) {
+                       fprintf(stderr, "'%s' is not a valid URL", gasURLs[i]);
+                       continue ;
+               }               
+
+               printf("Proto: %s, Host: %s, Path: %s\n", uri->Proto, uri->Host, uri->Path);
+
+               if( uri->Path[0] == '\0' || uri->Path[strlen(uri->Path)-1] == '/' )
+                       outfile = "index.html";
+               else {
+                       outfile = strrchr(uri->Path, '/');
+                       if( !outfile )
+                               outfile = uri->Path;
+                       else
+                               outfile += 1;
+               }
+
+               if( strcmp(uri->Proto, "http") == 0 ) {
+                       proto = PROTO_HTTP;
+               }
+               else if( strcmp(uri->Proto, "https") == 0 ) {
+                       proto = PROTO_HTTPS;
+               }
+               else {
+                       // Unknown
+                       fprintf(stderr, "Unknown protocol '%s'\n", uri->Proto);
+                       free(uri);
+                       continue ;
+               }
+
+               if( proto != PROTO_HTTP ) {
+                       fprintf(stderr, "TODO: Support protocols other than HTTP\n");
+                       free(uri);
+                       continue ;
+               }
+
+               rv = getaddrinfo(uri->Host, "http", NULL, &addrinfo);
+               if( rv != 0 ) {
+                       fprintf(stderr, "Unable to resolve %s: %s\n", uri->Host, gai_strerror(rv));
+                       continue ;
+               }
+
+               for( struct addrinfo *addr = addrinfo; addr != NULL; addr = addr->ai_next )
+               {
+                        int    bSkipLine = 0;
+                       // TODO: Convert to POSIX/BSD
+                       // NOTE: using addr->ai_addr will break for IPv6, as there is more info before the address
+                        int    sock;
+                       
+                       printf("Attempting [%s]:80\n", Net_PrintAddress(addr->ai_family, addr->ai_addr->sa_data));
+                       
+                       sock = Net_OpenSocket_TCPC(addr->ai_family, addr->ai_addr->sa_data, 80);
+                       if( sock == -1 ) {
+                               continue ;
+                       }
+
+                       _SysDebug("Connected as %i", sock);
+                       
+                       writef(sock, "GET /%s HTTP/1.1\r\n", uri->Path);
+                       writef(sock, "Host: %s\r\n", uri->Host);
+//                     writef(sock, "Accept-Encodings: */*\r\n");
+                       writef(sock, "User-Agent: awget/0.1 (Acess2)\r\n");
+                       writef(sock, "\r\n");
+                       
+                       // Parse headers
+                       char    inbuf[BUFSIZ+1];
+                       size_t  offset = 0, len = 0;
+                        int    state = 0;
+                       size_t  bytes_seen = 0;
+                       size_t  bytes_wanted = -1;      // invalid
+                       
+
+                       inbuf[0] = '\0';
+                       while( state == 0 || state == 1 )
+                       {
+                               if( offset == BUFSIZ ) {
+                                       bSkipLine = 1;
+                                       offset = 0;
+                               }
+                               inbuf[len] = '\0';
+                       
+                               char    *eol = strchr(inbuf, '\n');
+                               // No end of line char? read some more
+                               if( eol == NULL ) {
+                                       // TODO: Handle -1 return
+                                       len += read(sock, inbuf + offset, BUFSIZ - 1 - offset);
+                                       continue ;
+                               }
+
+                               // abuse offset as the end of the string        
+                               offset = (eol - inbuf) + 1;
+
+                               // Clear EOL bytes
+                               *eol = '\0';
+                               // Nuke the \r
+                               if( eol - 1 >= inbuf )
+                                       eol[-1] = '\0';
+                               
+                               if( !bSkipLine )
+                                       state = _ParseHeaderLine(inbuf, state, &bytes_wanted);
+               
+                               // Move unused data down in memory      
+                               len -= offset;
+                               memmove( inbuf, inbuf + offset, BUFSIZ - offset );
+                               offset = len;
+                       }
+
+                       if( state == 2 )
+                       {
+                               _SysDebug("RXing %i bytes to '%s'", bytes_wanted, outfile);
+                                int    outfd = open(outfile, O_WR|O_CREAT, 0666);
+                               if( outfd == -1 ) {
+                                       fprintf(stderr, "Unable to open '%s' for writing\n", outfile);
+                               }
+                               else
+                               {
+                                       // Write the remainder of the buffer
+                                       do
+                                       {
+                                               write(outfd, inbuf, len);
+                                               bytes_seen += len;
+                                               _SysDebug("%i/%i bytes done", bytes_seen, bytes_wanted);
+                                       } while( bytes_seen < bytes_wanted && (len = read(sock, inbuf, sizeof(inbuf))) > 0 );
+                                       close(outfd);
+                               }
+                       }
+                       
+                       _SysDebug("Closing socket");
+                       close(sock);
+                       break ;
+               }
+
+               free(uri);
+       }
+       
+       return 0;
+}
+
+int _ParseHeaderLine(char *Line, int State, size_t *Size)
+{
+       _SysDebug("Header - %s", Line);
+       // First line (Status and version)
+       if( State == 0 )
+       {
+               // HACK - assumes HTTP/1.1 (well, 9 chars before status)
+               switch( atoi(Line + 9) )
+               {
+               case 200:
+                       // All good!
+                       return 1;
+               default:
+                       fprintf(stderr, "Unknown HTTP status - %s\n", Line + 9);
+                       return -1;
+               }
+       }
+       // Last line?
+       else if( Line[0] == '\0' )
+       {
+               return 2;
+       }
+       // Body lines
+       else
+       {
+               char    *value;
+               char    *colon = strchr(Line, ':');
+               if(colon == NULL)       return 1;
+
+               *colon = '\0';
+               value = colon + 2;
+               if( strcmp(Line, "Content-Length") == 0 ) {
+                       *Size = atoi(value);
+               }
+               else {
+                       printf("Ignorning header '%s' = '%s'\n", Line, value);
+               }
+
+               return 1;
+       }
+}
+
+void writef(int fd, const char *format, ...)
+{
+       va_list args;
+       size_t  len;
+       
+       va_start(args, format);
+       len = vsnprintf(NULL, 0, format, args);
+       va_end(args);
+       
+       char data[len + 1];
+       va_start(args, format);
+       vsnprintf(data, len+1, format, args);
+       va_end(args);
+       
+       write(fd, data, len);
+}
+
index d7dab2d..4aafe56 100644 (file)
@@ -6,6 +6,7 @@
 MAKEDEP  = $(CC) -M
 
 ASFLAGS  += -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
 CFLAGS   := -g -Wall -fPIC -fno-stack-protector -O3
-LDFLAGS  := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined
+LDFLAGS  := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined `$(CC) -print-libgcc-file-name`
index e32dd60..e252210 100644 (file)
@@ -30,11 +30,14 @@ install: all
 ifneq ($(_XBIN),)
        $(xCP) $(_XBIN) $(DISTROOT)/Libs/
 endif
+#ifneq ($(INCFILES),)
+#      for f in $(INCFILES); do ln -s $f $(ACESSDIR)/include/$f; done
+#endif
 
 $(_BIN): $(OBJ) $(_LIBS)
        @mkdir -p $(dir $(_BIN))
        @echo [LD] -o $(BIN) $(OBJ)
-       @$(LD) $(LDFLAGS) -o $(_BIN) $(OBJ)
+       @$(LD) $(LDFLAGS) -o $(_BIN) $(OBJ) $(shell $(CC) -print-libgcc-file-name)
        @$(DISASM) -S $(_BIN) > $(_OBJPREFIX)$(BIN).dsm
 
 $(_OBJPREFIX)%.o: %.c
diff --git a/Usermode/Libraries/acess.ld_src/acess_armv6.ld.h b/Usermode/Libraries/acess.ld_src/acess_armv6.ld.h
new file mode 100644 (file)
index 0000000..0ea7f90
--- /dev/null
@@ -0,0 +1,235 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+             "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+SEARCH_DIR(__LIBDIR)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x8000)); . = SEGMENT_START("text-segment", 0x8000);
+  .interp         : { *(.interp) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  .hash           : { *(.hash) }
+  .gnu.hash       : { *(.gnu.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.dyn        :
+    {
+      *(.rel.init)
+      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+      *(.rel.fini)
+      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+      *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+      *(.rel.ctors)
+      *(.rel.dtors)
+      *(.rel.got)
+      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+      PROVIDE_HIDDEN (__rel_iplt_start = .);
+      *(.rel.iplt)
+      PROVIDE_HIDDEN (__rel_iplt_end = .);
+      PROVIDE_HIDDEN (__rela_iplt_start = .);
+      PROVIDE_HIDDEN (__rela_iplt_end = .);
+    }
+  .rela.dyn       :
+    {
+      *(.rela.init)
+      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+      *(.rela.fini)
+      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+      *(.rela.ctors)
+      *(.rela.dtors)
+      *(.rela.got)
+      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+      PROVIDE_HIDDEN (__rel_iplt_start = .);
+      PROVIDE_HIDDEN (__rel_iplt_end = .);
+      PROVIDE_HIDDEN (__rela_iplt_start = .);
+      *(.rela.iplt)
+      PROVIDE_HIDDEN (__rela_iplt_end = .);
+    }
+  .rel.plt        :
+    {
+      *(.rel.plt)
+    }
+  .rela.plt       :
+    {
+      *(.rela.plt)
+    }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .iplt           : { *(.iplt) }
+  .text           :
+  {
+    *(.text.unlikely .text.*_unlikely)
+    *(.text.exit .text.exit.*)
+    *(.text.startup .text.startup.*)
+    *(.text.hot .text.hot.*)
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+   PROVIDE_HIDDEN(__exidx_start = .);
+  .ARM.exidx   : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+   PROVIDE_HIDDEN(__exidx_end = .);
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(SORT(.fini_array.*)))
+    KEEP (*(.fini_array))
+    PROVIDE_HIDDEN (__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 (*crtbegin?.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*crtbegin?.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+  .data           :
+  {
+    __data_start = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  __bss_start__ = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  _bss_end__ = . ; __bss_end__ = . ;
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  __end__ = . ;
+  _end = .; PROVIDE (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 .zdebug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames .zdebug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges .zdebug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames .zdebug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.* .zdebug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev .zdebug_abbrev) }
+  .debug_line     0 : { *(.debug_line .zdebug_line) }
+  .debug_frame    0 : { *(.debug_frame .zdebug_frame) }
+  .debug_str      0 : { *(.debug_str .zdebug_str) }
+  .debug_loc      0 : { *(.debug_loc .zdebug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo .zdebug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames .zdebug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames .zdebug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames .zdebug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames .zdebug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes .zdebug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges .zdebug_ranges) }
+    .stack         0x80000 :
+  {
+    _stack = .;
+    *(.stack)
+  }
+  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
+  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
+
+
index 49afb1e..d451b2c 100644 (file)
@@ -9,6 +9,7 @@ OBJ += arch/$(ARCHDIR).ao_
 BIN = ld-acess.so
 EXTRABIN := libld-acess.so
 EXTRACLEAN := $(_OBJPREFIX)_stublib.o
+INCFILES := sys/sys.h
 
 CFLAGS   = -g -Wall -fno-builtin -fno-leading-underscore -fno-stack-protector -fPIC
 CFLAGS  += $(CPPFLAGS)
@@ -19,7 +20,7 @@ include ../Makefile.tpl
 # create libld-acess.so
 $(_XBIN): $(_OBJPREFIX)_stublib.o
        @echo [LD] -o -shared libld-acess.so
-       $(LD) -shared -o $@ $<
+       $(LD) -shared -o $@ $< $(LDFLAGS)
 #      @$(LD) $(LDFLAGS) -o $@ $(OBJ)
 
 
index abf8043..1136226 100644 (file)
@@ -14,6 +14,7 @@ int _errno;
 #include "arch/syscalls.s.h"
 
 // libgcc functions
+#if 0
 uint64_t __udivdi3(uint64_t Num, uint64_t Den){return 0;}
 uint64_t __umoddi3(uint64_t Num, uint64_t Den){return 0;}
 
@@ -21,6 +22,8 @@ int32_t __divsi3(int32_t Num, int32_t Den){return 0;}
 int32_t __modsi3(int32_t Num, int32_t Den){return 0;}
 uint32_t __udivsi3(uint32_t Num, uint32_t Den){return 0;}
 uint32_t __umodsi3(uint32_t Num, uint32_t Den){return 0;}
+#endif
 
 void   *_crt0_exit_handler;
+void   abort(void){}
 
diff --git a/Usermode/Libraries/ld-acess.so_src/arch/armv6.S.h b/Usermode/Libraries/ld-acess.so_src/arch/armv6.S.h
new file mode 100644 (file)
index 0000000..3564392
--- /dev/null
@@ -0,0 +1,137 @@
+//
+// Acess2 ARMv7 - System Calls
+//
+
+.globl _start
+.extern SoMain
+_start:
+       pop {r0}
+       ldm sp, {r1,r2,r3}
+       bl SoMain
+       
+       mov r4, r0
+
+       pop {r0,r1,r2}
+       blx r4
+       
+       b _exit
+
+@ Stupid GCC
+.globl __ucmpdi2
+__ucmpdi2:
+       cmp r0, r2
+       movmi r0, #0
+       movmi pc, lr
+       movhi r0, #2
+       movhi pc, lr
+       cmp r1, r2
+       movmi r0, #0
+       movmi pc, lr
+       movhi r0, #2
+       movhi pc, lr
+       mov r0, #1
+       mov pc, lr
+
+@ Well, can't blame it
+@ - Clear the instruction cache
+.globl __clear_cache
+__clear_cache:
+       svc #0x1001
+       mov pc, lr
+
+@ DEST
+@ SRC
+@_memcpy:
+@      push rbp
+@      mov rbp, rsp
+@      
+@      ; RDI - First Param
+@      ; RSI - Second Param
+@      mov rcx, rdx    ; RDX - Third
+@      rep movsb
+@      
+@      pop rbp
+@      ret
+@
+.globl _errno
+_errno:        .long   0       @ Placed in .text, to allow use of relative addressing
+
+.macro syscall0 _name, _num    
+.globl \_name
+\_name:
+       push {lr}
+       svc #\_num
+       str r2, _errno
+       pop {pc}
+.endm
+
+.macro syscall5 _name, _num
+.globl \_name
+\_name:
+       push {r4, lr}
+       ldr r4, [sp,#8]
+       svc #\_num
+       str r2, _errno
+       pop {r4, pc}
+.endm
+
+.macro syscall6 _name, _num
+.globl \_name
+\_name:
+       push {r4,r5,lr}
+       ldr r4, [sp,#12]
+       ldr r5, [sp,#16]
+       svc #\_num
+       str r2, _errno
+       pop {r4,r5,pc}
+.endm
+
+#define SYSCALL0(_name,_num)   syscall0 _name, _num
+#define SYSCALL1(_name,_num)   SYSCALL0(_name, _num)
+#define SYSCALL2(_name,_num)   SYSCALL0(_name, _num)
+#define SYSCALL3(_name,_num)   SYSCALL0(_name, _num)
+#define SYSCALL4(_name,_num)   SYSCALL0(_name, _num)
+// TODO: 5/6 need special handling, because the args are on the stack
+#define SYSCALL5(_name,_num)   syscall5 _name, _num
+#define SYSCALL6(_name,_num)   syscall6 _name, _num
+
+// Override the clone syscall
+#define _exit  _exit_raw
+#define _clone _clone_raw
+#include "syscalls.s.h"
+#undef _exit
+#undef _clone
+
+.globl _clone
+_clone:
+       push {r4}
+       mov r4, r1
+       svc #SYS_CLONE
+       str r2, _errno
+       tst r4, r4
+       beq _clone_ret
+       @ If in child, set SP
+       tst r0,r0
+       movne sp, r4
+_clone_ret:
+       pop {r4}
+       mov pc, lr
+
+.globl _exit
+_exit:
+       svc #0
+       b .
+
+.globl abort
+abort:
+       mov r0, #0
+       svc #0
+       b .
+
+.globl __exidx_start
+__exidx_start:
+       b .
+.globl __exidx_end
+__exidx_end:
+       b .
+
diff --git a/Usermode/Libraries/ld-acess.so_src/arch/armv6.ld b/Usermode/Libraries/ld-acess.so_src/arch/armv6.ld
new file mode 100644 (file)
index 0000000..7f1b3c8
--- /dev/null
@@ -0,0 +1,69 @@
+ENTRY(_start)
+OUTPUT_FORMAT(elf32-littlearm)
+
+SECTIONS {
+       . = 0x6FFF0000;
+       gLinkedBase = .;
+       . += SIZEOF_HEADERS;
+       .interp          : { *(.interp) }
+       .note.gnu.build-id : { *(.note.gnu.build-id) }
+       .hash              : { *(.hash) }
+       .gnu.hash          : { *(.gnu.hash) }
+       .dynsym          : { *(.dynsym) }
+       .dynstr          : { *(.dynstr) }
+       .gnu.version    : { *(.gnu.version) }
+       .gnu.version_d  : { *(.gnu.version_d) }
+       .gnu.version_r  : { *(.gnu.version_r) }
+       .rel.dyn                :
+       {
+               *(.rel.init)
+               *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+               *(.rel.fini)
+               *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+               *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+               *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+               *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+               *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+               *(.rel.ctors)
+               *(.rel.dtors)
+               *(.rel.got)
+               *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+       }
+       .rela.dyn          :
+       {
+               *(.rela.init)
+               *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+               *(.rela.fini)
+               *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+               *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+               *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+               *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+               *(.rela.ctors)
+               *(.rela.dtors)
+               *(.rela.got)
+               *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+       }
+
+       .text : AT(ADDR(.text)) {
+               code = .;
+               *(.text)
+               *(.rodata*)
+               PROVIDE_HIDDEN(__exidx_start = .);
+               .ARM.exidx   : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+               PROVIDE_HIDDEN(__exidx_end = .);
+       }
+
+       .data ALIGN (0x1000) : AT(ADDR(.data)) {
+               data = .;
+               *(.data)
+       }
+
+       .bss ALIGN (0x1000) : AT(ADDR(.bss)) {
+               _sbss = .;
+               *(COMMON)
+               *(.bss)
+               _ebss = .;
+               bss = .;
+       }
+       _end = .;
+}
index c138784..fdbfb02 100644 (file)
@@ -44,11 +44,13 @@ SECTIONS {
                *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
        }
 
+       __exidx_start = .;
        .text : AT(ADDR(.text)) {
                code = .;
                *(.text)
                *(.rodata*)
        }
+       __exidx_end = .;
 
        .data ALIGN (0x1000) : AT(ADDR(.data)) {
                data = .;
index 88cea59..a978a35 100644 (file)
@@ -20,6 +20,7 @@ SYSCALL1(setgid, SYS_SETGID)
 
 SYSCALL1(SysSetName, SYS_SETNAME)
 SYSCALL2(SysGetName, SYS_GETNAME)
+SYSCALL0(_SysTimestamp, SYS_GETTIME)
 
 SYSCALL1(SysSetPri, SYS_SETPRI)
 
@@ -45,11 +46,12 @@ SYSCALL3(write, SYS_WRITE)  // int, uint, void*
 SYSCALL4(seek, SYS_SEEK)       // int, uint64_t, int
 SYSCALL1(tell, SYS_TELL)       // int
 SYSCALL3(finfo, SYS_FINFO)     // int, void*, int
-SYSCALL2(readdir, SYS_READDIR) // int, char*
+SYSCALL2(SysReadDir, SYS_READDIR)      // int, char*
 SYSCALL2(_SysGetACL,SYS_GETACL)        // int, void*
 SYSCALL1(chdir, SYS_CHDIR)     // char*
 SYSCALL3(ioctl, SYS_IOCTL)     // int, int, void*
 SYSCALL4(_SysMount, SYS_MOUNT) // char*, char*, char*, char*
 SYSCALL6(_SysSelect, SYS_SELECT)       // int, fd_set*, fd_set*, fd_set*, tTime*, uint32_t
+SYSCALL1(unlink, SYS_UNLINK)   // const char*
 
 SYSCALL3(_SysOpenChild, SYS_OPENCHILD)
index bbe45d6..4b081bc 100644 (file)
@@ -5,7 +5,9 @@
  * elf.c
  * - ELF32/ELF64 relocation
  */
-#define DEBUG  0
+#ifndef DEBUG  // This code is #include'd from the kernel, so DEBUG may already be defined
+# define DEBUG 0
+#endif
 
 #include "common.h"
 #include <stdint.h>
@@ -481,11 +483,20 @@ int Elf32GetSymbol(void *Base, const char *Name, void **ret, size_t *Size)
                return 0;
        }
 
+       // ... ok... maybe they haven't been relocated
+       if( (uintptr_t)symtab < (uintptr_t)Base )
+       {
+               symtab    = (void*)( (uintptr_t)symtab    + iBaseDiff );
+               pBuckets  = (void*)( (uintptr_t)pBuckets  + iBaseDiff );
+               dynstrtab = (void*)( (uintptr_t)dynstrtab + iBaseDiff );
+               SysDebug("Executable not yet relocated");
+       }
+
        nbuckets = pBuckets[0];
 //     iSymCount = pBuckets[1];
        pBuckets = &pBuckets[2];
        pChains = &pBuckets[ nbuckets ];
-       
+
        // Get hash
        iNameHash = ElfHashString(Name);
        iNameHash %= nbuckets;
@@ -517,7 +528,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename)
         int    i;
        Elf64_Ehdr      *hdr = Base;
        Elf64_Phdr      *phtab;
-       Elf64_Dyn       *dyntab;
+       Elf64_Dyn       *dyntab = NULL;
        Elf64_Addr      compiledBase = -1, baseDiff;
        Elf64_Sym       *symtab = NULL;
        char    *strtab = NULL;
@@ -543,7 +554,7 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename)
        DEBUGS("Elf64Relocate:  e_phnum = %i", hdr->e_phnum);
 
        // Scan for the dynamic table (and find the compiled base)
-       phtab = Base + hdr->e_phoff;
+       phtab = (void*)((uintptr_t)Base + hdr->e_phoff);
        for( i = 0; i < hdr->e_phnum; i ++ )
        {
                if(phtab[i].p_type == PT_DYNAMIC)
@@ -666,8 +677,8 @@ void *Elf64Relocate(void *Base, char **envp, const char *Filename)
                        break;
                case R_X86_64_COPY: {
                        size_t  size;
-                       void    *sym = GetSymbol(symname, &size);
-                       memcpy(ptr, sym, size);
+                       void    *symptr = GetSymbol(symname, &size);
+                       memcpy(ptr, symptr, size);
                        } break;
                case R_X86_64_GLOB_DAT:
                        *(uint64_t*)ptr = (uintptr_t)GetSymbol(symname, NULL);
index 41ba01f..1cec11e 100644 (file)
@@ -16,69 +16,33 @@ extern uint32_t     __umodsi3(uint32_t Num, uint32_t Den);
 #define STR(x) _STR(x)
 #define EXP(sym)       {&sym, STR(sym)}
 
+#define SYSCALL0(name,num)     EXP(name),
+#define SYSCALL1(name,num)     EXP(name),
+#define SYSCALL2(name,num)     EXP(name),
+#define SYSCALL3(name,num)     EXP(name),
+#define SYSCALL4(name,num)     EXP(name),
+#define SYSCALL5(name,num)     EXP(name),
+#define SYSCALL6(name,num)     EXP(name),
+
 // === CONSTANTS ===
 const struct {
        void    *Value;
        char    *Name;
 }      caLocalExports[] = {
        EXP(gLoadedLibraries),
-       EXP(_exit),
-       EXP(clone),
-       EXP(kill),
-       EXP(yield),
-       EXP(sleep),
-       EXP(_SysWaitEvent),
-       EXP(waittid),
-       EXP(gettid),
-       EXP(getpid),
-       EXP(getuid),
-       EXP(getgid),
-
-       EXP(setuid),
-       EXP(setgid),
-
-       EXP(SysSetName),
-       //EXP(SysGetName),
-
-       //EXP(SysSetPri),
-
-       EXP(SysSendMessage),
-       EXP(SysGetMessage),
-
-       EXP(_SysSpawn),
-       EXP(execve),
-       EXP(SysLoadBin),
-       EXP(SysUnloadBin),
-
-       EXP(_SysSetFaultHandler),
+       EXP(_errno),
        
-       EXP(open),
-       EXP(reopen),
-       EXP(close),
-       EXP(read),
-       EXP(write),
-       EXP(seek),
-       EXP(tell),
-       EXP(finfo),
-       EXP(readdir),
-       EXP(_SysGetACL),
-       EXP(chdir),
-       EXP(ioctl),
-       EXP(_SysMount),
-       EXP(_SysSelect),
-
-       EXP(_SysOpenChild),
-       
-       EXP(_SysGetPhys),
-       EXP(_SysAllocate),
-       EXP(_SysDebug),
-
+       #define __ASSEMBLER__
+       #include "arch/syscalls.s.h"
+       #undef __ASSEMBLER__
+#if 0
        EXP(__umoddi3),
        EXP(__udivdi3),
        EXP(__divsi3),
        EXP(__modsi3),
        EXP(__udivsi3),
        EXP(__umodsi3)
+#endif
 };
 
 const int      ciNumLocalExports = sizeof(caLocalExports)/sizeof(caLocalExports[0]);
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices.h
new file mode 100644 (file)
index 0000000..bfbb625
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * \file drivers.h
+ */
+#ifndef _SYS_DRIVERS_H
+#define _SYS_DRIVERS_H
+
+// === COMMON ===
+enum eDrv_Common {
+       DRV_IOCTL_NULL,
+       DRV_IOCTL_TYPE,
+       DRV_IOCTL_IDENT,
+       DRV_IOCTL_VER
+};
+
+enum eDrv_Types {
+       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
+       DRV_TYPE_TERMINAL,      //!< Terminal
+       DRV_TYPE_VIDEO,         //!< Video - LFB
+       DRV_TYPE_SOUND,         //!< Audio
+       DRV_TYPE_MOUSE,         //!< Mouse
+       DRV_TYPE_JOYSTICK       //!< Joystick / Gamepad
+};
+
+// === VIDEO ===
+enum eDrv_Video {
+       VID_IOCTL_SETMODE = 4,
+       VID_IOCTL_GETMODE,
+       VID_IOCTL_FINDMODE,
+       VID_IOCTL_MODEINFO,
+       VID_IOCTL_REQLFB        // Request LFB
+};\r
+struct sVideo_IOCtl_Mode {\r
+       short   id;\r
+       Uint16  width;\r
+       Uint16  height;\r
+       Uint16  bpp;\r
+};\r
+typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type
+
+// === MOUSE ===
+enum eDrv_Mouse {\r
+       MSE_IOCTL_SENS = 4,\r
+       MSE_IOCTL_MAX_X,\r
+       MSE_IOCTL_MAX_Y\r
+};
+
+// === Terminal ===
+#include "devices/terminal.h"
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/terminal.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/devices/terminal.h
new file mode 100644 (file)
index 0000000..c51b1b2
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * \file devices/terminal.h
+ */
+#ifndef _SYS_DEVICES_TERMINAL_H
+#define _SYS_DEVICES_TERMINAL_H
+
+#include <stdint.h>
+
+enum eDrv_Terminal {
+       TERM_IOCTL_MODETYPE = 4,
+       TERM_IOCTL_WIDTH,
+       TERM_IOCTL_HEIGHT,
+       TERM_IOCTL_QUERYMODE,
+       TERM_IOCTL_FORCESHOW,
+       TERM_IOCTL_GETSETCURSOR,
+       TERM_IOCTL_SETCURSORBITMAP
+};
+
+
+struct sTerm_IOCtl_Mode
+{
+       int16_t ID;             //!< Zero Based index of mode
+       int16_t DriverID;       //!< Driver's ID number (from ::tVideo_IOCtl_Mode)
+       uint16_t        Height; //!< Height
+       uint16_t        Width;  //!< Width
+       uint8_t Depth;  //!< Bits per cell
+       uint8_t Flags;  //!< Flags (1: Text Mode)
+};
+
+/**
+ * \brief Terminal Modes
+ */
+enum eTplTerminal_Modes {
+       /**
+        * \brief UTF-8 Text Mode
+        * Any writes to the terminal file are treated as UTF-8 encoded
+        * strings and reads will also return UTF-8 strings.
+        */
+       TERM_MODE_TEXT,
+       
+       /**
+        * \brief 32bpp Framebuffer
+        * Writes to the terminal file will write to the framebuffer.
+        * Reads will return UTF-32 characters
+        */
+       TERM_MODE_FB,
+       
+       /**
+        * \brief OpenGL 2D/3D
+        * Writes to the terminal file will send 3D commands
+        * Reads will return UTF-32 characters
+        * \note May or may not stay in the spec
+        */
+       TERM_MODE_OPENGL,
+       
+       NUM_TERM_MODES
+};
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/intdefs.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/intdefs.h
new file mode 100644 (file)
index 0000000..4214b5a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ */
+#ifndef _ACESS_INTDEFS_H_
+#define _ACESS_INTDEFS_H_
+
+#include <stdint.h>
+#include <limits.h>
+
+#if 0
+#define INT_MIN        -0x80000000
+#define INT_MAX        0x7FFFFFFF
+
+typedef unsigned char  __uint8_t;
+typedef unsigned short __uint16_t;
+typedef unsigned int   __uint32_t;
+typedef unsigned long long     __uint64_t;
+
+typedef signed char            __int8_t;
+typedef signed short   __int16_t;
+typedef signed int             __int32_t;
+typedef signed long long       __int64_t;
+
+#if defined(ARCHDIR_is_x86)
+typedef __int32_t      __intptr_t;
+typedef __uint32_t     __uintptr_t;
+#elif defined(ARCHDIR_is_x86_64)
+typedef __int64_t      __intptr_t;
+typedef __uint64_t     __uintptr_t;
+#elif defined(ARCHDIR_is_armv7) | defined(ARCHDIR_is_armv6)
+typedef __int32_t      __intptr_t;
+typedef __uint32_t     __uintptr_t;
+#else
+# error "Unknown pointer size"
+#endif
+
+#endif
+
+#endif
+
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h b/Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h
new file mode 100644 (file)
index 0000000..1a954d3
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Acess2 System Interface Header
+ */
+#ifndef _ACESS_SYS_H_
+#define _ACESS_SYS_H_
+
+#include <stdint.h>
+#include "../sys/types.h"
+
+// === CONSTANTS ===
+#ifndef NULL
+# define NULL  ((void*)0)
+#endif
+
+#define THREAD_EVENT_VFS       0x0001
+#define THREAD_EVENT_IPCMSG    0x0002
+#define THREAD_EVENT_SIGNAL    0x0004
+
+#define OPENFLAG_EXEC  0x01
+#define OPENFLAG_READ  0x02
+#define OPENFLAG_WRITE 0x04
+#define OPENFLAG_TRUNCATE      0x10
+#define OPENFLAG_APPEND        0x20
+#define        OPENFLAG_NOLINK 0x40
+#define        OPENFLAG_CREATE 0x80
+#ifndef SEEK_CUR
+# define SEEK_SET      1
+# define SEEK_CUR      0
+# define SEEK_END      -1
+#endif
+#define GETMSG_IGNORE  ((void*)-1)
+#define FILEFLAG_DIRECTORY     0x10
+#define FILEFLAG_SYMLINK       0x20
+
+// === TYPES ===
+
+// === VARIABLES ===
+extern int     _errno;
+
+// === FUNCTIONS ===
+extern void    _SysDebug(const char *format, ...);
+// --- Proc ---
+extern void    _exit(int status)       __attribute__((noreturn));
+extern void    sleep(void);
+extern void    yield(void);
+extern int     kill(int pid, int sig);
+//extern void  wait(int miliseconds);
+extern int     _SysWaitEvent(int EventMask);
+extern int     waittid(int id, int *status);
+extern int     clone(int flags, void *stack);
+extern int     execve(char *path, char **argv, char **envp);
+extern int     _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
+extern int     gettid(void);
+extern int     getpid(void);
+extern int     _SysSetFaultHandler(int (*Handler)(int));
+extern void    SysSetName(const char *Name);
+extern int     SysGetName(char *NameDest);
+extern int     SysSetPri(int Priority);
+extern int64_t _SysTimestamp(void);
+
+// --- Permissions ---
+extern int     getuid(void);
+extern int     getgid(void);
+extern void    setuid(int id);
+extern void    setgid(int id);
+
+// --- VFS ---
+extern int     chdir(const char *dir);
+extern int     open(const char *path, int flags, ...);
+extern int     reopen(int fd, const char *path, int flags);
+extern int     close(int fd);
+extern uint    read(int fd, void *buffer, uint length);
+extern uint    write(int fd, const void *buffer, uint length);
+extern int     seek(int fd, int64_t offset, int whence);
+extern uint64_t        tell(int fd);
+extern int     ioctl(int fd, int id, void *data);
+extern int     finfo(int fd, t_sysFInfo *info, int maxacls);
+extern int     SysReadDir(int fd, char *dest);
+extern int     _SysOpenChild(int fd, const char *name, int flags);
+extern int     _SysGetACL(int fd, t_sysACL *dest);
+extern int     _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
+extern int     _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, int64_t *timeout, unsigned int extraevents);
+#define select(nfs, rdfds, wrfds, erfds, timeout)      _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
+extern int     unlink(const char *pathname);
+
+// --- IPC ---
+extern int     SysSendMessage(pid_t dest, uint length, const void *Data);
+extern int     SysGetMessage(pid_t *src, void *Data);
+
+// --- MEMORY ---
+uint64_t       _SysGetPhys(uint vaddr);
+uint64_t       _SysAllocate(uint vaddr);
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/stddef_.h b/Usermode/Libraries/ld-acess.so_src/include_exp/stddef_.h
new file mode 100644 (file)
index 0000000..1995839
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+#include "acess/intdefs.h"
+
+#ifndef NULL
+# define NULL  ((void*)0)
+#endif
+
+typedef __intptr_t     size_t;
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/sys/basic_drivers.h b/Usermode/Libraries/ld-acess.so_src/include_exp/sys/basic_drivers.h
new file mode 100644 (file)
index 0000000..ee5334e
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * \file basic_drivers.h
+ */
+#ifndef _SYS_BASIC_DRIVERS_H
+#define _SYS_BASIC_DRIVERS_H
+
+// === COMMON ===
+enum eDrv_Common {
+       DRV_IOCTL_NULL,
+       DRV_IOCTL_TYPE,
+       DRV_IOCTL_IDENT,
+       DRV_IOCTL_VER
+};
+
+enum eDrv_Types {
+       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
+       DRV_TYPE_TERMINAL,      //!< Terminal
+       DRV_TYPE_VIDEO,         //!< Video - LFB
+       DRV_TYPE_SOUND,         //!< Audio
+       DRV_TYPE_MOUSE,         //!< Mouse
+       DRV_TYPE_JOYSTICK       //!< Joystick / Gamepad
+};
+
+// === VIDEO ===
+enum eDrv_Video {
+       VID_IOCTL_SETMODE = 4,
+       VID_IOCTL_GETMODE,
+       VID_IOCTL_FINDMODE,
+       VID_IOCTL_MODEINFO,
+       VID_IOCTL_REQLFB        // Request LFB
+};\r
+struct sVideo_IOCtl_Mode {\r
+       short   id;\r
+       Uint16  width;\r
+       Uint16  height;\r
+       Uint16  bpp;\r
+};\r
+typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type
+
+// === MOUSE ===
+enum eDrv_Mouse {\r
+       MSE_IOCTL_SENS = 4,\r
+       MSE_IOCTL_MAX_X,\r
+       MSE_IOCTL_MAX_Y\r
+};
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/sys/param.h b/Usermode/Libraries/ld-acess.so_src/include_exp/sys/param.h
new file mode 100644 (file)
index 0000000..b9b50e2
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Acess2 Dynamic Linker
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/param.h
+ * - System Parameters (?)
+ */
+#ifndef _SYS__PARAM_H_
+#define _SYS__PARAM_H_
+
+#endif
+
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/sys/stat.h b/Usermode/Libraries/ld-acess.so_src/include_exp/sys/stat.h
new file mode 100644 (file)
index 0000000..4a1c107
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ */
+#ifndef _SYS_STAT_H_
+#define _SYS_STAT_H_
+
+//#include "../acess/intdefs.h"        /* Evil */
+//#include "../stddef.h"
+#include <stdint.h>
+
+typedef void   *dev_t; /* TODO: How to identify a device with Acess */
+typedef uint64_t       ino_t;
+typedef unsigned int   blksize_t;
+typedef uint64_t       blkcnt_t;
+typedef unsigned int   nlink_t;
+typedef uint32_t       mode_t;
+
+typedef uint32_t       uid_t;
+typedef uint32_t       gid_t;
+
+#define        S_IFMT          0170000 /* type of file */
+#define                S_IFDIR 0040000 /* directory */
+#define                S_IFCHR 0020000 /* character special */
+#define                S_IFBLK 0060000 /* block special */
+#define                S_IFREG 0100000 /* regular */
+#define                S_IFLNK 0120000 /* symbolic link */
+#define                S_IFSOCK        0140000 /* socket */
+#define                S_IFIFO 0010000 /* fifo */
+
+
+struct stat
+{
+       dev_t     st_dev;     /* ID of device containing file */
+       ino_t     st_ino;     /* inode number */
+       mode_t    st_mode;    /* protection */
+       nlink_t   st_nlink;   /* number of hard links */
+       uid_t     st_uid;     /* user ID of owner */
+       gid_t     st_gid;     /* group ID of owner */
+       dev_t     st_rdev;    /* device ID (if special file) */
+       off_t     st_size;    /* total size, in bytes */
+       blksize_t st_blksize; /* blocksize for file system I/O */
+       blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
+       time_t    st_atime;   /* time of last access */
+       time_t    st_mtime;   /* time of last modification */
+       time_t    st_ctime;   /* time of last status change */
+};
+
+extern int stat(const char *path, struct stat *buf);
+extern int fstat(int fd, struct stat *buf);
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/sys/sys.h b/Usermode/Libraries/ld-acess.so_src/include_exp/sys/sys.h
new file mode 100644 (file)
index 0000000..7666d9a
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+ Syscall Definitions\r
+*/\r
+#ifndef _SYS_SYS_H_\r
+#define _SYS_SYS_H_\r
+\r
+#include <acess/sys.h>\r
+\r
+#include <sys/types.h>\r
+\r
+//#define O_RDONLY     OPENFLAG_READ\r
+//#define O_WRONLY     OPENFLAG_WRITE\r
+//#define O_CREAT      (OPENFLAG_CREATE|OPENFLAG_WRITE)\r
+//#define O_TRUNC      OPENFLAG_WRITE\r
+//#define O_APPEND     OPENFLAG_WRITE\r
+\r
+\r
+#if 0\r
+#define        OPEN_FLAG_READ  1\r
+#define        OPEN_FLAG_WRITE 2\r
+#define        OPEN_FLAG_EXEC  4\r
+\r
+enum {\r
+       K_WAITPID_DIE = 0\r
+};\r
+\r
+// === System Calls ===\r
+extern void    _exit(int ret);\r
+extern int     brk(int bssend);\r
+extern int     execve(char *file, char *args[], char *envp[]);\r
+extern int     fork();\r
+extern int     yield();\r
+extern int     sleep();\r
+\r
+extern int     open(char *file, int flags);\r
+extern int     close(int fp);\r
+extern int     read(int fp, int len, void *buf);\r
+extern int     write(int fp, int len, void *buf);\r
+extern int     tell(int fp);\r
+extern void    seek(int fp, int64_t dist, int flag);\r
+extern int     fstat(int fp, t_fstat *st);\r
+extern int     ioctl(int fp, int call, void *arg);\r
+extern int     readdir(int fp, char *file);\r
+\r
+extern int     select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);\r
+\r
+extern int     kdebug(char *fmt, ...);\r
+extern int     waitpid(int pid, int action);\r
+extern int     gettid();       // Get Thread ID\r
+extern int     getpid();       // Get Process ID\r
+extern int     sendmsg(int dest, unsigned int *Data);\r
+extern int     pollmsg(int *src, unsigned int *Data);\r
+extern int     getmsg(int *src, unsigned int *Data);\r
+#endif\r
+\r
+#endif\r
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/sys/types.h b/Usermode/Libraries/ld-acess.so_src/include_exp/sys/types.h
new file mode 100644 (file)
index 0000000..7c584d2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ */
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include "../acess/intdefs.h"
+
+typedef struct stat    t_fstat;
+
+#define FD_SETSIZE     128
+
+
+#define CLONE_VM       0x10
+
+typedef unsigned int   id_t;
+typedef unsigned long  pid_t;
+typedef unsigned long  tid_t;
+typedef signed long long int   time_t;
+typedef long long int  off_t;
+
+typedef unsigned int   uint;
+
+typedef unsigned short fd_set_ent_t;
+
+/**
+ * \brief fd_set for select()
+ */
+typedef struct
+{
+       fd_set_ent_t    flags[FD_SETSIZE/16];
+}      fd_set;
+
+struct s_sysACL {
+       unsigned long   object; /*!< Group or user (bit 31 determines) */
+       unsigned long   perms;  /*!< Inverted by bit 31 */
+};
+struct s_sysFInfo {
+       unsigned int    mount;
+       unsigned long long      inode;
+       unsigned int    uid;
+       unsigned int    gid;
+       unsigned int    flags;
+       unsigned long long      size;
+       time_t  atime;
+       time_t  mtime;
+       time_t  ctime;
+        int    numacls;
+       struct s_sysACL acls[];
+} __attribute__((packed));
+typedef struct s_sysFInfo      t_sysFInfo;
+typedef struct s_sysACL        t_sysACL;
+
+extern void    FD_ZERO(fd_set *fdsetp);
+extern void    FD_CLR(int fd, fd_set *fdsetp);
+extern void    FD_SET(int fd, fd_set *fdsetp);
+extern int     FD_ISSET(int fd, fd_set *fdsetp);
+
+#include "../sys/stat.h"
+
+#endif
diff --git a/Usermode/Libraries/ld-acess.so_src/include_exp/unistd.h b/Usermode/Libraries/ld-acess.so_src/include_exp/unistd.h
new file mode 100644 (file)
index 0000000..e1fee2e
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#define        O_RDWR  (OPENFLAG_READ|OPENFLAG_WRITE)
+#define O_WR   (OPENFLAG_WRITE)
+#define O_RD   (OPENFLAG_READ)
+#define O_CREAT        (OPENFLAG_CREATE)
+#define O_RDONLY       OPENFLAG_READ
+#define O_WRONLY       OPENFLAG_WRITE
+#define O_TRUNC        OPENFLAG_TRUNCATE
+#define O_APPEND       OPENFLAG_APPEND
+
+//typedef intptr_t     ssize_t;
+
+#include "acess/sys.h"
+
+
+#endif
+
index da37dea..0672102 100644 (file)
@@ -112,6 +112,7 @@ uint64_t __divmod64(uint64_t Num, uint64_t Den, uint64_t *Rem)
        return ret;
 }
 
+#if 0
 uint32_t __divmod32(uint32_t Num, uint32_t Den, uint32_t *Rem)
 {
        uint32_t        ret = 0, add = 1;
@@ -198,4 +199,5 @@ uint32_t __umodsi3(uint32_t Num, uint32_t Den)
        __divmod32(Num, Den, &ret);
        return ret;
 }
+#endif
 
index 49b2f86..985f9c8 100644 (file)
@@ -101,3 +101,8 @@ int CallUser(void *entry, void *sp)
        #endif\r
        for(;;);\r
 }\r
+\r
+void abort(void)\r
+{\r
+       _exit(-4);\r
+}\r
diff --git a/Usermode/Libraries/libaxwin2.so_src/Makefile b/Usermode/Libraries/libaxwin2.so_src/Makefile
deleted file mode 100644 (file)
index 240646b..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Acess 2 - AxWin GUI Library
-#
-
-include ../Makefile.cfg
-
-CPPFLAGS +=
-CFLAGS   += -Wall
-LDFLAGS  += -lc -soname libaxwin2.so
-
-OBJ = main.o messages.o
-BIN = libaxwin2.so
-
-include ../Makefile.tpl
diff --git a/Usermode/Libraries/libaxwin2.so_src/common.h b/Usermode/Libraries/libaxwin2.so_src/common.h
deleted file mode 100644 (file)
index 4e80c7f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- * 
- * common.h - Internal Variable and Constant definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-// === Includes ===
-#include <acess/sys.h>
-#include <axwin2/axwin.h>
-#include <stdlib.h>
-
-// === Constants ===
-enum eAxWin_Modes
-{
-       AXWIN_MODE_IPC
-};
-
-// === Variables ===
-extern int     giAxWin_Mode;
-extern int     giAxWin_PID;
-
-#endif
diff --git a/Usermode/Libraries/libaxwin2.so_src/main.c b/Usermode/Libraries/libaxwin2.so_src/main.c
deleted file mode 100644 (file)
index de08442..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- * 
- * main.c - Library Initialisation
- */
-#include "common.h"
-#include <string.h>
-
-// === GLOBALS ===
- int   giAxWin_Mode = 0;
- int   giAxWin_PID = 9;        // HACK!
-tAxWin_MessageCallback *gAxWin_DefaultCallback;
-
-// === CODE ===
-int SoMain()
-{
-       return 0;
-}
-
-tAxWin_Message *AxWin_int_SendAndWait(int RetID, tAxWin_Message *Message)
-{
-       tAxWin_Message  *msg;
-       tAxWin_RetMsg   *rmsg;
-
-       AxWin_SendMessage(Message);
-       
-       for(;;)
-       {
-               msg = AxWin_WaitForMessage();
-               
-               rmsg = (void*)msg->Data;
-               if(msg->ID == MSG_SRSP_RETURN && rmsg->ReqID == Message->ID )
-                       break;
-               
-               AxWin_HandleMessage(msg);
-               free(msg);
-       }
-       
-       return msg;
-}
-
-int AxWin_Register(const char *Name, tAxWin_MessageCallback *DefaultCallback)
-{
-       tAxWin_Message  req;
-       tAxWin_Message  *msg;
-        int    ret;
-        int    len = strlen(Name);
-       
-       req.ID = MSG_SREQ_REGISTER;
-       req.Size = 1 + (len+1)/4;
-       strcpy(req.Data, Name);
-       
-       msg = AxWin_int_SendAndWait(MSG_SRSP_RETURN, &req);
-       ret = ((tAxWin_RetMsg*)msg->Data)->Value;
-       free(msg);
-
-       gAxWin_DefaultCallback = DefaultCallback;
-       
-       return !!ret;
-}
-
-tAxWin_Element *AxWin_CreateWindow(const char *Title)
-{
-       tAxWin_Message  req;
-       tAxWin_Message  *msg;
-       tAxWin_Element  *ret;
-        int    len = strlen(Title);
-       
-       req.ID = MSG_SREQ_ADDWIN;
-       req.Size = 1 + (len+1)/4;
-       strcpy(req.Data, Title);
-       
-       msg = AxWin_int_SendAndWait(MSG_SRSP_RETURN, &req);
-       ret = (tAxWin_Element*) ((tAxWin_RetMsg*)msg->Data)->Value;
-       free(msg);
-       
-       return ret;
-}
-
-tAxWin_Element *AxWin_AddMenuItem(tAxWin_Element *Parent, const char *Label, int Message)
-{
-       return NULL;
-}
diff --git a/Usermode/Libraries/libaxwin2.so_src/messages.c b/Usermode/Libraries/libaxwin2.so_src/messages.c
deleted file mode 100644 (file)
index a314703..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- * 
- * messages.c - Message Handling
- */
-#include "common.h"
-
-// === PROTOTYPES ===
- int   AxWin_MessageLoop();
-tAxWin_Message *AxWin_WaitForMessage();
- int   AxWin_HandleMessage(tAxWin_Message *Message);
-
-// ===  ===
-
-// === CODE ===
-int AxWin_SendMessage(tAxWin_Message *Message)
-{
-       switch(giAxWin_Mode)
-       {
-       case AXWIN_MODE_IPC:
-               SysSendMessage(giAxWin_PID, Message->Size*4, Message);
-               break;
-       default:
-               break;
-       }
-       return 0;
-}
-
-/**
- * \brief Loop forever, checking and waiting for messages
- */
-int AxWin_MessageLoop()
-{
-       tAxWin_Message  *msg;
-        int    ret;
-       for(;;)
-       {
-               msg = AxWin_WaitForMessage();
-               ret = AxWin_HandleMessage(msg);
-               
-               if(ret < 0)     return 0;
-       }
-       return 0;
-}
-
-/**
- * \brief Wait for a message
- */
-tAxWin_Message *AxWin_WaitForMessage()
-{
-        int    length;
-       pid_t   src;
-       tAxWin_Message  *ret = NULL;
-       
-       switch( giAxWin_Mode )
-       {
-       case AXWIN_MODE_IPC:
-               while( (length = SysGetMessage(&src, NULL)) == 0 )      sleep();
-               ret = malloc(length);
-               SysGetMessage(NULL, ret);
-               break;
-       default:
-               break;
-       }
-       return ret;
-}
-
-/**
- * \brief Handles a recieved message
- */
-int AxWin_HandleMessage(tAxWin_Message *Message)
-{
-       switch(Message->ID)
-       {
-       default:        return 0;
-       }
-}
diff --git a/Usermode/Libraries/libaxwin2.so_src/windows.c b/Usermode/Libraries/libaxwin2.so_src/windows.c
deleted file mode 100644 (file)
index efb418b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- * 
- * window.c - Window Control
- */
-#include "common.h"
-
-// === TYPES & STRUCTURES ===
-struct sAxWin_Window
-{
-       struct sAxWin_Window    *Next;
-       uint32_t        WmHandle;
-       tAxWin_MessageCallback  *Callback;
-};
-
-// === PROTOTYPES ===
-tAxWin_Window  *AxWin_CreateWindow(
-       int16_t X, int16_t Y, int16_t W, int16_t H,
-       uint32_t Flags, tAxWin_MessageCallback *Callback
-       );
-
-// === GLOBALS ===
-//mutex_t      glProcessWindows;
-tAxWin_Window  *gProcessWindows;
-
-// === CODE ===
-tAxWin_Window  *AxWin_CreateWindow(
-       int16_t X, int16_t Y,
-       int16_t W, int16_t H,
-       uint32_t Flags, tAxWin_MessageCallback *Callback)
-{
-       tAxWin_Message  req;
-       tAxWin_Message  *msg;
-       tAxWin_Window   *win;
-       
-       req.ID = MSG_SREQ_NEWWINDOW;
-       req.Size = 1 + sizeof(struct sAxWin_SReq_NewWindow)/4;
-       req.SReq_NewWindow.X = X;
-       req.SReq_NewWindow.Y = Y;
-       req.SReq_NewWindow.W = W;
-       req.SReq_NewWindow.H = H;
-       req.SReq_NewWindow.Flags = Flags;
-       
-       AxWin_SendMessage(&msg);
-       
-       for(;;)
-       {
-               msg = AxWin_WaitForMessage();
-               
-               if(msg.ID == MSG_SRSP_WINDOW)
-                       break;
-               
-               AxWin_HandleMessage(msg);
-               free(msg);
-       }
-       
-       win = malloc(sizeof(tAxWin_Window));
-       win->WmHandle = msg->SRsp_Window.Handle;
-       win->Callback = Callback;
-       
-       //mutex_acquire(glProcessWindows);
-       win->Next = gProcessWindows;
-       gProcessWindows = win;
-       //mutex_release(glProcessWindows);
-       
-       return 0;
-}
diff --git a/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/axwin.h b/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/axwin.h
new file mode 100644 (file)
index 0000000..8d91173
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * axwin.h
+ * - Core API Header
+ */
+#ifndef _AXWIN3_AXWIN_H_
+#define _AXWIN3_AXWIN_H_
+
+#include <stddef.h>    // size_t
+
+// === CONSTANTS ===
+
+// === TYPES ===
+typedef struct sAxWin3_Window  *tHWND;
+typedef unsigned int   tAxWin3_Colour; // TODO: Actual 32-bit
+
+typedef void   (*tAxWin3_MessageCallback)(int SourceTID, int Length);
+typedef void   (*tAxWin3_HotkeyCallback)(void);
+
+typedef int    (*tAxWin3_WindowMessageHandler)(tHWND Window, int Message, int Length, void *Data);
+
+// --- Connection management
+extern void    AxWin3_Connect(const char *ServerDesc);
+extern tAxWin3_MessageCallback AxWin3_SetMessageCallback(tAxWin3_MessageCallback Callback);
+extern void    AxWin3_MainLoop(void);
+
+// --- Non-Window based functions
+extern int     AxWin3_GetDisplayCount(void);
+extern int     AxWin3_GetDisplayDims(int Display, int *X, int *Y, int *Width, int *Height);
+
+// --- Window creation/deletion
+/**
+ * \brief Create a new window (with the required client structures)
+ * \param Parent       Parent window handle
+ * \param Renderer     Symbolic name of the renderer to use
+ * \param RendererArg  Argument to pass to the renderer's initialisation
+ * \param DataBytes    Number of bytes to allocate for the caller's use
+ * \param MessageHandler       Function to call when a message arrives for the window
+ * \return New window handle
+ * \note Usually wrapped by renderer-specific functions
+ */
+extern tHWND   AxWin3_CreateWindow(
+       tHWND Parent,
+       const char *Renderer, int RendererArg,
+       int DataBytes,
+       tAxWin3_WindowMessageHandler MessageHandler
+       );
+/**
+ * \brief Destroy a window
+ * \param Window       Handle to a window to destroy
+ */
+extern void    AxWin3_DestroyWindow(tHWND Window);
+extern int     AxWin3_RegisterAction(tHWND Window, const char *Action, tAxWin3_HotkeyCallback cb);
+
+// --- Core window management functions
+extern void    AxWin3_SendMessage(tHWND Window, tHWND Dest, int Message, int Length, void *Data);
+extern void    *AxWin3_WaitMessage(tHWND Window, int MessageID, size_t *Length);
+extern void    AxWin3_SetWindowTitle(tHWND Window, const char *Title);
+extern void    AxWin3_FocusWindow(tHWND Window);
+extern void    AxWin3_ShowWindow(tHWND Window, int bShow);
+extern void    AxWin3_DecorateWindow(tHWND Window, int bDecorate);
+extern void    AxWin3_SetWindowPos(tHWND Window, short X, short Y, short W, short H);
+extern void    AxWin3_MoveWindow(tHWND Window, short X, short Y);
+extern void    AxWin3_ResizeWindow(tHWND Window, short W, short H);
+
+#endif
+
diff --git a/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/keysyms.h b/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/keysyms.h
new file mode 120000 (symlink)
index 0000000..93c2064
--- /dev/null
@@ -0,0 +1 @@
+../../../../../KernelLand/Kernel/include/keysyms.h
\ No newline at end of file
diff --git a/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/menu.h b/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/menu.h
new file mode 100644 (file)
index 0000000..323bf30
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * menu.h
+ * - Menu window type
+ */
+#ifndef _AXWIN3_MENU_H_
+#define _AXWIN3_MENU_H_
+
+typedef void   (*tAxWin3_Menu_Callback)(void *Ptr);
+typedef struct sAxWin3_MenuItem        tAxWin3_MenuItem;
+
+extern tHWND   AxWin3_Menu_Create(tHWND Parent);
+extern void    AxWin3_Menu_ShowAt(tHWND Menu, int X, int Y);
+
+extern tAxWin3_MenuItem        *AxWin3_Menu_AddItem(
+               tHWND Menu, const char *Label,
+               tAxWin3_Menu_Callback Cb, void *Ptr,
+               int Flags, tHWND SubMenu
+               );
+extern tAxWin3_MenuItem        *AxWin3_Menu_GetItem(tHWND Menu, int Index);
+extern void    AxWin3_Menu_SetFlags(tAxWin3_MenuItem *Item, int Flags, int Mask);
+
+#endif
+
diff --git a/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/widget.h b/Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/widget.h
new file mode 100644 (file)
index 0000000..9eca0b0
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * widget.h
+ * - Server-side widget library
+ */
+#ifndef _AXWIN3_WIDGET_H_
+#define _AXWIN3_WIDGET_H_
+
+#include "axwin.h"
+
+typedef struct sAxWin3_Widget  tAxWin3_Widget;
+
+// --- Callback types
+typedef int    (*tAxWin3_Widget_FireCb)(tAxWin3_Widget *Widget);
+typedef int    (*tAxWin3_Widget_KeyUpDownCb)(tAxWin3_Widget *Widget, int KeySym);
+typedef int    (*tAxWin3_Widget_KeyFireCb)(tAxWin3_Widget *Widget, int KeySym, int Character);
+typedef int    (*tAxWin3_Widget_MouseMoveCb)(tAxWin3_Widget *Widget, int X, int Y);
+typedef int    (*tAxWin3_Widget_MouseBtnCb)(tAxWin3_Widget *Widget, int X, int Y, int Button, int bPressed);
+
+// --- Windows
+extern tHWND   AxWin3_Widget_CreateWindow(tHWND Parent, int W, int H, int RootEleFlags);
+extern void    AxWin3_Widget_DestroyWindow(tHWND Window);
+extern tAxWin3_Widget  *AxWin3_Widget_GetRoot(tHWND Window);
+
+// --- Element Creation
+extern tAxWin3_Widget  *AxWin3_Widget_AddWidget(tAxWin3_Widget *Parent, int Type, int Flags, const char *DebugName);
+extern void    AxWin3_Widget_DelWidget(tAxWin3_Widget *Widget);
+
+// --- Callbacks
+extern void    AxWin3_Widget_SetFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_FireCb Callback);
+extern void    AxWin3_Widget_SetKeyHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyUpDownCb Callback);
+extern void    AxWin3_Widget_SetKeyFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyFireCb Callback);
+extern void    AxWin3_Widget_SetMouseMoveHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseMoveCb Callback);
+extern void    AxWin3_Widget_SetMouseButtonHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseBtnCb Callback);
+// --- Manipulation
+extern void    AxWin3_Widget_SetFlags(tAxWin3_Widget *Widget, int FlagSet, int FlagMask);
+extern void    AxWin3_Widget_SetSize(tAxWin3_Widget *Widget, int Size);
+extern void    AxWin3_Widget_SetText(tAxWin3_Widget *Widget, const char *Text);
+extern void    AxWin3_Widget_SetColour(tAxWin3_Widget *Widget, int Index, tAxWin3_Colour Colour);
+// --- Inspection
+extern char    *AxWin3_Widget_GetText(tAxWin3_Widget *Widget);
+
+enum eElementTypes
+{
+       ELETYPE_NONE,
+
+       ELETYPE_SUBWIN,
+
+       ELETYPE_BOX,    //!< Content box (invisible in itself)
+       ELETYPE_TEXT,   //!< Text
+       ELETYPE_IMAGE,  //!< Image
+       ELETYPE_BUTTON, //!< Push Button
+       ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
+       ELETYPE_TEXTINPUT,      //!< Text Input Field
+       ELETYPE_TEXTBOX,        //!< Text Box Input
+
+       ELETYPE_TABBAR, //!< Tab Bar
+       ELETYPE_TOOLBAR,        //!< Tool Bar
+       
+       NUM_ELETYPES
+};
+
+enum eElementFlags
+{
+       /**
+        * \brief Rendered
+        * 
+        * If set, the element will be ignored in calculating sizes and
+        * rendering.
+        */
+       ELEFLAG_NORENDER    = 0x001,
+       /**
+        * \brief Element visibility
+        * 
+        * If set, the element is not drawn (but still is used for size calculations)
+        */
+       ELEFLAG_INVISIBLE   = 0x002,
+       
+       /**
+        * \brief Position an element absulutely (ignored in size calcs)
+        */
+       ELEFLAG_ABSOLUTEPOS = 0x004,
+       
+       /**
+        * \brief Fixed size element
+        */
+       ELEFLAG_FIXEDSIZE   = 0x008,
+       
+       /**
+        * \brief Element "orientation"
+        * 
+        * Vertical means that the children of this element are stacked,
+        * otherwise they list horizontally
+        */
+       ELEFLAG_VERTICAL    = 0x010,//  ELEFLAG_HORIZONTAL  = 0x000,
+       /**
+        * \brief Action for text that overflows
+        */
+       ELEFLAG_WRAP        = 0x020,//  ELEFLAG_NOWRAP      = 0x000,
+       /**
+        * \brief Cross size action
+        * 
+        * If this flag is set, the element will only be as large (across
+        * its parent) as is needed to encase the contents of the element.
+        * Otherwise, the element will expand to fill all avaliable space.
+        */
+       ELEFLAG_NOEXPAND    = 0x040,
+       
+       /**
+        * \brief With (length) size action
+        * If this flag is set, the element will only be as large as
+        * is required along it's parent
+        */
+       ELEFLAG_NOSTRETCH   = 0x080,
+       
+       /**
+        * \brief Center alignment
+        */
+       ELEFLAG_ALIGN_CENTER= 0x100,
+       /**
+        * \brief Right/Bottom alignment
+        * 
+        * If set, the element aligns to the end of avaliable space (instead
+        * of the beginning)
+        */
+       ELEFLAG_ALIGN_END       = 0x200
+};
+
+
+#endif
+
index 7142820..6484897 100644 (file)
@@ -8,7 +8,10 @@ CFLAGS   +=
 ASFLAGS  +=\r
 LDFLAGS  += -soname libc.so -Map map.txt -lgcc\r
 \r
+INCFILES := stdio.h stdlib.h\r
+\r
 OBJ  = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o rand.o\r
+OBJ += perror.o\r
 OBJ += arch/$(ARCHDIR).ao\r
 # signals.o\r
 DEPFILES := $(OBJ:%.o=%.d)\r
@@ -16,9 +19,3 @@ BIN = libc.so
 \r
 include ../Makefile.tpl\r
 \r
-#all: $(OUTPUTDIR)Libs/crt0.o\r
-\r
-# C Runtime 0\r
-#$(OUTPUTDIR)Libs/crt0.o: crt0.asm\r
-#      @echo --- $(AS) -o $@\r
-#      @$(AS) $(ASFLAGS) -o $@ $<\r
diff --git a/Usermode/Libraries/libc.so_src/arch/armv6.S b/Usermode/Libraries/libc.so_src/arch/armv6.S
new file mode 100644 (file)
index 0000000..be4887e
--- /dev/null
@@ -0,0 +1,24 @@
+@ 
+@ Acess2 C Library
+@ - By John Hodge (thePowersGang)
+@ 
+@ arch/armv6.S
+@ - ARMv6 specific code
+.globl setjmp
+setjmp:
+       @ RO: Buffer
+       stm r0, {r0-r14}
+       eor r0, r0
+       mov pc, lr
+
+.globl longjmp
+longjmp:
+       @ R0: Buffer
+       @ R1: Value
+       add r0, #8
+       ldm r0, {r2-r14}
+       mov r0, r1
+       tst r0, r0
+       addeq r0, #1
+       mov pc, lr      @ Will return to after setjmp
+
index 441e72e..c0013c9 100644 (file)
@@ -131,6 +131,25 @@ EXPORT void fflush(FILE *fp)
        ///\todo Implement\r
 }\r
 \r
+EXPORT void clearerr(FILE *stream)\r
+{\r
+       /// \todo Impliment\r
+}\r
+\r
+EXPORT int feof(FILE *stream)\r
+{\r
+       return 0;       //stream->;     // ?\r
+}\r
+\r
+EXPORT int ferror(FILE *stream)\r
+{\r
+       return 0;\r
+}\r
+EXPORT int fileno(FILE *stream)\r
+{\r
+       return stream->FD;\r
+}\r
+\r
 EXPORT off_t ftell(FILE *fp)\r
 {\r
        if(!fp || !fp->FD)      return -1;\r
@@ -154,27 +173,14 @@ EXPORT int vfprintf(FILE *fp, const char *format, va_list args)
 {\r
        va_list tmpList;\r
         int    size;\r
-       char    sbuf[1024];\r
-       char    *buf = sbuf;\r
 \r
        if(!fp || !format)      return -1;\r
 \r
        va_copy(tmpList, args);\r
        \r
-       size = vsnprintf(sbuf, sizeof(sbuf), (char*)format, tmpList);\r
-       \r
-       if( size >= sizeof(sbuf) )\r
-       {\r
-               buf = (char*)malloc(size+1);\r
-               if(!buf) {\r
-                       WRITE_STR(_stdout, "vfprintf ERROR: malloc() failed");\r
-                       return 0;\r
-               }\r
-               buf[size] = '\0';\r
-       \r
-               // Print\r
-               vsnprintf(buf, size+1, (char*)format, args);\r
-       }\r
+       size = vsnprintf(NULL, 0, (char*)format, tmpList);\r
+       char    buf[size+1];\r
+       vsnprintf(buf, size+1, (char*)format, args);\r
        \r
        // Write to stream\r
        write(fp->FD, buf, size);\r
@@ -543,29 +549,17 @@ EXPORT int printf(const char *format, ...)
 {\r
        #if 1\r
         int    size;\r
-       char    sbuf[1024];\r
-       char    *buf = sbuf;\r
        va_list args;\r
        \r
        // Get final size\r
        va_start(args, format);\r
-       size = vsnprintf(sbuf, 1024, (char*)format, args);\r
+       size = vsnprintf(NULL, 0, (char*)format, args);\r
+       va_end(args);\r
+       char buf[size+1];\r
+       // Fill Buffer\r
+       va_start(args, format);\r
+       vsnprintf(buf, size+1, (char*)format, args);\r
        va_end(args);\r
-       \r
-       if( size >= 1024 ) {\r
-               // Allocate buffer\r
-               buf = (char*)malloc(size+1);\r
-               if(buf) {\r
-                       WRITE_STR(_stdout, "PRINTF ERROR: malloc() failed\n");\r
-                       return 0;\r
-               }\r
-               buf[size] = '\0';\r
-       \r
-               // Fill Buffer\r
-               va_start(args, format);\r
-               vsnprintf(buf, size+1, (char*)format, args);\r
-               va_end(args);\r
-       }\r
        \r
        // Send to stdout\r
        write(_stdout, buf, size+1);\r
index 4fcc8be..d529f65 100644 (file)
@@ -7,6 +7,12 @@ heap.c - Heap Manager
 #include <string.h>\r
 #include "lib.h"\r
 \r
+#if 0\r
+# define DEBUGS(s...)  _SysDebug(s)\r
+#else\r
+# define DEBUGS(s...)  do{}while(0)\r
+#endif\r
+\r
 // === Constants ===\r
 #define MAGIC  0xACE55051      //AcessOS1\r
 #define MAGIC_FREE     (~MAGIC)\r
@@ -19,6 +25,7 @@ typedef unsigned int Uint;
 typedef struct {\r
        uint32_t        magic;\r
        size_t  size;\r
+       char    data[];\r
 }      heap_head;\r
 typedef struct {\r
        heap_head       *header;\r
@@ -38,6 +45,7 @@ EXPORT void   *sbrk(int increment);
 LOCAL void     *extendHeap(int bytes);\r
 static void    *FindHeapBase();\r
 LOCAL uint     brk(uintptr_t newpos);\r
+LOCAL void     Heap_Dump(void);\r
 \r
 //Code\r
 \r
@@ -53,7 +61,7 @@ EXPORT void *malloc(size_t bytes)
        size_t  closestMatch = 0;\r
        void    *bestMatchAddr = 0;\r
        heap_head       *curBlock;\r
-       \r
+\r
 //     _SysDebug("&_heap_start = %p, _heap_start = %p", &_heap_start, _heap_start);\r
        // Initialise Heap\r
        if(_heap_start == NULL)\r
@@ -84,6 +92,7 @@ EXPORT void *malloc(size_t bytes)
                else if(curBlock->magic != MAGIC)\r
                {\r
                        //Corrupt Heap\r
+                       Heap_Dump();\r
                        _SysDebug("malloc: Corrupt Heap\n");\r
                        return NULL;\r
                }\r
@@ -109,9 +118,12 @@ EXPORT void *malloc(size_t bytes)
                        return NULL;\r
                }\r
                curBlock->magic = MAGIC;\r
-               return (void*)((uintptr_t)curBlock + sizeof(heap_head));\r
+               DEBUGS("malloc(0x%x) = %p (extend) 0x%x", bytes, curBlock->data, bestSize);\r
+               return curBlock->data;\r
        }\r
        \r
+       heap_head *besthead = (void*)bestMatchAddr;\r
+       \r
        //Split Block?\r
        if(closestMatch - bestSize > BLOCK_SIZE) {\r
                heap_foot       *foot;\r
@@ -129,13 +141,15 @@ EXPORT void *malloc(size_t bytes)
                foot = (heap_foot*)(bestMatchAddr + closestMatch - sizeof(heap_foot));\r
                foot->header = curBlock;\r
                \r
-               ((heap_head*)bestMatchAddr)->magic = MAGIC;     //mark as used\r
-               return (void*)(bestMatchAddr + sizeof(heap_head));\r
+               besthead->magic = MAGIC;        //mark as used\r
+               DEBUGS("malloc(0x%x) = %p (split) 0x%x", bytes, besthead->data, bestSize);\r
+               return besthead->data;\r
        }\r
        \r
        //Don't Split the block\r
-       ((heap_head*)bestMatchAddr)->magic = MAGIC;\r
-       return (void*)(bestMatchAddr+sizeof(heap_head));\r
+       besthead->magic = MAGIC;\r
+       DEBUGS("malloc(0x%x) = %p (reuse) 0x%x", bytes, besthead->data, besthead->size);\r
+       return besthead->data;\r
 }\r
 \r
 /**\r
@@ -168,6 +182,7 @@ EXPORT void free(void *mem)
                return;\r
        \r
        head->magic = MAGIC_FREE;\r
+       DEBUGS("free(%p) : 0x%x bytes", mem, head->size);\r
        \r
        //Unify Right\r
        if((intptr_t)head + head->size < (intptr_t)_heap_end)\r
@@ -429,3 +444,25 @@ LOCAL uint brk(uintptr_t newpos)
        \r
        return ret;     // Return old curpos\r
 }\r
+\r
+void Heap_Dump(void)\r
+{\r
+       heap_head *cur = _heap_start;\r
+       while( cur < (heap_head*)_heap_end )\r
+       {\r
+               switch( cur->magic )\r
+               {\r
+               case MAGIC:\r
+                       _SysDebug("Used block %p[0x%x] - ptr=%p", cur, cur->size, cur->data);\r
+                       break;\r
+               case MAGIC_FREE:\r
+                       _SysDebug("Free block %p[0x%x] - ptr=%p", cur, cur->size, cur->data);\r
+                       break;\r
+               default:\r
+                       _SysDebug("Block %p bad magic (0x%x)", cur, cur->magic);\r
+                       return ;\r
+               }\r
+               cur = (void*)( (char*)cur + cur->size );\r
+       }\r
+}\r
+\r
diff --git a/Usermode/Libraries/libc.so_src/include_exp/assert.h b/Usermode/Libraries/libc.so_src/include_exp/assert.h
new file mode 100644 (file)
index 0000000..07b20b3
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * assert.h
+ * - assert(expr)
+ */
+#ifndef _LIBC__ASSERT_H_
+#define _LIBC__ASSERT_H_
+
+#ifdef NDEBUG
+# define assert(expr)  do{}while(0)
+#else
+# define assert(expr)  do{if(!(expr)) { fprintf(stderr, "%s:%i: Assertion '%s' failed\n", __FILE__, __LINE__, #expr); exit(-1);}}while(0)
+#endif
+
+#endif
+
diff --git a/Usermode/Libraries/libc.so_src/include_exp/ctype.h b/Usermode/Libraries/libc.so_src/include_exp/ctype.h
new file mode 100644 (file)
index 0000000..4c5613b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * ctype.h
+ * - Type manipulation?
+ */
+#ifndef _CTYPE_H_
+#define _CTYPE_H_
+
+static inline int isalpha(int ch) {
+       if('A'<=ch&&ch<='Z')    return 1;
+       if('a'<=ch&&ch<='z')    return 1;
+       return 0;
+}
+static inline int isdigit(int ch) {
+       if('0'<=ch&&ch<='9')    return 1;
+       return 0;
+}
+
+static inline int isalnum(int ch) {
+       return isalpha(ch) || isdigit(ch);
+}
+
+static inline int toupper(int ch) {
+       if('a'<=ch && ch <='z')
+               return ch - 'a' + 'A';
+       return ch;
+}
+
+static inline int isspace(int ch) {
+       if(ch == ' ')   return 1;
+       if(ch == '\t')  return 1;
+       if(ch == '\r')  return 1;
+       if(ch == '\n')  return 1;
+       return 0;
+}
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/include_exp/errno.h b/Usermode/Libraries/libc.so_src/include_exp/errno.h
new file mode 100644 (file)
index 0000000..ea352f3
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _ERRNO_H_
+#define _ERRNO_H_
+
+// TODO: Fully implement errno.h, make sure it matches the kernel one
+
+extern int     _errno;
+#define        errno   _errno
+
+#define strerror(_x)   "Unimplemented"
+
+enum
+{
+       EOK,
+       EINVAL,
+       ERANGE,
+       ENODEV,
+       EBADF,
+       EINTR,
+       EAGAIN,
+       ENOMEM,
+
+       EADDRNOTAVAIL,
+       EINPROGRESS,
+
+       E_LAST
+};
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/include_exp/setjmp.h b/Usermode/Libraries/libc.so_src/include_exp/setjmp.h
new file mode 100644 (file)
index 0000000..53f3fbf
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Acess2 LibC
+ * - By John Hodge (thePowersGang)
+ * 
+ * setjmp.h
+ * - setjmp/longjmp support
+ */
+#ifndef _LIBC_SETJMP_H_
+#define _LIBC_SETJMP_H_
+
+#if ARCHDIR_is_x86
+typedef uint32_t       jmp_buf[8];
+#elif ARCHDIR_is_x86_64
+typedef uint64_t       jmp_buf[16];
+#else
+# error "Unknown Architecture"
+#endif
+
+extern int     setjmp(jmp_buf buf);
+extern void    longjmp(jmp_buf buf, int val);
+
+#endif
+
diff --git a/Usermode/Libraries/libc.so_src/include_exp/signal.h b/Usermode/Libraries/libc.so_src/include_exp/signal.h
new file mode 100644 (file)
index 0000000..cc72b00
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * signal.h
+ * - POSIX Signal Emulation/Interface
+ */
+#ifndef _SIGNAL_H_
+#define _SIGNAL_H_
+
+#define SIG_DFL        ((void*)0)
+#define SIG_ERR        ((void*)-1)
+
+#define        SIGABRT 6
+
+#define SIGPIPE        1001
+#define SIGCHLD        1002
+
+#endif
+
diff --git a/Usermode/Libraries/libc.so_src/include_exp/stdio.h b/Usermode/Libraries/libc.so_src/include_exp/stdio.h
new file mode 100644 (file)
index 0000000..faf20f0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * AcessOS LibC
+ * stdlib.h
+ */
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* === Types === */
+typedef struct sFILE   FILE;
+
+/* === CONSTANTS === */
+#define EOF    (-1)
+#define BUFSIZ 1024
+
+/* --- Standard IO --- */
+extern int     printf(const char *format, ...);
+extern int     vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args);
+extern int     vsprintf(char *buf, const char *format, va_list args);
+extern int     sprintf(char *buf, const char *format, ...);
+extern int     snprintf(char *buf, size_t maxlen, const char *format, ...);
+extern void    perror(const char *s);
+
+extern FILE    *fopen(const char *file, const char *mode);
+extern FILE    *freopen(const char *file, const char *mode, FILE *fp);
+extern FILE    *fdopen(int fd, const char *modes);
+extern int     fclose(FILE *fp);
+extern void    fflush(FILE *fp);
+extern off_t   ftell(FILE *fp);
+extern int     fseek(FILE *fp, long int amt, int whence);
+extern void    clearerr(FILE *stream);
+extern int     feof(FILE *stream);
+extern int     ferror(FILE *stream);
+extern int     fileno(FILE *stream);
+
+extern size_t  fread(void *buf, size_t size, size_t n, FILE *fp);
+extern size_t  fwrite(void *buf, size_t size, size_t n, FILE *fp);
+extern int     fgetc(FILE *fp);
+extern int     fputc(int ch, FILE *fp);
+extern int     getchar(void);
+extern int     putchar(int ch);
+
+extern int     fprintf(FILE *fp, const char *format, ...);
+extern int     vfprintf(FILE *fp, const char *format, va_list args);
+
+extern FILE    *stdin;
+extern FILE    *stdout;
+extern FILE    *stderr;
+
+#endif
+
diff --git a/Usermode/Libraries/libc.so_src/include_exp/stdlib.h b/Usermode/Libraries/libc.so_src/include_exp/stdlib.h
new file mode 100644 (file)
index 0000000..8acfb8b
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+ * AcessOS LibC\r
+ * stdlib.h\r
+ */\r
+#ifndef __STDLIB_H\r
+#define __STDLIB_H\r
+\r
+#include <stddef.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+\r
+#define EXIT_FAILURE   1\r
+#define EXIT_SUCCESS   0\r
+\r
+/* --- Spinlock Macros --- */\r
+/* TODO: Support non-x86 architectures */\r
+#define DEFLOCK(_name) static int _spinlock_##_name=0;\r
+#define LOCK(_name)    do{int v=1;while(v){__asm__ __volatile__("lock cmpxchgl %0, (%1)":"=a"(v):"D"((&_spinlock_##_name)),"a"(1));yield();}}while(0)\r
+#define UNLOCK(_name) __asm__ __volatile__("lock andl $0, (%0)"::"D"(&_spinlock_##_name))\r
+\r
+/* --- StdLib --- */\r
+extern void    _exit(int code) __attribute__((noreturn));      /* NOTE: Also defined in acess/sys.h */\r
+extern long long       strtoll(const char *ptr, char **end, int base);\r
+extern long    strtol(const char *ptr, char **end, int base);\r
+extern int     atoi(const char *ptr);\r
+extern void    exit(int status) __attribute__((noreturn));\r
+extern void    atexit(void (*__func)(void));\r
+extern void    qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));\r
+extern int     abs(int j);\r
+extern long int        labs(long int j);\r
+extern long long int   llabs(long long int j);\r
+\r
+/* --- Environment --- */\r
+extern char    *getenv(const char *name);\r
+\r
+/* --- Heap --- */\r
+extern void    free(void *mem);\r
+extern void    *malloc(size_t bytes);\r
+extern void    *calloc(size_t __nmemb, size_t __size);\r
+extern void    *realloc(void *__ptr, size_t __size);\r
+extern int     IsHeap(void *ptr);\r
+\r
+/* --- Random --- */\r
+extern void    srand(unsigned int seed);\r
+extern int     rand(void);\r
+extern int     rand_p(unsigned int *seedp);\r
+\r
+#ifndef SEEK_CUR\r
+# define SEEK_CUR      0\r
+# define SEEK_SET      1\r
+# define SEEK_END      (-1)\r
+#endif\r
+\r
+#endif\r
diff --git a/Usermode/Libraries/libc.so_src/include_exp/string.h b/Usermode/Libraries/libc.so_src/include_exp/string.h
new file mode 100644 (file)
index 0000000..7c38602
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * AcessOS LibC
+ * string.h
+ */
+#ifndef __STRING_H
+#define __STRING_H
+
+#include <stddef.h>
+
+/* Strings */
+extern size_t  strlen(const char *string);
+extern size_t  strnlen(const char *string, size_t maxlen);
+extern int     strcmp(const char *str1, const char *str2);
+extern int     strncmp(const char *str1, const char *str2, size_t maxlen);
+extern int     strcasecmp(const char *s1, const char *s2);
+extern int     strncasecmp(const char *s1, const char *s2, size_t maxlen);
+extern char    *strcpy(char *dst, const char *src);
+extern char    *strncpy(char *dst, const char *src, size_t num);
+extern char    *strcat(char *dst, const char *src);
+extern char    *strdup(const char *src);
+extern char    *strndup(const char *src, size_t length);
+extern char    *strchr(const char *str, int character);
+extern char    *strrchr(const char *str, int character);
+extern char    *strstr(const char *str1, const char *str2);
+extern size_t  strcspn(const char *haystack, const char *reject);
+extern size_t  strspn(const char *haystack, const char *accept);
+
+/* Memory */
+extern void *memset(void *dest, int val, size_t count);
+extern void *memcpy(void *dest, const void *src, size_t count);
+extern void *memmove(void *dest, const void *src, size_t count);
+extern int     memcmp(const void *mem1, const void *mem2, size_t count);
+extern void    *memchr(const void *ptr, int value, size_t num);
+
+#endif
diff --git a/Usermode/Libraries/libc.so_src/include_exp/time.h b/Usermode/Libraries/libc.so_src/include_exp/time.h
new file mode 100644 (file)
index 0000000..bd7afce
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * time.h
+ * - POSIX time functions
+ */
+#ifndef _TIME_H_
+#define _TIME_H_
+
+#include <acess/intdefs.h>
+#include <sys/types.h> // time_t
+
+struct tm
+{
+        int    tm_sec;
+        int    tm_min;
+        int    tm_hour;
+        int    tm_mday;
+        int    tm_mon;
+        int    tm_year;        // 1900 based
+        int    tm_wday;
+        int    tm_yday;
+        int    tm_isdst;
+};
+
+#define CLOCKS_PER_SEC 1000
+
+typedef signed long long       clock_t;
+
+extern clock_t clock();
+
+#endif
+
diff --git a/Usermode/Libraries/libc.so_src/perror.c b/Usermode/Libraries/libc.so_src/perror.c
new file mode 100644 (file)
index 0000000..0431635
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * perror.c
+ * - perror() and friends
+ */
+#include <errno.h>
+#include <stdio.h>
+
+void perror(const char *s)
+{
+       fprintf(stderr, "%s: Error (%i)\n", s, errno);
+}
index f689f34..23f3925 100644 (file)
@@ -4,6 +4,7 @@ include $(BASE)header.mk
 
 # Variables
 SRCS := stub.c heap.c stdlib.c env.c fileIO.c string.c select.c
+SRCS += perror.c
 SRCS += arch/$(ARCHDIR).$(ASSUFFIX)
 # signals.c
 BIN  := $(OUTPUTDIR)Libs/libc.so
index 191f526..c91106c 100644 (file)
@@ -2,12 +2,12 @@
  * AcessOS Basic C Library\r
  * stdlib.c\r
  */\r
-/**\r
- * \todo Move half of these to stdio\r
- */\r
 #include <acess/sys.h>\r
 #include <stdlib.h>\r
 #include <stdio.h>\r
+#include <errno.h>\r
+#include <ctype.h>\r
+#include <limits.h>\r
 #include "lib.h"\r
 \r
 #define _stdout        1\r
@@ -71,66 +71,96 @@ EXPORT void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void
        }\r
 }\r
 \r
-/**\r
- * \fn EXPORT int atoi(const char *str)\r
- * \brief Convert a string to an integer\r
- */\r
-EXPORT int atoi(const char *str)\r
+EXPORT long long strtoll(const char *str, char **end, int base)\r
 {\r
         int    neg = 0;\r
-        int    ret = 0;\r
-       \r
-       // NULL Check\r
-       if(!str)        return 0;\r
+       long long       ret = 0;\r
        \r
-       while(*str == ' ' || *str == '\t')      str++;\r
+       if( !str || base < 0 || base > 36 || base == 1 ) {\r
+               if(end)\r
+                       *end = (char*)str;\r
+               errno = EINVAL;\r
+               return 0;\r
+       }\r
+\r
+       while( isspace(*str) )\r
+               str++;\r
        \r
-       // Check for negative\r
-       if(*str == '-') {\r
-               neg = 1;\r
+       // Check for negative (or positive) sign\r
+       if(*str == '-' || *str == '+') {\r
+               neg = (*str == '-');\r
                str++;\r
        }\r
        \r
-       if(*str == '0') {\r
+       if( base == 0 || base == 16 ) {\r
+               if( *str == '0' && str[1] == 'x' ) {\r
+                       str += 2;\r
+                       base = 16;\r
+               }\r
+       }\r
+       \r
+       if( base == 0 && *str == '0' ) {\r
                str ++;\r
-               if(*str == 'x') {\r
-                       str++;\r
-                       // Hex\r
-                       while( ('0' <= *str && *str <= '9')\r
-                               || ('A' <= *str && *str <= 'F' )\r
-                               || ('a' <= *str && *str <= 'f' )\r
-                               )\r
-                       {\r
-                               ret *= 16;\r
-                               if(*str <= '9') {\r
-                                       ret += *str - '0';\r
-                               } else if (*str <= 'F') {\r
-                                       ret += *str - 'A' + 10;\r
-                               } else {\r
-                                       ret += *str - 'a' + 10;\r
-                               }\r
-                               str++;\r
-                       }\r
-               } else {\r
-                       // Octal\r
-                       while( '0' <= *str && *str <= '7' )\r
-                       {\r
-                               ret *= 8;\r
-                               ret += *str - '0';\r
-                               str++;\r
-                       }\r
+               base = 8;\r
+       }\r
+\r
+       if( base == 0 )\r
+               base = 10;\r
+\r
+       while( *str )\r
+       {\r
+                int    next = -1;\r
+               if( base <= 10 ) {\r
+                       if( '0' <= *str && *str <= '0'+base-1 )\r
+                               next = *str - '0';\r
                }\r
-       } else {\r
-               // Decimal\r
-               while( '0' <= *str && *str <= '9' )\r
-               {\r
-                       ret *= 10;\r
-                       ret += *str - '0';\r
-                       str++;\r
+               else {\r
+                       if( '0' <= *str && *str <= '9' )\r
+                               next = *str - '0';\r
+                       if( 'A' <= *str && *str <= 'A'+base-10-1 )\r
+                               next = *str - 'A';\r
+                       if( 'a' <= *str && *str <= 'a'+base-10-1 )\r
+                               next = *str - 'a';\r
                }\r
+               if( next < 0 )\r
+                       break;\r
+               ret *= base;\r
+               ret += next;\r
+               str ++;\r
        }\r
-       \r
-       // Negate if needed\r
-       if(neg) ret = -ret;\r
+\r
+       if( neg )\r
+               ret = -ret;     \r
+\r
+       if(end)\r
+               *end = (char*)str;\r
        return ret;\r
 }\r
+\r
+EXPORT long strtol(const char *str, char **end, int base)\r
+{\r
+       long long tmp = strtoll(str, end, base);\r
+       if( tmp > LONG_MAX || tmp < LONG_MIN ) {\r
+               errno = ERANGE;\r
+               return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN;\r
+       }\r
+       return tmp;\r
+}\r
+\r
+/**\r
+ * \fn EXPORT int atoi(const char *str)\r
+ * \brief Convert a string to an integer\r
+ */\r
+EXPORT int atoi(const char *str)\r
+{\r
+       long long       tmp = strtoll(str, NULL, 0);\r
+       if( tmp > INT_MAX || tmp < INT_MIN ) {\r
+               errno = ERANGE;\r
+               return (tmp > INT_MAX) ? INT_MAX : INT_MIN;\r
+       }\r
+       return tmp;\r
+}\r
+\r
+int abs(int j) { return j < 0 ? -j : j; }\r
+long int labs(long int j) { return j < 0 ? -j : j; }\r
+\r
index e9e1574..3cadee9 100644 (file)
@@ -273,10 +273,11 @@ EXPORT void *memmove(void *dest, const void *src, size_t count)
        char *sp = (char *)src;
        char *dp = (char *)dest;
        // Check if the areas overlap
-       if( (intptr_t)dest > (intptr_t)src && (intptr_t)dest < (intptr_t)src+count )
-               for(;count--;) dp[count] = sp[count];
+       if( (intptr_t)src < (intptr_t)dest && (intptr_t)dest < (intptr_t)src+count )
+               for(;count--;)
+                       dp[count] = sp[count];
        else
-               for(;count--;) *dp++ = *sp++;
+               memcpy(dest, src, count);
        return dest;
 }
 
diff --git a/Usermode/Libraries/libimage.so_src/include_exp/image.h b/Usermode/Libraries/libimage.so_src/include_exp/image.h
new file mode 100644 (file)
index 0000000..69e1549
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ */
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+// === TYPES ===
+typedef struct sImage  tImage;
+struct sImage
+{
+       short   Width;
+       short   Height;
+        int    Format;
+       uint8_t Data[];
+};
+
+// === CONSTANTS ===
+enum eImageFormats
+{
+       IMGFMT_BGRA,
+       IMGFMT_RGB,
+       NUM_IMGFMTS
+};
+
+#endif
index aa2f2f9..29abaaa 100644 (file)
@@ -6,7 +6,7 @@ CPPFLAGS +=
 CFLAGS   += -Wall
 LDFLAGS  += -lc -soname libnet.so
 
-OBJ = main.o address.o
+OBJ = main.o address.o socket.o
 BIN = libnet.so
 
 include ../Makefile.tpl
diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h
new file mode 100644 (file)
index 0000000..43445d1
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Acess2 Common Networking Library
+ * By John Hodge (thePowersGang)
+ */
+
+#ifndef __LIBNET_H_
+#define __LIBNET_H_
+
+enum {
+       NET_ADDRTYPE_NULL = 0,
+       NET_ADDRTYPE_IPV4 = 4,
+       NET_ADDRTYPE_IPV6 = 6
+};
+
+/**
+ * \brief Parse a string as an IP Address
+ * \param String       Input string
+ * \param Addr Output binary format of the address
+ * \return Address family (0: Invalid, 4: IPv4, 6: IPv6)
+ */
+extern int     Net_ParseAddress(const char *String, void *Addr);
+
+/**
+ * \brief Convert a network address into a string
+ * \param AddressType  Address family as returned by Net_ParseAddress
+ * \param Address      Address data
+ */
+extern const char *Net_PrintAddress(int AddressType, void *Address);
+
+/**
+ * \brief Get the size in bytes of an address type
+ * \param AddressType  Address type returned by Net_ParseAddress
+ * \return Size of an address in bytes
+ */
+extern int Net_GetAddressSize(int AddressType);
+
+/**
+ * \brief Get the interface required to reach \a Addr
+ * \param AddrType     Addresss Family (4: IPv4, 6: IPv6)
+ * \param Addr Address in binary format
+ * \return Interface number
+ */
+extern char    *Net_GetInterface(int AddrType, void *Addr);
+
+/**
+ * \brief Open a network socket file
+ * \param AddrType     Address family
+ * \param Addr Binary address
+ * \param SocketName   Socket type to open (e.g. tcpc for TCP client)
+ *                      If NULL, the node directory is opened
+ * \return Socket file descriptor (as returned by \a open), or -1 on error
+ * 
+ * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName>
+ * 
+ */
+extern int     Net_OpenSocket(int AddrType, void *Addr, const char *SocketName);
+
+extern int     Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port);
+
+#endif
index 403a339..2adaf1b 100644 (file)
@@ -29,32 +29,6 @@ int Net_GetAddressSize(int AddressType)
        }
 }
 
-int Net_OpenSocket(int AddrType, void *Addr, const char *Filename)
-{
-        int    addrLen = Net_GetAddressSize(AddrType);
-        int    i;
-       uint8_t *addrBuffer = Addr;
-       char    hexAddr[addrLen*2+1];
-       
-       for( i = 0; i < addrLen; i ++ )
-               sprintf(hexAddr+i*2, "%02x", addrBuffer[i]);
-       
-       if(Filename)
-       {
-                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
-               char    path[len+1];
-               snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
-               return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
-       }
-       else
-       {
-                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
-               char    path[len+1];
-               snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
-               return open(path, OPENFLAG_READ);
-       }
-}
-
 //TODO: Move out to another file
 char *Net_GetInterface(int AddressType, void *Address)
 {
@@ -75,7 +49,7 @@ char *Net_GetInterface(int AddressType, void *Address)
                // Open
                fd = open("/Devices/ip/routes", 0);
                if( !fd ) {
-                       fprintf(stderr, "ERROR: It seems that '/Devices/ip/routes' does not exist, are you running Acess2?\n");
+                       fprintf(stderr, "ERROR: Unable to open '/Devices/ip/routes'\n");
                        return NULL;
                }
                
@@ -99,7 +73,7 @@ char *Net_GetInterface(int AddressType, void *Address)
                // Open route
                fd = open(buf, 0);
                if( fd == -1 ) {
-                       fprintf(stderr, "Net_GetInterface - ERROR: Unabel to open %s\n", buf);
+                       fprintf(stderr, "Net_GetInterface - ERROR: Unable to open %s\n", buf);
                        return NULL;    // Shouldn't happen :/
                }
                
diff --git a/Usermode/Libraries/libnet.so_src/net.h b/Usermode/Libraries/libnet.so_src/net.h
deleted file mode 100644 (file)
index 7200efe..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Acess2 Common Networking Library
- * By John Hodge (thePowersGang)
- */
-
-#ifndef __LIBNET_H_
-#define __LIBNET_H_
-
-enum {
-       NET_ADDRTYPE_NULL = 0,
-       NET_ADDRTYPE_IPV4 = 4,
-       NET_ADDRTYPE_IPV6 = 6
-};
-
-/**
- * \brief Parse a string as an IP Address
- * \param String       Input string
- * \param Addr Output binary format of the address
- * \return Address family (0: Invalid, 4: IPv4, 6: IPv6)
- */
-extern int     Net_ParseAddress(const char *String, void *Addr);
-
-/**
- * \brief Convert a network address into a string
- * \param AddressType  Address family as returned by Net_ParseAddress
- * \param Address      Address data
- */
-extern const char *Net_PrintAddress(int AddressType, void *Address);
-
-/**
- * \brief Get the size in bytes of an address type
- * \param AddressType  Address type returned by Net_ParseAddress
- * \return Size of an address in bytes
- */
-extern int Net_GetAddressSize(int AddressType);
-
-/**
- * \brief Get the interface required to reach \a Addr
- * \param AddrType     Addresss Family (4: IPv4, 6: IPv6)
- * \param Addr Address in binary format
- * \return Interface number
- */
-extern char    *Net_GetInterface(int AddrType, void *Addr);
-
-/**
- * \brief Open a network socket file
- * \param AddrType     Address family
- * \param Addr Binary address
- * \param SocketName   Socket type to open (e.g. tcpc for TCP client)
- *                      If NULL, the node directory is opened
- * \return Socket file descriptor (as returned by \a open), or -1 on error
- * 
- * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName>
- * 
- */
-extern int     Net_OpenSocket(int AddrType, void *Addr, const char *SocketName);
-
-#endif
diff --git a/Usermode/Libraries/libnet.so_src/socket.c b/Usermode/Libraries/libnet.so_src/socket.c
new file mode 100644 (file)
index 0000000..0b54079
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Acess2 Networking Toolkit
+ * By John Hodge (thePowersGang)
+ * 
+ * socket.c
+ * - 
+ */
+#include <net.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <acess/sys.h>
+
+int Net_OpenSocket(int AddrType, void *Addr, const char *Filename)
+{
+        int    addrLen = Net_GetAddressSize(AddrType);
+        int    i;
+       uint8_t *addrBuffer = Addr;
+       char    hexAddr[addrLen*2+1];
+       
+       for( i = 0; i < addrLen; i ++ )
+               sprintf(hexAddr+i*2, "%02x", addrBuffer[i]);
+       
+       if(Filename)
+       {
+                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
+               char    path[len+1];
+               snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
+               _SysDebug("%s", path);
+               return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
+       }
+       else
+       {
+                int    len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
+               char    path[len+1];
+               snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
+               return open(path, OPENFLAG_READ);
+       }
+}
+
+int Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port)
+{
+       int fd = Net_OpenSocket(AddrType, Addr, "tcpc");
+       if( fd == -1 )  return -1;
+       
+       ioctl(fd, 5, &Port);    // Remote Port
+        ioctl(fd, 6, Addr);    // Remote address
+       ioctl(fd, 7, NULL);     // connect
+       return fd;
+}
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/dirent.h b/Usermode/Libraries/libposix.so_src/include_exp/dirent.h
new file mode 100644 (file)
index 0000000..4f2c0b3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * dirent.h
+ * - Directory Reading
+ */
+#ifndef _LIBPOSIX__SYS__DIRENT_H_
+#define _LIBPOSIX__SYS__DIRENT_H_
+
+#define NAME_MAX       255
+
+struct dirent
+{
+       ino_t   d_ino;
+       char    d_name[NAME_MAX+1];
+};
+
+typedef struct DIR_s   DIR;
+
+extern int     closedir(DIR *);
+extern DIR     *opendir(const char *);
+extern struct dirent   *readdir(DIR *);
+extern int     readdir_r(DIR *, struct dirent *, struct dirent **);
+extern void    rewinddir(DIR *);
+extern void    seekdir(DIR *, long int);
+extern long int        telldir(DIR *);
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/fcntl.h b/Usermode/Libraries/libposix.so_src/include_exp/fcntl.h
new file mode 100644 (file)
index 0000000..5fee9a1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Acess2 C Library (UNIX Emulation)
+ * - By John Hodge (thePowersGang)
+ *
+ * fcntl.h
+ * - ??
+ */
+
+#ifndef _FCNTL_H_
+#define _FCNTL_H_
+
+#include <sys/sys.h>
+
+// Hacks to handle different behaviors in Acess
+
+// Open doesn't take a chmod
+#define open(_1,_2,...)        open(_1, _2)
+
+// Close returns void
+#define close(_1)      (close(_1),0)
+
+// Acess doesn't implement lseek
+#define lseek(_1,_2,_3)        (seek(_1,_2,_3),tell(_1))
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/grp.h b/Usermode/Libraries/libposix.so_src/include_exp/grp.h
new file mode 100644 (file)
index 0000000..b3d42bf
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * grp.h
+ * - Group Management
+ */
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/pwd.h b/Usermode/Libraries/libposix.so_src/include_exp/pwd.h
new file mode 100644 (file)
index 0000000..66b157f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * pwd.h
+ * - Password Structure
+ */
+#ifndef _LIBPOSIX__PWD_H_
+#define _LIBPOSIX__PWD_H_
+
+#include <sys/types.h> // gid_t/uid_t
+
+struct passwd
+{
+       char    *pw_name;
+       uid_t   pw_uid;
+       gid_t   pw_gid;
+       char    *pw_dir;
+       char    *pw_shell;
+};
+
+extern struct passwd   *getpwnam(const char *);
+extern struct passwd   *getpwuid(uid_t);
+extern int     getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **);
+extern int     getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **);
+extern void    endpwent(void);
+extern struct passwd   *getpwent(void);
+extern void    setpwent(void);
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/sys/resource.h b/Usermode/Libraries/libposix.so_src/include_exp/sys/resource.h
new file mode 100644 (file)
index 0000000..f9a64cb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/resource.h
+ * - (XSI) Resource Operations
+ */
+#ifndef _LIBPOSIX__SYS__RESOURCE_H_
+#define _LIBPOSIX__SYS__RESOURCE_H_
+
+#include <sys/time.h>  // struct timeval
+
+// (get|set)priority(which)
+enum
+{
+       PRIO_PROCESS,
+       PRIO_PGRP,
+       PRIO_USER
+};
+
+typedef unsigned int   rlim_t;
+#define RLIM_INFINITY  -1
+#define RLIM_SAVED_MAX -2
+#define RLIM_SAVED_CUR -3
+
+struct rlimit
+{
+       rlim_t  rlim_cur;
+       rlim_t  rlim_max;
+};
+
+struct rusage
+{
+       struct timeval  ru_time;
+       struct timeval  ru_stime;
+};
+
+extern int     getpriority(int, id_t);
+extern int     getrlimit(int, struct rlimit *);
+extern int     getrusage(int, struct rusage *);
+extern int     setpriority(int, id_t, int);
+extern int     setrlimit(int, const struct rlimit *);
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/sys/time.h b/Usermode/Libraries/libposix.so_src/include_exp/sys/time.h
new file mode 100644 (file)
index 0000000..5cd2876
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/time.h
+ * - Timing calls
+ */
+#ifndef _LIBPOSIX__SYS__TIME_H_
+#define _LIBPOSIX__SYS__TIME_H_
+
+typedef unsigned long  suseconds_t;
+
+struct timeval
+{
+       time_t  tv_sec;
+       suseconds_t     tv_usec;
+};
+
+struct itimerval
+{
+       struct timeval  it_interval;
+       struct timeval  it_value;
+};
+
+// TODO: This should also define fd_set and select()
+
+extern int     getitimer(int, struct itimerval *);
+extern int     setitimer(int, const struct itimerval *, struct itimerval *);
+extern int     gettimeofday(struct timeval *, void *);
+// select
+extern int     utimes(const char *, const struct timeval [2]);
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/sys/wait.h b/Usermode/Libraries/libposix.so_src/include_exp/sys/wait.h
new file mode 100644 (file)
index 0000000..d37f5e5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/wait.h
+ * - Waiting
+ */
+#ifndef _LIBPOSIX__SYS__WAIT_H_
+#define _LIBPOSIX__SYS__WAIT_H_
+
+// POSIX, waitpid()
+#define        WNOHANG 0x01
+#define WUNTRACED      0x02
+
+// POSIX, status values
+#define WEXITSTATUS(v) v
+#define WIFCONTINUED(v)        0
+
+// POSIX/XSI, waitid(options)
+#define WEXITED        0x10
+#define WSTOPPED       0x20
+#define WCONTINUED     0x40
+#define WNOWAIT        0x80
+
+// POSIX/XSI, idtype_t
+typedef enum
+{
+       P_ALL,
+       P_PID,
+       P_PGID
+} idtype_t;
+
+// POSIX
+extern pid_t   wait(int *);
+// POSIX/XSI
+//extern int   waitid(idtype_t, id_t, siginfo_t *, int);
+// POSIX
+extern pid_t   waitpid(pid_t, int *, int);
+
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/syslog.h b/Usermode/Libraries/libposix.so_src/include_exp/syslog.h
new file mode 100644 (file)
index 0000000..ae891b7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * syslog.h
+ * - Centra Loggin
+ */
+#ifndef _LIBPOSIX__SYSLOG_H_
+#define _LIBPOSIX__SYSLOG_H_
+
+// openlog(logopt)
+#define LOG_PID        0x01
+#define LOG_CONS       0x02
+#define LOG_NDELAY     0x04
+#define LOG_ODELAY     0x08
+#define LOG_NOWAIT     0x10
+
+// openlog(facility)
+enum {
+       LOG_KERN,
+       LOG_USER,
+       LOG_MAIL,
+       LOG_NEWS,
+       LOG_UUCP,
+       LOG_DAEMON,
+       LOG_AUTH,
+       LOG_CRON,
+       LOG_LPR,
+       LOG_LOCAL0,
+       LOG_LOCAL1,
+       LOG_LOCAL2,
+       LOG_LOCAL3,
+       LOG_LOCAL4,
+       LOG_LOCAL5,
+       LOG_LOCAL6,
+       LOG_LOCAL7
+};
+
+// setlogmask(maskpri)
+#define LOG_MASK(pri)  pri
+
+// syslog(priority)
+enum {
+       LOG_EMERG,
+       LOG_ALERT,
+       LOG_CRIT,
+       LOG_ERR,
+       LOG_WARNING,
+       LOG_NOTICE,
+       LOG_INFO,
+       LOG_DEBUG
+};
+
+extern void    closelog(void);
+extern void    openlog(const char *, int, int);
+extern int     setlogmask(int);
+extern void    syslog(int, const char *, ...);
+
+#endif
+
diff --git a/Usermode/Libraries/libposix.so_src/include_exp/termios.h b/Usermode/Libraries/libposix.so_src/include_exp/termios.h
new file mode 100644 (file)
index 0000000..e29ff4c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * termios.h
+ * - Terminal Control
+ */
+#ifndef _LIBPOSIX__TERMIOS_H_
+#define _LIBPOSIX__TERMIOS_H_
+
+typedef unsigned char  cc_t;
+typedef unsigned long  speed_t;
+typedef unsigned short tcflag_t;
+
+enum {
+       VEOF,
+       VEOL,
+       VERASE,
+       VINTR,
+       VKILL,
+       VMIN,
+       VQUIT,
+       VSTART,
+       VSTOP,
+       VSUSP,
+       VTIME,
+       NCCS
+};
+
+struct termios
+{
+       tcflag_t        c_iflag;
+       tcflag_t        c_oflag;
+       tcflag_t        c_cflag;
+       tcflag_t        c_lflag;
+       cc_t    c_cc[NCCS];
+};
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/Makefile b/Usermode/Libraries/libpsocket.so_src/Makefile
new file mode 100644 (file)
index 0000000..81418ad
--- /dev/null
@@ -0,0 +1,12 @@
+# Acess 2 - POSIX Sockets
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS   += -Wall
+LDFLAGS  += -lc -soname libpsocket.so -lnet
+
+OBJ = main.o getaddrinfo.o socket.o
+BIN = libpsocket.so
+
+include ../Makefile.tpl
diff --git a/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c b/Usermode/Libraries/libpsocket.so_src/getaddrinfo.c
new file mode 100644 (file)
index 0000000..57120f0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * getaddrinfo.c
+ * - getaddrinfo/freeaddrinfo/getnameinfo/gai_strerror
+ */
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net.h>       // Net_ParseAddress
+#include <stdlib.h>    // malloc
+#include <string.h>    // memcpy
+#include <acess/sys.h>
+
+// === CODE ===
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+       static const struct addrinfo    defhints = {.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG};
+       struct addrinfo *ret = NULL;
+
+       // Error checks
+       if( !node && !service ) return EAI_NONAME;
+       
+       if( !hints )
+               hints = &defhints;
+
+       if( !node )
+       {
+               if( !(hints->ai_flags & AI_PASSIVE) )
+                       ;       // Use localhost
+               else
+                       ;       // Use wildcard
+       }
+       else
+       {
+               // 1. Check if the node is an IP address
+               // TODO: Break this function out into inet_pton?
+               {
+                        int    type;
+                       char    addrdata[16];
+                       type = Net_ParseAddress(node, addrdata);
+                       switch(type)
+                       {
+                       case 0:
+                               break;
+                       case 4: // IPv4
+                               ret = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
+                               ret->ai_family = AF_INET;
+                               ret->ai_socktype = 0;
+                               ret->ai_protocol = 0;
+                               ret->ai_addrlen = sizeof(struct in_addr);
+                               ret->ai_addr = (void*)( ret + 1 );
+                               ret->ai_canonname = 0;
+                               ret->ai_next = 0;
+                               ((struct sockaddr_in*)ret->ai_addr)->sin_family = AF_INET;
+                               ((struct sockaddr_in*)ret->ai_addr)->sin_port = 0;
+                               memcpy( &((struct sockaddr_in*)ret->ai_addr)->sin_addr, addrdata, 4 );
+                               break;
+                       default:
+                               _SysDebug("getaddrinfo: Unknown address family %i", type);
+                               return 1;
+                       }
+               }
+               
+               // 2. Check for a DNS name
+               // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set
+               if( !ret && !(hints->ai_flags & AI_NUMERICHOST) )
+               {
+                       // TODO: DNS Lookups
+                       // ? /Acess/Conf/Nameservers
+                       // ? /Acess/Conf/Hosts
+               }
+               
+               // 3. No Match, chuck sad
+               if( !ret )
+               {
+                       return EAI_NONAME;
+               }
+       }
+
+       int default_socktype = 0;
+       int default_protocol = 0;
+       int default_port = 0;
+       
+       // Convert `node` into types
+       if( service )
+       {
+               // TODO: Read something like /Acess/Conf/services
+       }
+
+       struct addrinfo *ai;
+       for( ai = ret; ai; ai = ai->ai_next)
+       {
+               struct sockaddr_in      *in = (void*)ai->ai_addr;
+               struct sockaddr_in6     *in6 = (void*)ai->ai_addr;
+               
+               // Check ai_socktype/ai_protocol
+               // TODO: Do both of these need to be zero for defaults to apply?
+               if( ai->ai_socktype == 0 )
+                       ai->ai_socktype = default_socktype;
+               if( ai->ai_protocol == 0 )
+                       ai->ai_protocol = default_protocol;
+               
+               switch(ai->ai_family)
+               {
+               case AF_INET:
+                       if( in->sin_port == 0 )
+                               in->sin_port = default_port;
+                       break;
+               case AF_INET6:
+                       if( in6->sin6_port == 0 )
+                               in6->sin6_port = default_port;
+                       break;
+               default:
+                       _SysDebug("getaddrinfo: Unknown address family %i (setting port)", ai->ai_family);
+                       return 1;
+               }
+       }
+
+       *res = ret;
+       return 0;
+}
+
+void freeaddrinfo(struct addrinfo *res)
+{
+       
+}
+
+const char *gai_strerror(int errnum)
+{
+       switch(errnum)
+       {
+       case EAI_SUCCESS:       return "No error";
+       case EAI_FAIL:          return "Permanent resolution failure";
+       default:        return "UNKNOWN";
+       }
+}
+
diff --git a/Usermode/Libraries/libpsocket.so_src/include_exp/arpa/inet.h b/Usermode/Libraries/libpsocket.so_src/include_exp/arpa/inet.h
new file mode 100644 (file)
index 0000000..effc288
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * arpa/inet.h
+ * - 
+ */
+#ifndef _LIBPSOCKET__ARPA__INET_H_
+#define _LIBPSOCKET__ARPA__INET_H_
+
+#include <netinet/in.h>
+#include <stdint.h>    // Should be inttypes.h?
+
+extern uint32_t htonl(uint32_t hostlong);
+extern uint16_t htons(uint16_t hostshort);
+extern uint32_t ntohl(uint32_t netlong);
+extern uint16_t ntohs(uint16_t netshort);
+
+extern in_addr_t       inet_addr(const char *cp);
+extern in_addr_t       inet_lnaof(struct in_addr in);
+extern struct in_addr  inet_makeaddr(in_addr_t net, in_addr_t lna);
+extern in_addr_t       inet_netof(struct in_addr in);
+extern in_addr_t       inet_network(const char *cp);
+extern char    *inet_ntoa(struct in_addr in);
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/include_exp/netdb.h b/Usermode/Libraries/libpsocket.so_src/include_exp/netdb.h
new file mode 100644 (file)
index 0000000..e9cf788
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _LIBPSOCKET__NETDB_H_
+#define _LIBPSOCKET__NETDB_H_
+
+#include <sys/socket.h>
+
+#define AI_PASSIVE     0x001
+#define AI_V4MAPPED    0x002
+#define AI_ADDRCONFIG  0x004
+#define AI_NUMERICHOST 0x008
+
+enum
+{
+       EAI_SUCCESS,
+       EAI_AGAIN,
+       EAI_BADFLAGS,
+       EAI_FAMILY,
+       EAI_SOCKTTPE,
+       
+       EAI_ADDRFAMILY,
+       EAI_FAIL,
+       EAI_MEMORY,
+       EAI_NODATA,
+       EAI_NONAME,
+       EAI_SERVICE,
+       EAI_SYSTEM
+};
+
+struct addrinfo
+{
+       int     ai_flags;
+       int     ai_family;
+       int     ai_socktype;
+       int     ai_protocol;
+       socklen_t       ai_addrlen;
+       struct sockaddr *ai_addr;
+       char    *ai_canonname;
+       struct addrinfo *ai_next;
+};
+
+extern int     getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+extern void    freeaddrinfo(struct addrinfo *res);
+const char     *gai_strerror(int errorcode);
+
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/include_exp/netinet/in.h b/Usermode/Libraries/libpsocket.so_src/include_exp/netinet/in.h
new file mode 100644 (file)
index 0000000..8abf766
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _LIBPSOCKET__NETINET__IN_H_
+#define _LIBPSOCKET__NETINET__IN_H_
+
+#include <stdint.h>
+
+typedef uint32_t       in_addr_t;
+
+struct in_addr
+{
+       in_addr_t s_addr;
+};
+
+struct sockaddr_in
+{
+       uint16_t        sin_family;
+       uint16_t        sin_port;
+       struct in_addr  sin_addr;
+};
+
+#define INADDR_ANY     0x00000000
+#define INADDR_BROADCAST       0xFFFFFFFF
+
+// getsockopt/setsockopt(level)
+enum {
+       IPPROTO_IP,
+       IPPROTO_ICMP,
+       IPPROTO_TCP,
+       IPPROTO_UDP
+};
+
+struct in6_addr
+{
+       unsigned char   s6_addr[16];
+};
+
+struct sockaddr_in6
+{
+       uint16_t        sin6_family;
+       uint16_t        sin6_port;
+       uint32_t        sin6_flowinfo;
+       struct in6_addr sin6_addr;
+       uint32_t        sin6_scope_id;
+};
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/include_exp/sys/socket.h b/Usermode/Libraries/libpsocket.so_src/include_exp/sys/socket.h
new file mode 100644 (file)
index 0000000..adc5a87
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/sockets.h
+ * - POSIX Sockets
+ */
+#ifndef _SYS_SOCKETS_H_
+#define _SYS_SOCKETS_H_
+
+#include <sys/types.h>
+#include <stddef.h>    // size_t
+
+typedef uint32_t       socklen_t;
+
+typedef enum
+{
+       AF_UNSPEC       = 0,
+       AF_PACKET       = 1,
+       AF_INET         = 4,
+       AF_INET6        = 6,
+} sa_family_t;
+
+struct sockaddr
+{
+       sa_family_t     sa_family;
+       char            sa_data[16];
+};
+
+struct msghdr
+{
+       void    *msg_name;
+       socklen_t       msg_namelen;
+       struct iovec    *msg_iov;
+       int     msg_iovlen;
+       void    *msg_control;
+       socklen_t       msg_controllen;
+       int     msg_flags;
+};
+
+struct cmsghdr
+{
+       socklen_t       cmsg_len;
+       int     cmsg_level;
+       int     cmsg_type;
+};
+
+#define SCM_RIGHTS     0x1
+
+#define CMSG_DATA(cmsg)        ((unsigned char*)(cmsg + 1))
+#define CMSG_NXTHDR(mhdr, cmsg)        0
+#define CMSG_FIRSTHDR(mhdr)    0
+
+struct linger
+{
+       int     l_onoff;
+       int     l_linger;
+};
+
+enum eSocketTypes
+{
+       SOCK_STREAM,    //!< Stream (TCP)
+       SOCK_DGRAM,     //!< Datagram (UDP)
+       SOCK_SEQPACKET, //!< 
+       SOCK_RAW,       //!< Raw packet access
+       SOCK_RDM        //!< Reliable non-ordered datagrams
+};
+
+/**
+ * \brief Values for \a domain of socket()
+ */
+enum eSocketDomains
+{
+       PF_LOCAL,       //!< Machine-local comms
+       PF_INET,        //!< IPv4
+       PF_INET6,       //!< IPv6
+       PF_PACKET       //!< Low level packet interface
+};
+#define PF_UNIX        PF_LOCAL
+
+/**
+ * \brief Create a new socket descriptor
+ * \param domain       Address family
+ */
+extern int     socket(int domain, int type, int protocol);
+
+/**
+ * \brief Bind a socket to an address
+ */
+extern int     bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+/**
+ * \brief Connect to another socket
+ */
+extern int     connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+/**
+ * \brief Listen for incoming connections
+ */
+extern int     listen(int sockfd, int backlog);
+
+/**
+ * \brief Accept an incoming connection
+ */
+extern int     accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen);
+
+extern int     recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *clientaddr, socklen_t *addrlen);
+extern int     recv(int sockfd, void *buffer, size_t length, int flags);
+extern int     sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *clientaddr, socklen_t addrlen);
+extern int     send(int sockfd, void *buffer, size_t length, int flags);
+
+extern int     setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
+extern int     getsockopt(int socket, int level, int option_name, void *option_value, socklen_t *option_len);
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/include_exp/sys/un.h b/Usermode/Libraries/libpsocket.so_src/include_exp/sys/un.h
new file mode 100644 (file)
index 0000000..e932016
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/un.h
+ * - UNIX Domain Sockets
+ */
+#ifndef _LIBPSOCKET__SYS__UN_H_
+#define _LIBPSOCKET__SYS__UN_H_
+
+#define _SUN_PATH_MAX  108
+
+// POSIX Defined
+struct sockaddr_un
+{
+       sa_family_t     sun_family;
+       char    sun_path[_SUN_PATH_MAX];
+};
+
+#endif
+
diff --git a/Usermode/Libraries/libpsocket.so_src/main.c b/Usermode/Libraries/libpsocket.so_src/main.c
new file mode 100644 (file)
index 0000000..99fbe2a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Entrypoint and misc code
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+int SoMain(void)
+{
+       return 0;
+}
+
+char *mkstr(const char *format, ...)
+{
+       va_list args;
+        int    len;
+       char    *ret;
+       
+       va_start(args, format);
+       len = vsnprintf(NULL, 0, format, args);
+       va_end(args);
+       ret = malloc(len + 1);
+       va_start(args, format);
+       vsnprintf(ret, len+1, format, args);
+       va_end(args);
+       return ret;
+}
+
diff --git a/Usermode/Libraries/libpsocket.so_src/socket.c b/Usermode/Libraries/libpsocket.so_src/socket.c
new file mode 100644 (file)
index 0000000..913f72f
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * socket.c
+ * - sys/socket.h calls
+ */
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>    // malloc/free
+#include <string.h>
+#include <netinet/in.h>
+
+#define MAXFD  32
+
+typedef struct s_sockinfo
+{
+        int    fd;
+       char    domain;
+       char    type;
+       char    protocol;
+       struct sockaddr *local;
+       struct sockaddr *remote;
+} t_sockinfo;
+
+struct s_sockinfo      gSockInfo[MAXFD];
+static int     giNumPreinit = 0;
+
+// === CODE ===
+static t_sockinfo *_GetInfo(int FD)
+{
+        int    i, nInit = 0;;
+       if( FD == 0 && giNumPreinit == MAXFD )
+               return NULL;
+       for( i = 0; i < MAXFD; i ++ )
+       {
+               if( gSockInfo[i].fd == FD )
+                       return &gSockInfo[i];
+               if( gSockInfo[i].fd )
+                       nInit ++;
+               if( FD != 0 && nInit == giNumPreinit )
+                       return NULL;
+       }
+       return NULL;
+}
+
+int socket(int domain, int type, int protocol)
+{
+       t_sockinfo      *si = NULL;
+       
+       if( domain < 0 || domain > AF_INET6 )   return -1;
+       if( type < 0 || type > SOCK_RDM )       return -1;
+
+       // Allocate an info struct
+       si = _GetInfo(0);
+       if( !si )       return -1;
+
+       int fd = open("/Devices/null", O_RDWR);
+       if( fd == -1 )  return -1;
+
+       giNumPreinit ++;
+       si->fd = fd;
+       si->domain = domain;
+       si->type = type;
+       si->protocol = protocol;
+       si->local = NULL;
+       si->remote = NULL;
+
+       return fd;
+} 
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+       t_sockinfo      *si = _GetInfo(sockfd);;
+       if( !si )       return -1;
+
+       if( si->local ) {
+               // Oops?
+               return -1;
+       }
+
+       si->local = malloc( addrlen );
+       memcpy(si->local, addr, addrlen);
+
+       return 0;
+}
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+       t_sockinfo      *si = _GetInfo(sockfd);;
+       if( !si )       return -1;
+
+       if( si->remote ) {
+               // Oops?
+               return -1;
+       }
+
+       si->remote = malloc( addrlen );
+       memcpy(si->remote, addr, addrlen);
+
+       return 0;
+}
+
+int listen(int sockfd, int backlog)
+{
+       // TODO: Save this to the t_sockinfo structure
+       return 0;
+}
+
+void _ClearInfo(t_sockinfo *si)
+{
+       if( si->local ) {
+               free(si->local);
+               si->local = NULL;
+       }
+       
+       if( si->remote ) {
+               free(si->remote);
+               si->remote = NULL;
+       }
+       
+       si->fd = 0;
+       giNumPreinit --;
+}
+
+void _CommitServer(int sockfd)
+{
+       t_sockinfo      *si = _GetInfo(sockfd);
+       if( !si )       return ;
+
+       const char      *file;
+       
+       file = "tcps";
+
+       if( !si->local ) {
+               // Um... oops?
+               return ;
+       }       
+
+       uint8_t *addrBuffer = NULL;
+       size_t addrLen = 0;
+       switch( si->local->sa_family )
+       {
+       case AF_INET:
+               addrBuffer = (void*)&((struct sockaddr_in*)si->local)->sin_addr;
+               addrLen = 4;
+               break;
+       case AF_INET6:
+               addrBuffer = (void*)&((struct sockaddr_in6*)si->local)->sin6_addr;
+               addrLen = 16;
+               break;
+       default:
+               return ;
+       }
+       
+       char    hexAddr[addrLen*2+1];
+        int    bNonZero = 0, i;
+       for( i = 0; i < addrLen; i ++ ) {
+               hexAddr[i*2+0] = "0123456789ABCDEF"[addrBuffer[i] >> 4];
+               hexAddr[i*2+1] = "0123456789ABCDEF"[addrBuffer[i] & 15];
+               if(addrBuffer[i]) bNonZero = 1;
+       }
+       
+       char    *path;
+       if( bNonZero )
+               path = mkstr("/Devices/ip/routes/@%i:%s/%s", si->local->sa_family, file);
+       else
+               path = mkstr("/Devices/ip/*%i/%s", si->local->sa_family, file);
+
+       reopen(si->fd, path, O_RDWR);
+       // TODO: Error-check
+       
+       free(path);
+
+       // TODO: Set up socket
+
+       _ClearInfo(si);
+}
+
+void _CommitClient(int sockfd)
+{
+       t_sockinfo      *si = _GetInfo(sockfd);
+       if( !si )       return ;
+
+       _ClearInfo(si);
+}
+
+int accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen)
+{
+       _CommitServer(sockfd);
+        int    child;
+
+
+       child = _SysOpenChild(sockfd, "", O_RDWR);
+       if( child == -1 )       return -1;
+       
+       ioctl(child, 8, clientaddr);
+       
+       return child;
+}
+
+int recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *clientaddr, socklen_t *addrlen)
+{
+       _CommitClient(sockfd);
+       // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
+       return read(sockfd, buffer, length);
+}
+
+int recv(int sockfd, void *buffer, size_t length, int flags)
+{
+       _CommitClient(sockfd);
+       return read(sockfd, buffer, length);
+}
+
+int sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *clientaddr, socklen_t addrlen)
+{
+       _CommitClient(sockfd);
+       // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
+       return write(sockfd, buffer, length);
+}
+
+int send(int sockfd, void *buffer, size_t length, int flags)
+{
+       _CommitClient(sockfd);
+       return write(sockfd, buffer, length);
+}
+
diff --git a/Usermode/Libraries/libreadline.so_src/include_exp/readline.h b/Usermode/Libraries/libreadline.so_src/include_exp/readline.h
new file mode 100644 (file)
index 0000000..555a24b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Acess2 Library Suite
+ * - Readline
+ * 
+ * Text mode entry with history
+ */
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+// === TYPES ===
+typedef struct sReadline       tReadline;
+
+// === STRUCTURES ===
+
+// === FUNCTIONS ===
+/**
+ * 
+ */
+extern tReadline       *Readline_Init(int UseHistory);
+
+/**
+ * \brief Read a line from stdin
+ * \return Heap string containing the command string (to be free'd by the caller)
+ */
+extern char    *Readline(tReadline *Info);
+
+/**
+ * \brief Read a line from stdin (non-blocking)
+ * \return Heap string containing the command string (to be free'd by the caller)
+ */
+extern char    *Readline_NonBlock(tReadline *Info);
+
+#endif
index 1408eef..719667d 100644 (file)
@@ -260,6 +260,10 @@ int Readline_int_ParseCharacter(tReadline *Info, char *Input)
                                write(STDOUT_FD, "\x1B[C", 3);
                                break;
                        }
+                       break;
+               case '\0':
+                       ofs --;
+                       break;
                }
                break;
        
diff --git a/Usermode/Libraries/liburi.so_src/include_exp/uri.h b/Usermode/Libraries/liburi.so_src/include_exp/uri.h
new file mode 100644 (file)
index 0000000..20b4b4c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Acess2 - URI Parser and opener
+ * By John Hodge (thePowersGang)
+ */
+#ifndef _LIB_URI_H_
+#define _LIB_URI_H_
+
+typedef struct sURI    tURI;
+typedef struct sURIFile        tURIFile;
+typedef struct sURIHandler     tURIHandler;
+
+enum eURIModes
+{
+       URI_MODE_READ  = 0x01,
+       URI_MODE_WRITE = 0x02
+};
+
+struct sURI
+{
+       char    *Proto;
+       char    *Host;
+       char    *PortStr;
+        int    PortNum;
+       char    *Path;
+};
+
+struct sURIHandler
+{
+       char    *Name;
+        int    BlockSize;
+       
+        int    (*Open)(char *Host, int Port, char *Path, int Flags);
+       void    (*Close)(int Handle);
+       size_t  (*Read)(int Handle, size_t Bytes, void *Buffer);
+       size_t  (*Write)(int Handle, size_t Bytes, void *Buffer);
+       size_t  (*GetSize)(int Handle);
+};
+
+// === FUNCTIONS ===
+extern tURI    *URI_Parse(const char *String);
+extern tURIFile        *URI_Open(int Mode, tURI *URI);
+extern int     URI_GetSize(tURIFile *File, size_t *Size);
+extern size_t  URI_Read(tURIFile *File, size_t Bytes, void *Buffer);
+extern size_t  URI_Write(tURIFile *File, size_t Bytes, void *Buffer);
+extern void    URI_Close(tURIFile *File);
+
+#endif
index 4786df9..5bac18f 100644 (file)
@@ -4,7 +4,8 @@ include $(BASE)header.mk
 
 # Rules
 ASFLAGS-$(DIR)  := -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS-$(DIR) := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
 CFLAGS-$(DIR)   := -g -Wall -fPIC -fno-stack-protector -O3
 LDFLAGS-$(DIR)  := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined
 
index f7e9120..e657288 100644 (file)
@@ -5,7 +5,6 @@
 # Include Root Makefile.cfg
 -include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
 
-
 # Set variables
 # > Usermode directory
 ACESSUSERDIR := $(ACESSDIR)/Usermode/
@@ -14,3 +13,4 @@ OUTPUTDIR := $(ACESSUSERDIR)Output/$(ARCH)/
 # > Distroot
 DISTROOT := $(DISTROOT)/$(ARCH)
 
+
diff --git a/Usermode/include/acess/devices.h b/Usermode/include/acess/devices.h
deleted file mode 100644 (file)
index bfbb625..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * \file drivers.h
- */
-#ifndef _SYS_DRIVERS_H
-#define _SYS_DRIVERS_H
-
-// === COMMON ===
-enum eDrv_Common {
-       DRV_IOCTL_NULL,
-       DRV_IOCTL_TYPE,
-       DRV_IOCTL_IDENT,
-       DRV_IOCTL_VER
-};
-
-enum eDrv_Types {
-       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
-       DRV_TYPE_TERMINAL,      //!< Terminal
-       DRV_TYPE_VIDEO,         //!< Video - LFB
-       DRV_TYPE_SOUND,         //!< Audio
-       DRV_TYPE_MOUSE,         //!< Mouse
-       DRV_TYPE_JOYSTICK       //!< Joystick / Gamepad
-};
-
-// === VIDEO ===
-enum eDrv_Video {
-       VID_IOCTL_SETMODE = 4,
-       VID_IOCTL_GETMODE,
-       VID_IOCTL_FINDMODE,
-       VID_IOCTL_MODEINFO,
-       VID_IOCTL_REQLFB        // Request LFB
-};\r
-struct sVideo_IOCtl_Mode {\r
-       short   id;\r
-       Uint16  width;\r
-       Uint16  height;\r
-       Uint16  bpp;\r
-};\r
-typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type
-
-// === MOUSE ===
-enum eDrv_Mouse {\r
-       MSE_IOCTL_SENS = 4,\r
-       MSE_IOCTL_MAX_X,\r
-       MSE_IOCTL_MAX_Y\r
-};
-
-// === Terminal ===
-#include "devices/terminal.h"
-
-#endif
diff --git a/Usermode/include/acess/devices/terminal.h b/Usermode/include/acess/devices/terminal.h
deleted file mode 100644 (file)
index c51b1b2..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * \file devices/terminal.h
- */
-#ifndef _SYS_DEVICES_TERMINAL_H
-#define _SYS_DEVICES_TERMINAL_H
-
-#include <stdint.h>
-
-enum eDrv_Terminal {
-       TERM_IOCTL_MODETYPE = 4,
-       TERM_IOCTL_WIDTH,
-       TERM_IOCTL_HEIGHT,
-       TERM_IOCTL_QUERYMODE,
-       TERM_IOCTL_FORCESHOW,
-       TERM_IOCTL_GETSETCURSOR,
-       TERM_IOCTL_SETCURSORBITMAP
-};
-
-
-struct sTerm_IOCtl_Mode
-{
-       int16_t ID;             //!< Zero Based index of mode
-       int16_t DriverID;       //!< Driver's ID number (from ::tVideo_IOCtl_Mode)
-       uint16_t        Height; //!< Height
-       uint16_t        Width;  //!< Width
-       uint8_t Depth;  //!< Bits per cell
-       uint8_t Flags;  //!< Flags (1: Text Mode)
-};
-
-/**
- * \brief Terminal Modes
- */
-enum eTplTerminal_Modes {
-       /**
-        * \brief UTF-8 Text Mode
-        * Any writes to the terminal file are treated as UTF-8 encoded
-        * strings and reads will also return UTF-8 strings.
-        */
-       TERM_MODE_TEXT,
-       
-       /**
-        * \brief 32bpp Framebuffer
-        * Writes to the terminal file will write to the framebuffer.
-        * Reads will return UTF-32 characters
-        */
-       TERM_MODE_FB,
-       
-       /**
-        * \brief OpenGL 2D/3D
-        * Writes to the terminal file will send 3D commands
-        * Reads will return UTF-32 characters
-        * \note May or may not stay in the spec
-        */
-       TERM_MODE_OPENGL,
-       
-       NUM_TERM_MODES
-};
-
-#endif
diff --git a/Usermode/include/acess/intdefs.h b/Usermode/include/acess/intdefs.h
deleted file mode 100644 (file)
index 46a06c4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- */
-#ifndef _ACESS_INTDEFS_H_
-#define _ACESS_INTDEFS_H_
-
-#define INT_MIN        -0x80000000
-#define INT_MAX        0x7FFFFFFF
-
-typedef unsigned char  __uint8_t;
-typedef unsigned short __uint16_t;
-typedef unsigned int   __uint32_t;
-typedef unsigned long long     __uint64_t;
-
-typedef signed char            __int8_t;
-typedef signed short   __int16_t;
-typedef signed int             __int32_t;
-typedef signed long long       __int64_t;
-
-#if defined(ARCHDIR_is_x86)
-typedef __int32_t      __intptr_t;
-typedef __uint32_t     __uintptr_t;
-#elif defined(ARCHDIR_is_x86_64)
-typedef __int64_t      __intptr_t;
-typedef __uint64_t     __uintptr_t;
-#elif defined(ARCHDIR_is_armv7)
-typedef __int32_t      __intptr_t;
-typedef __uint32_t     __uintptr_t;
-#else
-# error "Unknown pointer size"
-#endif
-
-//typedef uint64_t     off_t;
-
-#endif
-
diff --git a/Usermode/include/acess/sys.h b/Usermode/include/acess/sys.h
deleted file mode 100644 (file)
index cdd0187..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Acess2 System Interface Header
- */
-#ifndef _ACESS_SYS_H_
-#define _ACESS_SYS_H_
-
-#include <stdint.h>
-#include "../sys/types.h"
-
-// === CONSTANTS ===
-#ifndef NULL
-# define NULL  ((void*)0)
-#endif
-
-#define THREAD_EVENT_VFS       0x0001
-#define THREAD_EVENT_IPCMSG    0x0002
-#define THREAD_EVENT_SIGNAL    0x0004
-
-#define OPENFLAG_EXEC  0x01
-#define OPENFLAG_READ  0x02
-#define OPENFLAG_WRITE 0x04
-#define        OPENFLAG_NOLINK 0x40
-#define        OPENFLAG_CREATE 0x80
-#ifndef SEEK_CUR
-# define SEEK_SET      1
-# define SEEK_CUR      0
-# define SEEK_END      -1
-#endif
-#define GETMSG_IGNORE  ((void*)-1)
-#define FILEFLAG_DIRECTORY     0x10
-#define FILEFLAG_SYMLINK       0x20
-
-// === TYPES ===
-
-// === VARIABLES ===
-extern int     _errno;
-
-// === FUNCTIONS ===
-extern void    _SysDebug(const char *format, ...);
-// --- Proc ---
-extern void    _exit(int status)       __attribute__((noreturn));
-extern void    sleep(void);
-extern void    yield(void);
-extern int     kill(int pid, int sig);
-//extern void  wait(int miliseconds);
-extern int     _SysWaitEvent(int EventMask);
-extern int     waittid(int id, int *status);
-extern int     clone(int flags, void *stack);
-extern int     execve(char *path, char **argv, char **envp);
-extern int     _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
-extern int     gettid(void);
-extern int     getpid(void);
-extern int     _SysSetFaultHandler(int (*Handler)(int));
-extern void    SysSetName(const char *Name);
-//extern int   SysGetName(const char *Name);
-
-// --- Permissions ---
-extern int     getuid(void);
-extern int     getgid(void);
-extern void    setuid(int id);
-extern void    setgid(int id);
-
-// --- VFS ---
-extern int     chdir(const char *dir);
-extern int     open(const char *path, int flags, ...);
-extern int     reopen(int fd, const char *path, int flags);
-extern int     close(int fd);
-extern uint    read(int fd, void *buffer, uint length);
-extern uint    write(int fd, const void *buffer, uint length);
-extern int     seek(int fd, int64_t offset, int whence);
-extern uint64_t        tell(int fd);
-extern int     ioctl(int fd, int id, void *data);
-extern int     finfo(int fd, t_sysFInfo *info, int maxacls);
-extern int     readdir(int fd, char *dest);
-extern int     _SysOpenChild(int fd, char *name, int flags);
-extern int     _SysGetACL(int fd, t_sysACL *dest);
-extern int     _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
-extern int     _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, time_t *timeout, int extraevents);
-#define select(nfs, rdfds, wrfds, erfds, timeout)      _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
-
-// --- IPC ---
-extern int     SysSendMessage(pid_t dest, uint length, const void *Data);
-extern int     SysGetMessage(pid_t *src, void *Data);
-
-// --- MEMORY ---
-uint64_t       _SysGetPhys(uint vaddr);
-uint64_t       _SysAllocate(uint vaddr);
-
-#endif
diff --git a/Usermode/include/axwin/axwin.h b/Usermode/include/axwin/axwin.h
deleted file mode 100644 (file)
index 71af36a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * \file axwin.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Core functions
- */
-#ifndef _AXWIN_AXWIN_H
-#define _AXWIN_AXWIN_H
-
-// === Core Types ===
-typedef void   *tAxWin_Handle;
-
-// === Messaging ===
-#include "messages.h"
-
-extern int     AxWin_Register(const char *Name);
-
-extern int     AxWin_MessageLoop();
-extern int     AxWin_SendMessage(tAxWin_Message *Message);
-extern tAxWin_Message  *AxWin_WaitForMessage(void);
-extern int     AxWin_HandleMessage(tAxWin_Message *Message);
-
-// === Window Control ===
-/**
- * \brief Window Type
- * \note Opaque Type
- */
-typedef struct sAxWin_Window   tAxWin_Window;
-
-typedef int    tAxWin_MessageCallback(tAxWin_Message *);
-
-/**
- * \brief Window Flags
- * \{
- */
-#define WINFLAG_NOBORDER       0x100
-/**
- * \}
- */
-
-extern tAxWin_Window   *AxWin_CreateWindow(
-               int16_t X, int16_t Y, int16_t W, int16_t H,
-               uint32_t Flags, tAxWin_MessageCallback *Callback);
-
-#endif
diff --git a/Usermode/include/axwin/messages.h b/Usermode/include/axwin/messages.h
deleted file mode 100644 (file)
index 4d53ab5..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * \file messages.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Control Messages and structures
- */
-#ifndef _AXWIN_MESSAGES_H
-#define _AXWIN_MESSAGES_H
-
-#include <stdint.h>
-
-typedef struct sAxWin_Message  tAxWin_Message;
-typedef struct sAxWin_RetMsg   tAxWin_RetMsg;
-
-// Higherarchy:
-// - HANDLE
-//  + ELEMENT
-//   > DIALOG
-//   > TAB
-
-/**
- * \brief Message IDs
- */
-enum eAxWin_Messages
-{
-       // Server Requests
-       MSG_SREQ_PING,
-       // - Windows
-       MSG_SREQ_REGISTER,      // bool (char[] Name) - Registers this PID with the Window Manager
-       
-       MSG_SREQ_ADDTAB,        // TAB (char[] Name) - Adds a tab to the window
-       MSG_SREQ_DELTAB,        // void (TAB Tab)       - Closes a tab
-       
-       MSG_SREQ_NEWDIALOG,     // DIALOG (TAB Parent, char[] Name)     - Creates a dialog
-       MSG_SREQ_DELDIALOG,     // void (DIALOG Dialog) - Closes a dialog
-       
-       MSG_SREQ_SETNAME,       // void (ELEMENT Element, char[] Name)
-       MSG_SREQ_GETNAME,       // char[] (ELEMENT Element)
-       
-       // - Builtin Elements
-       MSG_SREQ_INSERT,        // void (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
-       
-       // - Drawing
-       //  All drawing functions take an ELEMENT as their first parameter.
-       //  This must be either a Tab, Dialog or Canvas control
-       MSG_SREQ_SETCOL,
-       MSG_SREQ_PSET,
-       MSG_SREQ_LINE,  MSG_SREQ_CURVE,
-       MSG_SREQ_RECT,  MSG_SREQ_FILLRECT,
-       MSG_SREQ_RIMG,  MSG_SREQ_SIMG,  // Register/Set Image
-       MSG_SREQ_SETFONT,       MSG_SREQ_PUTTEXT,
-       
-       // Server Responses
-       MSG_SRSP_VERSION,
-       MSG_SRSP_RETURN,        // {int RequestID, void[] Return Value} - Returns a value from a server request
-       
-       NUM_MSG
-};
-
-// --- Server Requests (Requests from the client of the server)
-/**
- * \brief Server Request - Ping (Get Server Version)
- */
-struct sAxWin_SReq_Ping
-{
-};
-
-/**
- * \brief Server Request - New Window
- * \see eAxWin_Messages.MSG_SREQ_NEWWINDOW
- */
-struct sAxWin_SReq_NewWindow
-{
-       uint16_t        X, Y, W, H;
-       uint32_t        Flags;
-};
-
-
-// --- Server Responses
-/**
- * \brief Server Response - Pong
- * \see eAxWin_Messages.MSG_SRSP_PONG
- */
-struct sAxWin_SRsp_Version
-{
-       uint8_t Major;
-       uint8_t Minor;
-       uint16_t        Build;
-};
-
-/**
- * \brief Server Response - New Window
- * \see eAxWin_Messages.MSG_SRSP_NEWWINDOW
- */
-struct sAxWin_SRsp_NewWindow
-{
-       uint32_t        Handle;
-};
-
-
-// === Core Message Structure
-/**
- * \brief Overarching Message Structure
- * \note sizeof(tAxWin_Message) is never valid
- */
-struct sAxWin_Message
-{
-       uint16_t        ID;
-       uint16_t        Size;   //!< Size in DWORDS
-       char    Data[];
-};
-
-struct sAxWin_RetMsg
-{
-       uint16_t        ReqID;
-       uint16_t        Rsvd;
-       union
-       {
-                uint8_t        Bool;
-               uint32_t        Handle;
-                int    Integer;
-       };
-};
-
-#endif
diff --git a/Usermode/include/axwin2/axwin.h b/Usermode/include/axwin2/axwin.h
deleted file mode 100644 (file)
index 77db620..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- * \file axwin2/axwin.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Core functions
- */
-#ifndef _AXWIN2_AXWIN_H
-#define _AXWIN2_AXWIN_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <axwin2/messages.h>
-
-// === Core Types ===
-typedef struct sAxWin_Element  tAxWin_Element;
-typedef int    tAxWin_MessageCallback(tAxWin_Message *);
-
-// === Functions ===
-extern int     AxWin_Register(const char *ApplicationName, tAxWin_MessageCallback *DefaultHandler);
-extern tAxWin_Element  *AxWin_CreateWindow(const char *TabTitle);
-extern tAxWin_Element  *AxWin_AddMenuItem(tAxWin_Element *Parent, const char *Label, int Message);
-
-extern int     AxWin_MessageLoop(void);
-extern int     AxWin_SendMessage(tAxWin_Message *Message);
-extern tAxWin_Message  *AxWin_WaitForMessage(void);
-extern int     AxWin_HandleMessage(tAxWin_Message *Message);
-
-// === Window Control ===
-
-extern tAxWin_Element  *AxWin_CreateElement(tAxWin_Element *Parent, int ElementType, int Flags, const char *DebugName);
-extern void    AxWin_SetFlags(tAxWin_Element *Element, int Flags);
-extern void    AxWin_SetText(tAxWin_Element *Element, const char *Text);
-extern void    AxWin_SetSize(tAxWin_Element *Element, int Size);
-extern void    AxWin_DeleteElement(tAxWin_Element *Element);
-
-// === CONSTANTS ===
-enum eElementFlags
-{
-       /**
-        * \brief Rendered
-        * 
-        * If set, the element will be ignored in calculating sizes and
-        * rendering.
-        */
-       ELEFLAG_NORENDER    = 0x001,
-       /**
-        * \brief Element visibility
-        * 
-        * If set, the element is not drawn (but still is used for size calculations)
-        */
-       ELEFLAG_INVISIBLE   = 0x002,
-       
-       /**
-        * \brief Position an element absulutely (ignored in size calcs)
-        */
-       ELEFLAG_ABSOLUTEPOS = 0x004,
-       
-       /**
-        * \brief Fixed size element
-        */
-       ELEFLAG_FIXEDSIZE   = 0x008,
-       
-       /**
-        * \brief Element "orientation"
-        * 
-        * Vertical means that the children of this element are stacked,
-        * otherwise they list horizontally
-        */
-       ELEFLAG_VERTICAL    = 0x010,//  ELEFLAG_HORIZONTAL  = 0x000,
-       /**
-        * \brief Action for text that overflows
-        */
-       ELEFLAG_WRAP        = 0x020,//  ELEFLAG_NOWRAP      = 0x000,
-       /**
-        * \brief Cross size action
-        * 
-        * If this flag is set, the element will only be as large (across
-        * its parent) as is needed to encase the contents of the element.
-        * Otherwise, the element will expand to fill all avaliable space.
-        */
-       ELEFLAG_NOEXPAND    = 0x040,
-       
-       /**
-        * \brief With (length) size action
-        * If this flag is set, the element will only be as large as
-        * is required along it's parent
-        */
-       ELEFLAG_NOSTRETCH   = 0x080,
-       
-       /**
-        * \brief Center alignment
-        */
-       ELEFLAG_ALIGN_CENTER= 0x100,
-       /**
-        * \brief Right/Bottom alignment
-        * 
-        * If set, the element aligns to the end of avaliable space (instead
-        * of the beginning)
-        */
-       ELEFLAG_ALIGN_END       = 0x200
-};
-
-#define ELEFLAG_WINDOW_MAXIMISED       0x10000
-
-/**
- */
-enum eElementTypes
-{
-       ELETYPE_NONE,
-
-       ELETYPE_WINDOW, //!< Window root element
-       
-       ELETYPE_BOX,    //!< Content box (invisible in itself)
-       ELETYPE_TABBAR, //!< Tab Bar
-       ELETYPE_TOOLBAR,        //!< Tool Bar
-       
-       ELETYPE_BUTTON, //!< Push Button
-       
-       ELETYPE_TEXT,   //!< Text
-       ELETYPE_IMAGE,  //!< Image
-       
-       ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
-       
-       MAX_ELETYPES    = 0x100
-};
-
-#endif
diff --git a/Usermode/include/axwin2/messages.h b/Usermode/include/axwin2/messages.h
deleted file mode 100644 (file)
index 61536f3..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * \file messages.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Control Messages and structures
- */
-#ifndef _AXWIN_MESSAGES_H
-#define _AXWIN_MESSAGES_H
-
-#include <stdint.h>
-
-typedef struct sAxWin_Message  tAxWin_Message;
-typedef struct sAxWin_RetMsg   tAxWin_RetMsg;
-
-// Higherarchy:
-// - HANDLE
-//  + ELEMENT
-//   > DIALOG
-//   > TAB
-
-/**
- * \brief Message IDs
- */
-enum eAxWin_Messages
-{
-       // Client->Server Requests
-       MSG_SREQ_PING,
-       // - Windows
-       MSG_SREQ_REGISTER,      // bool (char[] Name) - Registers this PID with the Window Manager
-       
-       MSG_SREQ_ADDWIN,        // ELEMENT (char[] Name) - Adds a tab to the window
-       
-       MSG_SREQ_SETICON,       // void (TAB Tab, char[] IconURI)       - Set the icon of a tab (or application)
-
-       MSG_SREQ_NEWDIALOG,     // DIALOG (TAB Parent, char[] Name)     - Creates a dialog
-       MSG_SREQ_DELDIALOG,     // void (DIALOG Dialog) - Closes a dialog
-       
-       MSG_SREQ_SETNAME,       // void (ELEMENT Element, char[] Name)
-       MSG_SREQ_GETNAME,       // char[] (ELEMENT Element)
-       
-       // - Builtin Elements
-       MSG_SREQ_INSERT,        // ELEMENT (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
-       MSG_SREQ_DELETE,        // void (ELEMENT Element)
-       
-       // - Drawing
-       //  All drawing functions take an ELEMENT as their first parameter.
-       //  This must be either a Window or Canvas control
-       MSG_SREQ_SETCOL,
-       MSG_SREQ_PSET,
-       MSG_SREQ_LINE,  MSG_SREQ_CURVE,
-       MSG_SREQ_RECT,  MSG_SREQ_FILLRECT,
-       MSG_SREQ_RIMG,  MSG_SREQ_SIMG,  // Register/Set Image
-       MSG_SREQ_SETFONT,       MSG_SREQ_PUTTEXT,
-
-       // - Callback Registration
-
-       // - WM Control
-       MSG_SREQ_SET_MAXIMIZE_AREA,     // void (uint16_t X, Y, W, H)
-       
-       // Server->Client Responses
-       MSG_SRSP_VERSION,
-       MSG_SRSP_RETURN,        // {int RequestID, void[] Return Value} - Returns a value from a server request
-       
-       NUM_MSG
-};
-
-// --- Server Requests (Requests from the client of the server)
-/**
- * \brief Server Request - Ping (Get Server Version)
- */
-struct sAxWin_SReq_Ping
-{
-};
-
-/**
- * \brief Server Request - New Window
- * \see eAxWin_Messages.MSG_SREQ_NEWWINDOW
- */
-struct sAxWin_SReq_NewWindow
-{
-       uint16_t        X, Y, W, H;
-       uint32_t        Flags;
-};
-
-struct sAxWin_SReq_NewElement
-{
-       uint16_t        Parent;
-       uint16_t        Type;
-       uint32_t        Flags;
-};
-
-
-// --- Server Responses
-/**
- * \brief Server Response - Pong
- * \see eAxWin_Messages.MSG_SRSP_PONG
- */
-struct sAxWin_SRsp_Version
-{
-       uint8_t Major;
-       uint8_t Minor;
-       uint16_t        Build;
-};
-
-
-// === Core Message Structure
-/**
- * \brief Overarching Message Structure
- * \note sizeof(tAxWin_Message) is never valid
- */
-struct sAxWin_Message
-{
-       uint32_t        Source;
-       uint16_t        ID;
-       uint16_t        Size;   // Size of data
-       char    Data[];
-};
-
-struct sAxWin_RetMsg
-{
-       uint16_t        ReqID;
-       uint16_t        Rsvd;
-       uint32_t        Value;
-};
-
-#endif
diff --git a/Usermode/include/axwin3/axwin.h b/Usermode/include/axwin3/axwin.h
deleted file mode 100644 (file)
index fe116e9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * axwin.h
- * - Core API Header
- */
-#ifndef _AXWIN3_AXWIN_H_
-#define _AXWIN3_AXWIN_H_
-
-// === CONSTANTS ===
-
-// === TYPES ===
-typedef struct sAxWin3_Window  *tHWND;
-typedef unsigned int   tAxWin3_Colour; // TODO: Actual 32-bit
-
-typedef void   (*tAxWin3_MessageCallback)(int SourceTID, int Length);
-
-typedef int    (*tAxWin3_WindowMessageHandler)(tHWND Window, int Message, int Length, void *Data);
-
-// --- Connection management
-extern void    AxWin3_Connect(const char *ServerDesc);
-extern tAxWin3_MessageCallback AxWin3_SetMessageCallback(tAxWin3_MessageCallback Callback);
-extern void    AxWin3_MainLoop(void);
-
-// --- Non-Window based functions
-extern int     AxWin3_GetDisplayCount(void);
-extern int     AxWin3_GetDisplayDims(int Display, int *X, int *Y, int *Width, int *Height);
-
-// --- Window creation/deletion
-/**
- * \brief Create a new window (with the required client structures)
- * \param Parent       Parent window handle
- * \param Renderer     Symbolic name of the renderer to use
- * \param RendererArg  Argument to pass to the renderer's initialisation
- * \param DataBytes    Number of bytes to allocate for the caller's use
- * \param MessageHandler       Function to call when a message arrives for the window
- * \return New window handle
- * \note Usually wrapped by renderer-specific functions
- */
-extern tHWND   AxWin3_CreateWindow(
-       tHWND Parent,
-       const char *Renderer, int RendererArg,
-       int DataBytes,
-       tAxWin3_WindowMessageHandler MessageHandler
-       );
-/**
- * \brief Destroy a window
- * \param Window       Handle to a window to destroy
- */
-extern void    AxWin3_DestroyWindow(tHWND Window);
-
-// --- Core window management functions
-extern void    AxWin3_SendMessage(tHWND Window, tHWND Dest, int Message, int Length, void *Data);
-extern void    AxWin3_SetWindowTitle(tHWND Window, const char *Title);
-extern void    AxWin3_FocusWindow(tHWND Window);
-extern void    AxWin3_ShowWindow(tHWND Window, int bShow);
-extern void    AxWin3_DecorateWindow(tHWND Window, int bDecorate);
-extern void    AxWin3_SetWindowPos(tHWND Window, short X, short Y, short W, short H);
-extern void    AxWin3_MoveWindow(tHWND Window, short X, short Y);
-extern void    AxWin3_ResizeWindow(tHWND Window, short W, short H);
-
-#endif
-
diff --git a/Usermode/include/axwin3/menu.h b/Usermode/include/axwin3/menu.h
deleted file mode 100644 (file)
index 323bf30..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * menu.h
- * - Menu window type
- */
-#ifndef _AXWIN3_MENU_H_
-#define _AXWIN3_MENU_H_
-
-typedef void   (*tAxWin3_Menu_Callback)(void *Ptr);
-typedef struct sAxWin3_MenuItem        tAxWin3_MenuItem;
-
-extern tHWND   AxWin3_Menu_Create(tHWND Parent);
-extern void    AxWin3_Menu_ShowAt(tHWND Menu, int X, int Y);
-
-extern tAxWin3_MenuItem        *AxWin3_Menu_AddItem(
-               tHWND Menu, const char *Label,
-               tAxWin3_Menu_Callback Cb, void *Ptr,
-               int Flags, tHWND SubMenu
-               );
-extern tAxWin3_MenuItem        *AxWin3_Menu_GetItem(tHWND Menu, int Index);
-extern void    AxWin3_Menu_SetFlags(tAxWin3_MenuItem *Item, int Flags, int Mask);
-
-#endif
-
diff --git a/Usermode/include/axwin3/widget.h b/Usermode/include/axwin3/widget.h
deleted file mode 100644 (file)
index 29a0225..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * widget.h
- * - Server-side widget library
- */
-#ifndef _AXWIN3_WIDGET_H_
-#define _AXWIN3_WIDGET_H_
-
-#include "axwin.h"
-
-typedef struct sAxWin3_Widget  tAxWin3_Widget;
-
-// --- Callback types
-typedef int    (*tAxWin3_Widget_FireCb)(tAxWin3_Widget *Widget);
-typedef int    (*tAxWin3_Widget_KeyUpDownCb)(tAxWin3_Widget *Widget, int KeySym);
-typedef int    (*tAxWin3_Widget_KeyFireCb)(tAxWin3_Widget *Widget, int KeySym, int Character);
-typedef int    (*tAxWin3_Widget_MouseMoveCb)(tAxWin3_Widget *Widget, int X, int Y);
-typedef int    (*tAxWin3_Widget_MouseBtnCb)(tAxWin3_Widget *Widget, int X, int Y, int Button, int bPressed);
-
-// --- Windows
-extern tHWND   AxWin3_Widget_CreateWindow(tHWND Parent, int W, int H, int RootEleFlags);
-extern void    AxWin3_Widget_DestroyWindow(tHWND Window);
-extern tAxWin3_Widget  *AxWin3_Widget_GetRoot(tHWND Window);
-
-// --- Element Creation
-extern tAxWin3_Widget  *AxWin3_Widget_AddWidget(tAxWin3_Widget *Parent, int Type, int Flags, const char *DebugName);
-extern void    AxWin3_Widget_DelWidget(tAxWin3_Widget *Widget);
-
-// --- Callbacks
-extern void    AxWin3_Widget_SetFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_FireCb Callback);
-extern void    AxWin3_Widget_SetKeyHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyUpDownCb Callback);
-extern void    AxWin3_Widget_SetKeyFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyFireCb Callback);
-extern void    AxWin3_Widget_SetMouseMoveHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseMoveCb Callback);
-extern void    AxWin3_Widget_SetMouseButtonHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseBtnCb Callback);
-// --- Manipulation
-extern void    AxWin3_Widget_SetFlags(tAxWin3_Widget *Widget, int FlagSet, int FlagMask);
-extern void    AxWin3_Widget_SetSize(tAxWin3_Widget *Widget, int Size);
-extern void    AxWin3_Widget_SetText(tAxWin3_Widget *Widget, const char *Text);
-extern void    AxWin3_Widget_SetColour(tAxWin3_Widget *Widget, int Index, tAxWin3_Colour Colour);
-// --- Inspection
-extern char    *AxWin3_Widget_GetText(tAxWin3_Widget *Widget);
-
-enum eElementTypes
-{
-       ELETYPE_NONE,
-
-       ELETYPE_BOX,    //!< Content box (invisible in itself)
-       ELETYPE_TEXT,   //!< Text
-       ELETYPE_IMAGE,  //!< Image
-       ELETYPE_BUTTON, //!< Push Button
-       ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
-       ELETYPE_TEXTINPUT,      //!< Text Input Field
-       ELETYPE_TEXTBOX,        //!< Text Box Input
-
-       ELETYPE_TABBAR, //!< Tab Bar
-       ELETYPE_TOOLBAR,        //!< Tool Bar
-       
-       NUM_ELETYPES
-};
-
-enum eElementFlags
-{
-       /**
-        * \brief Rendered
-        * 
-        * If set, the element will be ignored in calculating sizes and
-        * rendering.
-        */
-       ELEFLAG_NORENDER    = 0x001,
-       /**
-        * \brief Element visibility
-        * 
-        * If set, the element is not drawn (but still is used for size calculations)
-        */
-       ELEFLAG_INVISIBLE   = 0x002,
-       
-       /**
-        * \brief Position an element absulutely (ignored in size calcs)
-        */
-       ELEFLAG_ABSOLUTEPOS = 0x004,
-       
-       /**
-        * \brief Fixed size element
-        */
-       ELEFLAG_FIXEDSIZE   = 0x008,
-       
-       /**
-        * \brief Element "orientation"
-        * 
-        * Vertical means that the children of this element are stacked,
-        * otherwise they list horizontally
-        */
-       ELEFLAG_VERTICAL    = 0x010,//  ELEFLAG_HORIZONTAL  = 0x000,
-       /**
-        * \brief Action for text that overflows
-        */
-       ELEFLAG_WRAP        = 0x020,//  ELEFLAG_NOWRAP      = 0x000,
-       /**
-        * \brief Cross size action
-        * 
-        * If this flag is set, the element will only be as large (across
-        * its parent) as is needed to encase the contents of the element.
-        * Otherwise, the element will expand to fill all avaliable space.
-        */
-       ELEFLAG_NOEXPAND    = 0x040,
-       
-       /**
-        * \brief With (length) size action
-        * If this flag is set, the element will only be as large as
-        * is required along it's parent
-        */
-       ELEFLAG_NOSTRETCH   = 0x080,
-       
-       /**
-        * \brief Center alignment
-        */
-       ELEFLAG_ALIGN_CENTER= 0x100,
-       /**
-        * \brief Right/Bottom alignment
-        * 
-        * If set, the element aligns to the end of avaliable space (instead
-        * of the beginning)
-        */
-       ELEFLAG_ALIGN_END       = 0x200
-};
-
-
-#endif
-
diff --git a/Usermode/include/ctype.h b/Usermode/include/ctype.h
deleted file mode 100644 (file)
index 4c5613b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * ctype.h
- * - Type manipulation?
- */
-#ifndef _CTYPE_H_
-#define _CTYPE_H_
-
-static inline int isalpha(int ch) {
-       if('A'<=ch&&ch<='Z')    return 1;
-       if('a'<=ch&&ch<='z')    return 1;
-       return 0;
-}
-static inline int isdigit(int ch) {
-       if('0'<=ch&&ch<='9')    return 1;
-       return 0;
-}
-
-static inline int isalnum(int ch) {
-       return isalpha(ch) || isdigit(ch);
-}
-
-static inline int toupper(int ch) {
-       if('a'<=ch && ch <='z')
-               return ch - 'a' + 'A';
-       return ch;
-}
-
-static inline int isspace(int ch) {
-       if(ch == ' ')   return 1;
-       if(ch == '\t')  return 1;
-       if(ch == '\r')  return 1;
-       if(ch == '\n')  return 1;
-       return 0;
-}
-
-#endif
diff --git a/Usermode/include/errno.h b/Usermode/include/errno.h
deleted file mode 100644 (file)
index ea352f3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef _ERRNO_H_
-#define _ERRNO_H_
-
-// TODO: Fully implement errno.h, make sure it matches the kernel one
-
-extern int     _errno;
-#define        errno   _errno
-
-#define strerror(_x)   "Unimplemented"
-
-enum
-{
-       EOK,
-       EINVAL,
-       ERANGE,
-       ENODEV,
-       EBADF,
-       EINTR,
-       EAGAIN,
-       ENOMEM,
-
-       EADDRNOTAVAIL,
-       EINPROGRESS,
-
-       E_LAST
-};
-
-#endif
diff --git a/Usermode/include/fcntl.h b/Usermode/include/fcntl.h
deleted file mode 100644 (file)
index 5fee9a1..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Acess2 C Library (UNIX Emulation)
- * - By John Hodge (thePowersGang)
- *
- * fcntl.h
- * - ??
- */
-
-#ifndef _FCNTL_H_
-#define _FCNTL_H_
-
-#include <sys/sys.h>
-
-// Hacks to handle different behaviors in Acess
-
-// Open doesn't take a chmod
-#define open(_1,_2,...)        open(_1, _2)
-
-// Close returns void
-#define close(_1)      (close(_1),0)
-
-// Acess doesn't implement lseek
-#define lseek(_1,_2,_3)        (seek(_1,_2,_3),tell(_1))
-
-#endif
-
diff --git a/Usermode/include/image.h b/Usermode/include/image.h
deleted file mode 100644 (file)
index 69e1549..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- */
-#ifndef _IMAGE_H_
-#define _IMAGE_H_
-
-// === TYPES ===
-typedef struct sImage  tImage;
-struct sImage
-{
-       short   Width;
-       short   Height;
-        int    Format;
-       uint8_t Data[];
-};
-
-// === CONSTANTS ===
-enum eImageFormats
-{
-       IMGFMT_BGRA,
-       IMGFMT_RGB,
-       NUM_IMGFMTS
-};
-
-#endif
diff --git a/Usermode/include/net.h b/Usermode/include/net.h
deleted file mode 120000 (symlink)
index be2d196..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../Libraries/libnet.so_src/net.h
\ No newline at end of file
diff --git a/Usermode/include/readline.h b/Usermode/include/readline.h
deleted file mode 100644 (file)
index 555a24b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Acess2 Library Suite
- * - Readline
- * 
- * Text mode entry with history
- */
-#ifndef _READLINE_H_
-#define _READLINE_H_
-
-// === TYPES ===
-typedef struct sReadline       tReadline;
-
-// === STRUCTURES ===
-
-// === FUNCTIONS ===
-/**
- * 
- */
-extern tReadline       *Readline_Init(int UseHistory);
-
-/**
- * \brief Read a line from stdin
- * \return Heap string containing the command string (to be free'd by the caller)
- */
-extern char    *Readline(tReadline *Info);
-
-/**
- * \brief Read a line from stdin (non-blocking)
- * \return Heap string containing the command string (to be free'd by the caller)
- */
-extern char    *Readline_NonBlock(tReadline *Info);
-
-#endif
diff --git a/Usermode/include/setjmp.h b/Usermode/include/setjmp.h
deleted file mode 100644 (file)
index 53f3fbf..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Acess2 LibC
- * - By John Hodge (thePowersGang)
- * 
- * setjmp.h
- * - setjmp/longjmp support
- */
-#ifndef _LIBC_SETJMP_H_
-#define _LIBC_SETJMP_H_
-
-#if ARCHDIR_is_x86
-typedef uint32_t       jmp_buf[8];
-#elif ARCHDIR_is_x86_64
-typedef uint64_t       jmp_buf[16];
-#else
-# error "Unknown Architecture"
-#endif
-
-extern int     setjmp(jmp_buf buf);
-extern void    longjmp(jmp_buf buf, int val);
-
-#endif
-
diff --git a/Usermode/include/signal.h b/Usermode/include/signal.h
deleted file mode 100644 (file)
index cc72b00..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * signal.h
- * - POSIX Signal Emulation/Interface
- */
-#ifndef _SIGNAL_H_
-#define _SIGNAL_H_
-
-#define SIG_DFL        ((void*)0)
-#define SIG_ERR        ((void*)-1)
-
-#define        SIGABRT 6
-
-#define SIGPIPE        1001
-#define SIGCHLD        1002
-
-#endif
-
diff --git a/Usermode/include/sqlite3.h b/Usermode/include/sqlite3.h
deleted file mode 100644 (file)
index 55a7348..0000000
+++ /dev/null
@@ -1,4804 +0,0 @@
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the SQLite library
-** presents to client programs.  If a C-function, structure, datatype,
-** or constant definition does not appear in this file, then it is
-** not a published API of SQLite, is subject to change without
-** notice, and should not be referenced by programs that use SQLite.
-**
-** Some of the definitions that are in this file are marked as
-** "experimental".  Experimental interfaces are normally new
-** features recently added to SQLite.  We do not anticipate changes 
-** to experimental interfaces but reserve to make minor changes if
-** experience from use "in the wild" suggest such changes are prudent.
-**
-** The official C-language API documentation for SQLite is derived
-** from comments in this file.  This file is the authoritative source
-** on how SQLite interfaces are suppose to operate.
-**
-** The name of this file under configuration management is "sqlite.h.in".
-** The makefile makes some minor changes to this file (such as inserting
-** the version number) and changes its name to "sqlite3.h" as
-** part of the build process.
-**
-** @(#) $Id: sqlite.h.in,v 1.284 2008/02/06 14:11:35 drh Exp $
-*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
-#include <stdarg.h>     /* Needed for the definition of va_list */
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
-** Add the ability to override 'extern'
-*/
-#ifndef SQLITE_EXTERN
-# define SQLITE_EXTERN extern
-#endif
-
-/*
-** Make sure these symbols where not defined by some previous header
-** file.
-*/
-#ifdef SQLITE_VERSION
-# undef SQLITE_VERSION
-#endif
-#ifdef SQLITE_VERSION_NUMBER
-# undef SQLITE_VERSION_NUMBER
-#endif
-
-/*
-** CAPI3REF: Compile-Time Library Version Numbers {F10010}
-**
-** The SQLITE_VERSION and SQLITE_VERSION_NUMBER #defines in
-** the sqlite3.h file specify the version of SQLite with which
-** that header file is associated.
-**
-** The "version" of SQLite is a strong of the form "X.Y.Z".
-** The phrase "alpha" or "beta" might be appended after the Z.
-** The X value is major version number always 3 in SQLite3.
-** The X value only changes when  backwards compatibility is
-** broken and we intend to never break
-** backwards compatibility.  The Y value is the minor version
-** number and only changes when
-** there are major feature enhancements that are forwards compatible
-** but not backwards compatible.  The Z value is release number
-** and is incremented with
-** each release but resets back to 0 when Y is incremented.
-**
-** See also: [sqlite3_libversion()] and [sqlite3_libversion_number()].
-**
-** INVARIANTS:
-**
-** {F10011} The SQLITE_VERSION #define in the sqlite3.h header file
-**          evaluates to a string literal that is the SQLite version
-**          with which the header file is associated.
-**
-** {F10014} The SQLITE_VERSION_NUMBER #define resolves to an integer
-**          with the value  (X*1000000 + Y*1000 + Z) where X, Y, and
-**          Z are the major version, minor version, and release number.
-*/
-#define SQLITE_VERSION         "3.5.6"
-#define SQLITE_VERSION_NUMBER 3005006
-
-/*
-** CAPI3REF: Run-Time Library Version Numbers {F10020}
-** KEYWORDS: sqlite3_version
-**
-** These features provide the same information as the [SQLITE_VERSION]
-** and [SQLITE_VERSION_NUMBER] #defines in the header, but are associated
-** with the library instead of the header file.  Cautious programmers might
-** include a check in their application to verify that 
-** sqlite3_libversion_number() always returns the value 
-** [SQLITE_VERSION_NUMBER].
-**
-** The sqlite3_libversion() function returns the same information as is
-** in the sqlite3_version[] string constant.  The function is provided
-** for use in DLLs since DLL users usually do not have direct access to string
-** constants within the DLL.
-**
-** INVARIANTS:
-**
-** {F10021} The [sqlite3_libversion_number()] interface returns an integer
-**          equal to [SQLITE_VERSION_NUMBER]. 
-**
-** {F10022} The [sqlite3_version] string constant contains the text of the
-**          [SQLITE_VERSION] string. 
-**
-** {F10023} The [sqlite3_libversion()] function returns
-**          a pointer to the [sqlite3_version] string constant.
-*/
-SQLITE_EXTERN const char sqlite3_version[];
-const char *sqlite3_libversion(void);
-int sqlite3_libversion_number(void);
-
-/*
-** CAPI3REF: Test To See If The Library Is Threadsafe {F10100}
-**
-** SQLite can be compiled with or without mutexes.  When
-** the SQLITE_THREADSAFE C preprocessor macro is true, mutexes
-** are enabled and SQLite is threadsafe.  When that macro os false,
-** the mutexes are omitted.  Without the mutexes, it is not safe
-** to use SQLite from more than one thread.
-**
-** There is a measurable performance penalty for enabling mutexes.
-** So if speed is of utmost importance, it makes sense to disable
-** the mutexes.  But for maximum safety, mutexes should be enabled.
-** The default behavior is for mutexes to be enabled.
-**
-** This interface can be used by a program to make sure that the
-** version of SQLite that it is linking against was compiled with
-** the desired setting of the SQLITE_THREADSAFE macro.
-**
-** INVARIANTS:
-**
-** {F10101} The [sqlite3_threadsafe()] function returns nonzero if
-**          SQLite was compiled with its mutexes enabled or zero
-**          if SQLite was compiled with mutexes disabled.
-*/
-int sqlite3_threadsafe(void);
-
-/*
-** CAPI3REF: Database Connection Handle {F12000}
-** KEYWORDS: {database connection}
-**
-** Each open SQLite database is represented by pointer to an instance of the
-** opaque structure named "sqlite3".  It is useful to think of an sqlite3
-** pointer as an object.  The [sqlite3_open()], [sqlite3_open16()], and
-** [sqlite3_open_v2()] interfaces are its constructors
-** and [sqlite3_close()] is its destructor.  There are many other interfaces
-** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and
-** [sqlite3_busy_timeout()] to name but three) that are methods on this
-** object.
-*/
-typedef struct sqlite3 sqlite3;
-
-
-/*
-** CAPI3REF: 64-Bit Integer Types {F10200}
-** KEYWORDS: sqlite_int64 sqlite_uint64
-**
-** Because there is no cross-platform way to specify 64-bit integer types
-** SQLite includes typedefs for 64-bit signed and unsigned integers.
-**
-** The sqlite3_int64 and sqlite3_uint64 are the preferred type
-** definitions.  The sqlite_int64 and sqlite_uint64 types are
-** supported for backwards compatibility only.
-**
-** INVARIANTS:
-**
-** {F10201} The [sqlite_int64] and [sqlite3_int64] types specify a
-**          64-bit signed integer.
-**
-** {F10202} The [sqlite_uint64] and [sqlite3_uint64] types specify
-**          a 64-bit unsigned integer.
-*/
-#ifdef SQLITE_INT64_TYPE
-  typedef SQLITE_INT64_TYPE sqlite_int64;
-  typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
-#elif defined(_MSC_VER) || defined(__BORLANDC__)
-  typedef __int64 sqlite_int64;
-  typedef unsigned __int64 sqlite_uint64;
-#else
-  typedef long long int sqlite_int64;
-  typedef unsigned long long int sqlite_uint64;
-#endif
-typedef sqlite_int64 sqlite3_int64;
-typedef sqlite_uint64 sqlite3_uint64;
-
-/*
-** If compiling for a processor that lacks floating point support,
-** substitute integer for floating-point
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# define double sqlite3_int64
-#endif
-
-/*
-** CAPI3REF: Closing A Database Connection {F12010}
-**
-** This routine is the destructor for the [sqlite3] object.  
-**
-** Applications should [sqlite3_finalize | finalize] all
-** [prepared statements] and
-** [sqlite3_blob_close | close] all [sqlite3_blob | BLOBs] 
-** associated with the [sqlite3] object prior
-** to attempting to close the [sqlite3] object.
-**
-** <todo>What happens to pending transactions?  Are they
-** rolled back, or abandoned?</todo>
-**
-** INVARIANTS:
-**
-** {F12011} The [sqlite3_close()] interface destroys an [sqlite3] object
-**          allocated by a prior call to [sqlite3_open()],
-**          [sqlite3_open16()], or [sqlite3_open_v2()].
-**
-** {F12012} The [sqlite3_close()] function releases all memory used by the
-**          connection and closes all open files.
-**
-** {F12013} If the database connection contains
-**          [prepared statements] that have not been
-**          finalized by [sqlite3_finalize()], then [sqlite3_close()]
-**          returns [SQLITE_BUSY] and leaves the connection open.
-**
-** {F12014} Giving sqlite3_close() a NULL pointer is a harmless no-op.
-**
-** LIMITATIONS:
-**
-** {U12015} The parameter to [sqlite3_close()] must be an [sqlite3] object
-**          pointer previously obtained from [sqlite3_open()] or the 
-**          equivalent, or NULL.
-**
-** {U12016} The parameter to [sqlite3_close()] must not have been previously
-**          closed.
-*/
-int sqlite3_close(sqlite3 *);
-
-/*
-** The type for a callback function.
-** This is legacy and deprecated.  It is included for historical
-** compatibility and is not documented.
-*/
-typedef int (*sqlite3_callback)(void*,int,char**, char**);
-
-/*
-** CAPI3REF: One-Step Query Execution Interface {F12100}
-**
-** The sqlite3_exec() interface is a convenient way of running
-** one or more SQL statements without a lot of C code.  The
-** SQL statements are passed in as the second parameter to
-** sqlite3_exec().  The statements are evaluated one by one
-** until either an error or an interrupt is encountered or
-** until they are all done.  The 3rd parameter is an optional
-** callback that is invoked once for each row of any query results
-** produced by the SQL statements.  The 5th parameter tells where
-** to write any error messages.
-**
-** The sqlite3_exec() interface is implemented in terms of
-** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
-** The sqlite3_exec() routine does nothing that cannot be done
-** by [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
-** The sqlite3_exec() is just a convenient wrapper.
-**
-** INVARIANTS:
-** 
-** {F12101} The [sqlite3_exec()] interface evaluates zero or more UTF-8
-**          encoded, semicolon-separated, SQL statements in the
-**          zero-terminated string of its 2nd parameter within the
-**          context of the [sqlite3] object given in the 1st parameter.
-**
-** {F12104} The return value of [sqlite3_exec()] is SQLITE_OK if all
-**          SQL statements run successfully.
-**
-** {F12105} The return value of [sqlite3_exec()] is an appropriate 
-**          non-zero error code if any SQL statement fails.
-**
-** {F12107} If one or more of the SQL statements handed to [sqlite3_exec()]
-**          return results and the 3rd parameter is not NULL, then
-**          the callback function specified by the 3rd parameter is
-**          invoked once for each row of result.
-**
-** {F12110} If the callback returns a non-zero value then [sqlite3_exec()]
-**          will aborted the SQL statement it is currently evaluating,
-**          skip all subsequent SQL statements, and return [SQLITE_ABORT].
-**          <todo>What happens to *errmsg here?  Does the result code for
-**          sqlite3_errcode() get set?</todo>
-**
-** {F12113} The [sqlite3_exec()] routine will pass its 4th parameter through
-**          as the 1st parameter of the callback.
-**
-** {F12116} The [sqlite3_exec()] routine sets the 2nd parameter of its
-**          callback to be the number of columns in the current row of
-**          result.
-**
-** {F12119} The [sqlite3_exec()] routine sets the 3rd parameter of its 
-**          callback to be an array of pointers to strings holding the
-**          values for each column in the current result set row as
-**          obtained from [sqlite3_column_text()].
-**
-** {F12122} The [sqlite3_exec()] routine sets the 4th parameter of its
-**          callback to be an array of pointers to strings holding the
-**          names of result columns as obtained from [sqlite3_column_name()].
-**
-** {F12125} If the 3rd parameter to [sqlite3_exec()] is NULL then
-**          [sqlite3_exec()] never invokes a callback.  All query
-**          results are silently discarded.
-**
-** {F12128} If an error occurs while parsing or evaluating any of the SQL
-**          statements handed to [sqlite3_exec()] then [sqlite3_exec()] will
-**          return an [error code] other than [SQLITE_OK].
-**
-** {F12131} If an error occurs while parsing or evaluating any of the SQL
-**          handed to [sqlite3_exec()] and if the 5th parameter (errmsg)
-**          to [sqlite3_exec()] is not NULL, then an error message is
-**          allocated using the equivalent of [sqlite3_mprintf()] and
-**          *errmsg is made to point to that message.
-**
-** {F12134} The [sqlite3_exec()] routine does not change the value of
-**          *errmsg if errmsg is NULL or if there are no errors.
-**
-** {F12137} The [sqlite3_exec()] function sets the error code and message
-**          accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
-**
-** LIMITATIONS:
-**
-** {U12141} The first parameter to [sqlite3_exec()] must be an valid and open
-**          [database connection].
-**
-** {U12142} The database connection must not be closed while
-**          [sqlite3_exec()] is running.
-** 
-** {U12143} The calling function is should use [sqlite3_free()] to free
-**          the memory that *errmsg is left pointing at once the error
-**          message is no longer needed.
-**
-** {U12145} The SQL statement text in the 2nd parameter to [sqlite3_exec()]
-**          must remain unchanged while [sqlite3_exec()] is running.
-*/
-int sqlite3_exec(
-  sqlite3*,                                  /* An open database */
-  const char *sql,                           /* SQL to be evaluted */
-  int (*callback)(void*,int,char**,char**),  /* Callback function */
-  void *,                                    /* 1st argument to callback */
-  char **errmsg                              /* Error msg written here */
-);
-
-/*
-** CAPI3REF: Result Codes {F10210}
-** KEYWORDS: SQLITE_OK {error code} {error codes}
-**
-** Many SQLite functions return an integer result code from the set shown
-** here in order to indicates success or failure.
-**
-** See also: [SQLITE_IOERR_READ | extended result codes]
-*/
-#define SQLITE_OK           0   /* Successful result */
-/* beginning-of-error-codes */
-#define SQLITE_ERROR        1   /* SQL error or missing database */
-#define SQLITE_INTERNAL     2   /* Internal logic error in SQLite */
-#define SQLITE_PERM         3   /* Access permission denied */
-#define SQLITE_ABORT        4   /* Callback routine requested an abort */
-#define SQLITE_BUSY         5   /* The database file is locked */
-#define SQLITE_LOCKED       6   /* A table in the database is locked */
-#define SQLITE_NOMEM        7   /* A malloc() failed */
-#define SQLITE_READONLY     8   /* Attempt to write a readonly database */
-#define SQLITE_INTERRUPT    9   /* Operation terminated by sqlite3_interrupt()*/
-#define SQLITE_IOERR       10   /* Some kind of disk I/O error occurred */
-#define SQLITE_CORRUPT     11   /* The database disk image is malformed */
-#define SQLITE_NOTFOUND    12   /* NOT USED. Table or record not found */
-#define SQLITE_FULL        13   /* Insertion failed because database is full */
-#define SQLITE_CANTOPEN    14   /* Unable to open the database file */
-#define SQLITE_PROTOCOL    15   /* NOT USED. Database lock protocol error */
-#define SQLITE_EMPTY       16   /* Database is empty */
-#define SQLITE_SCHEMA      17   /* The database schema changed */
-#define SQLITE_TOOBIG      18   /* String or BLOB exceeds size limit */
-#define SQLITE_CONSTRAINT  19   /* Abort due to constraint violation */
-#define SQLITE_MISMATCH    20   /* Data type mismatch */
-#define SQLITE_MISUSE      21   /* Library used incorrectly */
-#define SQLITE_NOLFS       22   /* Uses OS features not supported on host */
-#define SQLITE_AUTH        23   /* Authorization denied */
-#define SQLITE_FORMAT      24   /* Auxiliary database format error */
-#define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
-#define SQLITE_NOTADB      26   /* File opened that is not a database file */
-#define SQLITE_ROW         100  /* sqlite3_step() has another row ready */
-#define SQLITE_DONE        101  /* sqlite3_step() has finished executing */
-/* end-of-error-codes */
-
-/*
-** CAPI3REF: Extended Result Codes {F10220}
-** KEYWORDS: {extended error code} {extended error codes}
-** KEYWORDS: {extended result codes}
-**
-** In its default configuration, SQLite API routines return one of 26 integer
-** [SQLITE_OK | result codes].  However, experience has shown that
-** many of these result codes are too course-grained.  They do not provide as
-** much information about problems as programmers might like.  In an effort to
-** address this, newer versions of SQLite (version 3.3.8 and later) include
-** support for additional result codes that provide more detailed information
-** about errors. The extended result codes are enabled or disabled
-** for each database connection using the [sqlite3_extended_result_codes()]
-** API.
-** 
-** Some of the available extended result codes are listed here.
-** One may expect the number of extended result codes will be expand
-** over time.  Software that uses extended result codes should expect
-** to see new result codes in future releases of SQLite.
-**
-** The SQLITE_OK result code will never be extended.  It will always
-** be exactly zero.
-** 
-** INVARIANTS:
-**
-** {F10223} The symbolic name for an extended result code always contains
-**          a related primary result code as a prefix.
-**
-** {F10224} Primary result code names contain a single "_" character.
-**
-** {F10225} Extended result code names contain two or more "_" characters.
-**
-** {F10226} The numeric value of an extended result code contains the
-**          numeric value of its corresponding primary result code it
-**          its least significant 8 bits.
-*/
-#define SQLITE_IOERR_READ          (SQLITE_IOERR | (1<<8))
-#define SQLITE_IOERR_SHORT_READ    (SQLITE_IOERR | (2<<8))
-#define SQLITE_IOERR_WRITE         (SQLITE_IOERR | (3<<8))
-#define SQLITE_IOERR_FSYNC         (SQLITE_IOERR | (4<<8))
-#define SQLITE_IOERR_DIR_FSYNC     (SQLITE_IOERR | (5<<8))
-#define SQLITE_IOERR_TRUNCATE      (SQLITE_IOERR | (6<<8))
-#define SQLITE_IOERR_FSTAT         (SQLITE_IOERR | (7<<8))
-#define SQLITE_IOERR_UNLOCK        (SQLITE_IOERR | (8<<8))
-#define SQLITE_IOERR_RDLOCK        (SQLITE_IOERR | (9<<8))
-#define SQLITE_IOERR_DELETE        (SQLITE_IOERR | (10<<8))
-#define SQLITE_IOERR_BLOCKED       (SQLITE_IOERR | (11<<8))
-#define SQLITE_IOERR_NOMEM         (SQLITE_IOERR | (12<<8))
-
-/*
-** CAPI3REF: Flags For File Open Operations {F10230}
-**
-** These bit values are intended for use in then
-** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
-*/
-#define SQLITE_OPEN_READONLY         0x00000001
-#define SQLITE_OPEN_READWRITE        0x00000002
-#define SQLITE_OPEN_CREATE           0x00000004
-#define SQLITE_OPEN_DELETEONCLOSE    0x00000008
-#define SQLITE_OPEN_EXCLUSIVE        0x00000010
-#define SQLITE_OPEN_MAIN_DB          0x00000100
-#define SQLITE_OPEN_TEMP_DB          0x00000200
-#define SQLITE_OPEN_TRANSIENT_DB     0x00000400
-#define SQLITE_OPEN_MAIN_JOURNAL     0x00000800
-#define SQLITE_OPEN_TEMP_JOURNAL     0x00001000
-#define SQLITE_OPEN_SUBJOURNAL       0x00002000
-#define SQLITE_OPEN_MASTER_JOURNAL   0x00004000
-
-/*
-** CAPI3REF: Device Characteristics {F10240}
-**
-** The xDeviceCapabilities method of the [sqlite3_io_methods]
-** object returns an integer which is a vector of the these
-** bit values expressing I/O characteristics of the mass storage
-** device that holds the file that the [sqlite3_io_methods]
-** refers to.
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic.  The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic.  The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around.  The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-*/
-#define SQLITE_IOCAP_ATOMIC          0x00000001
-#define SQLITE_IOCAP_ATOMIC512       0x00000002
-#define SQLITE_IOCAP_ATOMIC1K        0x00000004
-#define SQLITE_IOCAP_ATOMIC2K        0x00000008
-#define SQLITE_IOCAP_ATOMIC4K        0x00000010
-#define SQLITE_IOCAP_ATOMIC8K        0x00000020
-#define SQLITE_IOCAP_ATOMIC16K       0x00000040
-#define SQLITE_IOCAP_ATOMIC32K       0x00000080
-#define SQLITE_IOCAP_ATOMIC64K       0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND     0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL      0x00000400
-
-/*
-** CAPI3REF: File Locking Levels {F10250}
-**
-** SQLite uses one of these integer values as the second
-** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlite3_io_methods] object.
-*/
-#define SQLITE_LOCK_NONE          0
-#define SQLITE_LOCK_SHARED        1
-#define SQLITE_LOCK_RESERVED      2
-#define SQLITE_LOCK_PENDING       3
-#define SQLITE_LOCK_EXCLUSIVE     4
-
-/*
-** CAPI3REF: Synchronization Type Flags {F10260}
-**
-** When SQLite invokes the xSync() method of an
-** [sqlite3_io_methods] object it uses a combination of the
-** these integer values as the second argument.
-**
-** When the SQLITE_SYNC_DATAONLY flag is used, it means that the
-** sync operation only needs to flush data to mass storage.  Inode
-** information need not be flushed. The SQLITE_SYNC_NORMAL means 
-** to use normal fsync() semantics. The SQLITE_SYNC_FULL flag means 
-** to use Mac OS-X style fullsync instead of fsync().
-*/
-#define SQLITE_SYNC_NORMAL        0x00002
-#define SQLITE_SYNC_FULL          0x00003
-#define SQLITE_SYNC_DATAONLY      0x00010
-
-
-/*
-** CAPI3REF: OS Interface Open File Handle {F11110}
-**
-** An [sqlite3_file] object represents an open file in the OS
-** interface layer.  Individual OS interface implementations will
-** want to subclass this object by appending additional fields
-** for their own use.  The pMethods entry is a pointer to an
-** [sqlite3_io_methods] object that defines methods for performing
-** I/O operations on the open file.
-*/
-typedef struct sqlite3_file sqlite3_file;
-struct sqlite3_file {
-  const struct sqlite3_io_methods *pMethods;  /* Methods for an open file */
-};
-
-/*
-** CAPI3REF: OS Interface File Virtual Methods Object {F11120}
-**
-** Every file opened by the [sqlite3_vfs] xOpen method contains a pointer to
-** an instance of the this object.  This object defines the
-** methods used to perform various operations against the open file.
-**
-** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
-** [SQLITE_SYNC_FULL].  The first choice is the normal fsync().
-*  The second choice is an
-** OS-X style fullsync.  The SQLITE_SYNC_DATA flag may be ORed in to
-** indicate that only the data of the file and not its inode needs to be
-** synced.
-** 
-** The integer values to xLock() and xUnlock() are one of
-** <ul>
-** <li> [SQLITE_LOCK_NONE],
-** <li> [SQLITE_LOCK_SHARED],
-** <li> [SQLITE_LOCK_RESERVED],
-** <li> [SQLITE_LOCK_PENDING], or
-** <li> [SQLITE_LOCK_EXCLUSIVE].
-** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.  
-** The xCheckReservedLock() method looks
-** to see if any database connection, either in this
-** process or in some other process, is holding an RESERVED,
-** PENDING, or EXCLUSIVE lock on the file.  It returns true
-** if such a lock exists and false if not.
-** 
-** The xFileControl() method is a generic interface that allows custom
-** VFS implementations to directly control an open file using the
-** [sqlite3_file_control()] interface.  The second "op" argument
-** is an integer opcode.   The third
-** argument is a generic pointer which is intended to be a pointer
-** to a structure that may contain arguments or space in which to
-** write return values.  Potential uses for xFileControl() might be
-** functions to enable blocking locks with timeouts, to change the
-** locking strategy (for example to use dot-file locks), to inquire
-** about the status of a lock, or to break stale locks.  The SQLite
-** core reserves opcodes less than 100 for its own use. 
-** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
-** Applications that define a custom xFileControl method should use opcodes 
-** greater than 100 to avoid conflicts.
-**
-** The xSectorSize() method returns the sector size of the
-** device that underlies the file.  The sector size is the
-** minimum write that can be performed without disturbing
-** other bytes in the file.  The xDeviceCharacteristics()
-** method returns a bit vector describing behaviors of the
-** underlying device:
-**
-** <ul>
-** <li> [SQLITE_IOCAP_ATOMIC]
-** <li> [SQLITE_IOCAP_ATOMIC512]
-** <li> [SQLITE_IOCAP_ATOMIC1K]
-** <li> [SQLITE_IOCAP_ATOMIC2K]
-** <li> [SQLITE_IOCAP_ATOMIC4K]
-** <li> [SQLITE_IOCAP_ATOMIC8K]
-** <li> [SQLITE_IOCAP_ATOMIC16K]
-** <li> [SQLITE_IOCAP_ATOMIC32K]
-** <li> [SQLITE_IOCAP_ATOMIC64K]
-** <li> [SQLITE_IOCAP_SAFE_APPEND]
-** <li> [SQLITE_IOCAP_SEQUENTIAL]
-** </ul>
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic.  The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic.  The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around.  The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-*/
-typedef struct sqlite3_io_methods sqlite3_io_methods;
-struct sqlite3_io_methods {
-  int iVersion;
-  int (*xClose)(sqlite3_file*);
-  int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
-  int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
-  int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
-  int (*xSync)(sqlite3_file*, int flags);
-  int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
-  int (*xLock)(sqlite3_file*, int);
-  int (*xUnlock)(sqlite3_file*, int);
-  int (*xCheckReservedLock)(sqlite3_file*);
-  int (*xFileControl)(sqlite3_file*, int op, void *pArg);
-  int (*xSectorSize)(sqlite3_file*);
-  int (*xDeviceCharacteristics)(sqlite3_file*);
-  /* Additional methods may be added in future releases */
-};
-
-/*
-** CAPI3REF: Standard File Control Opcodes {F11310}
-**
-** These integer constants are opcodes for the xFileControl method
-** of the [sqlite3_io_methods] object and to the [sqlite3_file_control()]
-** interface.
-**
-** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging.  This
-** opcode cases the xFileControl method to write the current state of
-** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
-** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-*/
-#define SQLITE_FCNTL_LOCKSTATE        1
-
-/*
-** CAPI3REF: Mutex Handle {F17110}
-**
-** The mutex module within SQLite defines [sqlite3_mutex] to be an
-** abstract type for a mutex object.  The SQLite core never looks
-** at the internal representation of an [sqlite3_mutex].  It only
-** deals with pointers to the [sqlite3_mutex] object.
-**
-** Mutexes are created using [sqlite3_mutex_alloc()].
-*/
-typedef struct sqlite3_mutex sqlite3_mutex;
-
-/*
-** CAPI3REF: OS Interface Object {F11140}
-**
-** An instance of this object defines the interface between the
-** SQLite core and the underlying operating system.  The "vfs"
-** in the name of the object stands for "virtual file system".
-**
-** The iVersion field is initially 1 but may be larger for future
-** versions of SQLite.  Additional fields may be appended to this
-** object when the iVersion value is increased.
-**
-** The szOsFile field is the size of the subclassed [sqlite3_file]
-** structure used by this VFS.  mxPathname is the maximum length of
-** a pathname in this VFS.
-**
-** Registered vfs modules are kept on a linked list formed by
-** the pNext pointer.  The [sqlite3_vfs_register()]
-** and [sqlite3_vfs_unregister()] interfaces manage this list
-** in a thread-safe way.  The [sqlite3_vfs_find()] interface
-** searches the list.
-**
-** The pNext field is the only fields in the sqlite3_vfs 
-** structure that SQLite will ever modify.  SQLite will only access
-** or modify this field while holding a particular static mutex.
-** The application should never modify anything within the sqlite3_vfs
-** object once the object has been registered.
-**
-** The zName field holds the name of the VFS module.  The name must
-** be unique across all VFS modules.
-**
-** {F11141} SQLite will guarantee that the zFilename string passed to
-** xOpen() is a full pathname as generated by xFullPathname() and
-** that the string will be valid and unchanged until xClose() is
-** called.  {END} So the [sqlite3_file] can store a pointer to the
-** filename if it needs to remember the filename for some reason.
-**
-** {F11142} The flags argument to xOpen() includes all bits set in
-** the flags argument to [sqlite3_open_v2()].  Or if [sqlite3_open()]
-** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. {END}
-** If xOpen() opens a file read-only then it sets *pOutFlags to
-** include [SQLITE_OPEN_READONLY].  Other bits in *pOutFlags may be
-** set.
-** 
-** {F11143} SQLite will also add one of the following flags to the xOpen()
-** call, depending on the object being opened:
-** 
-** <ul>
-** <li>  [SQLITE_OPEN_MAIN_DB]
-** <li>  [SQLITE_OPEN_MAIN_JOURNAL]
-** <li>  [SQLITE_OPEN_TEMP_DB]
-** <li>  [SQLITE_OPEN_TEMP_JOURNAL]
-** <li>  [SQLITE_OPEN_TRANSIENT_DB]
-** <li>  [SQLITE_OPEN_SUBJOURNAL]
-** <li>  [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul> {END}
-**
-** The file I/O implementation can use the object type flags to
-** changes the way it deals with files.  For example, an application
-** that does not care about crash recovery or rollback, might make
-** the open of a journal file a no-op.  Writes to this journal are
-** also a no-op.  Any attempt to read the journal return SQLITE_IOERR.
-** Or the implementation might recognize the a database file will
-** be doing page-aligned sector reads and writes in a random order
-** and set up its I/O subsystem accordingly.
-** 
-** SQLite might also add one of the following flags to the xOpen
-** method:
-** 
-** <ul>
-** <li> [SQLITE_OPEN_DELETEONCLOSE]
-** <li> [SQLITE_OPEN_EXCLUSIVE]
-** </ul>
-** 
-** {F11145} The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed.  {F11146} The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP  databases, journals and for subjournals. 
-** {F11147} The [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened
-** for exclusive access.  This flag is set for all files except
-** for the main database file. {END}
-** 
-** {F11148} At least szOsFile bytes of memory is allocated by SQLite 
-** to hold the  [sqlite3_file] structure passed as the third 
-** argument to xOpen.  {END}  The xOpen method does not have to
-** allocate the structure; it should just fill it in.
-** 
-** {F11149} The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] 
-** to test for the existance of a file,
-** or [SQLITE_ACCESS_READWRITE] to test to see
-** if a file is readable and writable, or [SQLITE_ACCESS_READ]
-** to test to see if a file is at least readable.  {END} The file can be a 
-** directory.
-** 
-** {F11150} SQLite will always allocate at least mxPathname+1 byte for
-** the output buffers for xGetTempname and xFullPathname. {F11151} The exact
-** size of the output buffer is also passed as a parameter to both 
-** methods. {END} If the output buffer is not large enough, SQLITE_CANTOPEN
-** should be returned. As this is handled as a fatal error by SQLite,
-** vfs implementations should endeavor to prevent this by setting 
-** mxPathname to a sufficiently large value.
-** 
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
-** included in the VFS structure for completeness.
-** The xRandomness() function attempts to return nBytes bytes
-** of good-quality randomness into zOut.  The return value is
-** the actual number of bytes of randomness obtained.  The
-** xSleep() method cause the calling thread to sleep for at
-** least the number of microseconds given.  The xCurrentTime()
-** method returns a Julian Day Number for the current date and
-** time.
-*/
-typedef struct sqlite3_vfs sqlite3_vfs;
-struct sqlite3_vfs {
-  int iVersion;            /* Structure version number */
-  int szOsFile;            /* Size of subclassed sqlite3_file */
-  int mxPathname;          /* Maximum file pathname length */
-  sqlite3_vfs *pNext;      /* Next registered VFS */
-  const char *zName;       /* Name of this virtual file system */
-  void *pAppData;          /* Pointer to application-specific data */
-  int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
-               int flags, int *pOutFlags);
-  int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
-  int (*xAccess)(sqlite3_vfs*, const char *zName, int flags);
-  int (*xGetTempname)(sqlite3_vfs*, int nOut, char *zOut);
-  int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
-  void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
-  void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
-  void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol);
-  void (*xDlClose)(sqlite3_vfs*, void*);
-  int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
-  int (*xSleep)(sqlite3_vfs*, int microseconds);
-  int (*xCurrentTime)(sqlite3_vfs*, double*);
-  /* New fields may be appended in figure versions.  The iVersion
-  ** value will increment whenever this happens. */
-};
-
-/*
-** CAPI3REF: Flags for the xAccess VFS method {F11190}
-**
-** {F11191} These integer constants can be used as the third parameter to
-** the xAccess method of an [sqlite3_vfs] object. {END}  They determine
-** the kind of what kind of permissions the xAccess method is
-** looking for.  {F11192} With SQLITE_ACCESS_EXISTS, the xAccess method
-** simply checks to see if the file exists. {F11193} With
-** SQLITE_ACCESS_READWRITE, the xAccess method checks to see
-** if the file is both readable and writable.  {F11194} With
-** SQLITE_ACCESS_READ the xAccess method
-** checks to see if the file is readable.
-*/
-#define SQLITE_ACCESS_EXISTS    0
-#define SQLITE_ACCESS_READWRITE 1
-#define SQLITE_ACCESS_READ      2
-
-/*
-** CAPI3REF: Enable Or Disable Extended Result Codes {F12200}
-**
-** The sqlite3_extended_result_codes() routine enables or disables the
-** [SQLITE_IOERR_READ | extended result codes] feature of SQLite.
-** The extended result codes are disabled by default for historical
-** compatibility.
-**
-** INVARIANTS:
-**
-** {F12201} Each new [database connection] has the 
-**          [extended result codes] feature
-**          disabled by default.
-**
-** {F12202} The [sqlite3_extended_result_codes(D,F)] interface will enable
-**          [extended result codes] for the 
-**          [database connection] D if the F parameter
-**          is true, or disable them if F is false.
-*/
-int sqlite3_extended_result_codes(sqlite3*, int onoff);
-
-/*
-** CAPI3REF: Last Insert Rowid {F12220}
-**
-** Each entry in an SQLite table has a unique 64-bit signed
-** integer key called the "rowid". The rowid is always available
-** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
-** names are not also used by explicitly declared columns. If
-** the table has a column of type INTEGER PRIMARY KEY then that column
-** is another an alias for the rowid.
-**
-** This routine returns the rowid of the most recent
-** successful INSERT into the database from the database connection
-** shown in the first argument.  If no successful inserts
-** have ever occurred on this database connection, zero is returned.
-**
-** If an INSERT occurs within a trigger, then the rowid of the
-** inserted row is returned by this routine as long as the trigger
-** is running.  But once the trigger terminates, the value returned
-** by this routine reverts to the last value inserted before the
-** trigger fired.
-**
-** An INSERT that fails due to a constraint violation is not a
-** successful insert and does not change the value returned by this
-** routine.  Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK,
-** and INSERT OR ABORT make no changes to the return value of this
-** routine when their insertion fails.  When INSERT OR REPLACE 
-** encounters a constraint violation, it does not fail.  The
-** INSERT continues to completion after deleting rows that caused
-** the constraint problem so INSERT OR REPLACE will always change
-** the return value of this interface. 
-**
-** For the purposes of this routine, an insert is considered to
-** be successful even if it is subsequently rolled back.
-**
-** INVARIANTS:
-**
-** {F12221} The [sqlite3_last_insert_rowid()] function returns the
-**          rowid of the most recent successful insert done
-**          on the same database connection and within the same
-**          trigger context, or zero if there have
-**          been no qualifying inserts on that connection.
-**
-** {F12223} The [sqlite3_last_insert_rowid()] function returns
-**          same value when called from the same trigger context
-**          immediately before and after a ROLLBACK.
-**
-** LIMITATIONS:
-**
-** {U12232} If separate thread does a new insert on the same
-**          database connection while the [sqlite3_last_insert_rowid()]
-**          function is running and thus changes the last insert rowid,
-**          then the value returned by [sqlite3_last_insert_rowid()] is
-**          unpredictable and might not equal either the old or the new
-**          last insert rowid.
-*/
-sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
-
-/*
-** CAPI3REF: Count The Number Of Rows Modified {F12240}
-**
-** This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the connection specified by the first parameter.  Only
-** changes that are directly specified by the INSERT, UPDATE, or
-** DELETE statement are counted.  Auxiliary changes caused by
-** triggers are not counted. Use the [sqlite3_total_changes()] function
-** to find the total number of changes including changes caused by triggers.
-**
-** A "row changes" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement.  Rows that
-** are changed as side effects of REPLACE constraint resolution,
-** rollback, ABORT processing, DROP TABLE, or by any other
-** mechanisms do not count as direct row changes.
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a trigger.  Most SQL statements are
-** evaluated outside of any trigger.  This is the "top level"
-** trigger context.  If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger.  Subtriggers create subcontexts for their duration.
-**
-** Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** So when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level.
-** Within the body of a trigger, the sqlite3_changes() interface
-** can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include in changes
-** caused by subtriggers since they have their own context.
-**
-** SQLite implements the command "DELETE FROM table" without
-** a WHERE clause by dropping and recreating the table.  (This is much
-** faster than going through and deleting individual elements from the
-** table.)  Because of this optimization, the deletions in
-** "DELETE FROM table" are not row changes and will not be counted
-** by the sqlite3_changes() or [sqlite3_total_changes()] functions.
-** To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-**
-** INVARIANTS:
-**
-** {F12241} The [sqlite3_changes()] function returns the number of
-**          row changes caused by the most recent INSERT, UPDATE,
-**          or DELETE statement on the same database connection and
-**          within the same trigger context, or zero if there have
-**          not been any qualifying row changes.
-**
-** LIMITATIONS:
-**
-** {U12252} If a separate thread makes changes on the same database connection
-**          while [sqlite3_changes()] is running then the value returned
-**          is unpredictable and unmeaningful.
-*/
-int sqlite3_changes(sqlite3*);
-
-/*
-** CAPI3REF: Total Number Of Rows Modified {F12260}
-***
-** This function returns the number of row changes caused
-** by INSERT, UPDATE or DELETE statements since the database handle
-** was opened.  The count includes all changes from all trigger
-** contexts.  But the count does not include changes used to
-** implement REPLACE constraints, do rollbacks or ABORT processing,
-** or DROP table processing.
-** The changes
-** are counted as soon as the statement that makes them is completed 
-** (when the statement handle is passed to [sqlite3_reset()] or 
-** [sqlite3_finalize()]).
-**
-** SQLite implements the command "DELETE FROM table" without
-** a WHERE clause by dropping and recreating the table.  (This is much
-** faster than going
-** through and deleting individual elements form the table.)  Because of
-** this optimization, the change count for "DELETE FROM table" will be
-** zero regardless of the number of elements that were originally in the
-** table. To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-**
-** See also the [sqlite3_changes()] interface.
-**
-** INVARIANTS:
-** 
-** {F12261} The [sqlite3_total_changes()] returns the total number
-**          of row changes caused by INSERT, UPDATE, and/or DELETE
-**          statements on the same [database connection], in any
-**          trigger context, since the database connection was
-**          created.
-**
-** LIMITATIONS:
-**
-** {U12264} If a separate thread makes changes on the same database connection
-**          while [sqlite3_total_changes()] is running then the value 
-**          returned is unpredictable and unmeaningful.
-*/
-int sqlite3_total_changes(sqlite3*);
-
-/*
-** CAPI3REF: Interrupt A Long-Running Query {F12270}
-**
-** This function causes any pending database operation to abort and
-** return at its earliest opportunity. This routine is typically
-** called in response to a user action such as pressing "Cancel"
-** or Ctrl-C where the user wants a long query operation to halt
-** immediately.
-**
-** It is safe to call this routine from a thread different from the
-** thread that is currently running the database operation.  But it
-** is not safe to call this routine with a database connection that
-** is closed or might close before sqlite3_interrupt() returns.
-**
-** If an SQL is very nearly finished at the time when sqlite3_interrupt()
-** is called, then it might not have an opportunity to be interrupted.
-** It might continue to completion.
-** An SQL operation that is interrupted will return
-** [SQLITE_INTERRUPT].  If the interrupted SQL operation is an
-** INSERT, UPDATE, or DELETE that is inside an explicit transaction, 
-** then the entire transaction will be rolled back automatically.
-** A call to sqlite3_interrupt() has no effect on SQL statements
-** that are started after sqlite3_interrupt() returns.
-**
-** INVARIANTS:
-**
-** {F12271} The [sqlite3_interrupt()] interface will force all running
-**          SQL statements associated with the same database connection
-**          to halt after processing at most one additional row of
-**          data.
-**
-** {F12272} Any SQL statement that is interrupted by [sqlite3_interrupt()]
-**          will return [SQLITE_INTERRUPT].
-**
-** LIMITATIONS:
-**
-** {U12279} If the database connection closes while [sqlite3_interrupt()]
-**          is running then bad things will likely happen.
-*/
-void sqlite3_interrupt(sqlite3*);
-
-/*
-** CAPI3REF: Determine If An SQL Statement Is Complete {F10510}
-**
-** These routines are useful for command-line input to determine if the
-** currently entered text seems to form complete a SQL statement or
-** if additional input is needed before sending the text into
-** SQLite for parsing.  These routines return true if the input string
-** appears to be a complete SQL statement.  A statement is judged to be
-** complete if it ends with a semicolon token and is not a fragment of a
-** CREATE TRIGGER statement.  Semicolons that are embedded within
-** string literals or quoted identifier names or comments are not
-** independent tokens (they are part of the token in which they are
-** embedded) and thus do not count as a statement terminator.
-**
-** These routines do not parse the SQL and
-** so will not detect syntactically incorrect SQL.
-**
-** INVARIANTS:
-**
-** {F10511} The sqlite3_complete() and sqlite3_complete16() functions
-**          return true (non-zero) if and only if the last
-**          non-whitespace token in their input is a semicolon that
-**          is not in between the BEGIN and END of a CREATE TRIGGER
-**          statement.
-**
-** LIMITATIONS:
-**
-** {U10512} The input to sqlite3_complete() must be a zero-terminated
-**          UTF-8 string.
-**
-** {U10513} The input to sqlite3_complete16() must be a zero-terminated
-**          UTF-16 string in native byte order.
-*/
-int sqlite3_complete(const char *sql);
-int sqlite3_complete16(const void *sql);
-
-/*
-** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors {F12310}
-**
-** This routine identifies a callback function that might be
-** invoked whenever an attempt is made to open a database table 
-** that another thread or process has locked.
-** If the busy callback is NULL, then [SQLITE_BUSY]
-** or [SQLITE_IOERR_BLOCKED]
-** is returned immediately upon encountering the lock.
-** If the busy callback is not NULL, then the
-** callback will be invoked with two arguments.  The
-** first argument to the handler is a copy of the void* pointer which
-** is the third argument to this routine.  The second argument to
-** the handler is the number of times that the busy handler has
-** been invoked for this locking event.   If the
-** busy callback returns 0, then no additional attempts are made to
-** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
-** If the callback returns non-zero, then another attempt
-** is made to open the database for reading and the cycle repeats.
-**
-** The presence of a busy handler does not guarantee that
-** it will be invoked when there is lock contention.
-** If SQLite determines that invoking the busy handler could result in
-** a deadlock, it will go ahead and return [SQLITE_BUSY] or
-** [SQLITE_IOERR_BLOCKED] instead of invoking the
-** busy handler.
-** Consider a scenario where one process is holding a read lock that
-** it is trying to promote to a reserved lock and
-** a second process is holding a reserved lock that it is trying
-** to promote to an exclusive lock.  The first process cannot proceed
-** because it is blocked by the second and the second process cannot
-** proceed because it is blocked by the first.  If both processes
-** invoke the busy handlers, neither will make any progress.  Therefore,
-** SQLite returns [SQLITE_BUSY] for the first process, hoping that this
-** will induce the first process to release its read lock and allow
-** the second process to proceed.
-**
-** The default busy callback is NULL.
-**
-** The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
-** when SQLite is in the middle of a large transaction where all the
-** changes will not fit into the in-memory cache.  SQLite will
-** already hold a RESERVED lock on the database file, but it needs
-** to promote this lock to EXCLUSIVE so that it can spill cache
-** pages into the database file without harm to concurrent
-** readers.  If it is unable to promote the lock, then the in-memory
-** cache will be left in an inconsistent state and so the error
-** code is promoted from the relatively benign [SQLITE_BUSY] to
-** the more severe [SQLITE_IOERR_BLOCKED].  This error code promotion
-** forces an automatic rollback of the changes.  See the
-** <a href="http://www.sqlite.org/cvstrac/wiki?p=CorruptionFollowingBusyError">
-** CorruptionFollowingBusyError</a> wiki page for a discussion of why
-** this is important.
-**     
-** There can only be a single busy handler defined for each database
-** connection.  Setting a new busy handler clears any previous one. 
-** Note that calling [sqlite3_busy_timeout()] will also set or clear
-** the busy handler.
-**
-** INVARIANTS:
-**
-** {F12311} The [sqlite3_busy_handler()] function replaces the busy handler
-**          callback in the database connection identified by the 1st
-**          parameter with a new busy handler identified by the 2nd and 3rd
-**          parameters.
-**
-** {F12312} The default busy handler for new database connections is NULL.
-**
-** {F12314} When two or more database connection share a common cache,
-**          the busy handler for the database connection currently using
-**          the cache is invoked when the cache encounters a lock.
-**
-** {F12316} If a busy handler callback returns zero, then the SQLite
-**          interface that provoked the locking event will return
-**          [SQLITE_BUSY].
-**
-** {F12318} SQLite will invokes the busy handler with two argument which
-**          are a copy of the pointer supplied by the 3rd parameter to
-**          [sqlite3_busy_handler()] and a count of the number of prior
-**          invocations of the busy handler for the same locking event.
-**
-** LIMITATIONS:
-**
-** {U12319} A busy handler should not call close the database connection
-**          or prepared statement that invoked the busy handler.
-*/
-int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
-
-/*
-** CAPI3REF: Set A Busy Timeout {F12340}
-**
-** This routine sets a [sqlite3_busy_handler | busy handler]
-** that sleeps for a while when a
-** table is locked.  The handler will sleep multiple times until 
-** at least "ms" milliseconds of sleeping have been done. {F12343} After
-** "ms" milliseconds of sleeping, the handler returns 0 which
-** causes [sqlite3_step()] to return [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
-**
-** Calling this routine with an argument less than or equal to zero
-** turns off all busy handlers.
-**
-** There can only be a single busy handler for a particular database
-** connection.  If another busy handler was defined  
-** (using [sqlite3_busy_handler()]) prior to calling
-** this routine, that other busy handler is cleared.
-**
-** INVARIANTS:
-**
-** {F12341} The [sqlite3_busy_timeout()] function overrides any prior
-**          [sqlite3_busy_timeout()] or [sqlite3_busy_handler()] setting
-**          on the same database connection.
-**
-** {F12343} If the 2nd parameter to [sqlite3_busy_timeout()] is less than
-**          or equal to zero, then the busy handler is cleared so that
-**          all subsequent locking events immediately return [SQLITE_BUSY].
-**
-** {F12344} If the 2nd parameter to [sqlite3_busy_timeout()] is a positive
-**          number N, then a busy handler is set that repeatedly calls
-**          the xSleep() method in the VFS interface until either the
-**          lock clears or until the cumulative sleep time reported back
-**          by xSleep() exceeds N milliseconds.
-*/
-int sqlite3_busy_timeout(sqlite3*, int ms);
-
-/*
-** CAPI3REF: Convenience Routines For Running Queries {F12370}
-**
-** Definition: A <b>result table</b> is memory data structure created by the
-** [sqlite3_get_table()] interface.  A result table records the
-** complete query results from one or more queries.
-**
-** The table conceptually has a number of rows and columns.  But
-** these numbers are not part of the result table itself.  These
-** numbers are obtained separately.  Let N be the number of rows
-** and M be the number of columns.
-**
-** A result table is an array of pointers to zero-terminated
-** UTF-8 strings.  There are (N+1)*M elements in the array.  
-** The first M pointers point to zero-terminated strings that 
-** contain the names of the columns.
-** The remaining entries all point to query results.  NULL
-** values are give a NULL pointer.  All other values are in
-** their UTF-8 zero-terminated string representation as returned by
-** [sqlite3_column_text()].
-**
-** A result table might consists of one or more memory allocations.
-** It is not safe to pass a result table directly to [sqlite3_free()].
-** A result table should be deallocated using [sqlite3_free_table()].
-**
-** As an example of the result table format, suppose a query result
-** is as follows:
-**
-** <blockquote><pre>
-**        Name        | Age
-**        -----------------------
-**        Alice       | 43
-**        Bob         | 28
-**        Cindy       | 21
-** </pre></blockquote>
-**
-** There are two column (M==2) and three rows (N==3).  Thus the
-** result table has 8 entries.  Suppose the result table is stored
-** in an array names azResult.  Then azResult holds this content:
-**
-** <blockquote><pre>
-**        azResult&#91;0] = "Name";
-**        azResult&#91;1] = "Age";
-**        azResult&#91;2] = "Alice";
-**        azResult&#91;3] = "43";
-**        azResult&#91;4] = "Bob";
-**        azResult&#91;5] = "28";
-**        azResult&#91;6] = "Cindy";
-**        azResult&#91;7] = "21";
-** </pre></blockquote>
-**
-** The sqlite3_get_table() function evaluates one or more
-** semicolon-separated SQL statements in the zero-terminated UTF-8
-** string of its 2nd parameter.  It returns a result table to the
-** pointer given in its 3rd parameter.
-**
-** After the calling function has finished using the result, it should 
-** pass the pointer to the result table to sqlite3_free_table() in order to 
-** release the memory that was malloc-ed.  Because of the way the 
-** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
-** function must not try to call [sqlite3_free()] directly.  Only 
-** [sqlite3_free_table()] is able to release the memory properly and safely.
-**
-** The sqlite3_get_table() interface is implemented as a wrapper around
-** [sqlite3_exec()].  The sqlite3_get_table() routine does not have access
-** to any internal data structures of SQLite.  It uses only the public
-** interface defined here.  As a consequence, errors that occur in the
-** wrapper layer outside of the internal [sqlite3_exec()] call are not
-** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].
-**
-** INVARIANTS:
-**
-** {F12371} If a [sqlite3_get_table()] fails a memory allocation, then
-**          it frees the result table under construction, aborts the
-**          query in process, skips any subsequent queries, sets the
-**          *resultp output pointer to NULL and returns [SQLITE_NOMEM].
-**
-** {F12373} If the ncolumn parameter to [sqlite3_get_table()] is not NULL
-**          then [sqlite3_get_table()] write the number of columns in the
-**          result set of the query into *ncolumn if the query is
-**          successful (if the function returns SQLITE_OK).
-**
-** {F12374} If the nrow parameter to [sqlite3_get_table()] is not NULL
-**          then [sqlite3_get_table()] write the number of rows in the
-**          result set of the query into *nrow if the query is
-**          successful (if the function returns SQLITE_OK).
-**
-** {F12376} The [sqlite3_get_table()] function sets its *ncolumn value
-**          to the number of columns in the result set of the query in the
-**          sql parameter, or to zero if the query in sql has an empty
-**          result set.
-*/
-int sqlite3_get_table(
-  sqlite3*,             /* An open database */
-  const char *sql,      /* SQL to be evaluated */
-  char ***pResult,      /* Results of the query */
-  int *nrow,            /* Number of result rows written here */
-  int *ncolumn,         /* Number of result columns written here */
-  char **errmsg         /* Error msg written here */
-);
-void sqlite3_free_table(char **result);
-
-/*
-** CAPI3REF: Formatted String Printing Functions {F17400}
-**
-** These routines are workalikes of the "printf()" family of functions
-** from the standard C library.
-**
-** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
-** The strings returned by these two routines should be
-** released by [sqlite3_free()].   Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
-** memory to hold the resulting string.
-**
-** In sqlite3_snprintf() routine is similar to "snprintf()" from
-** the standard C library.  The result is written into the
-** buffer supplied as the second parameter whose size is given by
-** the first parameter. Note that the order of the
-** first two parameters is reversed from snprintf().  This is an
-** historical accident that cannot be fixed without breaking
-** backwards compatibility.  Note also that sqlite3_snprintf()
-** returns a pointer to its buffer instead of the number of
-** characters actually written into the buffer.  We admit that
-** the number of characters written would be a more useful return
-** value but we cannot change the implementation of sqlite3_snprintf()
-** now without breaking compatibility.
-**
-** As long as the buffer size is greater than zero, sqlite3_snprintf()
-** guarantees that the buffer is always zero-terminated.  The first
-** parameter "n" is the total size of the buffer, including space for
-** the zero terminator.  So the longest string that can be completely
-** written will be n-1 characters.
-**
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf formatting options apply.  In addition, there
-** is are "%q", "%Q", and "%z" options.
-**
-** The %q option works like %s in that it substitutes a null-terminated
-** string from the argument list.  But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal.  By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, so some string variable contains text as follows:
-**
-** <blockquote><pre>
-**  char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-**  sqlite3_exec(db, zSQL, 0, 0, 0);
-**  sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-**  INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct.  Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-**  INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error.  As a general rule you
-** should always use %q instead of %s when inserting text into a string 
-** literal.
-**
-** The %Q option works like %q except it also adds single quotes around
-** the outside of the total string.  Or if the parameter in the argument
-** list is a NULL pointer, %Q substitutes the text "NULL" (without single
-** quotes) in place of the %Q option. {END}  So, for example, one could say:
-**
-** <blockquote><pre>
-**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-**  sqlite3_exec(db, zSQL, 0, 0, 0);
-**  sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** The "%z" formatting option works exactly like "%s" with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string. {END}
-**
-** INVARIANTS:
-**
-** {F17403}  The [sqlite3_mprintf()] and [sqlite3_vmprintf()] interfaces
-**           return either pointers to zero-terminated UTF-8 strings held in
-**           memory obtained from [sqlite3_malloc()] or NULL pointers if
-**           a call to [sqlite3_malloc()] fails.
-**
-** {F17406}  The [sqlite3_snprintf()] interface writes a zero-terminated
-**           UTF-8 string into the buffer pointed to by the second parameter
-**           provided that the first parameter is greater than zero.
-**
-** {F17407}  The [sqlite3_snprintf()] interface does not writes slots of
-**           its output buffer (the second parameter) outside the range
-**           of 0 through N-1 (where N is the first parameter)
-**           regardless of the length of the string
-**           requested by the format specification.
-**   
-*/
-char *sqlite3_mprintf(const char*,...);
-char *sqlite3_vmprintf(const char*, va_list);
-char *sqlite3_snprintf(int,char*,const char*, ...);
-
-/*
-** CAPI3REF: Memory Allocation Subsystem {F17300}
-**
-** The SQLite core  uses these three routines for all of its own
-** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation.  The
-** windows VFS uses native malloc and free for some operations.
-**
-** The sqlite3_malloc() routine returns a pointer to a block
-** of memory at least N bytes in length, where N is the parameter.
-** If sqlite3_malloc() is unable to obtain sufficient free
-** memory, it returns a NULL pointer.  If the parameter N to
-** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
-** a NULL pointer.
-**
-** Calling sqlite3_free() with a pointer previously returned
-** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
-** that it might be reused.  The sqlite3_free() routine is
-** a no-op if is called with a NULL pointer.  Passing a NULL pointer
-** to sqlite3_free() is harmless.  After being freed, memory
-** should neither be read nor written.  Even reading previously freed
-** memory might result in a segmentation fault or other severe error.
-** Memory corruption, a segmentation fault, or other severe error
-** might result if sqlite3_free() is called with a non-NULL pointer that
-** was not obtained from sqlite3_malloc() or sqlite3_free().
-**
-** The sqlite3_realloc() interface attempts to resize a
-** prior memory allocation to be at least N bytes, where N is the
-** second parameter.  The memory allocation to be resized is the first
-** parameter.  If the first parameter to sqlite3_realloc()
-** is a NULL pointer then its behavior is identical to calling
-** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
-** If the second parameter to sqlite3_realloc() is zero or
-** negative then the behavior is exactly the same as calling
-** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
-** Sqlite3_realloc() returns a pointer to a memory allocation
-** of at least N bytes in size or NULL if sufficient memory is unavailable.
-** If M is the size of the prior allocation, then min(N,M) bytes
-** of the prior allocation are copied into the beginning of buffer returned
-** by sqlite3_realloc() and the prior allocation is freed.
-** If sqlite3_realloc() returns NULL, then the prior allocation
-** is not freed.
-**
-** The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary. {END}
-**
-** The default implementation
-** of the memory allocation subsystem uses the malloc(), realloc()
-** and free() provided by the standard C library. {F17382} However, if 
-** SQLite is compiled with the following C preprocessor macro
-**
-** <blockquote> SQLITE_MEMORY_SIZE=<i>NNN</i> </blockquote>
-**
-** where <i>NNN</i> is an integer, then SQLite create a static
-** array of at least <i>NNN</i> bytes in size and use that array
-** for all of its dynamic memory allocation needs. {END}  Additional
-** memory allocator options may be added in future releases.
-**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted.  That capability
-** is no longer provided.  Only built-in memory allocators can be
-** used.
-**
-** The windows OS interface layer calls
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular windows
-** installation.  Memory allocation errors are detected, but
-** they are reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
-** INVARIANTS:
-**
-** {F17303}  The [sqlite3_malloc(N)] interface returns either a pointer to 
-**           newly checked-out block of at least N bytes of memory
-**           that is 8-byte aligned, 
-**           or it returns NULL if it is unable to fulfill the request.
-**
-** {F17304}  The [sqlite3_malloc(N)] interface returns a NULL pointer if
-**           N is less than or equal to zero.
-**
-** {F17305}  The [sqlite3_free(P)] interface releases memory previously
-**           returned from [sqlite3_malloc()] or [sqlite3_realloc()],
-**           making it available for reuse.
-**
-** {F17306}  A call to [sqlite3_free(NULL)] is a harmless no-op.
-**
-** {F17310}  A call to [sqlite3_realloc(0,N)] is equivalent to a call
-**           to [sqlite3_malloc(N)].
-**
-** {F17312}  A call to [sqlite3_realloc(P,0)] is equivalent to a call
-**           to [sqlite3_free(P)].
-**
-** {F17315}  The SQLite core uses [sqlite3_malloc()], [sqlite3_realloc()],
-**           and [sqlite3_free()] for all of its memory allocation and
-**           deallocation needs.
-**
-** {F17318}  The [sqlite3_realloc(P,N)] interface returns either a pointer
-**           to a block of checked-out memory of at least N bytes in size
-**           that is 8-byte aligned, or a NULL pointer.
-**
-** {F17321}  When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
-**           copies the first K bytes of content from P into the newly allocated
-**           where K is the lessor of N and the size of the buffer P.
-**
-** {F17322}  When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
-**           releases the buffer P.
-**
-** {F17323}  When [sqlite3_realloc(P,N)] returns NULL, the buffer P is
-**           not modified or released.
-**
-** LIMITATIONS:
-**
-** {U17350}  The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
-**           must be either NULL or else a pointer obtained from a prior
-**           invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that has
-**           not been released.
-**
-** {U17351}  The application must not read or write any part of 
-**           a block of memory after it has been released using
-**           [sqlite3_free()] or [sqlite3_realloc()].
-**
-*/
-void *sqlite3_malloc(int);
-void *sqlite3_realloc(void*, int);
-void sqlite3_free(void*);
-
-/*
-** CAPI3REF: Memory Allocator Statistics {F17370}
-**
-** SQLite provides these two interfaces for reporting on the status
-** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()]
-** the memory allocation subsystem included within the SQLite.
-**
-** INVARIANTS:
-**
-** {F17371} The [sqlite3_memory_used()] routine returns the
-**          number of bytes of memory currently outstanding 
-**          (malloced but not freed).
-**
-** {F17373} The [sqlite3_memory_highwater()] routine returns the maximum
-**          value of [sqlite3_memory_used()] 
-**          since the highwater mark was last reset.
-**
-** {F17374} The values returned by [sqlite3_memory_used()] and
-**          [sqlite3_memory_highwater()] include any overhead
-**          added by SQLite in its implementation of [sqlite3_malloc()],
-**          but not overhead added by the any underlying system library
-**          routines that [sqlite3_malloc()] may call.
-** 
-** {F17375} The memory highwater mark is reset to the current value of
-**          [sqlite3_memory_used()] if and only if the parameter to
-**          [sqlite3_memory_highwater()] is true.  The value returned
-**          by [sqlite3_memory_highwater(1)] is the highwater mark
-**          prior to the reset.
-*/
-sqlite3_int64 sqlite3_memory_used(void);
-sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
-
-/*
-** CAPI3REF: Compile-Time Authorization Callbacks {F12500}
-**
-** This routine registers a authorizer callback with a particular
-** database connection, supplied in the first argument.
-** The authorizer callback is invoked as SQL statements are being compiled
-** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()].  At various
-** points during the compilation process, as logic is being created
-** to perform various actions, the authorizer callback is invoked to
-** see if those actions are allowed.  The authorizer callback should
-** return SQLITE_OK to allow the action, [SQLITE_IGNORE] to disallow the
-** specific action but allow the SQL statement to continue to be
-** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
-** rejected with an error.   If the authorizer callback returns
-** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
-** then [sqlite3_prepare_v2()] or equivalent call that triggered
-** the authorizer will fail with an error message.
-**
-** When the callback returns [SQLITE_OK], that means the operation
-** requested is ok.  When the callback returns [SQLITE_DENY], the
-** [sqlite3_prepare_v2()] or equivalent call that triggered the
-** authorizer will fail with an error message explaining that
-** access is denied.  If the authorizer code is [SQLITE_READ]
-** and the callback returns [SQLITE_IGNORE] then the prepared
-** statement is constructed to insert a NULL value in place of
-** the table column that would have
-** been read if [SQLITE_OK] had been returned.  The [SQLITE_IGNORE]
-** return can be used to deny an untrusted user access to individual
-** columns of a table.
-**
-** The first parameter to the authorizer callback is a copy of
-** the third parameter to the sqlite3_set_authorizer() interface.
-** The second parameter to the callback is an integer 
-** [SQLITE_COPY | action code] that specifies the particular action
-** to be authorized. The third through sixth
-** parameters to the callback are zero-terminated strings that contain 
-** additional details about the action to be authorized.
-**
-** An authorizer is used when preparing SQL statements from an untrusted
-** source, to ensure that the SQL statements do not try to access data
-** that they are not allowed to see, or that they do not try to
-** execute malicious statements that damage the database.  For
-** example, an application may allow a user to enter arbitrary
-** SQL queries for evaluation by a database.  But the application does
-** not want the user to be able to make arbitrary changes to the
-** database.  An authorizer could then be put in place while the
-** user-entered SQL is being prepared that disallows everything
-** except SELECT statements.  
-**
-** Only a single authorizer can be in place on a database connection
-** at a time.  Each call to sqlite3_set_authorizer overrides the
-** previous call.  Disable the authorizer by installing a NULL callback.
-** The authorizer is disabled by default.
-**
-** Note that the authorizer callback is invoked only during 
-** [sqlite3_prepare()] or its variants.  Authorization is not
-** performed during statement evaluation in [sqlite3_step()].
-**
-** INVARIANTS:
-**
-** {F12501} The [sqlite3_set_authorizer(D,...)] interface registers a
-**          authorizer callback with database connection D.
-**
-** {F12502} The authorizer callback is invoked as SQL statements are
-**          being compiled
-**
-** {F12503} If the authorizer callback returns any value other than
-**          [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] then
-**          the [sqlite3_prepare_v2()] or equivalent call that caused
-**          the authorizer callback to run shall fail with an
-**          [SQLITE_ERROR] error code and an appropriate error message.
-**
-** {F12504} When the authorizer callback returns [SQLITE_OK], the operation
-**          described is coded normally.
-**
-** {F12505} When the authorizer callback returns [SQLITE_DENY], the
-**          [sqlite3_prepare_v2()] or equivalent call that caused the
-**          authorizer callback to run shall fail
-**          with an [SQLITE_ERROR] error code and an error message
-**          explaining that access is denied.
-**
-** {F12506} If the authorizer code (the 2nd parameter to the authorizer
-**          callback) is [SQLITE_READ] and the authorizer callback returns
-**          [SQLITE_IGNORE] then the prepared statement is constructed to
-**          insert a NULL value in place of the table column that would have
-**          been read if [SQLITE_OK] had been returned.
-**
-** {F12507} If the authorizer code (the 2nd parameter to the authorizer
-**          callback) is anything other than [SQLITE_READ], then
-**          a return of [SQLITE_IGNORE] has the same effect as [SQLITE_DENY]. 
-**
-** {F12510} The first parameter to the authorizer callback is a copy of
-**          the third parameter to the [sqlite3_set_authorizer()] interface.
-**
-** {F12511} The second parameter to the callback is an integer 
-**          [SQLITE_COPY | action code] that specifies the particular action
-**          to be authorized.
-**
-** {F12512} The third through sixth parameters to the callback are
-**          zero-terminated strings that contain 
-**          additional details about the action to be authorized.
-**
-** {F12520} Each call to [sqlite3_set_authorizer()] overrides the
-**          any previously installed authorizer.
-**
-** {F12521} A NULL authorizer means that no authorization
-**          callback is invoked.
-**
-** {F12522} The default authorizer is NULL.
-*/
-int sqlite3_set_authorizer(
-  sqlite3*,
-  int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
-  void *pUserData
-);
-
-/*
-** CAPI3REF: Authorizer Return Codes {F12590}
-**
-** The [sqlite3_set_authorizer | authorizer callback function] must
-** return either [SQLITE_OK] or one of these two constants in order
-** to signal SQLite whether or not the action is permitted.  See the
-** [sqlite3_set_authorizer | authorizer documentation] for additional
-** information.
-*/
-#define SQLITE_DENY   1   /* Abort the SQL statement with an error */
-#define SQLITE_IGNORE 2   /* Don't allow access, but don't generate an error */
-
-/*
-** CAPI3REF: Authorizer Action Codes {F12550}
-**
-** The [sqlite3_set_authorizer()] interface registers a callback function
-** that is invoked to authorizer certain SQL statement actions.  The
-** second parameter to the callback is an integer code that specifies
-** what action is being authorized.  These are the integer action codes that
-** the authorizer callback may be passed.
-**
-** These action code values signify what kind of operation is to be 
-** authorized.  The 3rd and 4th parameters to the authorization
-** callback function will be parameters or NULL depending on which of these
-** codes is used as the second parameter.  The 5th parameter to the
-** authorizer callback is the name of the database ("main", "temp", 
-** etc.) if applicable.  The 6th parameter to the authorizer callback
-** is the name of the inner-most trigger or view that is responsible for
-** the access attempt or NULL if this access attempt is directly from 
-** top-level SQL code.
-**
-** INVARIANTS:
-**
-** {F12551} The second parameter to an 
-**          [sqlite3_set_authorizer | authorizer callback is always an integer
-**          [SQLITE_COPY | authorizer code] that specifies what action
-**          is being authorized.
-**
-** {F12552} The 3rd and 4th parameters to the 
-**          [sqlite3_set_authorizer | authorization callback function]
-**          will be parameters or NULL depending on which 
-**          [SQLITE_COPY | authorizer code] is used as the second parameter.
-**
-** {F12553} The 5th parameter to the
-**          [sqlite3_set_authorizer | authorizer callback] is the name
-**          of the database (example: "main", "temp", etc.) if applicable.
-**
-** {F12554} The 6th parameter to the
-**          [sqlite3_set_authorizer | authorizer callback] is the name
-**          of the inner-most trigger or view that is responsible for
-**          the access attempt or NULL if this access attempt is directly from 
-**          top-level SQL code.
-*/
-/******************************************* 3rd ************ 4th ***********/
-#define SQLITE_CREATE_INDEX          1   /* Index Name      Table Name      */
-#define SQLITE_CREATE_TABLE          2   /* Table Name      NULL            */
-#define SQLITE_CREATE_TEMP_INDEX     3   /* Index Name      Table Name      */
-#define SQLITE_CREATE_TEMP_TABLE     4   /* Table Name      NULL            */
-#define SQLITE_CREATE_TEMP_TRIGGER   5   /* Trigger Name    Table Name      */
-#define SQLITE_CREATE_TEMP_VIEW      6   /* View Name       NULL            */
-#define SQLITE_CREATE_TRIGGER        7   /* Trigger Name    Table Name      */
-#define SQLITE_CREATE_VIEW           8   /* View Name       NULL            */
-#define SQLITE_DELETE                9   /* Table Name      NULL            */
-#define SQLITE_DROP_INDEX           10   /* Index Name      Table Name      */
-#define SQLITE_DROP_TABLE           11   /* Table Name      NULL            */
-#define SQLITE_DROP_TEMP_INDEX      12   /* Index Name      Table Name      */
-#define SQLITE_DROP_TEMP_TABLE      13   /* Table Name      NULL            */
-#define SQLITE_DROP_TEMP_TRIGGER    14   /* Trigger Name    Table Name      */
-#define SQLITE_DROP_TEMP_VIEW       15   /* View Name       NULL            */
-#define SQLITE_DROP_TRIGGER         16   /* Trigger Name    Table Name      */
-#define SQLITE_DROP_VIEW            17   /* View Name       NULL            */
-#define SQLITE_INSERT               18   /* Table Name      NULL            */
-#define SQLITE_PRAGMA               19   /* Pragma Name     1st arg or NULL */
-#define SQLITE_READ                 20   /* Table Name      Column Name     */
-#define SQLITE_SELECT               21   /* NULL            NULL            */
-#define SQLITE_TRANSACTION          22   /* NULL            NULL            */
-#define SQLITE_UPDATE               23   /* Table Name      Column Name     */
-#define SQLITE_ATTACH               24   /* Filename        NULL            */
-#define SQLITE_DETACH               25   /* Database Name   NULL            */
-#define SQLITE_ALTER_TABLE          26   /* Database Name   Table Name      */
-#define SQLITE_REINDEX              27   /* Index Name      NULL            */
-#define SQLITE_ANALYZE              28   /* Table Name      NULL            */
-#define SQLITE_CREATE_VTABLE        29   /* Table Name      Module Name     */
-#define SQLITE_DROP_VTABLE          30   /* Table Name      Module Name     */
-#define SQLITE_FUNCTION             31   /* Function Name   NULL            */
-#define SQLITE_COPY                  0   /* No longer used */
-
-/*
-** CAPI3REF: Tracing And Profiling Functions {F12280}
-**
-** These routines register callback functions that can be used for
-** tracing and profiling the execution of SQL statements.
-**
-** The callback function registered by sqlite3_trace() is invoked at
-** various times when an SQL statement is being run by [sqlite3_step()].
-** The callback returns a UTF-8 rendering of the SQL statement text
-** as the statement first begins executing.  Additional callbacks occur
-** as each triggersubprogram is entered.  The callbacks for triggers
-** contain a UTF-8 SQL comment that identifies the trigger.
-** 
-** The callback function registered by sqlite3_profile() is invoked
-** as each SQL statement finishes.  The profile callback contains
-** the original statement text and an estimate of wall-clock time
-** of how long that statement took to run.
-**
-** The sqlite3_profile() API is currently considered experimental and
-** is subject to change or removal in a future release.
-**
-** The trigger reporting feature of the trace callback is considered
-** experimental and is subject to change or removal in future releases.
-** Future versions of SQLite might also add new trace callback 
-** invocations.
-**
-** INVARIANTS:
-**
-** {F12281} The callback function registered by [sqlite3_trace()] is
-**          whenever an SQL statement first begins to execute and
-**          whenever a trigger subprogram first begins to run.
-**
-** {F12282} Each call to [sqlite3_trace()] overrides the previously
-**          registered trace callback.
-**
-** {F12283} A NULL trace callback disables tracing.
-**
-** {F12284} The first argument to the trace callback is a copy of
-**          the pointer which was the 3rd argument to [sqlite3_trace()].
-**
-** {F12285} The second argument to the trace callback is a
-**          zero-terminated UTF8 string containing the original text
-**          of the SQL statement as it was passed into [sqlite3_prepare_v2()]
-**          or the equivalent, or an SQL comment indicating the beginning
-**          of a trigger subprogram.
-**
-** {F12287} The callback function registered by [sqlite3_profile()] is invoked
-**          as each SQL statement finishes.
-**
-** {F12288} The first parameter to the profile callback is a copy of
-**          the 3rd parameter to [sqlite3_profile()].
-**
-** {F12289} The second parameter to the profile callback is a
-**          zero-terminated UTF-8 string that contains the complete text of
-**          the SQL statement as it was processed by [sqlite3_prepare_v2()]
-**          or the equivalent.
-**
-** {F12290} The third parameter to the profile  callback is an estimate
-**          of the number of nanoseconds of wall-clock time required to
-**          run the SQL statement from start to finish.
-*/
-void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-void *sqlite3_profile(sqlite3*,
-   void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
-
-/*
-** CAPI3REF: Query Progress Callbacks {F12910}
-**
-** This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()].   An example use for this 
-** interface is to keep a GUI updated during a large query.
-**
-** If the progress callback returns non-zero, the opertion is
-** interrupted.  This feature can be used to implement a
-** "Cancel" button on a GUI dialog box.
-**
-** INVARIANTS:
-**
-** {F12911} The callback function registered by [sqlite3_progress_handler()]
-**          is invoked periodically during long running calls to
-**          [sqlite3_step()].
-**
-** {F12912} The progress callback is invoked once for every N virtual
-**          machine opcodes, where N is the second argument to 
-**          the [sqlite3_progress_handler()] call that registered
-**          the callback.  <todo>What if N is less than 1?</todo>
-**
-** {F12913} The progress callback itself is identified by the third
-**          argument to [sqlite3_progress_handler()].
-**
-** {F12914} The fourth argument [sqlite3_progress_handler()] is a
-***         void pointer passed to the progress callback
-**          function each time it is invoked.
-**
-** {F12915} If a call to [sqlite3_step()] results in fewer than
-**          N opcodes being executed,
-**          then the progress callback is never invoked. {END}
-** 
-** {F12916} Every call to [sqlite3_progress_handler()]
-**          overwrites any previously registere progress handler.
-**
-** {F12917} If the progress handler callback is NULL then no progress
-**          handler is invoked.
-**
-** {F12918} If the progress callback returns a result other than 0, then
-**          the behavior is a if [sqlite3_interrupt()] had been called.
-*/
-void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
-
-/*
-** CAPI3REF: Opening A New Database Connection {F12700}
-**
-** These routines open an SQLite database file whose name
-** is given by the filename argument.
-** The filename argument is interpreted as UTF-8
-** for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
-** in the native byte order for [sqlite3_open16()].
-** An [sqlite3*] handle is usually returned in *ppDb, even
-** if an error occurs.  The only exception is if SQLite is unable
-** to allocate memory to hold the [sqlite3] object, a NULL will
-** be written into *ppDb instead of a pointer to the [sqlite3] object.
-** If the database is opened (and/or created)
-** successfully, then [SQLITE_OK] is returned.  Otherwise an
-** error code is returned.  The
-** [sqlite3_errmsg()] or [sqlite3_errmsg16()]  routines can be used to obtain
-** an English language description of the error.
-**
-** The default encoding for the database will be UTF-8 if
-** [sqlite3_open()] or [sqlite3_open_v2()] is called and
-** UTF-16 in the native byte order if [sqlite3_open16()] is used.
-**
-** Whether or not an error occurs when it is opened, resources
-** associated with the [sqlite3*] handle should be released by passing it
-** to [sqlite3_close()] when it is no longer required.
-**
-** The [sqlite3_open_v2()] interface works like [sqlite3_open()] 
-** except that it acccepts two additional parameters for additional control
-** over the new database connection.  The flags parameter can be
-** one of:
-**
-** <ol>
-** <li>  [SQLITE_OPEN_READONLY]
-** <li>  [SQLITE_OPEN_READWRITE]
-** <li>  [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
-** </ol>
-**
-** The first value opens the database read-only. 
-** If the database does not previously exist, an error is returned.
-** The second option opens
-** the database for reading and writing if possible, or reading only if
-** if the file is write protected.  In either case the database
-** must already exist or an error is returned.  The third option
-** opens the database for reading and writing and creates it if it does
-** not already exist.
-** The third options is behavior that is always used for [sqlite3_open()]
-** and [sqlite3_open16()].
-**
-** If the filename is ":memory:", then an private
-** in-memory database is created for the connection.  This in-memory
-** database will vanish when the database connection is closed.  Future
-** version of SQLite might make use of additional special filenames
-** that begin with the ":" character.  It is recommended that 
-** when a database filename really does begin with
-** ":" that you prefix the filename with a pathname like "./" to
-** avoid ambiguity.
-**
-** If the filename is an empty string, then a private temporary
-** on-disk database will be created.  This private database will be
-** automatically deleted as soon as the database connection is closed.
-**
-** The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system 
-** interface that the new database connection should use.  If the
-** fourth parameter is a NULL pointer then the default [sqlite3_vfs]
-** object is used.
-**
-** <b>Note to windows users:</b>  The encoding used for the filename argument
-** of [sqlite3_open()] and [sqlite3_open_v2()] must be UTF-8, not whatever
-** codepage is currently defined.  Filenames containing international
-** characters must be converted to UTF-8 prior to passing them into
-** [sqlite3_open()] or [sqlite3_open_v2()].
-**
-** INVARIANTS:
-**
-** {F12701} The [sqlite3_open()], [sqlite3_open16()], and
-**          [sqlite3_open_v2()] interfaces create a new
-**          [database connection] associated with
-**          the database file given in their first parameter.
-**
-** {F12702} The filename argument is interpreted as UTF-8
-**          for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
-**          in the native byte order for [sqlite3_open16()].
-**
-** {F12703} A successful invocation of [sqlite3_open()], [sqlite3_open16()], 
-**          or [sqlite3_open_v2()] writes a pointer to a new
-**          [database connection] into *ppDb.
-**
-** {F12704} The [sqlite3_open()], [sqlite3_open16()], and
-**          [sqlite3_open_v2()] interfaces return [SQLITE_OK] upon success,
-**          or an appropriate [error code] on failure.
-**
-** {F12706} The default text encoding for a new database created using
-**          [sqlite3_open()] or [sqlite3_open_v2()] will be UTF-8.
-**
-** {F12707} The default text encoding for a new database created using
-**          [sqlite3_open16()] will be UTF-16.
-**
-** {F12709} The [sqlite3_open(F,D)] interface is equivalent to
-**          [sqlite3_open_v2(F,D,G,0)] where the G parameter is
-**          [SQLITE_OPEN_READWRITE]|[SQLITE_OPEN_CREATE].
-**
-** {F12711} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
-**          bit value [SQLITE_OPEN_READONLY] then the database is opened
-**          for reading only.
-**
-** {F12712} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
-**          bit value [SQLITE_OPEN_READWRITE] then the database is opened
-**          reading and writing if possible, or for reading only if the
-**          file is write protected by the operating system.
-**
-** {F12713} If the G parameter to [sqlite3_open(v2(F,D,G,V)] omits the
-**          bit value [SQLITE_OPEN_CREATE] and the database does not
-**          previously exist, an error is returned.
-**
-** {F12714} If the G parameter to [sqlite3_open(v2(F,D,G,V)] contains the
-**          bit value [SQLITE_OPEN_CREATE] and the database does not
-**          previously exist, then an attempt is made to create and
-**          initialize the database.
-**
-** {F12717} If the filename argument to [sqlite3_open()], [sqlite3_open16()],
-**          or [sqlite3_open_v2()] is ":memory:", then an private,
-**          ephemeral, in-memory database is created for the connection.
-**          <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
-**          in sqlite3_open_v2()?</todo>
-**
-** {F12719} If the filename is an empty string, then a private, ephermeral
-**          on-disk database will be created.
-**          <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
-**          in sqlite3_open_v2()?</todo>
-**
-** {F12721} The [database connection] created by 
-**          [sqlite3_open_v2(F,D,G,V)] will use the
-**          [sqlite3_vfs] object identified by the V parameter, or
-**          the default [sqlite3_vfs] object is V is a NULL pointer.
-*/
-int sqlite3_open(
-  const char *filename,   /* Database filename (UTF-8) */
-  sqlite3 **ppDb          /* OUT: SQLite db handle */
-);
-int sqlite3_open16(
-  const void *filename,   /* Database filename (UTF-16) */
-  sqlite3 **ppDb          /* OUT: SQLite db handle */
-);
-int sqlite3_open_v2(
-  const char *filename,   /* Database filename (UTF-8) */
-  sqlite3 **ppDb,         /* OUT: SQLite db handle */
-  int flags,              /* Flags */
-  const char *zVfs        /* Name of VFS module to use */
-);
-
-/*
-** CAPI3REF: Error Codes And Messages {F12800}
-**
-** The sqlite3_errcode() interface returns the numeric
-** [SQLITE_OK | result code] or [SQLITE_IOERR_READ | extended result code]
-** for the most recent failed sqlite3_* API call associated
-** with [sqlite3] handle 'db'. If a prior API call failed but the
-** most recent API call succeeded, the return value from sqlite3_errcode()
-** is undefined.
-**
-** The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF8 or UTF16 respectively.
-** Memory to hold the error message string is managed internally.
-** The application does not need to worry with freeing the result.
-** However, the error string might be overwritten or deallocated b
-** subsequent calls to other SQLite interface functions.
-**
-** INVARIANTS:
-**
-** {F12801} The [sqlite3_errcode(D)] interface returns the numeric
-**          [SQLITE_OK | result code] or
-**          [SQLITE_IOERR_READ | extended result code]
-**          for the most recent failed interface call associated
-**          with [sqlite3] handle D.
-**
-** {U12802} If a prior API call failed but the most recent API call
-**          succeeded, the return value from [sqlite3_errcode()],
-**          [sqlite3_errmsg()], and [sqlite3_errmsg16()] are undefined.
-**
-** {F12803} The [sqlite3_errmsg(D)] and [sqlite3_errmsg16(D)]
-**          interfaces return English-language text that describes
-**          the error in the mostly recently failed interface call,
-**          encoded as either UTF8 or UTF16 respectively.
-**
-** {U12804} The strings returned by [sqlite3_errmsg()] and [sqlite3_errmsg16()]
-**          are only valid until the next SQLite interface call.
-**
-** {F12807} Calls to [sqlite3_errcode()], [sqlite3_errmsg()], and
-**          [sqlite3_errmsg16()] themselves do not affect the
-**          results of future invocations of these routines.
-**
-** {F12808} Calls to API routines that do not return an error code
-**          (example: [sqlite3_data_count()]) do not
-**          change the error code or message returned by
-**          [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
-**
-** {F12809} Interfaces that are not associated with a specific
-**          [database connection] (examples:
-**          [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()]
-**          do not change the values returned by
-**          [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
-*/
-int sqlite3_errcode(sqlite3 *db);
-const char *sqlite3_errmsg(sqlite3*);
-const void *sqlite3_errmsg16(sqlite3*);
-
-/*
-** CAPI3REF: SQL Statement Object {F13000}
-** KEYWORDS: {prepared statement} {prepared statements}
-**
-** An instance of this object represent single SQL statements.  This
-** object is variously known as a "prepared statement" or a 
-** "compiled SQL statement" or simply as a "statement".
-** 
-** The life of a statement object goes something like this:
-**
-** <ol>
-** <li> Create the object using [sqlite3_prepare_v2()] or a related
-**      function.
-** <li> Bind values to host parameters using
-**      [sqlite3_bind_blob | sqlite3_bind_* interfaces].
-** <li> Run the SQL by calling [sqlite3_step()] one or more times.
-** <li> Reset the statement using [sqlite3_reset()] then go back
-**      to step 2.  Do this zero or more times.
-** <li> Destroy the object using [sqlite3_finalize()].
-** </ol>
-**
-** Refer to documentation on individual methods above for additional
-** information.
-*/
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-/*
-** CAPI3REF: Compiling An SQL Statement {F13010}
-**
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of these routines. 
-**
-** The first argument "db" is an [database connection] 
-** obtained from a prior call to [sqlite3_open()], [sqlite3_open_v2()]
-** or [sqlite3_open16()]. 
-** The second argument "zSql" is the statement to be compiled, encoded
-** as either UTF-8 or UTF-16.  The sqlite3_prepare() and sqlite3_prepare_v2()
-** interfaces uses UTF-8 and sqlite3_prepare16() and sqlite3_prepare16_v2()
-** use UTF-16. {END}
-**
-** If the nByte argument is less
-** than zero, then zSql is read up to the first zero terminator.
-** If nByte is non-negative, then it is the maximum number of 
-** bytes read from zSql.  When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or 
-** until the nByte-th byte, whichever comes first. {END}
-**
-** *pzTail is made to point to the first byte past the end of the
-** first SQL statement in zSql.  These routines only compiles the first
-** statement in zSql, so *pzTail is left pointing to what remains
-** uncompiled.
-**
-** *ppStmt is left pointing to a compiled [prepared statement] that can be
-** executed using [sqlite3_step()].  Or if there is an error, *ppStmt may be
-** set to NULL.  If the input text contains no SQL (if the input
-** is and empty string or a comment) then *ppStmt is set to NULL.
-** {U13018} The calling procedure is responsible for deleting the
-** compiled SQL statement
-** using [sqlite3_finalize()] after it has finished with it.
-**
-** On success, [SQLITE_OK] is returned.  Otherwise an 
-** [error code] is returned.
-**
-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
-** recommended for all new programs. The two older interfaces are retained
-** for backwards compatibility, but their use is discouraged.
-** In the "v2" interfaces, the prepared statement
-** that is returned (the [sqlite3_stmt] object) contains a copy of the 
-** original SQL text. {END} This causes the [sqlite3_step()] interface to
-** behave a differently in two ways:
-**
-** <ol>
-** <li>
-** If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
-** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.  If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA].  But unlike the legacy behavior, 
-** [SQLITE_SCHEMA] is now a fatal error.  Calling
-** [sqlite3_prepare_v2()] again will not make the
-** error go away.  Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return. {END}
-** </li>
-**
-** <li>
-** When an error occurs, 
-** [sqlite3_step()] will return one of the detailed 
-** [error codes] or [extended error codes]. 
-** The legacy behavior was that [sqlite3_step()] would only return a generic
-** [SQLITE_ERROR] result code and you would have to make a second call to
-** [sqlite3_reset()] in order to find the underlying cause of the problem.
-** With the "v2" prepare interfaces, the underlying reason for the error is
-** returned immediately.
-** </li>
-** </ol>
-**
-** INVARIANTS:
-**
-** {F13011} The [sqlite3_prepare(db,zSql,...)] and
-**          [sqlite3_prepare_v2(db,zSql,...)] interfaces interpret the
-**          text in their zSql parameter as UTF-8.
-**
-** {F13012} The [sqlite3_prepare16(db,zSql,...)] and
-**          [sqlite3_prepare16_v2(db,zSql,...)] interfaces interpret the
-**          text in their zSql parameter as UTF-16 in the native byte order.
-**
-** {F13013} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
-**          and its variants is less than zero, then SQL text is
-**          read from zSql is read up to the first zero terminator.
-**
-** {F13014} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
-**          and its variants is non-negative, then nBytes bytes
-**          SQL text is read from zSql.
-**
-** {F13015} In [sqlite3_prepare_v2(db,zSql,N,P,pzTail)] and its variants
-**          if the zSql input text contains more than one SQL statement
-**          and pzTail is not NULL, then *pzTail is made to point to the
-**          first byte past the end of the first SQL statement in zSql.
-**          <todo>What does *pzTail point to if there is one statement?</todo>
-**
-** {F13016} A successful call to [sqlite3_prepare_v2(db,zSql,N,ppStmt,...)]
-**          or one of its variants writes into *ppStmt a pointer to a new
-**          [prepared statement] or a pointer to NULL
-**          if zSql contains nothing other than whitespace or comments. 
-**
-** {F13019} The [sqlite3_prepare_v2()] interface and its variants return
-**          [SQLITE_OK] or an appropriate [error code] upon failure.
-*/
-int sqlite3_prepare(
-  sqlite3 *db,            /* Database handle */
-  const char *zSql,       /* SQL statement, UTF-8 encoded */
-  int nByte,              /* Maximum length of zSql in bytes. */
-  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
-  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare_v2(
-  sqlite3 *db,            /* Database handle */
-  const char *zSql,       /* SQL statement, UTF-8 encoded */
-  int nByte,              /* Maximum length of zSql in bytes. */
-  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
-  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare16(
-  sqlite3 *db,            /* Database handle */
-  const void *zSql,       /* SQL statement, UTF-16 encoded */
-  int nByte,              /* Maximum length of zSql in bytes. */
-  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
-  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare16_v2(
-  sqlite3 *db,            /* Database handle */
-  const void *zSql,       /* SQL statement, UTF-16 encoded */
-  int nByte,              /* Maximum length of zSql in bytes. */
-  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
-  const void **pzTail     /* OUT: Pointer to unused portion of zSql */
-);
-
-/*
-** CAPIREF: Retrieving Statement SQL {F13100}
-**
-** This intereface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement].
-**
-** INVARIANTS:
-**
-** {F13101} If the [prepared statement] passed as 
-**          the an argument to [sqlite3_sql()] was compiled
-**          compiled using either [sqlite3_prepare_v2()] or
-**          [sqlite3_prepare16_v2()],
-**          then [sqlite3_sql()] function returns a pointer to a
-**          zero-terminated string containing a UTF-8 rendering
-**          of the original SQL statement.
-**
-** {F13102} If the [prepared statement] passed as 
-**          the an argument to [sqlite3_sql()] was compiled
-**          compiled using either [sqlite3_prepare()] or
-**          [sqlite3_prepare16()],
-**          then [sqlite3_sql()] function returns a NULL pointer.
-**
-** {F13103} The string returned by [sqlite3_sql(S)] is valid until the
-**          [prepared statement] S is deleted using [sqlite3_finalize(S)].
-*/
-const char *sqlite3_sql(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF:  Dynamically Typed Value Object  {F15000}
-**
-** SQLite uses the sqlite3_value object to represent all values
-** that are or can be stored in a database table.
-** SQLite uses dynamic typing for the values it stores.  
-** Values stored in sqlite3_value objects can be
-** be integers, floating point values, strings, BLOBs, or NULL.
-*/
-typedef struct Mem sqlite3_value;
-
-/*
-** CAPI3REF:  SQL Function Context Object {F16001}
-**
-** The context in which an SQL function executes is stored in an
-** sqlite3_context object.  A pointer to an sqlite3_context
-** object is always first parameter to application-defined SQL functions.
-*/
-typedef struct sqlite3_context sqlite3_context;
-
-/*
-** CAPI3REF:  Binding Values To Prepared Statements {F13500}
-**
-** In the SQL strings input to [sqlite3_prepare_v2()] and its
-** variants, literals may be replace by a parameter in one
-** of these forms:
-**
-** <ul>
-** <li>  ?
-** <li>  ?NNN
-** <li>  :VVV
-** <li>  @VVV
-** <li>  $VVV
-** </ul>
-**
-** In the parameter forms shown above NNN is an integer literal,
-** VVV alpha-numeric parameter name.
-** The values of these parameters (also called "host parameter names"
-** or "SQL parameters")
-** can be set using the sqlite3_bind_*() routines defined here.
-**
-** The first argument to the sqlite3_bind_*() routines always
-** is a pointer to the [sqlite3_stmt] object returned from
-** [sqlite3_prepare_v2()] or its variants. The second
-** argument is the index of the parameter to be set. The
-** first parameter has an index of 1.  When the same named
-** parameter is used more than once, second and subsequent
-** occurrences have the same index as the first occurrence. 
-** The index for named parameters can be looked up using the
-** [sqlite3_bind_parameter_name()] API if desired.  The index
-** for "?NNN" parameters is the value of NNN.
-** The NNN value must be between 1 and the compile-time
-** parameter SQLITE_MAX_VARIABLE_NUMBER (default value: 999).
-**
-** The third argument is the value to bind to the parameter.
-**
-** In those
-** routines that have a fourth argument, its value is the number of bytes
-** in the parameter.  To be clear: the value is the number of <u>bytes</u>
-** in the value, not the number of characters.   The number
-** of bytes does not include the zero-terminator at the end of strings.
-** If the fourth parameter is negative, the length of the string is
-** number of bytes up to the first zero terminator.
-**
-** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. If the fifth argument is
-** the special value [SQLITE_STATIC], then SQLite assumes that the
-** information is in static, unmanaged space and does not need to be freed.
-** If the fifth argument has the value [SQLITE_TRANSIENT], then
-** SQLite makes its own private copy of the data immediately, before
-** the sqlite3_bind_*() routine returns.
-**
-** The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
-** is filled with zeros.  A zeroblob uses a fixed amount of memory
-** (just an integer to hold it size) while it is being processed.
-** Zeroblobs are intended to serve as place-holders for BLOBs whose
-** content is later written using 
-** [sqlite3_blob_open | increment BLOB I/O] routines. A negative
-** value for the zeroblob results in a zero-length BLOB.
-**
-** The sqlite3_bind_*() routines must be called after
-** [sqlite3_prepare_v2()] (and its variants) or [sqlite3_reset()] and
-** before [sqlite3_step()].
-** Bindings are not cleared by the [sqlite3_reset()] routine.
-** Unbound parameters are interpreted as NULL.
-**
-** These routines return [SQLITE_OK] on success or an error code if
-** anything goes wrong.  [SQLITE_RANGE] is returned if the parameter
-** index is out of range.  [SQLITE_NOMEM] is returned if malloc fails.
-** [SQLITE_MISUSE] might be returned if these routines are called on a
-** virtual machine that is the wrong state or which has already been finalized.
-** Detection of misuse is unreliable.  Applications should not depend
-** on SQLITE_MISUSE returns.  SQLITE_MISUSE is intended to indicate a
-** a logic error in the application.  Future versions of SQLite might
-** panic rather than return SQLITE_MISUSE.
-**
-** See also: [sqlite3_bind_parameter_count()],
-** [sqlite3_bind_parameter_name()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13506} The [sqlite3_prepare | SQL statement compiler] recognizes
-**          tokens of the forms "?", "?NNN", "$VVV", ":VVV", and "@VVV"
-**          as SQL parameters, where NNN is any sequence of one or more
-**          digits and where VVV is any sequence of one or more 
-**          alphanumeric characters or "::" optionally followed by
-**          a string containing no spaces and contained within parentheses.
-**
-** {F13509} The initial value of an SQL parameter is NULL.
-**
-** {F13512} The index of an "?" SQL parameter is one larger than the
-**          largest index of SQL parameter to the left, or 1 if
-**          the "?" is the leftmost SQL parameter.
-**
-** {F13515} The index of an "?NNN" SQL parameter is the integer NNN.
-**
-** {F13518} The index of an ":VVV", "$VVV", or "@VVV" SQL parameter is
-**          the same as the index of leftmost occurances of the same
-**          parameter, or one more than the largest index over all
-**          parameters to the left if this is the first occurrance
-**          of this parameter, or 1 if this is the leftmost parameter.
-**
-** {F13521} The [sqlite3_prepare | SQL statement compiler] fail with
-**          an [SQLITE_RANGE] error if the index of an SQL parameter
-**          is less than 1 or greater than SQLITE_MAX_VARIABLE_NUMBER.
-**
-** {F13524} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,V,...)]
-**          associate the value V with all SQL parameters having an
-**          index of N in the [prepared statement] S.
-**
-** {F13527} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,...)]
-**          override prior calls with the same values of S and N.
-**
-** {F13530} Bindings established by [sqlite3_bind_text | sqlite3_bind(S,...)]
-**          persist across calls to [sqlite3_reset(S)].
-**
-** {F13533} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-**          [sqlite3_bind_text(S,N,V,L,D)], or
-**          [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds the first L
-**          bytes of the blob or string pointed to by V, when L
-**          is non-negative.
-**
-** {F13536} In calls to [sqlite3_bind_text(S,N,V,L,D)] or
-**          [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds characters
-**          from V through the first zero character when L is negative.
-**
-** {F13539} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-**          [sqlite3_bind_text(S,N,V,L,D)], or
-**          [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
-**          constant [SQLITE_STATIC], SQLite assumes that the value V
-**          is held in static unmanaged space that will not change
-**          during the lifetime of the binding.
-**
-** {F13542} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-**          [sqlite3_bind_text(S,N,V,L,D)], or
-**          [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
-**          constant [SQLITE_TRANSIENT], the routine makes a 
-**          private copy of V value before it returns.
-**
-** {F13545} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-**          [sqlite3_bind_text(S,N,V,L,D)], or
-**          [sqlite3_bind_text16(S,N,V,L,D)] when D is a pointer to
-**          a function, SQLite invokes that function to destroy the
-**          V value after it has finished using the V value.
-**
-** {F13548} In calls to [sqlite3_bind_zeroblob(S,N,V,L)] the value bound
-**          is a blob of L bytes, or a zero-length blob if L is negative.
-*/
-int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-int sqlite3_bind_double(sqlite3_stmt*, int, double);
-int sqlite3_bind_int(sqlite3_stmt*, int, int);
-int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-int sqlite3_bind_null(sqlite3_stmt*, int);
-int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-
-/*
-** CAPI3REF: Number Of SQL Parameters {F13600}
-**
-** This routine can be used to find the number of SQL parameters
-** in a prepared statement.  SQL parameters are tokens of the
-** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as
-** place-holders for values that are [sqlite3_bind_blob | bound]
-** to the parameters at a later time.
-**
-** This routine actually returns the index of the largest parameter.
-** For all forms except ?NNN, this will correspond to the number of
-** unique parameters.  If parameters of the ?NNN are used, there may
-** be gaps in the list.
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_name()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13601} The [sqlite3_bind_parameter_count(S)] interface returns
-**          the largest index of all SQL parameters in the
-**          [prepared statement] S, or 0 if S
-**          contains no SQL parameters.
-*/
-int sqlite3_bind_parameter_count(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Name Of A Host Parameter {F13620}
-**
-** This routine returns a pointer to the name of the n-th
-** SQL parameter in a [prepared statement].
-** SQL parameters of the form ":AAA" or "@AAA" or "$AAA" have a name
-** which is the string ":AAA" or "@AAA" or "$VVV". 
-** In other words, the initial ":" or "$" or "@"
-** is included as part of the name.
-** Parameters of the form "?" or "?NNN" have no name.
-**
-** The first host parameter has an index of 1, not 0.
-**
-** If the value n is out of range or if the n-th parameter is
-** nameless, then NULL is returned.  The returned string is
-** always in the UTF-8 encoding even if the named parameter was
-** originally specified as UTF-16 in [sqlite3_prepare16()] or
-** [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13621} The [sqlite3_bind_parameter_name(S,N)] interface returns
-**          a UTF-8 rendering of the name of the SQL parameter in
-**          [prepared statement] S having index N, or
-**          NULL if there is no SQL parameter with index N or if the
-**          parameter with index N is an anonymous parameter "?" or
-**          a numbered parameter "?NNN".
-*/
-const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
-
-/*
-** CAPI3REF: Index Of A Parameter With A Given Name {F13640}
-**
-** Return the index of an SQL parameter given its name.  The
-** index value returned is suitable for use as the second
-** parameter to [sqlite3_bind_blob|sqlite3_bind()].  A zero
-** is returned if no matching parameter is found.  The parameter
-** name must be given in UTF-8 even if the original statement
-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13641} The [sqlite3_bind_parameter_index(S,N)] interface returns
-**          the index of SQL parameter in [prepared statement]
-**          S whose name matches the UTF-8 string N, or 0 if there is
-**          no match.
-*/
-int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
-
-/*
-** CAPI3REF: Reset All Bindings On A Prepared Statement {F13660}
-**
-** Contrary to the intuition of many, [sqlite3_reset()] does not
-** reset the [sqlite3_bind_blob | bindings] on a 
-** [prepared statement].  Use this routine to
-** reset all host parameters to NULL.
-**
-** INVARIANTS:
-**
-** {F13661} The [sqlite3_clear_bindings(S)] interface resets all
-**          SQL parameter bindings in [prepared statement] S
-**          back to NULL.
-*/
-int sqlite3_clear_bindings(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number Of Columns In A Result Set {F13710}
-**
-** Return the number of columns in the result set returned by the 
-** [prepared statement]. This routine returns 0
-** if pStmt is an SQL statement that does not return data (for 
-** example an UPDATE).
-**
-** INVARIANTS:
-**
-** {F13711} The [sqlite3_column_count(S)] interface returns the number of
-**          columns in the result set generated by the
-**          [prepared statement] S, or 0 if S does not generate
-**          a result set.
-*/
-int sqlite3_column_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Column Names In A Result Set {F13720}
-**
-** These routines return the name assigned to a particular column
-** in the result set of a SELECT statement.  The sqlite3_column_name()
-** interface returns a pointer to a zero-terminated UTF8 string
-** and sqlite3_column_name16() returns a pointer to a zero-terminated
-** UTF16 string.  The first parameter is the
-** [prepared statement] that implements the SELECT statement.
-** The second parameter is the column number.  The left-most column is
-** number 0.
-**
-** The returned string pointer is valid until either the 
-** [prepared statement] is destroyed by [sqlite3_finalize()]
-** or until the next call sqlite3_column_name() or sqlite3_column_name16()
-** on the same column.
-**
-** If sqlite3_malloc() fails during the processing of either routine
-** (for example during a conversion from UTF-8 to UTF-16) then a
-** NULL pointer is returned.
-**
-** The name of a result column is the value of the "AS" clause for
-** that column, if there is an AS clause.  If there is no AS clause
-** then the name of the column is unspecified and may change from
-** one release of SQLite to the next.
-**
-** INVARIANTS:
-**
-** {F13721} A successful invocation of the [sqlite3_column_name(S,N)]
-**          interface returns the name
-**          of the Nth column (where 0 is the left-most column) for the
-**          result set of [prepared statement] S as a
-**          zero-terminated UTF-8 string.
-**
-** {F13723} A successful invocation of the [sqlite3_column_name16(S,N)]
-**          interface returns the name
-**          of the Nth column (where 0 is the left-most column) for the
-**          result set of [prepared statement] S as a
-**          zero-terminated UTF-16 string in the native byte order.
-**
-** {F13724} The [sqlite3_column_name()] and [sqlite3_column_name16()]
-**          interfaces return a NULL pointer if they are unable to
-**          allocate memory memory to hold there normal return strings.
-**
-** {F13725} If the N parameter to [sqlite3_column_name(S,N)] or
-**          [sqlite3_column_name16(S,N)] is out of range, then the
-**          interfaces returns a NULL pointer.
-** 
-** {F13726} The strings returned by [sqlite3_column_name(S,N)] and
-**          [sqlite3_column_name16(S,N)] are valid until the next
-**          call to either routine with the same S and N parameters
-**          or until [sqlite3_finalize(S)] is called.
-**
-** {F13727} When a result column of a [SELECT] statement contains
-**          an AS clause, the name of that column is the indentifier
-**          to the right of the AS keyword.
-*/
-const char *sqlite3_column_name(sqlite3_stmt*, int N);
-const void *sqlite3_column_name16(sqlite3_stmt*, int N);
-
-/*
-** CAPI3REF: Source Of Data In A Query Result {F13740}
-**
-** These routines provide a means to determine what column of what
-** table in which database a result of a SELECT statement comes from.
-** The name of the database or table or column can be returned as
-** either a UTF8 or UTF16 string.  The _database_ routines return
-** the database name, the _table_ routines return the table name, and
-** the origin_ routines return the column name.
-** The returned string is valid until
-** the [prepared statement] is destroyed using
-** [sqlite3_finalize()] or until the same information is requested
-** again in a different encoding.
-**
-** The names returned are the original un-aliased names of the
-** database, table, and column.
-**
-** The first argument to the following calls is a [prepared statement].
-** These functions return information about the Nth column returned by 
-** the statement, where N is the second function argument.
-**
-** If the Nth column returned by the statement is an expression
-** or subquery and is not a column value, then all of these functions
-** return NULL.  These routine might also return NULL if a memory
-** allocation error occurs.  Otherwise, they return the 
-** name of the attached database, table and column that query result
-** column was extracted from.
-**
-** As with all other SQLite APIs, those postfixed with "16" return
-** UTF-16 encoded strings, the other functions return UTF-8. {END}
-**
-** These APIs are only available if the library was compiled with the 
-** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
-**
-** {U13751}
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
-** INVARIANTS:
-**
-** {F13741} The [sqlite3_column_database_name(S,N)] interface returns either
-**          the UTF-8 zero-terminated name of the database from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13742} The [sqlite3_column_database_name16(S,N)] interface returns either
-**          the UTF-16 native byte order
-**          zero-terminated name of the database from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13743} The [sqlite3_column_table_name(S,N)] interface returns either
-**          the UTF-8 zero-terminated name of the table from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13744} The [sqlite3_column_table_name16(S,N)] interface returns either
-**          the UTF-16 native byte order
-**          zero-terminated name of the table from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13745} The [sqlite3_column_origin_name(S,N)] interface returns either
-**          the UTF-8 zero-terminated name of the table column from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13746} The [sqlite3_column_origin_name16(S,N)] interface returns either
-**          the UTF-16 native byte order
-**          zero-terminated name of the table column from which the 
-**          Nth result column of [prepared statement] S 
-**          is extracted, or NULL if the the Nth column of S is a
-**          general expression or if unable to allocate memory
-**          to store the name.
-**          
-** {F13748} The return values from
-**          [sqlite3_column_database_name|column metadata interfaces]
-**          are valid
-**          for the lifetime of the [prepared statement]
-**          or until the encoding is changed by another metadata
-**          interface call for the same prepared statement and column.
-**
-** LIMITATIONS:
-**
-** {U13751} If two or more threads call one or more
-**          [sqlite3_column_database_name|column metadata interfaces]
-**          the same [prepared statement] and result column
-**          at the same time then the results are undefined.
-*/
-const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
-
-/*
-** CAPI3REF: Declared Datatype Of A Query Result {F13760}
-**
-** The first parameter is a [prepared statement]. 
-** If this statement is a SELECT statement and the Nth column of the 
-** returned result set of that SELECT is a table column (not an
-** expression or subquery) then the declared type of the table
-** column is returned.  If the Nth column of the result set is an
-** expression or subquery, then a NULL pointer is returned.
-** The returned string is always UTF-8 encoded.  {END} 
-** For example, in the database schema:
-**
-** CREATE TABLE t1(c1 VARIANT);
-**
-** And the following statement compiled:
-**
-** SELECT c1 + 1, c1 FROM t1;
-**
-** Then this routine would return the string "VARIANT" for the second
-** result column (i==1), and a NULL pointer for the first result column
-** (i==0).
-**
-** SQLite uses dynamic run-time typing.  So just because a column
-** is declared to contain a particular type does not mean that the
-** data stored in that column is of the declared type.  SQLite is
-** strongly typed, but the typing is dynamic not static.  Type
-** is associated with individual values, not with the containers
-** used to hold those values.
-**
-** INVARIANTS:
-**
-** {F13761}  A successful call to [sqlite3_column_decltype(S,N)]
-**           returns a zero-terminated UTF-8 string containing the
-**           the declared datatype of the table column that appears
-**           as the Nth column (numbered from 0) of the result set to the
-**           [prepared statement] S.
-**
-** {F13762}  A successful call to [sqlite3_column_decltype16(S,N)]
-**           returns a zero-terminated UTF-16 native byte order string
-**           containing the declared datatype of the table column that appears
-**           as the Nth column (numbered from 0) of the result set to the
-**           [prepared statement] S.
-**
-** {F13763}  If N is less than 0 or N is greater than or equal to
-**           the number of columns in [prepared statement] S
-**           or if the Nth column of S is an expression or subquery rather
-**           than a table column or if a memory allocation failure
-**           occurs during encoding conversions, then
-**           calls to [sqlite3_column_decltype(S,N)] or
-**           [sqlite3_column_decltype16(S,N)] return NULL.
-*/
-const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
-
-/* 
-** CAPI3REF:  Evaluate An SQL Statement {F13200}
-**
-** After an [prepared statement] has been prepared with a call
-** to either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or to one of
-** the legacy interfaces [sqlite3_prepare()] or [sqlite3_prepare16()],
-** then this function must be called one or more times to evaluate the 
-** statement.
-**
-** The details of the behavior of this sqlite3_step() interface depend
-** on whether the statement was prepared using the newer "v2" interface
-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
-** interface [sqlite3_prepare()] and [sqlite3_prepare16()].  The use of the
-** new "v2" interface is recommended for new applications but the legacy
-** interface will continue to be supported.
-**
-** In the lagacy interface, the return value will be either [SQLITE_BUSY], 
-** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
-** With the "v2" interface, any of the other [SQLITE_OK | result code]
-** or [SQLITE_IOERR_READ | extended result code] might be returned as
-** well.
-**
-** [SQLITE_BUSY] means that the database engine was unable to acquire the
-** database locks it needs to do its job.  If the statement is a COMMIT
-** or occurs outside of an explicit transaction, then you can retry the
-** statement.  If the statement is not a COMMIT and occurs within a
-** explicit transaction then you should rollback the transaction before
-** continuing.
-**
-** [SQLITE_DONE] means that the statement has finished executing
-** successfully.  sqlite3_step() should not be called again on this virtual
-** machine without first calling [sqlite3_reset()] to reset the virtual
-** machine back to its initial state.
-**
-** If the SQL statement being executed returns any data, then 
-** [SQLITE_ROW] is returned each time a new row of data is ready
-** for processing by the caller. The values may be accessed using
-** the [sqlite3_column_int | column access functions].
-** sqlite3_step() is called again to retrieve the next row of data.
-** 
-** [SQLITE_ERROR] means that a run-time error (such as a constraint
-** violation) has occurred.  sqlite3_step() should not be called again on
-** the VM. More information may be found by calling [sqlite3_errmsg()].
-** With the legacy interface, a more specific error code (example:
-** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth)
-** can be obtained by calling [sqlite3_reset()] on the
-** [prepared statement].  In the "v2" interface,
-** the more specific error code is returned directly by sqlite3_step().
-**
-** [SQLITE_MISUSE] means that the this routine was called inappropriately.
-** Perhaps it was called on a [prepared statement] that has
-** already been [sqlite3_finalize | finalized] or on one that had 
-** previously returned [SQLITE_ERROR] or [SQLITE_DONE].  Or it could
-** be the case that the same database connection is being used by two or
-** more threads at the same moment in time.
-**
-** <b>Goofy Interface Alert:</b>
-** In the legacy interface, 
-** the sqlite3_step() API always returns a generic error code,
-** [SQLITE_ERROR], following any error other than [SQLITE_BUSY]
-** and [SQLITE_MISUSE].  You must call [sqlite3_reset()] or
-** [sqlite3_finalize()] in order to find one of the specific
-** [error codes] that better describes the error.
-** We admit that this is a goofy design.  The problem has been fixed
-** with the "v2" interface.  If you prepare all of your SQL statements
-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
-** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()], then the 
-** more specific [error codes] are returned directly
-** by sqlite3_step().  The use of the "v2" interface is recommended.
-**
-** INVARIANTS:
-**
-** {F13202}  If [prepared statement] S is ready to be
-**           run, then [sqlite3_step(S)] advances that prepared statement
-**           until to completion or until it is ready to return another
-**           row of the result set or an interrupt or run-time error occurs.
-**
-** {F15304}  When a call to [sqlite3_step(S)] causes the 
-**           [prepared statement] S to run to completion,
-**           the function returns [SQLITE_DONE].
-**
-** {F15306}  When a call to [sqlite3_step(S)] stops because it is ready
-**           to return another row of the result set, it returns
-**           [SQLITE_ROW].
-**
-** {F15308}  If a call to [sqlite3_step(S)] encounters an
-**           [sqlite3_interrupt|interrupt] or a run-time error,
-**           it returns an appropraite error code that is not one of
-**           [SQLITE_OK], [SQLITE_ROW], or [SQLITE_DONE].
-**
-** {F15310}  If an [sqlite3_interrupt|interrupt] or run-time error
-**           occurs during a call to [sqlite3_step(S)]
-**           for a [prepared statement] S created using
-**           legacy interfaces [sqlite3_prepare()] or
-**           [sqlite3_prepare16()] then the function returns either
-**           [SQLITE_ERROR], [SQLITE_BUSY], or [SQLITE_MISUSE].
-*/
-int sqlite3_step(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number of columns in a result set {F13770}
-**
-** Return the number of values in the current row of the result set.
-**
-** INVARIANTS:
-**
-** {F13771}  After a call to [sqlite3_step(S)] that returns
-**           [SQLITE_ROW], the [sqlite3_data_count(S)] routine
-**           will return the same value as the
-**           [sqlite3_column_count(S)] function.
-**
-** {F13772}  After [sqlite3_step(S)] has returned any value other than
-**           [SQLITE_ROW] or before [sqlite3_step(S)] has been 
-**           called on the [prepared statement] for
-**           the first time since it was [sqlite3_prepare|prepared]
-**           or [sqlite3_reset|reset], the [sqlite3_data_count(S)]
-**           routine returns zero.
-*/
-int sqlite3_data_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Fundamental Datatypes {F10265}
-** KEYWORDS: SQLITE_TEXT
-**
-** {F10266}Every value in SQLite has one of five fundamental datatypes:
-**
-** <ul>
-** <li> 64-bit signed integer
-** <li> 64-bit IEEE floating point number
-** <li> string
-** <li> BLOB
-** <li> NULL
-** </ul> {END}
-**
-** These constants are codes for each of those types.
-**
-** Note that the SQLITE_TEXT constant was also used in SQLite version 2
-** for a completely different meaning.  Software that links against both
-** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT not
-** SQLITE_TEXT.
-*/
-#define SQLITE_INTEGER  1
-#define SQLITE_FLOAT    2
-#define SQLITE_BLOB     4
-#define SQLITE_NULL     5
-#ifdef SQLITE_TEXT
-# undef SQLITE_TEXT
-#else
-# define SQLITE_TEXT     3
-#endif
-#define SQLITE3_TEXT     3
-
-/*
-** CAPI3REF: Results Values From A Query {F13800}
-**
-** These routines form the "result set query" interface.
-**
-** These routines return information about
-** a single column of the current result row of a query.  In every
-** case the first argument is a pointer to the 
-** [prepared statement] that is being
-** evaluated (the [sqlite3_stmt*] that was returned from 
-** [sqlite3_prepare_v2()] or one of its variants) and
-** the second argument is the index of the column for which information 
-** should be returned.  The left-most column of the result set
-** has an index of 0.
-**
-** If the SQL statement is not currently point to a valid row, or if the
-** the column index is out of range, the result is undefined. 
-** These routines may only be called when the most recent call to
-** [sqlite3_step()] has returned [SQLITE_ROW] and neither
-** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently.
-** If any of these routines are called after [sqlite3_reset()] or
-** [sqlite3_finalize()] or after [sqlite3_step()] has returned
-** something other than [SQLITE_ROW], the results are undefined.
-** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
-** are called from a different thread while any of these routines
-** are pending, then the results are undefined.  
-**
-** The sqlite3_column_type() routine returns 
-** [SQLITE_INTEGER | datatype code] for the initial data type
-** of the result column.  The returned value is one of [SQLITE_INTEGER],
-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].  The value
-** returned by sqlite3_column_type() is only meaningful if no type
-** conversions have occurred as described below.  After a type conversion,
-** the value returned by sqlite3_column_type() is undefined.  Future
-** versions of SQLite may change the behavior of sqlite3_column_type()
-** following a type conversion.
-**
-** If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() 
-** routine returns the number of bytes in that BLOB or string.
-** If the result is a UTF-16 string, then sqlite3_column_bytes() converts
-** the string to UTF-8 and then returns the number of bytes.
-** If the result is a numeric value then sqlite3_column_bytes() uses
-** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
-** the number of bytes in that string.
-** The value returned does not include the zero terminator at the end
-** of the string.  For clarity: the value returned is the number of
-** bytes in the string, not the number of characters.
-**
-** Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
-** even empty strings, are always zero terminated.  The return
-** value from sqlite3_column_blob() for a zero-length blob is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.  
-** The zero terminator is not included in this count.
-**
-** These routines attempt to convert the value where appropriate.  For
-** example, if the internal representation is FLOAT and a text result
-** is requested, [sqlite3_snprintf()] is used internally to do the conversion
-** automatically.  The following table details the conversions that
-** are applied:
-**
-** <blockquote>
-** <table border="1">
-** <tr><th> Internal<br>Type <th> Requested<br>Type <th>  Conversion
-**
-** <tr><td>  NULL    <td> INTEGER   <td> Result is 0
-** <tr><td>  NULL    <td>  FLOAT    <td> Result is 0.0
-** <tr><td>  NULL    <td>   TEXT    <td> Result is NULL pointer
-** <tr><td>  NULL    <td>   BLOB    <td> Result is NULL pointer
-** <tr><td> INTEGER  <td>  FLOAT    <td> Convert from integer to float
-** <tr><td> INTEGER  <td>   TEXT    <td> ASCII rendering of the integer
-** <tr><td> INTEGER  <td>   BLOB    <td> Same as for INTEGER->TEXT
-** <tr><td>  FLOAT   <td> INTEGER   <td> Convert from float to integer
-** <tr><td>  FLOAT   <td>   TEXT    <td> ASCII rendering of the float
-** <tr><td>  FLOAT   <td>   BLOB    <td> Same as FLOAT->TEXT
-** <tr><td>  TEXT    <td> INTEGER   <td> Use atoi()
-** <tr><td>  TEXT    <td>  FLOAT    <td> Use atof()
-** <tr><td>  TEXT    <td>   BLOB    <td> No change
-** <tr><td>  BLOB    <td> INTEGER   <td> Convert to TEXT then use atoi()
-** <tr><td>  BLOB    <td>  FLOAT    <td> Convert to TEXT then use atof()
-** <tr><td>  BLOB    <td>   TEXT    <td> Add a zero terminator if needed
-** </table>
-** </blockquote>
-**
-** The table above makes reference to standard C library functions atoi()
-** and atof().  SQLite does not really use these functions.  It has its
-** on equavalent internal routines.  The atoi() and atof() names are
-** used in the table for brevity and because they are familiar to most
-** C programmers.
-**
-** Note that when type conversions occur, pointers returned by prior
-** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
-** sqlite3_column_text16() may be invalidated. 
-** Type conversions and pointer invalidations might occur
-** in the following cases:
-**
-** <ul>
-** <li><p>  The initial content is a BLOB and sqlite3_column_text() 
-**          or sqlite3_column_text16() is called.  A zero-terminator might
-**          need to be added to the string.</p></li>
-**
-** <li><p>  The initial content is UTF-8 text and sqlite3_column_bytes16() or
-**          sqlite3_column_text16() is called.  The content must be converted
-**          to UTF-16.</p></li>
-**
-** <li><p>  The initial content is UTF-16 text and sqlite3_column_bytes() or
-**          sqlite3_column_text() is called.  The content must be converted
-**          to UTF-8.</p></li>
-** </ul>
-**
-** Conversions between UTF-16be and UTF-16le are always done in place and do
-** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified.  Other kinds
-** of conversion are done in place when it is possible, but sometime it is
-** not possible and in those cases prior pointers are invalidated.  
-**
-** The safest and easiest to remember policy is to invoke these routines
-** in one of the following ways:
-**
-**  <ul>
-**  <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
-**  <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
-**  <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-**  </ul>
-**
-** In other words, you should call sqlite3_column_text(), sqlite3_column_blob(),
-** or sqlite3_column_text16() first to force the result into the desired
-** format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to
-** find the size of the result.  Do not mix call to sqlite3_column_text() or
-** sqlite3_column_blob() with calls to sqlite3_column_bytes16().  And do not
-** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes().
-**
-** The pointers returned are valid until a type conversion occurs as
-** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
-** [sqlite3_finalize()] is called.  The memory space used to hold strings
-** and blobs is freed automatically.  Do <b>not</b> pass the pointers returned
-** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into 
-** [sqlite3_free()].
-**
-** If a memory allocation error occurs during the evaluation of any
-** of these routines, a default value is returned.  The default value
-** is either the integer 0, the floating point number 0.0, or a NULL
-** pointer.  Subsequent calls to [sqlite3_errcode()] will return
-** [SQLITE_NOMEM].
-**
-** INVARIANTS:
-**
-** {F13803} The [sqlite3_column_blob(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a blob and then returns a
-**          pointer to the converted value.
-**
-** {F13806} The [sqlite3_column_bytes(S,N)] interface returns the
-**          number of bytes in the blob or string (exclusive of the
-**          zero terminator on the string) that was returned by the
-**          most recent call to [sqlite3_column_blob(S,N)] or
-**          [sqlite3_column_text(S,N)].
-**
-** {F13809} The [sqlite3_column_bytes16(S,N)] interface returns the
-**          number of bytes in the string (exclusive of the
-**          zero terminator on the string) that was returned by the
-**          most recent call to [sqlite3_column_text16(S,N)].
-**
-** {F13812} The [sqlite3_column_double(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a floating point value and
-**          returns a copy of that value.
-**
-** {F13815} The [sqlite3_column_int(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a 32-bit signed integer and
-**          returns a copy of that integer.
-**
-** {F13818} The [sqlite3_column_int64(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a 64-bit signed integer and
-**          returns a copy of that integer.
-**
-** {F13821} The [sqlite3_column_text(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a zero-terminated UTF-8 
-**          string and returns a pointer to that string.
-**
-** {F13824} The [sqlite3_column_text16(S,N)] interface converts the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S into a zero-terminated 2-byte
-**          aligned UTF-16 native byte order
-**          string and returns a pointer to that string.
-**
-** {F13827} The [sqlite3_column_type(S,N)] interface returns
-**          one of [SQLITE_NULL], [SQLITE_INTEGER], [SQLITE_FLOAT],
-**          [SQLITE_TEXT], or [SQLITE_BLOB] as appropriate for
-**          the Nth column in the current row of the result set for
-**          [prepared statement] S.
-**
-** {F13830} The [sqlite3_column_value(S,N)] interface returns a
-**          pointer to the [sqlite3_value] object that for the
-**          Nth column in the current row of the result set for
-**          [prepared statement] S.
-*/
-const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-double sqlite3_column_double(sqlite3_stmt*, int iCol);
-int sqlite3_column_int(sqlite3_stmt*, int iCol);
-sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-int sqlite3_column_type(sqlite3_stmt*, int iCol);
-sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
-
-/*
-** CAPI3REF: Destroy A Prepared Statement Object {F13300}
-**
-** The sqlite3_finalize() function is called to delete a 
-** [prepared statement]. If the statement was
-** executed successfully, or not executed at all, then SQLITE_OK is returned.
-** If execution of the statement failed then an 
-** [error code] or [extended error code]
-** is returned. 
-**
-** This routine can be called at any point during the execution of the
-** [prepared statement].  If the virtual machine has not 
-** completed execution when this routine is called, that is like
-** encountering an error or an interrupt.  (See [sqlite3_interrupt()].) 
-** Incomplete updates may be rolled back and transactions cancelled,  
-** depending on the circumstances, and the 
-** [error code] returned will be [SQLITE_ABORT].
-**
-** INVARIANTS:
-**
-** {F11302} The [sqlite3_finalize(S)] interface destroys the
-**          [prepared statement] S and releases all
-**          memory and file resources held by that object.
-**
-** {F11304} If the most recent call to [sqlite3_step(S)] for the
-**          [prepared statement] S returned an error,
-**          then [sqlite3_finalize(S)] returns that same error.
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Reset A Prepared Statement Object {F13330}
-**
-** The sqlite3_reset() function is called to reset a 
-** [prepared statement] object.
-** back to its initial state, ready to be re-executed.
-** Any SQL statement variables that had values bound to them using
-** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
-** Use [sqlite3_clear_bindings()] to reset the bindings.
-**
-** {F11332} The [sqlite3_reset(S)] interface resets the [prepared statement] S
-**          back to the beginning of its program.
-**
-** {F11334} If the most recent call to [sqlite3_step(S)] for 
-**          [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-**          or if [sqlite3_step(S)] has never before been called on S,
-**          then [sqlite3_reset(S)] returns [SQLITE_OK].
-**
-** {F11336} If the most recent call to [sqlite3_step(S)] for
-**          [prepared statement] S indicated an error, then
-**          [sqlite3_reset(S)] returns an appropriate [error code].
-**
-** {F11338} The [sqlite3_reset(S)] interface does not change the values
-**          of any [sqlite3_bind_blob|bindings] on [prepared statement] S.
-*/
-int sqlite3_reset(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Create Or Redefine SQL Functions {F16100}
-** KEYWORDS: {function creation routines} 
-**
-** These two functions (collectively known as
-** "function creation routines") are used to add SQL functions or aggregates
-** or to redefine the behavior of existing SQL functions or aggregates.  The
-** difference only between the two is that the second parameter, the
-** name of the (scalar) function or aggregate, is encoded in UTF-8 for
-** sqlite3_create_function() and UTF-16 for sqlite3_create_function16().
-**
-** The first argument is the [database connection] that holds the
-** SQL function or aggregate is to be added or redefined. If a single
-** program uses more than one database handle internally, then SQL
-** functions or aggregates must be added individually to each database
-** handle with which they will be used.
-**
-** The second parameter is the name of the SQL function to be created
-** or redefined.
-** The length of the name is limited to 255 bytes, exclusive of the 
-** zero-terminator.  Note that the name length limit is in bytes, not
-** characters.  Any attempt to create a function with a longer name
-** will result in an SQLITE_ERROR error.
-**
-** The third parameter is the number of arguments that the SQL function or
-** aggregate takes. If this parameter is negative, then the SQL function or
-** aggregate may take any number of arguments.
-**
-** The fourth parameter, eTextRep, specifies what 
-** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters.  Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be.  But some implementations may be
-** more efficient with one encoding than another.  It is allowed to
-** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
-** times with the same function but with different values of eTextRep.
-** When multiple implementations of the same function are available, SQLite
-** will pick the one that involves the least amount of data conversion.
-** If there is only a single implementation which does not care what
-** text encoding is used, then the fourth argument should be
-** [SQLITE_ANY].
-**
-** The fifth parameter is an arbitrary pointer.  The implementation
-** of the function can gain access to this pointer using
-** [sqlite3_user_data()].
-**
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
-** pointers to C-language functions that implement the SQL
-** function or aggregate. A scalar SQL function requires an implementation of
-** the xFunc callback only, NULL pointers should be passed as the xStep
-** and xFinal parameters. An aggregate SQL function requires an implementation
-** of xStep and xFinal and NULL should be passed for xFunc. To delete an
-** existing SQL function or aggregate, pass NULL for all three function
-** callback.
-**
-** It is permitted to register multiple implementations of the same
-** functions with the same name but with either differing numbers of
-** arguments or differing perferred text encodings.  SQLite will use
-** the implementation most closely matches the way in which the
-** SQL function is used.
-**
-** INVARIANTS:
-**
-** {F16103} The [sqlite3_create_function16()] interface behaves exactly
-**          like [sqlite3_create_function()] in every way except that it
-**          interprets the zFunctionName argument as
-**          zero-terminated UTF-16 native byte order instead of as a
-**          zero-terminated UTF-8.
-**
-** {F16106} 
-*/
-int sqlite3_create_function(
-  sqlite3 *db,
-  const char *zFunctionName,
-  int nArg,
-  int eTextRep,
-  void *pApp,
-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
-  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
-  void (*xFinal)(sqlite3_context*)
-);
-int sqlite3_create_function16(
-  sqlite3 *db,
-  const void *zFunctionName,
-  int nArg,
-  int eTextRep,
-  void *pApp,
-  void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
-  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
-  void (*xFinal)(sqlite3_context*)
-);
-
-/*
-** CAPI3REF: Text Encodings {F10267}
-**
-** These constant define integer codes that represent the various
-** text encodings supported by SQLite.
-*/
-#define SQLITE_UTF8           1
-#define SQLITE_UTF16LE        2
-#define SQLITE_UTF16BE        3
-#define SQLITE_UTF16          4    /* Use native byte order */
-#define SQLITE_ANY            5    /* sqlite3_create_function only */
-#define SQLITE_UTF16_ALIGNED  8    /* sqlite3_create_collation only */
-
-/*
-** CAPI3REF: Obsolete Functions
-**
-** These functions are all now obsolete.  In order to maintain
-** backwards compatibility with older code, we continue to support
-** these functions.  However, new development projects should avoid
-** the use of these functions.  To help encourage people to avoid
-** using these functions, we are not going to tell you want they do.
-*/
-int sqlite3_aggregate_count(sqlite3_context*);
-int sqlite3_expired(sqlite3_stmt*);
-int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-int sqlite3_global_recover(void);
-void sqlite3_thread_cleanup(void);
-int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
-
-/*
-** CAPI3REF: Obtaining SQL Function Parameter Values {F15100}
-**
-** The C-language implementation of SQL functions and aggregates uses
-** this set of interface routines to access the parameter values on
-** the function or aggregate.
-**
-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
-** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
-** [sqlite3_value] objects.  There is one [sqlite3_value] object for
-** each parameter to the SQL function.  These routines are used to
-** extract values from the [sqlite3_value] objects.
-**
-** These routines work just like the corresponding 
-** [sqlite3_column_blob | sqlite3_column_* routines] except that 
-** these routines take a single [sqlite3_value*] pointer instead
-** of an [sqlite3_stmt*] pointer and an integer column number.
-**
-** The sqlite3_value_text16() interface extracts a UTF16 string
-** in the native byte-order of the host machine.  The
-** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
-** extract UTF16 strings as big-endian and little-endian respectively.
-**
-** The sqlite3_value_numeric_type() interface attempts to apply
-** numeric affinity to the value.  This means that an attempt is
-** made to convert the value to an integer or floating point.  If
-** such a conversion is possible without loss of information (in other
-** words if the value is a string that looks like a number)
-** then the conversion is done.  Otherwise no conversion occurs.  The 
-** [SQLITE_INTEGER | datatype] after conversion is returned.
-**
-** Please pay particular attention to the fact that the pointer that
-** is returned from [sqlite3_value_blob()], [sqlite3_value_text()], or
-** [sqlite3_value_text16()] can be invalidated by a subsequent call to
-** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
-** or [sqlite3_value_text16()].  
-**
-** These routines must be called from the same thread as
-** the SQL function that supplied the sqlite3_value* parameters.
-** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()]
-** interface, then these routines should be called from the same thread
-** that ran [sqlite3_column_value()].
-**
-*/
-const void *sqlite3_value_blob(sqlite3_value*);
-int sqlite3_value_bytes(sqlite3_value*);
-int sqlite3_value_bytes16(sqlite3_value*);
-double sqlite3_value_double(sqlite3_value*);
-int sqlite3_value_int(sqlite3_value*);
-sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-const unsigned char *sqlite3_value_text(sqlite3_value*);
-const void *sqlite3_value_text16(sqlite3_value*);
-const void *sqlite3_value_text16le(sqlite3_value*);
-const void *sqlite3_value_text16be(sqlite3_value*);
-int sqlite3_value_type(sqlite3_value*);
-int sqlite3_value_numeric_type(sqlite3_value*);
-
-/*
-** CAPI3REF: Obtain Aggregate Function Context {F16210}
-**
-** The implementation of aggregate SQL functions use this routine to allocate
-** a structure for storing their state.  
-** {F16211} The first time the sqlite3_aggregate_context() routine is
-** is called for a particular aggregate, SQLite allocates nBytes of memory
-** zeros that memory, and returns a pointer to it.
-** {F16212} On second and subsequent calls to sqlite3_aggregate_context()
-** for the same aggregate function index, the same buffer is returned. {END}
-** The implementation
-** of the aggregate can use the returned buffer to accumulate data.
-**
-** {F16213} SQLite automatically frees the allocated buffer when the aggregate
-** query concludes. {END}
-**
-** The first parameter should be a copy of the 
-** [sqlite3_context | SQL function context] that is the first
-** parameter to the callback routine that implements the aggregate
-** function.
-**
-** This routine must be called from the same thread in which
-** the aggregate SQL function is running.
-*/
-void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
-
-/*
-** CAPI3REF: User Data For Functions {F16240}
-**
-** {F16241} The sqlite3_user_data() interface returns a copy of
-** the pointer that was the pUserData parameter (the 5th parameter)
-** of the the [sqlite3_create_function()]
-** and [sqlite3_create_function16()] routines that originally
-** registered the application defined function. {END}
-**
-** {U16243} This routine must be called from the same thread in which
-** the application-defined function is running.
-*/
-void *sqlite3_user_data(sqlite3_context*);
-
-/*
-** CAPI3REF: Function Auxiliary Data {F16270}
-**
-** The following two functions may be used by scalar SQL functions to
-** associate meta-data with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated meta-data may be preserved. This may
-** be used, for example, to add a regular-expression matching scalar
-** function. The compiled version of the regular expression is stored as
-** meta-data associated with the SQL value passed as the regular expression
-** pattern.  The compiled regular expression can be reused on multiple
-** invocations of the same function so that the original pattern string
-** does not need to be recompiled on each invocation.
-**
-** {F16271}
-** The sqlite3_get_auxdata() interface returns a pointer to the meta-data
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function.
-** {F16272} If no meta-data has been ever been set for the Nth
-** argument of the function, or if the cooresponding function parameter
-** has changed since the meta-data was set, then sqlite3_get_auxdata()
-** returns a NULL pointer.
-**
-** {F16275} The sqlite3_set_auxdata() interface saves the meta-data
-** pointed to by its 3rd parameter as the meta-data for the N-th
-** argument of the application-defined function. {END} Subsequent
-** calls to sqlite3_get_auxdata() might return this data, if it has
-** not been destroyed. 
-** {F16277} If it is not NULL, SQLite will invoke the destructor 
-** function given by the 4th parameter to sqlite3_set_auxdata() on
-** the meta-data when the corresponding function parameter changes
-** or when the SQL statement completes, whichever comes first. {END}
-**
-** In practice, meta-data is preserved between function calls for
-** expressions that are constant at compile time. This includes literal
-** values and SQL variables.
-**
-** These routines must be called from the same thread in which
-** the SQL function is running.
-*/
-void *sqlite3_get_auxdata(sqlite3_context*, int N);
-void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
-
-
-/*
-** CAPI3REF: Constants Defining Special Destructor Behavior {F10280}
-**
-** These are special value for the destructor that is passed in as the
-** final argument to routines like [sqlite3_result_blob()].  If the destructor
-** argument is SQLITE_STATIC, it means that the content pointer is constant
-** and will never change.  It does not need to be destroyed.  The 
-** SQLITE_TRANSIENT value means that the content will likely change in
-** the near future and that SQLite should make its own private copy of
-** the content before returning.
-**
-** The typedef is necessary to work around problems in certain
-** C++ compilers.  See ticket #2191.
-*/
-typedef void (*sqlite3_destructor_type)(void*);
-#define SQLITE_STATIC      ((sqlite3_destructor_type)0)
-#define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)
-
-/*
-** CAPI3REF: Setting The Result Of An SQL Function {F16400}
-**
-** These routines are used by the xFunc or xFinal callbacks that
-** implement SQL functions and aggregates.  See
-** [sqlite3_create_function()] and [sqlite3_create_function16()]
-** for additional information.
-**
-** These functions work very much like the 
-** [sqlite3_bind_blob | sqlite3_bind_*] family of functions used
-** to bind values to host parameters in prepared statements.
-** Refer to the
-** [sqlite3_bind_blob | sqlite3_bind_* documentation] for
-** additional information.
-**
-** {F16402} The sqlite3_result_blob() interface sets the result from
-** an application defined function to be the BLOB whose content is pointed
-** to by the second parameter and which is N bytes long where N is the
-** third parameter. 
-** {F16403} The sqlite3_result_zeroblob() inerfaces set the result of
-** the application defined function to be a BLOB containing all zero
-** bytes and N bytes in size, where N is the value of the 2nd parameter.
-**
-** {F16407} The sqlite3_result_double() interface sets the result from
-** an application defined function to be a floating point value specified
-** by its 2nd argument.
-**
-** {F16409} The sqlite3_result_error() and sqlite3_result_error16() functions
-** cause the implemented SQL function to throw an exception.
-** {F16411} SQLite uses the string pointed to by the
-** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
-** as the text of an error message. {F16412} SQLite interprets the error
-** message string from sqlite3_result_error() as UTF8.  {F16413} SQLite
-** interprets the string from sqlite3_result_error16() as UTF16 in native
-** byte order.  {F16414} If the third parameter to sqlite3_result_error()
-** or sqlite3_result_error16() is negative then SQLite takes as the error
-** message all text up through the first zero character.
-** {F16415} If the third parameter to sqlite3_result_error() or
-** sqlite3_result_error16() is non-negative then SQLite takes that many
-** bytes (not characters) from the 2nd parameter as the error message.
-** {F16417} The sqlite3_result_error() and sqlite3_result_error16()
-** routines make a copy private copy of the error message text before
-** they return.  {END} Hence, the calling function can deallocate or
-** modify the text after they return without harm.
-** The sqlite3_result_error_code() function changes the error code
-** returned by SQLite as a result of an error in a function.  By default,
-** the error code is SQLITE_ERROR. 
-**
-** {F16421} The sqlite3_result_toobig() interface causes SQLite
-** to throw an error indicating that a string or BLOB is to long
-** to represent.  {F16422} The sqlite3_result_nomem() interface
-** causes SQLite to throw an exception indicating that the a
-** memory allocation failed.
-**
-** {F16431} The sqlite3_result_int() interface sets the return value
-** of the application-defined function to be the 32-bit signed integer
-** value given in the 2nd argument.
-** {F16432} The sqlite3_result_int64() interface sets the return value
-** of the application-defined function to be the 64-bit signed integer
-** value given in the 2nd argument.
-**
-** {F16437} The sqlite3_result_null() interface sets the return value
-** of the application-defined function to be NULL.
-**
-** {F16441} The sqlite3_result_text(), sqlite3_result_text16(), 
-** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
-** set the return value of the application-defined function to be
-** a text string which is represented as UTF-8, UTF-16 native byte order,
-** UTF-16 little endian, or UTF-16 big endian, respectively.
-** {F16442} SQLite takes the text result from the application from
-** the 2nd parameter of the sqlite3_result_text* interfaces.
-** {F16444} If the 3rd parameter to the sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter 
-** through the first zero character.
-** {F16447} If the 3rd parameter to the sqlite3_result_text* interfaces
-** is non-negative, then as many bytes (not characters) of the text
-** pointed to by the 2nd parameter are taken as the application-defined
-** function result.
-** {F16451} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
-** function as the destructor on the text or blob result when it has
-** finished using that result.
-** {F16453} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is the special constant SQLITE_STATIC, then
-** SQLite assumes that the text or blob result is constant space and
-** does not copy the space or call a destructor when it has
-** finished using that result.
-** {F16454} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
-** then SQLite makes a copy of the result into space obtained from
-** from [sqlite3_malloc()] before it returns.
-**
-** {F16461} The sqlite3_result_value() interface sets the result of
-** the application-defined function to be a copy the [sqlite3_value]
-** object specified by the 2nd parameter.  {F16463} The
-** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
-** so that [sqlite3_value] specified in the parameter may change or
-** be deallocated after sqlite3_result_value() returns without harm.
-**
-** {U16491} These routines are called from within the different thread 
-** than the one containing the application-defined function that recieved
-** the [sqlite3_context] pointer, the results are undefined.
-*/
-void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_double(sqlite3_context*, double);
-void sqlite3_result_error(sqlite3_context*, const char*, int);
-void sqlite3_result_error16(sqlite3_context*, const void*, int);
-void sqlite3_result_error_toobig(sqlite3_context*);
-void sqlite3_result_error_nomem(sqlite3_context*);
-void sqlite3_result_error_code(sqlite3_context*, int);
-void sqlite3_result_int(sqlite3_context*, int);
-void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-void sqlite3_result_null(sqlite3_context*);
-void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-void sqlite3_result_zeroblob(sqlite3_context*, int n);
-
-/*
-** CAPI3REF: Define New Collating Sequences {F16600}
-**
-** {F16601}
-** These functions are used to add new collation sequences to the
-** [sqlite3*] handle specified as the first argument. 
-**
-** {F16602}
-** The name of the new collation sequence is specified as a UTF-8 string
-** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). {F16603} In all cases
-** the name is passed as the second function argument.
-**
-** {F16604}
-** The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE] or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian or UTF-16 big-endian respectively. {F16605} The
-** third argument might also be [SQLITE_UTF16_ALIGNED] to indicate that
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF16 in the native byte order of the host computer.
-**
-** {F16607}
-** A pointer to the user supplied routine must be passed as the fifth
-** argument. {F16609} If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore).
-** {F16611} Each time the application
-** supplied function is invoked, it is passed a copy of the void* passed as
-** the fourth argument to sqlite3_create_collation() or
-** sqlite3_create_collation16() as its first parameter.
-**
-** {F16612}
-** The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered. {END} The application defined collation routine should
-** return negative, zero or positive if
-** the first string is less than, equal to, or greater than the second
-** string. i.e. (STRING1 - STRING2).
-**
-** {F16615}
-** The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** excapt that it takes an extra argument which is a destructor for
-** the collation.  {F16617} The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** {F16618}  Collations are destroyed when
-** they are overridden by later calls to the collation creation functions
-** or when the [sqlite3*] database handle is closed using [sqlite3_close()].
-*/
-int sqlite3_create_collation(
-  sqlite3*, 
-  const char *zName, 
-  int eTextRep, 
-  void*,
-  int(*xCompare)(void*,int,const void*,int,const void*)
-);
-int sqlite3_create_collation_v2(
-  sqlite3*, 
-  const char *zName, 
-  int eTextRep, 
-  void*,
-  int(*xCompare)(void*,int,const void*,int,const void*),
-  void(*xDestroy)(void*)
-);
-int sqlite3_create_collation16(
-  sqlite3*, 
-  const char *zName, 
-  int eTextRep, 
-  void*,
-  int(*xCompare)(void*,int,const void*,int,const void*)
-);
-
-/*
-** CAPI3REF: Collation Needed Callbacks {F16700}
-**
-** {F16701}
-** To avoid having to register all collation sequences before a database
-** can be used, a single callback function may be registered with the
-** database handle to be called whenever an undefined collation sequence is
-** required.
-**
-** {F16702}
-** If the function is registered using the sqlite3_collation_needed() API,
-** then it is passed the names of undefined collation sequences as strings
-** encoded in UTF-8. {F16703} If sqlite3_collation_needed16() is used, the names
-** are passed as UTF-16 in machine native byte order. {F16704} A call to either
-** function replaces any existing callback.
-**
-** {F16705} When the callback is invoked, the first argument passed is a copy
-** of the second argument to sqlite3_collation_needed() or
-** sqlite3_collation_needed16(). {F16706} The second argument is the database
-** handle.  {F16707} The third argument is one of [SQLITE_UTF8],
-** [SQLITE_UTF16BE], or [SQLITE_UTF16LE], indicating the most
-** desirable form of the collation sequence function required.
-** {F16708} The fourth parameter is the name of the
-** required collation sequence. {END}
-**
-** The callback function should register the desired collation using
-** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
-** [sqlite3_create_collation_v2()].
-*/
-int sqlite3_collation_needed(
-  sqlite3*, 
-  void*, 
-  void(*)(void*,sqlite3*,int eTextRep,const char*)
-);
-int sqlite3_collation_needed16(
-  sqlite3*, 
-  void*,
-  void(*)(void*,sqlite3*,int eTextRep,const void*)
-);
-
-/*
-** Specify the key for an encrypted database.  This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_key(
-  sqlite3 *db,                   /* Database to be rekeyed */
-  const void *pKey, int nKey     /* The key */
-);
-
-/*
-** Change the key on an open database.  If the current database is not
-** encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_rekey(
-  sqlite3 *db,                   /* Database to be rekeyed */
-  const void *pKey, int nKey     /* The new key */
-);
-
-/*
-** CAPI3REF:  Suspend Execution For A Short Time {F10530}
-**
-** {F10531} The sqlite3_sleep() function
-** causes the current thread to suspend execution
-** for at least a number of milliseconds specified in its parameter.
-**
-** {F10532} If the operating system does not support sleep requests with 
-** millisecond time resolution, then the time will be rounded up to 
-** the nearest second. {F10533} The number of milliseconds of sleep actually 
-** requested from the operating system is returned.
-**
-** {F10534} SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object. {END}
-*/
-int sqlite3_sleep(int);
-
-/*
-** CAPI3REF:  Name Of The Folder Holding Temporary Files {F10310}
-**
-** If this global variable is made to point to a string which is
-** the name of a folder (a.ka. directory), then all temporary files
-** created by SQLite will be placed in that directory.  If this variable
-** is NULL pointer, then SQLite does a search for an appropriate temporary
-** file directory.
-**
-** It is not safe to modify this variable once a database connection
-** has been opened.  It is intended that this variable be set once
-** as part of process initialization and before any SQLite interface
-** routines have been call and remain unchanged thereafter.
-*/
-SQLITE_EXTERN char *sqlite3_temp_directory;
-
-/*
-** CAPI3REF:  Test To See If The Database Is In Auto-Commit Mode {F12930}
-**
-** The sqlite3_get_autocommit() interfaces returns non-zero or
-** zero if the given database connection is or is not in autocommit mode,
-** respectively.   Autocommit mode is on
-** by default.  Autocommit mode is disabled by a [BEGIN] statement.
-** Autocommit mode is reenabled by a [COMMIT] or [ROLLBACK].
-**
-** If certain kinds of errors occur on a statement within a multi-statement
-** transactions (errors including [SQLITE_FULL], [SQLITE_IOERR], 
-** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the
-** transaction might be rolled back automatically.  The only way to
-** find out if SQLite automatically rolled back the transaction after
-** an error is to use this function.
-**
-** INVARIANTS:
-**
-** {F12931} The [sqlite3_get_autocommit()] interface returns non-zero or
-**          zero if the given database connection is or is not in autocommit
-**          mode, respectively.
-**
-** {F12932} Autocommit mode is on by default.
-**
-** {F12933} Autocommit mode is disabled by a successful [BEGIN] statement.
-**
-** {F12934} Autocommit mode is enabled by a successful [COMMIT] or [ROLLBACK]
-**          statement.
-** 
-**
-** LIMITATIONS:
-***
-** {U12936} If another thread changes the autocommit status of the database
-**          connection while this routine is running, then the return value
-**          is undefined.
-*/
-int sqlite3_get_autocommit(sqlite3*);
-
-/*
-** CAPI3REF:  Find The Database Handle Of A Prepared Statement {F13120}
-**
-** {F13121} The sqlite3_db_handle interface
-** returns the [sqlite3*] database handle to which a
-** [prepared statement] belongs.
-** {F13122} the database handle returned by sqlite3_db_handle
-** is the same database handle that was
-** the first argument to the [sqlite3_prepare_v2()] or its variants
-** that was used to create the statement in the first place.
-*/
-sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
-
-
-/*
-** CAPI3REF: Commit And Rollback Notification Callbacks {F12950}
-**
-** {F12951} The sqlite3_commit_hook() interface registers a callback
-** function to be invoked whenever a transaction is committed.
-** {F12952} Any callback set by a previous call to sqlite3_commit_hook()
-** for the same database connection is overridden.
-** {F12953} The sqlite3_rollback_hook() interface registers a callback
-** function to be invoked whenever a transaction is committed.
-** {F12954} Any callback set by a previous call to sqlite3_commit_hook()
-** for the same database connection is overridden.
-** {F12956} The pArg argument is passed through
-** to the callback.  {F12957} If the callback on a commit hook function 
-** returns non-zero, then the commit is converted into a rollback.
-**
-** {F12958} If another function was previously registered, its
-** pArg value is returned.  Otherwise NULL is returned.
-**
-** {F12959} Registering a NULL function disables the callback.
-**
-** {F12961} For the purposes of this API, a transaction is said to have been 
-** rolled back if an explicit "ROLLBACK" statement is executed, or
-** an error or constraint causes an implicit rollback to occur.
-** {F12962} The rollback callback is not invoked if a transaction is
-** automatically rolled back because the database connection is closed.
-** {F12964} The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
-** <todo> Check on this </todo> {END}
-**
-** These are experimental interfaces and are subject to change.
-*/
-void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
-
-/*
-** CAPI3REF: Data Change Notification Callbacks {F12970}
-**
-** {F12971} The sqlite3_update_hook() interface
-** registers a callback function with the database connection identified by the 
-** first argument to be invoked whenever a row is updated, inserted or deleted.
-** {F12972} Any callback set by a previous call to this function for the same 
-** database connection is overridden.
-**
-** {F12974} The second argument is a pointer to the function to invoke when a 
-** row is updated, inserted or deleted. 
-** {F12976} The first argument to the callback is
-** a copy of the third argument to sqlite3_update_hook().
-** {F12977} The second callback 
-** argument is one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE],
-** depending on the operation that caused the callback to be invoked.
-** {F12978} The third and 
-** fourth arguments to the callback contain pointers to the database and 
-** table name containing the affected row.
-** {F12979} The final callback parameter is 
-** the rowid of the row.
-** {F12981} In the case of an update, this is the rowid after 
-** the update takes place.
-**
-** {F12983} The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).
-**
-** {F12984} If another function was previously registered, its pArg value
-** is returned.  {F12985} Otherwise NULL is returned.
-*/
-void *sqlite3_update_hook(
-  sqlite3*, 
-  void(*)(void *,int ,char const *,char const *,sqlite3_int64),
-  void*
-);
-
-/*
-** CAPI3REF:  Enable Or Disable Shared Pager Cache {F10330}
-**
-** {F10331}
-** This routine enables or disables the sharing of the database cache
-** and schema data structures between connections to the same database.
-** {F10332}
-** Sharing is enabled if the argument is true and disabled if the argument
-** is false.
-**
-** {F10333} Cache sharing is enabled and disabled
-** for an entire process. {END} This is a change as of SQLite version 3.5.0.
-** In prior versions of SQLite, sharing was
-** enabled or disabled for each thread separately.
-**
-** {F10334}
-** The cache sharing mode set by this interface effects all subsequent
-** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** {F10335} Existing database connections continue use the sharing mode
-** that was in effect at the time they were opened. {END}
-**
-** Virtual tables cannot be used with a shared cache.  {F10336} When shared
-** cache is enabled, the [sqlite3_create_module()] API used to register
-** virtual tables will always return an error. {END}
-**
-** {F10337} This routine returns [SQLITE_OK] if shared cache was
-** enabled or disabled successfully.  {F10338} An [error code]
-** is returned otherwise. {END}
-**
-** {F10339} Shared cache is disabled by default. {END} But this might change in
-** future releases of SQLite.  Applications that care about shared
-** cache setting should set it explicitly.
-*/
-int sqlite3_enable_shared_cache(int);
-
-/*
-** CAPI3REF:  Attempt To Free Heap Memory {F17340}
-**
-** {F17341} The sqlite3_release_memory() interface attempts to
-** free N bytes of heap memory by deallocating non-essential memory
-** allocations held by the database labrary. {END}  Memory used
-** to cache database pages to improve performance is an example of
-** non-essential memory.  {F16342} sqlite3_release_memory() returns
-** the number of bytes actually freed, which might be more or less
-** than the amount requested.
-*/
-int sqlite3_release_memory(int);
-
-/*
-** CAPI3REF:  Impose A Limit On Heap Size {F17350}
-**
-** {F16351} The sqlite3_soft_heap_limit() interface
-** places a "soft" limit on the amount of heap memory that may be allocated
-** by SQLite. {F16352} If an internal allocation is requested 
-** that would exceed the soft heap limit, [sqlite3_release_memory()] is
-** invoked one or more times to free up some space before the allocation
-** is made. {END}
-**
-** {F16353} The limit is called "soft", because if
-** [sqlite3_release_memory()] cannot
-** free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
-**
-** {F16354}
-** A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** {F16355} The default value for the soft heap limit is zero.
-**
-** SQLite makes a best effort to honor the soft heap limit.  
-** {F16356} But if the soft heap limit cannot honored, execution will
-** continue without error or notification. {END}  This is why the limit is 
-** called a "soft" limit.  It is advisory only.
-**
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs.  Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. {F16357} The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. {END}  In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
-*/
-void sqlite3_soft_heap_limit(int);
-
-/*
-** CAPI3REF:  Extract Metadata About A Column Of A Table {F12850}
-**
-** This routine
-** returns meta-data about a specific column of a specific database
-** table accessible using the connection handle passed as the first function 
-** argument.
-**
-** The column is identified by the second, third and fourth parameters to 
-** this function. The second parameter is either the name of the database
-** (i.e. "main", "temp" or an attached database) containing the specified
-** table or NULL. If it is NULL, then all attached databases are searched
-** for the table using the same algorithm as the database engine uses to 
-** resolve unqualified table references.
-**
-** The third and fourth parameters to this function are the table and column 
-** name of the desired column, respectively. Neither of these parameters 
-** may be NULL.
-**
-** Meta information is returned by writing to the memory locations passed as
-** the 5th and subsequent parameters to this function. Any of these 
-** arguments may be NULL, in which case the corresponding element of meta 
-** information is ommitted.
-**
-** <pre>
-** Parameter     Output Type      Description
-** -----------------------------------
-**
-**   5th         const char*      Data type
-**   6th         const char*      Name of the default collation sequence 
-**   7th         int              True if the column has a NOT NULL constraint
-**   8th         int              True if the column is part of the PRIMARY KEY
-**   9th         int              True if the column is AUTOINCREMENT
-** </pre>
-**
-**
-** The memory pointed to by the character pointers returned for the 
-** declaration type and collation sequence is valid only until the next 
-** call to any sqlite API function.
-**
-** If the specified table is actually a view, then an error is returned.
-**
-** If the specified column is "rowid", "oid" or "_rowid_" and an 
-** INTEGER PRIMARY KEY column has been explicitly declared, then the output 
-** parameters are set for the explicitly declared column. If there is no
-** explicitly declared IPK column, then the output parameters are set as 
-** follows:
-**
-** <pre>
-**     data type: "INTEGER"
-**     collation sequence: "BINARY"
-**     not null: 0
-**     primary key: 1
-**     auto increment: 0
-** </pre>
-**
-** This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an SQLITE error code is returned and an error message
-** left in the database handle (to be retrieved using sqlite3_errmsg()).
-**
-** This API is only available if the library was compiled with the
-** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
-*/
-int sqlite3_table_column_metadata(
-  sqlite3 *db,                /* Connection handle */
-  const char *zDbName,        /* Database name or NULL */
-  const char *zTableName,     /* Table name */
-  const char *zColumnName,    /* Column name */
-  char const **pzDataType,    /* OUTPUT: Declared data type */
-  char const **pzCollSeq,     /* OUTPUT: Collation sequence name */
-  int *pNotNull,              /* OUTPUT: True if NOT NULL constraint exists */
-  int *pPrimaryKey,           /* OUTPUT: True if column part of PK */
-  int *pAutoinc               /* OUTPUT: True if column is auto-increment */
-);
-
-/*
-** CAPI3REF: Load An Extension {F12600}
-**
-** {F12601} The sqlite3_load_extension() interface
-** attempts to load an SQLite extension library contained in the file
-** zFile. {F12602} The entry point is zProc. {F12603} zProc may be 0
-** in which case the name of the entry point defaults
-** to "sqlite3_extension_init".
-**
-** {F12604} The sqlite3_load_extension() interface shall
-** return [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
-**
-** {F12605}
-** If an error occurs and pzErrMsg is not 0, then the
-** sqlite3_load_extension() interface shall attempt to fill *pzErrMsg with 
-** error message text stored in memory obtained from [sqlite3_malloc()].
-** {END}  The calling function should free this memory
-** by calling [sqlite3_free()].
-**
-** {F12606}
-** Extension loading must be enabled using [sqlite3_enable_load_extension()]
-** prior to calling this API or an error will be returned.
-*/
-int sqlite3_load_extension(
-  sqlite3 *db,          /* Load the extension into this database connection */
-  const char *zFile,    /* Name of the shared library containing extension */
-  const char *zProc,    /* Entry point.  Derived from zFile if 0 */
-  char **pzErrMsg       /* Put error message here if not 0 */
-);
-
-/*
-** CAPI3REF:  Enable Or Disable Extension Loading {F12620}
-**
-** So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following
-** API is provided to turn the [sqlite3_load_extension()] mechanism on and
-** off.  {F12622} It is off by default. {END} See ticket #1863.
-**
-** {F12621} Call the sqlite3_enable_load_extension() routine
-** with onoff==1 to turn extension loading on
-** and call it with onoff==0 to turn it back off again. {END}
-*/
-int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
-
-/*
-** CAPI3REF: Make Arrangements To Automatically Load An Extension {F12640}
-**
-** {F12641} This function
-** registers an extension entry point that is automatically invoked
-** whenever a new database connection is opened using
-** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()]. {END}
-**
-** This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new database connections.
-**
-** {F12642} Duplicate extensions are detected so calling this routine multiple
-** times with the same extension is harmless.
-**
-** {F12643} This routine stores a pointer to the extension in an array
-** that is obtained from sqlite_malloc(). {END} If you run a memory leak
-** checker on your program and it reports a leak because of this
-** array, then invoke [sqlite3_reset_auto_extension()] prior
-** to shutdown to free the memory.
-**
-** {F12644} Automatic extensions apply across all threads. {END}
-**
-** This interface is experimental and is subject to change or
-** removal in future releases of SQLite.
-*/
-int sqlite3_auto_extension(void *xEntryPoint);
-
-
-/*
-** CAPI3REF: Reset Automatic Extension Loading {F12660}
-**
-** {F12661} This function disables all previously registered
-** automatic extensions. {END}  This
-** routine undoes the effect of all prior [sqlite3_auto_extension()]
-** calls.
-**
-** {F12662} This call disabled automatic extensions in all threads. {END}
-**
-** This interface is experimental and is subject to change or
-** removal in future releases of SQLite.
-*/
-void sqlite3_reset_auto_extension(void);
-
-
-/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental.  The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stablizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
-** Structures used by the virtual table interface
-*/
-typedef struct sqlite3_vtab sqlite3_vtab;
-typedef struct sqlite3_index_info sqlite3_index_info;
-typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
-typedef struct sqlite3_module sqlite3_module;
-
-/*
-** A module is a class of virtual tables.  Each module is defined
-** by an instance of the following structure.  This structure consists
-** mostly of methods for the module.
-*/
-struct sqlite3_module {
-  int iVersion;
-  int (*xCreate)(sqlite3*, void *pAux,
-               int argc, const char *const*argv,
-               sqlite3_vtab **ppVTab, char**);
-  int (*xConnect)(sqlite3*, void *pAux,
-               int argc, const char *const*argv,
-               sqlite3_vtab **ppVTab, char**);
-  int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
-  int (*xDisconnect)(sqlite3_vtab *pVTab);
-  int (*xDestroy)(sqlite3_vtab *pVTab);
-  int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
-  int (*xClose)(sqlite3_vtab_cursor*);
-  int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
-                int argc, sqlite3_value **argv);
-  int (*xNext)(sqlite3_vtab_cursor*);
-  int (*xEof)(sqlite3_vtab_cursor*);
-  int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
-  int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
-  int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
-  int (*xBegin)(sqlite3_vtab *pVTab);
-  int (*xSync)(sqlite3_vtab *pVTab);
-  int (*xCommit)(sqlite3_vtab *pVTab);
-  int (*xRollback)(sqlite3_vtab *pVTab);
-  int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
-                       void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
-                       void **ppArg);
-
-  int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
-};
-
-/*
-** The sqlite3_index_info structure and its substructures is used to
-** pass information into and receive the reply from the xBestIndex
-** method of an sqlite3_module.  The fields under **Inputs** are the
-** inputs to xBestIndex and are read-only.  xBestIndex inserts its
-** results into the **Outputs** fields.
-**
-** The aConstraint[] array records WHERE clause constraints of the
-** form:
-**
-**         column OP expr
-**
-** Where OP is =, &lt;, &lt;=, &gt;, or &gt;=.  
-** The particular operator is stored
-** in aConstraint[].op.  The index of the column is stored in 
-** aConstraint[].iColumn.  aConstraint[].usable is TRUE if the
-** expr on the right-hand side can be evaluated (and thus the constraint
-** is usable) and false if it cannot.
-**
-** The optimizer automatically inverts terms of the form "expr OP column"
-** and makes other simplifications to the WHERE clause in an attempt to
-** get as many WHERE clause terms into the form shown above as possible.
-** The aConstraint[] array only reports WHERE clause terms in the correct
-** form that refer to the particular virtual table being queried.
-**
-** Information about the ORDER BY clause is stored in aOrderBy[].
-** Each term of aOrderBy records a column of the ORDER BY clause.
-**
-** The xBestIndex method must fill aConstraintUsage[] with information
-** about what parameters to pass to xFilter.  If argvIndex>0 then
-** the right-hand side of the corresponding aConstraint[] is evaluated
-** and becomes the argvIndex-th entry in argv.  If aConstraintUsage[].omit
-** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.
-**
-** The idxNum and idxPtr values are recorded and passed into xFilter.
-** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
-**
-** The orderByConsumed means that output from xFilter will occur in
-** the correct order to satisfy the ORDER BY clause so that no separate
-** sorting step is required.
-**
-** The estimatedCost value is an estimate of the cost of doing the
-** particular lookup.  A full scan of a table with N entries should have
-** a cost of N.  A binary search of a table of N entries should have a
-** cost of approximately log(N).
-*/
-struct sqlite3_index_info {
-  /* Inputs */
-  int nConstraint;           /* Number of entries in aConstraint */
-  struct sqlite3_index_constraint {
-     int iColumn;              /* Column on left-hand side of constraint */
-     unsigned char op;         /* Constraint operator */
-     unsigned char usable;     /* True if this constraint is usable */
-     int iTermOffset;          /* Used internally - xBestIndex should ignore */
-  } *aConstraint;            /* Table of WHERE clause constraints */
-  int nOrderBy;              /* Number of terms in the ORDER BY clause */
-  struct sqlite3_index_orderby {
-     int iColumn;              /* Column number */
-     unsigned char desc;       /* True for DESC.  False for ASC. */
-  } *aOrderBy;               /* The ORDER BY clause */
-
-  /* Outputs */
-  struct sqlite3_index_constraint_usage {
-    int argvIndex;           /* if >0, constraint is part of argv to xFilter */
-    unsigned char omit;      /* Do not code a test for this constraint */
-  } *aConstraintUsage;
-  int idxNum;                /* Number used to identify the index */
-  char *idxStr;              /* String, possibly obtained from sqlite3_malloc */
-  int needToFreeIdxStr;      /* Free idxStr using sqlite3_free() if true */
-  int orderByConsumed;       /* True if output is already ordered */
-  double estimatedCost;      /* Estimated cost of using this index */
-};
-#define SQLITE_INDEX_CONSTRAINT_EQ    2
-#define SQLITE_INDEX_CONSTRAINT_GT    4
-#define SQLITE_INDEX_CONSTRAINT_LE    8
-#define SQLITE_INDEX_CONSTRAINT_LT    16
-#define SQLITE_INDEX_CONSTRAINT_GE    32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-
-/*
-** This routine is used to register a new module name with an SQLite
-** connection.  Module names must be registered before creating new
-** virtual tables on the module, or before using preexisting virtual
-** tables of the module.
-*/
-int sqlite3_create_module(
-  sqlite3 *db,               /* SQLite connection to register module with */
-  const char *zName,         /* Name of the module */
-  const sqlite3_module *,    /* Methods for the module */
-  void *                     /* Client data for xCreate/xConnect */
-);
-
-/*
-** This routine is identical to the sqlite3_create_module() method above,
-** except that it allows a destructor function to be specified. It is
-** even more experimental than the rest of the virtual tables API.
-*/
-int sqlite3_create_module_v2(
-  sqlite3 *db,               /* SQLite connection to register module with */
-  const char *zName,         /* Name of the module */
-  const sqlite3_module *,    /* Methods for the module */
-  void *,                    /* Client data for xCreate/xConnect */
-  void(*xDestroy)(void*)     /* Module destructor function */
-);
-
-/*
-** Every module implementation uses a subclass of the following structure
-** to describe a particular instance of the module.  Each subclass will
-** be tailored to the specific needs of the module implementation.   The
-** purpose of this superclass is to define certain fields that are common
-** to all module implementations.
-**
-** Virtual tables methods can set an error message by assigning a
-** string obtained from sqlite3_mprintf() to zErrMsg.  The method should
-** take care that any prior string is freed by a call to sqlite3_free()
-** prior to assigning a new string to zErrMsg.  After the error message
-** is delivered up to the client application, the string will be automatically
-** freed by sqlite3_free() and the zErrMsg field will be zeroed.  Note
-** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field
-** since virtual tables are commonly implemented in loadable extensions which
-** do not have access to sqlite3MPrintf() or sqlite3Free().
-*/
-struct sqlite3_vtab {
-  const sqlite3_module *pModule;  /* The module for this virtual table */
-  int nRef;                       /* Used internally */
-  char *zErrMsg;                  /* Error message from sqlite3_mprintf() */
-  /* Virtual table implementations will typically add additional fields */
-};
-
-/* Every module implementation uses a subclass of the following structure
-** to describe cursors that point into the virtual table and are used
-** to loop through the virtual table.  Cursors are created using the
-** xOpen method of the module.  Each module implementation will define
-** the content of a cursor structure to suit its own needs.
-**
-** This superclass exists in order to define fields of the cursor that
-** are common to all implementations.
-*/
-struct sqlite3_vtab_cursor {
-  sqlite3_vtab *pVtab;      /* Virtual table of this cursor */
-  /* Virtual table implementations will typically add additional fields */
-};
-
-/*
-** The xCreate and xConnect methods of a module use the following API
-** to declare the format (the names and datatypes of the columns) of
-** the virtual tables they implement.
-*/
-int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
-
-/*
-** Virtual tables can provide alternative implementations of functions
-** using the xFindFunction method.  But global versions of those functions
-** must exist in order to be overloaded.
-**
-** This API makes sure a global version of a function with a particular
-** name and number of parameters exists.  If no such function exists
-** before this API is called, a new function is created.  The implementation
-** of the new function always causes an exception to be thrown.  So
-** the new function is not good for anything by itself.  Its only
-** purpose is to be a place-holder function that can be overloaded
-** by virtual tables.
-**
-** This API should be considered part of the virtual table interface,
-** which is experimental and subject to change.
-*/
-int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
-
-/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental.  The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
-*/
-
-/*
-** CAPI3REF: A Handle To An Open BLOB {F17800}
-**
-** An instance of the following opaque structure is used to 
-** represent an blob-handle.  A blob-handle is created by
-** [sqlite3_blob_open()] and destroyed by [sqlite3_blob_close()].
-** The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
-** can be used to read or write small subsections of the blob.
-** The [sqlite3_blob_bytes()] interface returns the size of the
-** blob in bytes.
-*/
-typedef struct sqlite3_blob sqlite3_blob;
-
-/*
-** CAPI3REF: Open A BLOB For Incremental I/O {F17810}
-**
-** {F17811} This interfaces opens a handle to the blob located
-** in row iRow,, column zColumn, table zTable in database zDb;
-** in other words,  the same blob that would be selected by:
-**
-** <pre>
-**     SELECT zColumn FROM zDb.zTable WHERE rowid = iRow;
-** </pre> {END}
-**
-** {F17812} If the flags parameter is non-zero, the blob is opened for 
-** read and write access. If it is zero, the blob is opened for read 
-** access. {END}
-**
-** {F17813} On success, [SQLITE_OK] is returned and the new 
-** [sqlite3_blob | blob handle] is written to *ppBlob. 
-** {F17814} Otherwise an error code is returned and 
-** any value written to *ppBlob should not be used by the caller.
-** {F17815} This function sets the database-handle error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
-** <todo>We should go through and mark all interfaces that behave this
-** way with a similar statement</todo>
-*/
-int sqlite3_blob_open(
-  sqlite3*,
-  const char *zDb,
-  const char *zTable,
-  const char *zColumn,
-  sqlite3_int64 iRow,
-  int flags,
-  sqlite3_blob **ppBlob
-);
-
-/*
-** CAPI3REF:  Close A BLOB Handle {F17830}
-**
-** Close an open [sqlite3_blob | blob handle].
-**
-** {F17831} Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in autocommit mode.
-** {F17832} If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit. {END}
-** Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed.  {F17833} Any errors that occur during
-** closing are reported as a non-zero return value.
-**
-** {F17839} The BLOB is closed unconditionally.  Even if this routine returns
-** an error code, the BLOB is still closed.
-*/
-int sqlite3_blob_close(sqlite3_blob *);
-
-/*
-** CAPI3REF:  Return The Size Of An Open BLOB {F17805}
-**
-** {F16806} Return the size in bytes of the blob accessible via the open 
-** [sqlite3_blob | blob-handle] passed as an argument.
-*/
-int sqlite3_blob_bytes(sqlite3_blob *);
-
-/*
-** CAPI3REF:  Read Data From A BLOB Incrementally {F17850}
-**
-** This function is used to read data from an open 
-** [sqlite3_blob | blob-handle] into a caller supplied buffer.
-** {F17851} n bytes of data are copied into buffer
-** z from the open blob, starting at offset iOffset.
-**
-** {F17852} If offset iOffset is less than n bytes from the end of the blob, 
-** [SQLITE_ERROR] is returned and no data is read.  {F17853} If n is
-** less than zero [SQLITE_ERROR] is returned and no data is read.
-**
-** {F17854} On success, SQLITE_OK is returned. Otherwise, an 
-** [error code] or an [extended error code] is returned.
-*/
-int sqlite3_blob_read(sqlite3_blob *, void *z, int n, int iOffset);
-
-/*
-** CAPI3REF:  Write Data Into A BLOB Incrementally {F17870}
-**
-** This function is used to write data into an open 
-** [sqlite3_blob | blob-handle] from a user supplied buffer.
-** {F17871} n bytes of data are copied from the buffer
-** pointed to by z into the open blob, starting at offset iOffset.
-**
-** {F17872} If the [sqlite3_blob | blob-handle] passed as the first argument
-** was not opened for writing (the flags parameter to [sqlite3_blob_open()]
-*** was zero), this function returns [SQLITE_READONLY].
-**
-** {F17873} This function may only modify the contents of the blob; it is
-** not possible to increase the size of a blob using this API.
-** {F17874} If offset iOffset is less than n bytes from the end of the blob, 
-** [SQLITE_ERROR] is returned and no data is written.  {F17875} If n is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-**
-** {F17876} On success, SQLITE_OK is returned. Otherwise, an 
-** [error code] or an [extended error code] is returned.
-*/
-int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
-
-/*
-** CAPI3REF:  Virtual File System Objects {F11200}
-**
-** A virtual filesystem (VFS) is an [sqlite3_vfs] object
-** that SQLite uses to interact
-** with the underlying operating system.  Most builds come with a
-** single default VFS that is appropriate for the host computer.
-** New VFSes can be registered and existing VFSes can be unregistered.
-** The following interfaces are provided.
-**
-** {F11201} The sqlite3_vfs_find() interface returns a pointer to 
-** a VFS given its name.  {F11202} Names are case sensitive.
-** {F11203} Names are zero-terminated UTF-8 strings.
-** {F11204} If there is no match, a NULL
-** pointer is returned. {F11205} If zVfsName is NULL then the default 
-** VFS is returned. {END}
-**
-** {F11210} New VFSes are registered with sqlite3_vfs_register().
-** {F11211} Each new VFS becomes the default VFS if the makeDflt flag is set.
-** {F11212} The same VFS can be registered multiple times without injury.
-** {F11213} To make an existing VFS into the default VFS, register it again
-** with the makeDflt flag set. {U11214} If two different VFSes with the
-** same name are registered, the behavior is undefined.  {U11215} If a
-** VFS is registered with a name that is NULL or an empty string,
-** then the behavior is undefined.
-** 
-** {F11220} Unregister a VFS with the sqlite3_vfs_unregister() interface.
-** {F11221} If the default VFS is unregistered, another VFS is chosen as
-** the default.  The choice for the new VFS is arbitrary.
-*/
-sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-int sqlite3_vfs_unregister(sqlite3_vfs*);
-
-/*
-** CAPI3REF: Mutexes {F17000}
-**
-** The SQLite core uses these routines for thread
-** synchronization.  Though they are intended for internal
-** use by SQLite, code that links against SQLite is
-** permitted to use any of these routines.
-**
-** The SQLite source code contains multiple implementations 
-** of these mutex routines.  An appropriate implementation
-** is selected automatically at compile-time.  The following
-** implementations are available in the SQLite core:
-**
-** <ul>
-** <li>   SQLITE_MUTEX_OS2
-** <li>   SQLITE_MUTEX_PTHREAD
-** <li>   SQLITE_MUTEX_W32
-** <li>   SQLITE_MUTEX_NOOP
-** </ul>
-**
-** The SQLITE_MUTEX_NOOP implementation is a set of routines 
-** that does no real locking and is appropriate for use in 
-** a single-threaded application.  The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
-** are appropriate for use on os/2, unix, and windows.
-** 
-** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
-** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
-** implementation is included with the library.  The
-** mutex interface routines defined here become external
-** references in the SQLite library for which implementations
-** must be provided by the application.  This facility allows an
-** application that links against SQLite to provide its own mutex
-** implementation without having to modify the SQLite core.
-**
-** {F17011} The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. {F17012} If it returns NULL
-** that means that a mutex could not be allocated. {F17013} SQLite
-** will unwind its stack and return an error. {F17014} The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
-**
-** <ul>
-** <li>  SQLITE_MUTEX_FAST
-** <li>  SQLITE_MUTEX_RECURSIVE
-** <li>  SQLITE_MUTEX_STATIC_MASTER
-** <li>  SQLITE_MUTEX_STATIC_MEM
-** <li>  SQLITE_MUTEX_STATIC_MEM2
-** <li>  SQLITE_MUTEX_STATIC_PRNG
-** <li>  SQLITE_MUTEX_STATIC_LRU
-** </ul> {END}
-**
-** {F17015} The first two constants cause sqlite3_mutex_alloc() to create
-** a new mutex.  The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
-** is used but not necessarily so when SQLITE_MUTEX_FAST is used. {END}
-** The mutex implementation does not need to make a distinction
-** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to.  {F17016} But SQLite will only request a recursive mutex in
-** cases where it really needs one.  {END} If a faster non-recursive mutex
-** implementation is available on the host platform, the mutex subsystem
-** might return such a mutex in response to SQLITE_MUTEX_FAST.
-**
-** {F17017} The other allowed parameters to sqlite3_mutex_alloc() each return
-** a pointer to a static preexisting mutex. {END}  Four static mutexes are
-** used by the current version of SQLite.  Future versions of SQLite
-** may add additional static mutexes.  Static mutexes are for internal
-** use by SQLite only.  Applications that use SQLite mutexes should
-** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
-** SQLITE_MUTEX_RECURSIVE.
-**
-** {F17018} Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
-** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call.  {F17034} But for the static 
-** mutex types, the same mutex is returned on every call that has
-** the same type number. {END}
-**
-** {F17019} The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. {F17020} SQLite is careful to deallocate every
-** dynamic mutex that it allocates. {U17021} The dynamic mutexes must not be in 
-** use when they are deallocated. {U17022} Attempting to deallocate a static
-** mutex results in undefined behavior. {F17023} SQLite never deallocates
-** a static mutex. {END}
-**
-** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
-** to enter a mutex. {F17024} If another thread is already within the mutex,
-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
-** SQLITE_BUSY. {F17025}  The sqlite3_mutex_try() interface returns SQLITE_OK
-** upon successful entry.  {F17026} Mutexes created using
-** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** {F17027} In such cases the,
-** mutex must be exited an equal number of times before another thread
-** can enter.  {U17028} If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** {F17029} SQLite will never exhibit
-** such behavior in its own use of mutexes. {END}
-**
-** Some systems (ex: windows95) do not the operation implemented by
-** sqlite3_mutex_try().  On those systems, sqlite3_mutex_try() will
-** always return SQLITE_BUSY.  {F17030} The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior. {END}
-**
-** {F17031} The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread.  {U17032} The behavior
-** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated.  {F17033} SQLite will
-** never do either. {END}
-**
-** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
-*/
-sqlite3_mutex *sqlite3_mutex_alloc(int);
-void sqlite3_mutex_free(sqlite3_mutex*);
-void sqlite3_mutex_enter(sqlite3_mutex*);
-int sqlite3_mutex_try(sqlite3_mutex*);
-void sqlite3_mutex_leave(sqlite3_mutex*);
-
-/*
-** CAPI3REF: Mutex Verifcation Routines {F17080}
-**
-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. {F17081} The SQLite core
-** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core.  {F17082} The core only
-** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag.  {U17087} External mutex implementations
-** are only required to provide these routines if SQLITE_DEBUG is
-** defined and if NDEBUG is not defined.
-**
-** {F17083} These routines should return true if the mutex in their argument
-** is held or not held, respectively, by the calling thread. {END}
-**
-** {X17084} The implementation is not required to provided versions of these
-** routines that actually work.
-** If the implementation does not provide working
-** versions of these routines, it should at least provide stubs
-** that always return true so that one does not get spurious
-** assertion failures. {END}
-**
-** {F17085} If the argument to sqlite3_mutex_held() is a NULL pointer then
-** the routine should return 1.  {END} This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist.  But the
-** the reason the mutex does not exist is because the build is not
-** using mutexes.  And we do not want the assert() containing the
-** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do.  {F17086} The sqlite3_mutex_notheld() 
-** interface should also return 1 when given a NULL pointer.
-*/
-int sqlite3_mutex_held(sqlite3_mutex*);
-int sqlite3_mutex_notheld(sqlite3_mutex*);
-
-/*
-** CAPI3REF: Mutex Types {F17001}
-**
-** {F17002} The [sqlite3_mutex_alloc()] interface takes a single argument
-** which is one of these integer constants. {END}
-*/
-#define SQLITE_MUTEX_FAST             0
-#define SQLITE_MUTEX_RECURSIVE        1
-#define SQLITE_MUTEX_STATIC_MASTER    2
-#define SQLITE_MUTEX_STATIC_MEM       3  /* sqlite3_malloc() */
-#define SQLITE_MUTEX_STATIC_MEM2      4  /* sqlite3_release_memory() */
-#define SQLITE_MUTEX_STATIC_PRNG      5  /* sqlite3_random() */
-#define SQLITE_MUTEX_STATIC_LRU       6  /* lru page list */
-
-/*
-** CAPI3REF: Low-Level Control Of Database Files {F11300}
-**
-** {F11301} The [sqlite3_file_control()] interface makes a direct call to the
-** xFileControl method for the [sqlite3_io_methods] object associated
-** with a particular database identified by the second argument. {F11302} The
-** name of the database is the name assigned to the database by the
-** <a href="lang_attach.html">ATTACH</a> SQL command that opened the
-** database. {F11303} To control the main database file, use the name "main"
-** or a NULL pointer. {F11304} The third and fourth parameters to this routine
-** are passed directly through to the second and third parameters of
-** the xFileControl method.  {F11305} The return value of the xFileControl
-** method becomes the return value of this routine.
-**
-** {F11306} If the second parameter (zDbName) does not match the name of any
-** open database file, then SQLITE_ERROR is returned. {F11307} This error
-** code is not remembered and will not be recalled by [sqlite3_errcode()]
-** or [sqlite3_errmsg()]. {U11308} The underlying xFileControl method might
-** also return SQLITE_ERROR.  {U11309} There is no way to distinguish between
-** an incorrect zDbName and an SQLITE_ERROR return from the underlying
-** xFileControl method. {END}
-**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
-*/
-int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
-
-/*
-** CAPI3REF: Testing Interface {F11400}
-**
-** The sqlite3_test_control() interface is used to read out internal
-** state of SQLite and to inject faults into SQLite for testing
-** purposes.  The first parameter a operation code that determines
-** the number, meaning, and operation of all subsequent parameters.
-**
-** This interface is not for use by applications.  It exists solely
-** for verifying the correct operation of the SQLite library.  Depending
-** on how the SQLite library is compiled, this interface might not exist.
-**
-** The details of the operation codes, their meanings, the parameters
-** they take, and what they do are all subject to change without notice.
-** Unlike most of the SQLite API, this function is not guaranteed to
-** operate consistently from one release to the next.
-*/
-int sqlite3_test_control(int op, ...);
-
-/*
-** CAPI3REF: Testing Interface Operation Codes {F11410}
-**
-** These constants are the valid operation code parameters used
-** as the first argument to [sqlite3_test_control()].
-**
-** These parameters and their meansing are subject to change
-** without notice.  These values are for testing purposes only.
-** Applications should not use any of these parameters or the
-** [sqlite3_test_control()] interface.
-*/
-#define SQLITE_TESTCTRL_FAULT_CONFIG             1
-#define SQLITE_TESTCTRL_FAULT_FAILURES           2
-#define SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES    3
-#define SQLITE_TESTCTRL_FAULT_PENDING            4
-
-
-
-
-
-/*
-** Undo the hack that converts floating point types to integer for
-** builds on processors without floating point support.
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# undef double
-#endif
-
-#ifdef __cplusplus
-}  /* End of the 'extern "C"' block */
-#endif
-#endif
diff --git a/Usermode/include/stddef.h b/Usermode/include/stddef.h
deleted file mode 100644 (file)
index 1995839..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef _STDDEF_H_
-#define _STDDEF_H_
-
-#include "acess/intdefs.h"
-
-#ifndef NULL
-# define NULL  ((void*)0)
-#endif
-
-typedef __intptr_t     size_t;
-
-#endif
diff --git a/Usermode/include/stdint.h b/Usermode/include/stdint.h
deleted file mode 100644 (file)
index 5df57ea..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- */
-#ifndef _STDINT_H_
-#define _STDINT_H_
-
-#include "acess/intdefs.h"
-
-#define INT_MIN        -0x80000000
-#define INT_MAX        0x7FFFFFFF
-
-typedef __uint8_t      uint8_t;
-typedef __uint16_t     uint16_t;
-typedef __uint32_t     uint32_t;
-typedef __uint64_t     uint64_t;
-typedef __int8_t       int8_t;
-typedef __int16_t      int16_t;
-typedef __int32_t      int32_t;
-typedef __int64_t      int64_t;
-
-typedef __intptr_t     intptr_t;
-typedef __uintptr_t    uintptr_t;
-
-//typedef uint64_t     off_t;
-
-#endif
diff --git a/Usermode/include/stdio.h b/Usermode/include/stdio.h
deleted file mode 100644 (file)
index be4f20a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * AcessOS LibC
- * stdlib.h
- */
-#ifndef __STDIO_H
-#define __STDIO_H
-
-#include <stdlib.h>
-#include <stdarg.h>
-
-/* === Types === */
-typedef struct sFILE   FILE;
-
-/* === CONSTANTS === */
-#define EOF    (-1)
-#define BUFSIZ 1024
-
-/* --- Standard IO --- */
-extern int     printf(const char *format, ...);
-extern int     vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args);
-extern int     vsprintf(char *buf, const char *format, va_list args);
-extern int     sprintf(char *buf, const char *format, ...);
-extern int     snprintf(char *buf, size_t maxlen, const char *format, ...);
-
-extern FILE    *fopen(const char *file, const char *mode);
-extern FILE    *freopen(const char *file, const char *mode, FILE *fp);
-extern FILE    *fdopen(int fd, const char *modes);
-extern int     fclose(FILE *fp);
-extern void    fflush(FILE *fp);
-extern off_t   ftell(FILE *fp);
-extern int     fseek(FILE *fp, long int amt, int whence);
-
-extern size_t  fread(void *buf, size_t size, size_t n, FILE *fp);
-extern size_t  fwrite(void *buf, size_t size, size_t n, FILE *fp);
-extern int     fgetc(FILE *fp);
-extern int     fputc(int ch, FILE *fp);
-extern int     getchar(void);
-extern int     putchar(int ch);
-
-extern int     fprintf(FILE *fp, const char *format, ...);
-extern int     vfprintf(FILE *fp, const char *format, va_list args);
-
-extern FILE    *stdin;
-extern FILE    *stdout;
-extern FILE    *stderr;
-
-#endif
-
diff --git a/Usermode/include/stdlib.h b/Usermode/include/stdlib.h
deleted file mode 100644 (file)
index 0e6d9e0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*\r
- * AcessOS LibC\r
- * stdlib.h\r
- */\r
-#ifndef __STDLIB_H\r
-#define __STDLIB_H\r
-\r
-#include <stddef.h>\r
-#include <stdarg.h>\r
-#include <sys/types.h>\r
-\r
-#define EXIT_FAILURE   1\r
-#define EXIT_SUCCESS   0\r
-\r
-/* --- Spinlock Macros --- */\r
-/* TODO: Support non-x86 architectures */\r
-#define DEFLOCK(_name) static int _spinlock_##_name=0;\r
-#define LOCK(_name)    do{int v=1;while(v){__asm__ __volatile__("lock cmpxchgl %0, (%1)":"=a"(v):"D"((&_spinlock_##_name)),"a"(1));yield();}}while(0)\r
-#define UNLOCK(_name) __asm__ __volatile__("lock andl $0, (%0)"::"D"(&_spinlock_##_name))\r
-\r
-/* --- StdLib --- */\r
-extern void    _exit(int code) __attribute__((noreturn));      /* NOTE: Also defined in acess/sys.h */\r
-extern int     atoi(const char *ptr);\r
-extern void    exit(int status) __attribute__((noreturn));\r
-extern void    atexit(void (*__func)(void));\r
-extern void    qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));\r
-\r
-/* --- Environment --- */\r
-extern char    *getenv(const char *name);\r
-\r
-/* --- Heap --- */\r
-extern void    free(void *mem);\r
-extern void    *malloc(size_t bytes);\r
-extern void    *calloc(size_t __nmemb, size_t __size);\r
-extern void    *realloc(void *__ptr, size_t __size);\r
-extern int     IsHeap(void *ptr);\r
-\r
-/* --- Random --- */\r
-extern void    srand(unsigned int seed);\r
-extern int     rand(void);\r
-extern int     rand_p(unsigned int *seedp);\r
-\r
-#ifndef SEEK_CUR\r
-# define SEEK_CUR      0\r
-# define SEEK_SET      1\r
-# define SEEK_END      (-1)\r
-#endif\r
-\r
-#endif\r
diff --git a/Usermode/include/string.h b/Usermode/include/string.h
deleted file mode 100644 (file)
index 7c38602..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * AcessOS LibC
- * string.h
- */
-#ifndef __STRING_H
-#define __STRING_H
-
-#include <stddef.h>
-
-/* Strings */
-extern size_t  strlen(const char *string);
-extern size_t  strnlen(const char *string, size_t maxlen);
-extern int     strcmp(const char *str1, const char *str2);
-extern int     strncmp(const char *str1, const char *str2, size_t maxlen);
-extern int     strcasecmp(const char *s1, const char *s2);
-extern int     strncasecmp(const char *s1, const char *s2, size_t maxlen);
-extern char    *strcpy(char *dst, const char *src);
-extern char    *strncpy(char *dst, const char *src, size_t num);
-extern char    *strcat(char *dst, const char *src);
-extern char    *strdup(const char *src);
-extern char    *strndup(const char *src, size_t length);
-extern char    *strchr(const char *str, int character);
-extern char    *strrchr(const char *str, int character);
-extern char    *strstr(const char *str1, const char *str2);
-extern size_t  strcspn(const char *haystack, const char *reject);
-extern size_t  strspn(const char *haystack, const char *accept);
-
-/* Memory */
-extern void *memset(void *dest, int val, size_t count);
-extern void *memcpy(void *dest, const void *src, size_t count);
-extern void *memmove(void *dest, const void *src, size_t count);
-extern int     memcmp(const void *mem1, const void *mem2, size_t count);
-extern void    *memchr(const void *ptr, int value, size_t num);
-
-#endif
diff --git a/Usermode/include/sys/basic_drivers.h b/Usermode/include/sys/basic_drivers.h
deleted file mode 100644 (file)
index ee5334e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * \file basic_drivers.h
- */
-#ifndef _SYS_BASIC_DRIVERS_H
-#define _SYS_BASIC_DRIVERS_H
-
-// === COMMON ===
-enum eDrv_Common {
-       DRV_IOCTL_NULL,
-       DRV_IOCTL_TYPE,
-       DRV_IOCTL_IDENT,
-       DRV_IOCTL_VER
-};
-
-enum eDrv_Types {
-       DRV_TYPE_NULL,          //!< NULL Type - Custom Interface
-       DRV_TYPE_TERMINAL,      //!< Terminal
-       DRV_TYPE_VIDEO,         //!< Video - LFB
-       DRV_TYPE_SOUND,         //!< Audio
-       DRV_TYPE_MOUSE,         //!< Mouse
-       DRV_TYPE_JOYSTICK       //!< Joystick / Gamepad
-};
-
-// === VIDEO ===
-enum eDrv_Video {
-       VID_IOCTL_SETMODE = 4,
-       VID_IOCTL_GETMODE,
-       VID_IOCTL_FINDMODE,
-       VID_IOCTL_MODEINFO,
-       VID_IOCTL_REQLFB        // Request LFB
-};\r
-struct sVideo_IOCtl_Mode {\r
-       short   id;\r
-       Uint16  width;\r
-       Uint16  height;\r
-       Uint16  bpp;\r
-};\r
-typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type
-
-// === MOUSE ===
-enum eDrv_Mouse {\r
-       MSE_IOCTL_SENS = 4,\r
-       MSE_IOCTL_MAX_X,\r
-       MSE_IOCTL_MAX_Y\r
-};
-
-#endif
diff --git a/Usermode/include/sys/socket.h b/Usermode/include/sys/socket.h
deleted file mode 100644 (file)
index 43cb3d6..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Acess2 C Library
- *
- * sys/sockets.h
- * - POSIX Sockets
- *
- * By John Hodge (thePowersGang)
- */
-#ifndef _SYS_SOCKETS_H_
-#define _SYS_SOCKETS_H_
-
-typedef int    socklen_t;
-
-typedef enum
-{
-       AF_UNSPEC       = 0,
-       AF_INET         = 4,
-       AF_INET6        = 6
-} sa_family_t;
-
-struct sockaddr
-{
-       sa_family_t     sa_family;
-       char            sa_data[16];
-};
-
-/**
- * \brief Values for \a domain of socket()
- */
-enum eSocketDomains
-{
-       PF_LOCAL,       //!< Machine-local comms
-       PF_INET,        //!< IPv4
-       PF_INET6,       //!< IPv6
-       PF_PACKET       //!< Low level packet interface
-};
-#define PF_UNIX        PF_LOCAL
-
-enum eSocketTypes
-{
-       SOCK_STREAM,    //!< Stream (TCP)
-       SOCK_DGRAM,     //!< Datagram (UDP)
-       SOCK_SEQPACKET, //!< 
-       SOCK_RAW,       //!< Raw packet access
-       SOCK_RDM        //!< Reliable non-ordered datagrams
-};
-
-/**
- * \brief Create a new socket descriptor
- * \param domain       Address family
- */
-extern int     socket(int domain, int type, int protocol);
-
-/**
- * \brief Bind a socket to an address
- */
-extern int     bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
-/**
- * \brief Connect to another socket
- */
-extern int     connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
-/**
- * \brief Listen for incoming connections
- */
-extern int     listen(int sockfd, int backlog);
-
-/**
- * \brief Accept an incoming connection
- */
-extern int     accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen);
-
-#endif
-
diff --git a/Usermode/include/sys/stat.h b/Usermode/include/sys/stat.h
deleted file mode 100644 (file)
index 1813365..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- */
-#ifndef _SYS_STAT_H_
-#define _SYS_STAT_H_
-
-#include "../acess/intdefs.h"  /* Evil */
-#include "../stddef.h"
-
-;
-typedef void   *dev_t; /* TODO: How to identify a device with Acess */
-typedef __uint64_t     ino_t;
-typedef unsigned int   blksize_t;
-typedef __uint64_t     blkcnt_t;
-typedef unsigned int   nlink_t;
-typedef __uint32_t     mode_t;
-
-typedef __uint32_t     uid_t;
-typedef __uint32_t     gid_t;
-
-#define        S_IFMT          0170000 /* type of file */
-#define                S_IFDIR 0040000 /* directory */
-#define                S_IFCHR 0020000 /* character special */
-#define                S_IFBLK 0060000 /* block special */
-#define                S_IFREG 0100000 /* regular */
-#define                S_IFLNK 0120000 /* symbolic link */
-#define                S_IFSOCK        0140000 /* socket */
-#define                S_IFIFO 0010000 /* fifo */
-
-
-struct stat
-{
-       dev_t     st_dev;     /* ID of device containing file */
-       ino_t     st_ino;     /* inode number */
-       mode_t    st_mode;    /* protection */
-       nlink_t   st_nlink;   /* number of hard links */
-       uid_t     st_uid;     /* user ID of owner */
-       gid_t     st_gid;     /* group ID of owner */
-       dev_t     st_rdev;    /* device ID (if special file) */
-       off_t     st_size;    /* total size, in bytes */
-       blksize_t st_blksize; /* blocksize for file system I/O */
-       blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
-       time_t    st_atime;   /* time of last access */
-       time_t    st_mtime;   /* time of last modification */
-       time_t    st_ctime;   /* time of last status change */
-};
-
-extern int stat(const char *path, struct stat *buf);
-extern int fstat(int fd, struct stat *buf);
-
-#endif
diff --git a/Usermode/include/sys/sys.h b/Usermode/include/sys/sys.h
deleted file mode 100644 (file)
index 08bf31e..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*\r
- Syscall Definitions\r
-*/\r
-#ifndef _SYS_SYS_H_\r
-#define _SYS_SYS_H_\r
-\r
-#include <acess/sys.h>\r
-\r
-#include <sys/types.h>\r
-\r
-#define O_RDONLY       OPENFLAG_READ\r
-#define O_WRONLY       OPENFLAG_WRITE\r
-#define O_CREAT        (OPENFLAG_CREATE|OPENFLAG_WRITE)\r
-#define O_TRUNC        OPENFLAG_WRITE\r
-#define O_APPEND       OPENFLAG_WRITE\r
-\r
-\r
-#if 0\r
-#define        OPEN_FLAG_READ  1\r
-#define        OPEN_FLAG_WRITE 2\r
-#define        OPEN_FLAG_EXEC  4\r
-\r
-enum {\r
-       K_WAITPID_DIE = 0\r
-};\r
-\r
-// === System Calls ===\r
-extern void    _exit(int ret);\r
-extern int     brk(int bssend);\r
-extern int     execve(char *file, char *args[], char *envp[]);\r
-extern int     fork();\r
-extern int     yield();\r
-extern int     sleep();\r
-\r
-extern int     open(char *file, int flags);\r
-extern int     close(int fp);\r
-extern int     read(int fp, int len, void *buf);\r
-extern int     write(int fp, int len, void *buf);\r
-extern int     tell(int fp);\r
-extern void    seek(int fp, int64_t dist, int flag);\r
-extern int     fstat(int fp, t_fstat *st);\r
-extern int     ioctl(int fp, int call, void *arg);\r
-extern int     readdir(int fp, char *file);\r
-\r
-extern int     select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);\r
-\r
-extern int     kdebug(char *fmt, ...);\r
-extern int     waitpid(int pid, int action);\r
-extern int     gettid();       // Get Thread ID\r
-extern int     getpid();       // Get Process ID\r
-extern int     sendmsg(int dest, unsigned int *Data);\r
-extern int     pollmsg(int *src, unsigned int *Data);\r
-extern int     getmsg(int *src, unsigned int *Data);\r
-#endif\r
-\r
-#endif\r
diff --git a/Usermode/include/sys/types.h b/Usermode/include/sys/types.h
deleted file mode 100644 (file)
index 4e38de3..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- */
-#ifndef _SYS_TYPES_H
-#define _SYS_TYPES_H
-
-#include "../acess/intdefs.h"
-
-typedef struct stat    t_fstat;
-
-#define FD_SETSIZE     128
-
-
-#define CLONE_VM       0x10
-
-typedef unsigned long  pid_t;
-typedef unsigned long  tid_t;
-typedef signed long long int   time_t;
-typedef long long int  off_t;
-
-typedef unsigned int   uint;
-
-typedef unsigned short fd_set_ent_t;
-
-/**
- * \brief fd_set for select()
- */
-typedef struct
-{
-       fd_set_ent_t    flags[FD_SETSIZE/16];
-}      fd_set;
-
-struct s_sysACL {
-       unsigned long   object; /*!< Group or user (bit 31 determines) */
-       unsigned long   perms;  /*!< Inverted by bit 31 */
-};
-struct s_sysFInfo {
-       unsigned int    mount;
-       unsigned long long      inode;
-       unsigned int    uid;
-       unsigned int    gid;
-       unsigned int    flags;
-       unsigned long long      size;
-       time_t  atime;
-       time_t  mtime;
-       time_t  ctime;
-        int    numacls;
-       struct s_sysACL acls[];
-} __attribute__((packed));
-typedef struct s_sysFInfo      t_sysFInfo;
-typedef struct s_sysACL        t_sysACL;
-
-extern void    FD_ZERO(fd_set *fdsetp);
-extern void    FD_CLR(int fd, fd_set *fdsetp);
-extern void    FD_SET(int fd, fd_set *fdsetp);
-extern int     FD_ISSET(int fd, fd_set *fdsetp);
-
-typedef __uint8_t      u_int8_t;
-typedef __uint16_t     u_int16_t;
-typedef __uint32_t     u_int32_t;
-
-#include "../sys/stat.h"
-
-#endif
diff --git a/Usermode/include/time.h b/Usermode/include/time.h
deleted file mode 100644 (file)
index bd7afce..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * time.h
- * - POSIX time functions
- */
-#ifndef _TIME_H_
-#define _TIME_H_
-
-#include <acess/intdefs.h>
-#include <sys/types.h> // time_t
-
-struct tm
-{
-        int    tm_sec;
-        int    tm_min;
-        int    tm_hour;
-        int    tm_mday;
-        int    tm_mon;
-        int    tm_year;        // 1900 based
-        int    tm_wday;
-        int    tm_yday;
-        int    tm_isdst;
-};
-
-#define CLOCKS_PER_SEC 1000
-
-typedef signed long long       clock_t;
-
-extern clock_t clock();
-
-#endif
-
diff --git a/Usermode/include/unistd.h b/Usermode/include/unistd.h
deleted file mode 100644 (file)
index d7d194d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _UNISTD_H_
-#define _UNISTD_H_
-
-#define        O_RDWR  (OPENFLAG_READ|OPENFLAG_WRITE)
-
-#include "acess/sys.h"
-
-
-#endif
-
diff --git a/Usermode/include/uri.h b/Usermode/include/uri.h
deleted file mode 100644 (file)
index 20b4b4c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Acess2 - URI Parser and opener
- * By John Hodge (thePowersGang)
- */
-#ifndef _LIB_URI_H_
-#define _LIB_URI_H_
-
-typedef struct sURI    tURI;
-typedef struct sURIFile        tURIFile;
-typedef struct sURIHandler     tURIHandler;
-
-enum eURIModes
-{
-       URI_MODE_READ  = 0x01,
-       URI_MODE_WRITE = 0x02
-};
-
-struct sURI
-{
-       char    *Proto;
-       char    *Host;
-       char    *PortStr;
-        int    PortNum;
-       char    *Path;
-};
-
-struct sURIHandler
-{
-       char    *Name;
-        int    BlockSize;
-       
-        int    (*Open)(char *Host, int Port, char *Path, int Flags);
-       void    (*Close)(int Handle);
-       size_t  (*Read)(int Handle, size_t Bytes, void *Buffer);
-       size_t  (*Write)(int Handle, size_t Bytes, void *Buffer);
-       size_t  (*GetSize)(int Handle);
-};
-
-// === FUNCTIONS ===
-extern tURI    *URI_Parse(const char *String);
-extern tURIFile        *URI_Open(int Mode, tURI *URI);
-extern int     URI_GetSize(tURIFile *File, size_t *Size);
-extern size_t  URI_Read(tURIFile *File, size_t Bytes, void *Buffer);
-extern size_t  URI_Write(tURIFile *File, size_t Bytes, void *Buffer);
-extern void    URI_Close(tURIFile *File);
-
-#endif

UCC git Repository :: git.ucc.asn.au