Added IO Cache Library, Moved FDD Driver to Modules Tree, Fixed Doxygen commenting
authorJohn Hodge <[email protected]>
Fri, 6 Nov 2009 10:29:56 +0000 (18:29 +0800)
committerJohn Hodge <[email protected]>
Fri, 6 Nov 2009 10:29:56 +0000 (18:29 +0800)
14 files changed:
Kernel/Makefile
Kernel/drv/fdd.c [deleted file]
Kernel/drv/iocache.c [new file with mode: 0644]
Kernel/drv/vterm.c
Kernel/include/fs_devfs.h
Kernel/include/iocache.h [new file with mode: 0644]
Kernel/include/tpl_drv_common.h
Kernel/include/tpl_drv_keyboard.h
Kernel/include/tpl_drv_video.h
Kernel/include/vfs.h
Makefile.cfg
Modules/FDD/Makefile [new file with mode: 0644]
Modules/FDD/fdd.c [new file with mode: 0644]
Modules/Makefile.tpl

index 5f15597..9bec844 100644 (file)
@@ -21,7 +21,7 @@ OBJ += binary.o bin/elf.o
 OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o vfs/memfile.o vfs/nodecache.o
 OBJ += vfs/fs/root.o vfs/fs/devfs.o
 OBJ += $(addprefix vfs/fs/, $(addsuffix .o,$(FILESYSTEMS)))
-OBJ += drv/fifo.o drv/dma.o drv/pci.o drv/kb.o drv/vga.o drv/vterm.o
+OBJ += drv/fifo.o drv/dma.o drv/iocache.o drv/pci.o drv/kb.o drv/vga.o drv/vterm.o
 OBJ += $(addprefix drv/, $(addsuffix .o,$(DRIVERS)))
 OBJ := $(addsuffix .$(ARCH), $(OBJ))
 MODS += $(addprefix ../Modules/, $(addsuffix .xo.$(ARCH),$(MODULES)))
@@ -33,13 +33,16 @@ DEPFILES := $(DEPFILES:%.o.$(ARCH)=%.d.$(ARCH))
 SRCFILES  = $(OBJ:%.o.$(ARCH)=%.c)
 SRCFILES := $(SRCFILES:%.ao.$(ARCH)=%.asm)
 
-.PHONY: all clean
+.PHONY: all clean apidoc
 
 all: $(BIN)
 
 clean:
        @$(RM) $(BIN) $(OBJ) $(DEPFILES)
 
+apidoc:
+       doxygen Doxyfile.api
+
 $(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
        @echo --- LD -o $(BIN)
        @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) -Map ../Map.$(ARCH).txt
diff --git a/Kernel/drv/fdd.c b/Kernel/drv/fdd.c
deleted file mode 100644 (file)
index 3c86b08..0000000
+++ /dev/null
@@ -1,770 +0,0 @@
-/*\r
- * AcessOS 0.1\r
- * Floppy Disk Access Code\r
- */\r
-#define DEBUG  1\r
-#include <common.h>\r
-#include <modules.h>\r
-#include <fs_devfs.h>\r
-#include <tpl_drv_common.h>\r
-#include <dma.h>\r
-\r
-#define WARN   0\r
-\r
-// === CONSTANTS ===\r
-// --- Current Version\r
-#define FDD_VERSION     ((0<<8)|(75))\r
-\r
-// --- Options\r
-#define USE_CACHE      1       // Use Sector Cache\r
-#define        CACHE_SIZE      32      // Number of cachable sectors\r
-#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation\r
-#define MOTOR_ON_DELAY 500             // Miliseconds\r
-#define MOTOR_OFF_DELAY        2000    // Miliseconds\r
-\r
-// === TYPEDEFS ===\r
-/**\r
- * \brief Representation of a floppy drive\r
- */\r
-typedef struct {\r
-        int    type;\r
-       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off\r
-        int    track[2];\r
-        int    timer;\r
-       tVFS_Node       Node;\r
-} t_floppyDevice;\r
-\r
-/**\r
- * \brief Cached Sector\r
- */\r
-typedef struct {\r
-       Uint64  timestamp;\r
-       Uint16  disk;\r
-       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
-       Uint8   data[512];\r
-} t_floppySector;\r
-\r
-// === CONSTANTS ===\r
-static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };\r
-static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
-static const short     cPORTBASE[] = { 0x3F0, 0x370 };\r
-\r
-enum FloppyPorts {\r
-       PORT_STATUSA    = 0x0,\r
-       PORT_STATUSB    = 0x1,\r
-       PORT_DIGOUTPUT  = 0x2,\r
-       PORT_MAINSTATUS = 0x4,\r
-       PORT_DATARATE   = 0x4,\r
-       PORT_DATA               = 0x5,\r
-       PORT_DIGINPUT   = 0x7,\r
-       PORT_CONFIGCTRL = 0x7\r
-};\r
-\r
-enum FloppyCommands {\r
-       FIX_DRIVE_DATA  = 0x03,\r
-       HECK_DRIVE_STATUS       = 0x04,\r
-       CALIBRATE_DRIVE = 0x07,\r
-       CHECK_INTERRUPT_STATUS = 0x08,\r
-       SEEK_TRACK              = 0x0F,\r
-       READ_SECTOR_ID  = 0x4A,\r
-       FORMAT_TRACK    = 0x4D,\r
-       READ_TRACK              = 0x42,\r
-       READ_SECTOR             = 0x66,\r
-       WRITE_SECTOR    = 0xC5,\r
-       WRITE_DELETE_SECTOR     = 0xC9,\r
-       READ_DELETE_SECTOR      = 0xCC,\r
-};\r
-\r
-// === PROTOTYPES ===\r
-// --- Filesystem\r
- int   FDD_Install(char **Arguments);\r
-char   *FDD_ReadDir(tVFS_Node *Node, int pos);\r
-tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
- int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
-Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-// --- Raw Disk Access\r
- int   FDD_ReadSector(int disk, int lba, void *buf);\r
-// --- Helpers\r
-void   FDD_IRQHandler(int Num);\r
-void   FDD_WaitIRQ();\r
-void   FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
-inline void    FDD_AquireSpinlock();\r
-inline void    FDD_FreeSpinlock();\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock();\r
-inline void FDD_FreeCacheSpinlock();\r
-#endif\r
-void   FDD_int_SendByte(int base, char byte);\r
- int   FDD_int_GetByte(int base);\r
-void   FDD_Reset(int id);\r
-void   FDD_Recalibrate(int disk);\r
- int   FDD_int_SeekTrack(int disk, int head, int track);\r
-void   FDD_int_TimerCallback(int arg);\r
-void   FDD_int_StopMotor(int disk);\r
-void   FDD_int_StartMotor(int disk);\r
- int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);\r
-\r
-// === GLOBALS ===\r
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, NULL);\r
-t_floppyDevice gFDD_Devices[2];\r
-volatile int   fdd_inUse = 0;\r
-volatile int   fdd_irq6 = 0;\r
-tDevFS_Driver  gFDD_DriverInfo = {\r
-       NULL, "fdd",\r
-       {\r
-       .Size = -1,\r
-       .NumACLs = 1,\r
-       .ACLs = &gVFS_ACL_EveryoneRX,\r
-       .Flags = VFS_FFLAG_DIRECTORY,\r
-       .ReadDir = FDD_ReadDir,\r
-       .FindDir = FDD_FindDir,\r
-       .IOCtl = FDD_IOCtl\r
-       }\r
-};\r
-#if USE_CACHE\r
-int    siFDD_CacheInUse = 0;\r
-int    siFDD_SectorCacheSize = CACHE_SIZE;\r
-t_floppySector sFDD_SectorCache[CACHE_SIZE];\r
-#endif\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int FDD_Install(char **Arguments)\r
- * \brief Installs floppy driver\r
- */\r
-int FDD_Install(char **Arguments)\r
-{\r
-       Uint8 data;\r
-       \r
-       // Determine Floppy Types (From CMOS)\r
-       outb(0x70, 0x10);\r
-       data = inb(0x71);\r
-       gFDD_Devices[0].type = data >> 4;\r
-       gFDD_Devices[1].type = data & 0xF;\r
-       gFDD_Devices[0].track[0] = -1;\r
-       gFDD_Devices[1].track[1] = -1;\r
-       \r
-       Log("[FDD ] Detected Disk 0: %s and Disk 1: %s\n", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
-       \r
-       // Clear FDD IRQ Flag\r
-       FDD_SensInt(0x3F0, NULL, NULL);\r
-       // Install IRQ6 Handler\r
-       IRQ_AddHandler(6, FDD_IRQHandler);\r
-       // Reset Primary FDD Controller\r
-       FDD_Reset(0);\r
-       \r
-       // Initialise Root Node\r
-       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime\r
-               = gFDD_DriverInfo.RootNode.ATime = now();\r
-       \r
-       // Initialise Child Nodes\r
-       gFDD_Devices[0].Node.Inode = 0;\r
-       gFDD_Devices[0].Node.Flags = 0;\r
-       gFDD_Devices[0].Node.NumACLs = 0;\r
-       gFDD_Devices[0].Node.Read = FDD_ReadFS;\r
-       gFDD_Devices[0].Node.Write = NULL;//fdd_writeFS;\r
-       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));\r
-       \r
-       gFDD_Devices[1].Node.Inode = 1;\r
-       \r
-       // Set Lengths\r
-       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
-       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
-       \r
-       // Create Sector Cache\r
-       #if USE_CACHE\r
-       //sFDD_SectorCache = malloc(sizeof(*sFDD_SectorCache)*CACHE_SIZE);\r
-       //siFDD_SectorCacheSize = CACHE_SIZE;\r
-       #endif\r
-       \r
-       // Register with devfs\r
-       DevFS_AddDevice(&gFDD_DriverInfo);\r
-       \r
-       return 0;\r
-}\r
-\r
-/**\r
- * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
- * \brief Read Directory\r
- */\r
-char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
-{\r
-       char    name[2] = "0\0";\r
-       //Update Accessed Time\r
-       //gFDD_DrvInfo.rootNode.atime = now();\r
-       \r
-       //Check for bounds\r
-       if(pos >= 2 || pos < 0)\r
-               return NULL;\r
-       \r
-       if(gFDD_Devices[pos].type == 0)\r
-               return VFS_SKIP;\r
-       \r
-       name[0] += pos;\r
-       \r
-       //Return\r
-       return strdup(name);\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);\r
- * \brief Find File Routine (for vfs_node)\r
- */\r
-tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename)\r
-{\r
-        int    i;\r
-       \r
-       ENTER("sfilename", filename);\r
-       \r
-       // Sanity check string\r
-       if(filename == NULL) {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Check string length (should be 1)\r
-       if(filename[0] == '\0' || filename[1] != '\0') {\r
-               LEAVE('n');\r
-               return NULL;\r
-       }\r
-       \r
-       // Get First character\r
-       i = filename[0] - '0';\r
-       \r
-       // Check for 1st disk and if it is present return\r
-       if(i == 0 && gFDD_Devices[0].type != 0) {\r
-               LEAVE('p', &gFDD_Devices[0].Node);\r
-               return &gFDD_Devices[0].Node;\r
-       }\r
-       \r
-       // Check for 2nd disk and if it is present return\r
-       if(i == 1 && gFDD_Devices[1].type != 0) {\r
-               LEAVE('p', &gFDD_Devices[1].Node);\r
-               return &gFDD_Devices[1].Node;\r
-       }\r
-       \r
-       // Else return null\r
-       LEAVE('n');\r
-       return NULL;\r
-}\r
-\r
-/**\r
- * \fn int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
- * \brief Stub ioctl function\r
- */\r
-int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
-{\r
-       switch(id)\r
-       {\r
-       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;\r
-       case DRV_IOCTL_IDENT:   memcpy(data, "FDD\0", 4);       return 1;\r
-       case DRV_IOCTL_VERSION: return FDD_VERSION;\r
-       default:        return 0;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn Uint64 fdd_readFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
- * \brief Read Data from a disk\r
-*/\r
-Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
-{\r
-       int i = 0;\r
-       int     disk;\r
-       Uint32  buf[128];\r
-       \r
-       ENTER("xoff xlen pbuffer", off, len, buffer);\r
-       \r
-       if(node == NULL) {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       \r
-       if(node->Inode != 0 && node->Inode != 1) {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       \r
-       disk = node->Inode;\r
-       \r
-       // Update Accessed Time\r
-       node->ATime = now();\r
-       \r
-       if((off & 0x1FF) || (len & 0x1FF))\r
-       {\r
-               // Un-Aligned Offset/Length\r
-                int    startOff = off>>9;\r
-                int    sectOff = off&0x1FF;\r
-                int    sectors = (len+0x1FF)>>9;\r
-       \r
-               LOG("Non-aligned Read");\r
-               \r
-               //Read Starting Sector\r
-               if(!FDD_ReadSector(disk, startOff, buf))\r
-                       return 0;\r
-               memcpy(buffer, (char*)(buf+sectOff), len>512-sectOff?512-sectOff:len);\r
-               \r
-               //If the data size is one sector or less\r
-               if(len <= 512-sectOff) {\r
-                       LEAVE('X', len);\r
-                       return len;     //Return\r
-               }\r
-               buffer += 512-sectOff;\r
-       \r
-               //Read Middle Sectors\r
-               for(i=1;i<sectors-1;i++)        {\r
-                       if(!FDD_ReadSector(disk, startOff+i, buf)) {\r
-                               LEAVE('i', -1);\r
-                               return -1;\r
-                       }\r
-                       memcpy(buffer, buf, 512);\r
-                       buffer += 512;\r
-               }\r
-       \r
-               //Read End Sectors\r
-               if(!FDD_ReadSector(disk, startOff+i, buf))\r
-                       return 0;\r
-               memcpy(buffer, buf, (len&0x1FF)-sectOff);\r
-               
-               LEAVE('X', len);\r
-               return len;\r
-       }\r
-       else\r
-       {\r
-                int    count = len >> 9;\r
-                int    sector = off >> 9;\r
-               LOG("Aligned Read");\r
-               //Aligned Offset and Length - Simple Code\r
-               for(i=0;i<count;i++)\r
-               {\r
-                       FDD_ReadSector(disk, sector, buf);\r
-                       memcpy(buffer, buf, 512);\r
-                       buffer += 512;\r
-                       sector++;\r
-               }
-               LEAVE('i', len);\r
-               return len;\r
-       }\r
-}\r
-\r
-/**\r
- * \fn int FDD_ReadSector(int disk, int lba, void *buf)\r
- * \fn Read a sector from disk\r
-*/\r
-int FDD_ReadSector(int disk, int lba, void *buf)\r
-{\r
-        int    cyl, head, sec;\r
-        int    spt, base;\r
-        int    i;\r
-       \r
-       ENTER("idisk xlba pbuf", disk, lba, buf);\r
-       \r
-       #if USE_CACHE\r
-       FDD_AquireCacheSpinlock();\r
-       for(i=0;i<siFDD_SectorCacheSize;i++)\r
-       {\r
-               if(sFDD_SectorCache[i].timestamp == 0)  continue;\r
-               if(sFDD_SectorCache[i].disk == disk\r
-               && sFDD_SectorCache[i].sector == lba) {\r
-                       LOG("Found %i in cache %i", lba, i);\r
-                       memcpy(buf, sFDD_SectorCache[i].data, 512);\r
-                       sFDD_SectorCache[i].timestamp = now();\r
-                       FDD_FreeCacheSpinlock();\r
-                       LEAVE('i', 1);\r
-                       return 1;\r
-               }\r
-       }\r
-       LOG("Read %i from Disk", lba);\r
-       FDD_FreeCacheSpinlock();\r
-       #endif\r
-       \r
-       base = cPORTBASE[disk>>1];\r
-       \r
-       LOG("Calculating Disk Dimensions");\r
-       //Get CHS position\r
-       if(FDD_int_GetDims(gFDD_Devices[disk].type, lba, &cyl, &head, &sec, &spt) != 1) {\r
-               LEAVE('i', -1);\r
-               return -1;\r
-       }\r
-       \r
-       // Remove Old Timer\r
-       Time_RemoveTimer(gFDD_Devices[disk].timer);\r
-       // Check if Motor is on\r
-       if(gFDD_Devices[disk].motorState == 0) {\r
-               FDD_int_StartMotor(disk);\r
-       }\r
-       \r
-       LOG("Wait for Motor Spinup");\r
-       \r
-       // Wait for spinup\r
-       while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();\r
-       \r
-       LOG("C:%i,H:%i,S:%i", cyl, head, sec);\r
-       LOG("Acquire Spinlock");\r
-       \r
-       FDD_AquireSpinlock();\r
-       \r
-       // Seek to track\r
-       outb(base+CALIBRATE_DRIVE, 0);\r
-       i = 0;\r
-       while(FDD_int_SeekTrack(disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )        Threads_Yield();\r
-       //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ\r
-       \r
-       LOG("Setting DMA for read");\r
-       \r
-       //Read Data from DMA\r
-       DMA_SetChannel(2, 512, 1);      // Read 512 Bytes\r
-       \r
-       LOG("Sending read command");\r
-       \r
-       //Threads_Wait(100);    // Wait for Head to settle\r
-       Time_Delay(100);\r
-       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6\r
-       FDD_int_SendByte(base, (head << 2) | (disk&1));\r
-       FDD_int_SendByte(base, (Uint8)cyl);\r
-       FDD_int_SendByte(base, (Uint8)head);\r
-       FDD_int_SendByte(base, (Uint8)sec);\r
-       FDD_int_SendByte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})\r
-       FDD_int_SendByte(base, spt);    // SPT\r
-       FDD_int_SendByte(base, 0x1B);   // Gap Length (27 is default)\r
-       FDD_int_SendByte(base, 0xFF);   // Data Length\r
-       \r
-       // Wait for IRQ\r
-       LOG("Waiting for Data to be read");\r
-       FDD_WaitIRQ();\r
-       \r
-       // Read Data from DMA\r
-       LOG(" FDD_ReadSector: Reading Data");\r
-       DMA_ReadData(2, 512, buf);\r
-       \r
-       // Clear Input Buffer\r
-       LOG("Clearing Input Buffer");\r
-       FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
-       FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
-       \r
-       LOG("Realeasing Spinlock and Setting motor to stop");\r
-       // Release Spinlock\r
-       FDD_FreeSpinlock();\r
-       \r
-       //Set timer to turn off motor affter a gap\r
-       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)disk);   //One Shot Timer
-\r
-       #if USE_CACHE\r
-       {\r
-               FDD_AquireCacheSpinlock();\r
-               int oldest = 0;\r
-               for(i=0;i<siFDD_SectorCacheSize;i++)\r
-               {\r
-                       if(sFDD_SectorCache[i].timestamp == 0) {\r
-                               oldest = i;\r
-                               break;\r
-                       }\r
-                       if(sFDD_SectorCache[i].timestamp < sFDD_SectorCache[oldest].timestamp)\r
-                               oldest = i;\r
-               }\r
-               sFDD_SectorCache[oldest].timestamp = now();\r
-               sFDD_SectorCache[oldest].disk = disk;\r
-               sFDD_SectorCache[oldest].sector = lba;\r
-               memcpy(sFDD_SectorCache[oldest].data, buf, 512);\r
-               FDD_FreeCacheSpinlock();\r
-       }\r
-       #endif\r
-
-       LEAVE('i', 1);\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_SeekTrack(int disk, int track)\r
- * \brief Seek disk to selected track\r
- */\r
-int FDD_int_SeekTrack(int disk, int head, int track)\r
-{\r
-       Uint8   sr0, cyl;\r
-        int    base;\r
-       \r
-       base = cPORTBASE[disk>>1];\r
-       \r
-       // Check if seeking is needed\r
-       if(gFDD_Devices[disk].track[head] == track)\r
-               return 1;\r
-       \r
-       // - Seek Head 0\r
-       FDD_int_SendByte(base, SEEK_TRACK);\r
-       FDD_int_SendByte(base, (head<<2)|(disk&1));\r
-       FDD_int_SendByte(base, track);  // Send Seek command\r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ\r
-       if((sr0 & 0xF0) != 0x20) {
-               LOG("sr0 = 0x%x", sr0);
-               return 0;       //Check Status
-       }\r
-       if(cyl != track)        return 0;\r
-       \r
-       // Set Track in structure\r
-       gFDD_Devices[disk].track[head] = track;\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
- * \brief Get Dimensions of a disk\r
- */\r
-int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
-{\r
-       switch(type) {\r
-       case 0:\r
-               return 0;\r
-       \r
-       // 360Kb 5.25"\r
-       case 1:\r
-               *spt = 9;\r
-               *s = (lba % 9) + 1;\r
-               *c = lba / 18;\r
-               *h = (lba / 9) & 1;\r
-               break;\r
-       \r
-       // 1220Kb 5.25"\r
-       case 2:\r
-               *spt = 15;\r
-               *s = (lba % 15) + 1;\r
-               *c = lba / 30;\r
-               *h = (lba / 15) & 1;\r
-               break;\r
-       \r
-       // 720Kb 3.5"\r
-       case 3:\r
-               *spt = 9;\r
-               *s = (lba % 9) + 1;\r
-               *c = lba / 18;\r
-               *h = (lba / 9) & 1;\r
-               break;\r
-       \r
-       // 1440Kb 3.5"\r
-       case 4:\r
-               *spt = 18;\r
-               *s = (lba % 18) + 1;\r
-               *c = lba / 36;\r
-               *h = (lba / 18) & 1;\r
-               break;\r
-               \r
-       // 2880Kb 3.5"\r
-       case 5:\r
-               *spt = 36;\r
-               *s = (lba % 36) + 1;\r
-               *c = lba / 72;\r
-               *h = (lba / 32) & 1;\r
-               break;\r
-               \r
-       default:\r
-               return -2;\r
-       }\r
-       return 1;\r
-}\r
-\r
-/**\r
- * \fn void FDD_IRQHandler(int Num)\r
- * \brief Handles IRQ6\r
- */\r
-void FDD_IRQHandler(int Num)\r
-{\r
-    fdd_irq6 = 1;\r
-}\r
-\r
-/**\r
- * \fn FDD_WaitIRQ()\r
- * \brief Wait for an IRQ6\r
- */\r
-void FDD_WaitIRQ()\r
-{\r
-       // Wait for IRQ\r
-       while(!fdd_irq6)        Threads_Yield();\r
-       fdd_irq6 = 0;\r
-}\r
-\r
-void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
-{\r
-       FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);\r
-       if(sr0) *sr0 = FDD_int_GetByte(base);\r
-       else    FDD_int_GetByte(base);\r
-       if(cyl) *cyl = FDD_int_GetByte(base);\r
-       else    FDD_int_GetByte(base);\r
-}\r
-\r
-void FDD_AquireSpinlock()\r
-{\r
-       while(fdd_inUse)\r
-               Threads_Yield();\r
-       fdd_inUse = 1;\r
-}\r
-\r
-inline void FDD_FreeSpinlock()\r
-{\r
-       fdd_inUse = 0;\r
-}\r
-\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock()\r
-{\r
-       while(siFDD_CacheInUse) Threads_Yield();\r
-       siFDD_CacheInUse = 1;\r
-}\r
-inline void FDD_FreeCacheSpinlock()\r
-{\r
-       siFDD_CacheInUse = 0;\r
-}\r
-#endif\r
-\r
-/**\r
- * void FDD_int_SendByte(int base, char byte)\r
- * \brief Sends a command to the controller\r
- */\r
-void FDD_int_SendByte(int base, char byte)\r
-{\r
-    volatile int state;\r
-    int timeout = 128;\r
-    for( ; timeout--; )\r
-    {\r
-        state = inb(base + PORT_MAINSTATUS);\r
-        if ((state & 0xC0) == 0x80)\r
-        {\r
-            outb(base + PORT_DATA, byte);\r
-            return;\r
-        }\r
-        inb(0x80);     //Delay\r
-    }\r
-       #if WARN\r
-               Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
-       #endif\r
-}\r
-\r
-/**\r
- * int FDD_int_GetByte(int base, char byte)\r
- * \brief Receive data from fdd controller\r
- */\r
-int FDD_int_GetByte(int base)\r
-{\r
-    volatile int state;\r
-    int timeout;\r
-    for( timeout = 128; timeout--; )\r
-    {\r
-        state = inb((base + PORT_MAINSTATUS));\r
-        if ((state & 0xd0) == 0xd0)\r
-               return inb(base + PORT_DATA);\r
-        inb(0x80);\r
-    }\r
-    return -1;\r
-}\r
-\r
-/**\r
- * \brief Recalibrate the specified disk\r
- */\r
-void FDD_Recalibrate(int disk)\r
-{\r
-       ENTER("idisk", disk);\r
-       \r
-       LOG("Starting Motor");\r
-       FDD_int_StartMotor(disk);\r
-       // Wait for Spinup\r
-       while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();\r
-       \r
-       LOG("Sending Calibrate Command");\r
-       FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
-       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);\r
-       \r
-       LOG("Waiting for IRQ");\r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);\r
-       \r
-       LOG("Stopping Motor");\r
-       FDD_int_StopMotor(disk);\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \brief Reset the specified FDD controller\r
- */\r
-void FDD_Reset(int id)\r
-{\r
-       int base = cPORTBASE[id];\r
-       \r
-       ENTER("iID", id);\r
-       \r
-       outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC\r
-       outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)\r
-       \r
-       LOG("Awaiting IRQ");\r
-       \r
-       FDD_WaitIRQ();\r
-       FDD_SensInt(base, NULL, NULL);\r
-       \r
-       LOG("Setting Driver Info");\r
-       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s\r
-       FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
-       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)\r
-       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1\r
-       while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track\r
-       while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track\r
-       \r
-       LOG("Recalibrating Disk");\r
-       FDD_Recalibrate((id<<1)|0);\r
-       FDD_Recalibrate((id<<1)|1);
-\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_TimerCallback()\r
- * \brief Called by timer\r
- */\r
-void FDD_int_TimerCallback(int arg)\r
-{\r
-       ENTER("iarg", arg);\r
-       if(gFDD_Devices[arg].motorState == 1)\r
-               gFDD_Devices[arg].motorState = 2;\r
-       Time_RemoveTimer(gFDD_Devices[arg].timer);\r
-       gFDD_Devices[arg].timer = -1;\r
-       LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StartMotor(char disk)\r
- * \brief Starts FDD Motor\r
- */\r
-void FDD_int_StartMotor(int disk)\r
-{\r
-       Uint8   state;\r
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
-       state |= 1 << (4+disk);\r
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
-       gFDD_Devices[disk].motorState = 1;\r
-       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)disk);        //One Shot Timer\r
-}\r
-\r
-/**\r
- * \fn void FDD_int_StopMotor(int disk)\r
- * \brief Stops FDD Motor\r
- */\r
-void FDD_int_StopMotor(int disk)\r
-{\r
-       Uint8   state;\r
-       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
-       state &= ~( 1 << (4+disk) );\r
-       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
-    gFDD_Devices[disk].motorState = 0;\r
-}\r
-\r
-/**\r
- * \fn void ModuleUnload()\r
- * \brief Prepare the module for removal\r
- */\r
-void ModuleUnload()\r
-{\r
-       int i;\r
-       FDD_AquireSpinlock();\r
-       for(i=0;i<4;i++) {\r
-               Time_RemoveTimer(gFDD_Devices[i].timer);\r
-               FDD_int_StopMotor(i);\r
-       }\r
-       //IRQ_Clear(6);\r
-}\r
diff --git a/Kernel/drv/iocache.c b/Kernel/drv/iocache.c
new file mode 100644 (file)
index 0000000..8ea6929
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Acess2 Kernel
+ * - IO Cache
+ * 
+ * By thePowersGang (John Hodge)
+ */
+#include <common.h>
+#include <iocache.h>
+
+// === TYPES ===
+typedef struct sIOCache_Ent    tIOCache_Ent;
+
+// === STRUCTURES ===
+struct sIOCache_Ent
+{
+       tIOCache_Ent    *Next;
+       Uint64  Num;
+       Sint64  LastAccess;
+       Sint64  LastWrite;
+       Uint8   Data[];
+};
+
+struct sIOCache
+{
+       tIOCache        *Next;
+        int    SectorSize;
+        int    Lock;
+        int    Mode;
+       Uint32  ID;
+       tIOCache_WriteCallback  Write;
+        int    CacheSize;
+        int    CacheUsed;
+       tIOCache_Ent    *Entries;
+};
+
+// === GLOBALS ===
+ int   glIOCache_Caches;
+tIOCache       *gIOCache_Caches = NULL;
+ int   giIOCache_NumCaches = 0;
+
+// === CODE ===
+/**
+ * \fn tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
+ * \brief Creates a new IO Cache
+ */
+tIOCache *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize )
+{
+       tIOCache        *ret = malloc( sizeof(tIOCache) );
+       
+       // Sanity Check
+       if(!ret)        return NULL;
+       
+       // Fill Structure
+       ret->SectorSize = SectorSize;
+       ret->Mode = IOCACHE_WRITEBACK;
+       ret->ID = ID;
+       ret->Write = Write;
+       ret->CacheSize = CacheSize;
+       ret->CacheUsed = 0;
+       ret->Entries = 0;
+       
+       // Append to list
+       LOCK( &glIOCache_Caches );
+       ret->Next = gIOCache_Caches;
+       gIOCache_Caches = ret;
+       RELEASE( &glIOCache_Caches );
+       
+       // Return
+       return ret;
+}
+
+/**
+ * \fn int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Read from a cached sector
+ */
+int IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       tIOCache_Ent    *ent;
+       
+       // Sanity Check!
+       if(!Cache || !Buffer)
+               return -1;
+       
+       // Lock
+       LOCK( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               RELEASE( &Cache->Lock );
+               return -1;
+       }
+       
+       // Search the list
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               // Have we found what we are looking for?
+               if( ent->Num == Sector ) {
+                       memcpy(Buffer, ent->Data, Cache->SectorSize);
+                       ent->LastAccess = now();
+                       RELEASE( &Cache->Lock );
+                       return 1;
+               }
+               // It's a sorted list, so as soon as we go past `Sector` we know
+               // it's not there
+               if(ent->Num > Sector)   break;
+       }
+       
+       RELEASE( &Cache->Lock );
+       return 0;
+}
+
+/**
+ * \fn int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Cache a sector
+ */
+int IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       tIOCache_Ent    *ent, *prev;
+       tIOCache_Ent    *new;
+       tIOCache_Ent    *oldest = NULL, *oldestPrev;
+       
+       // Sanity Check!
+       if(!Cache || !Buffer)
+               return -1;
+       
+       // Lock
+       LOCK( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               RELEASE( &Cache->Lock );
+               return -1;
+       }
+       
+       // Search the list
+       prev = (tIOCache_Ent*)&Cache->Entries;
+       for( ent = Cache->Entries; ent; prev = ent, ent = ent->Next )
+       {
+               // Is it already here?
+               if( ent->Num == Sector ) {
+                       RELEASE( &Cache->Lock );
+                       return 0;
+               }
+               
+               // Check if we have found the oldest entry
+               if( !oldest || oldest->LastAccess > ent->LastAccess ) {
+                       oldest = ent;
+                       oldestPrev = prev;
+               }
+               
+               // Here we go!
+               if(ent->Num > Sector)
+                       break;
+       }
+       
+       // Create the new entry
+       new = malloc( sizeof(tIOCache_Ent) + Cache->SectorSize );
+       new->Next = ent;
+       new->Num = Sector;
+       new->LastAccess = now();
+       new->LastWrite = 0;     // Zero is special, it means unmodified
+       memcpy(new->Data, Buffer, Cache->SectorSize);
+       
+       // Have we reached the maximum cached entries?
+       if( Cache->CacheUsed == Cache->CacheSize )
+       {
+               tIOCache_Ent    *savedPrev = prev;
+               oldestPrev = (tIOCache_Ent*)&Cache->Entries;
+               // If so, search for the least recently accessed entry
+               for( ; ent; prev = ent, ent = ent->Next )
+               {       
+                       // Check if we have found the oldest entry
+                       if( !oldest || oldest->LastAccess > ent->LastAccess ) {
+                               oldest = ent;
+                               oldestPrev = prev;
+                       }
+               }
+               // Remove from list, write back and free
+               oldestPrev->Next = oldest->Next;
+               if(oldest->LastWrite && Cache->Mode != IOCACHE_VIRTUAL)
+                       Cache->Write(Cache->ID, oldest->Num, oldest->Data);
+               free(oldest);
+               
+               // Decrement the used count
+               Cache->CacheUsed --;
+               
+               // Restore `prev`
+               prev = savedPrev;
+       }
+       
+       // Append to list
+       prev->Next = new;
+       Cache->CacheUsed ++;
+       
+       // Release Spinlock
+       RELEASE( &Cache->Lock );
+       
+       // Return success
+       return 1;
+}
+
+/**
+ * \fn int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
+ * \brief Read from a cached sector
+ */
+int IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer )
+{
+       tIOCache_Ent    *ent;
+       
+       // Sanity Check!
+       if(!Cache || !Buffer)
+               return -1;
+       // Lock
+       LOCK( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               RELEASE( &Cache->Lock );
+               return -1;
+       }
+       
+       // Search the list
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               // Have we found what we are looking for?
+               if( ent->Num == Sector ) {
+                       memcpy(ent->Data, Buffer, Cache->SectorSize);
+                       ent->LastAccess = ent->LastWrite = now();
+                       
+                       if(Cache->Mode == IOCACHE_WRITEBACK) {
+                               Cache->Write(Cache->ID, Sector, Buffer);
+                               ent->LastWrite = 0;
+                       }
+                       
+                       RELEASE( &Cache->Lock );
+                       return 1;
+               }
+               // It's a sorted list, so as soon as we go past `Sector` we know
+               // it's not there
+               if(ent->Num > Sector)   break;
+       }
+       
+       RELEASE( &Cache->Lock );
+       return 0;
+}
+
+/**
+ * \fn void IOCache_Flush( tIOCache *Cache )
+ * \brief Flush a cache
+ */
+void IOCache_Flush( tIOCache *Cache )
+{
+       tIOCache_Ent    *ent;
+       
+       if( Cache->Mode == IOCACHE_VIRTUAL )    return;
+       
+       // Lock
+       LOCK( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               RELEASE( &Cache->Lock );
+               return;
+       }
+       
+       // Write All
+       for( ent = Cache->Entries; ent; ent = ent->Next )
+       {
+               Cache->Write(Cache->ID, ent->Num, ent->Data);
+               ent->LastWrite = 0;
+       }
+       
+       RELEASE( &Cache->Lock );
+}
+
+/**
+ * \fn void IOCache_Destroy( tIOCache *Cache )
+ * \brief Destroy a cache
+ */
+void IOCache_Destroy( tIOCache *Cache )
+{
+       tIOCache_Ent    *ent, *prev = NULL;
+       
+       // Lock
+       LOCK( &Cache->Lock );
+       if(Cache->CacheSize == 0) {
+               RELEASE( &Cache->Lock );
+               return;
+       }
+       
+       // Free All
+       for(ent = Cache->Entries;
+               ent;
+               prev = ent, ent = ent->Next, free(prev) )
+       {
+               if( Cache->Mode != IOCACHE_VIRTUAL )
+               {
+                       Cache->Write(Cache->ID, ent->Num, ent->Data);
+                       ent->LastWrite = 0;
+               }
+       }
+       
+       Cache->CacheSize = 0;
+       
+       RELEASE( &Cache->Lock );
+       
+       // Remove from list
+       LOCK( &glIOCache_Caches );
+       {
+               tIOCache        *ent;
+               tIOCache        *prev = (tIOCache*)&gIOCache_Caches;
+               for(ent = gIOCache_Caches;
+                       ent;
+                       prev = ent, ent = ent->Next )
+               {
+                       if(ent == Cache) {
+                               prev->Next = ent->Next;
+                               break;
+                       }
+               }
+       }
+       RELEASE( &glIOCache_Caches );
+       
+       free(Cache);
+}
index afd53ff..1dde000 100644 (file)
@@ -24,6 +24,7 @@
 #define        DEFAULT_COLOUR  (VT_COL_BLACK|(0xAAA<<16))
 
 #define        VT_FLAG_HIDECSR 0x01
+#define        VT_FLAG_HASFB   0x10    //!< Set if the VTerm has requested the Framebuffer
 
 enum eVT_InModes {
        VT_INMODE_TEXT8,        // UTF-8 Text Mode (VT100 Emulation)
@@ -184,7 +185,7 @@ int VT_Install(char **Arguments)
        DevFS_AddDevice( &gVT_DrvInfo );
        
        // Set kernel output to VT0
-       //Debug_SetKTerminal("/Devices/VTerm/0");
+       Debug_SetKTerminal("/Devices/VTerm/0");
        
        return 0;
 }
index 4b29cf1..add3eeb 100644 (file)
@@ -3,18 +3,30 @@
  * Device Filesystem (DevFS)
  * - vfs/fs/devfs.c
  */
+/**
+ * \file fs_devfs.h
+ * \brief Acess Device Filesystem interface
+ */
 #ifndef _FS_DEVFS_H
 #define _FS_DEVFS_H
 #include <vfs.h>
 
 // === TYPES ===
+/**
+ * \brief DevFS Driver
+ */
 typedef struct sDevFS_Driver {
-       struct sDevFS_Driver    *Next;
-       char    *Name;
-       tVFS_Node       RootNode;
+       struct sDevFS_Driver    *Next;  //!< Set to NULL by drivers (used internally)
+       char    *Name;  //!< Name of the driver file/folder
+       tVFS_Node       RootNode;       //!< Root node of driver
 } tDevFS_Driver;
 
 // === FUNCTIONS ===
+/**
+ * \fn int DevFS_AddDevice(tDevFS_Driver *Dev)
+ * \brief Registers a device in the Device filesystem
+ * \param Dev  Pointer to a persistant structure that represents the driver
+ */
 extern int     DevFS_AddDevice(tDevFS_Driver *Dev);
 
 #endif
diff --git a/Kernel/include/iocache.h b/Kernel/include/iocache.h
new file mode 100644 (file)
index 0000000..f008a2d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Acess2 Kernel
+ * - IO Cache
+ * 
+ * By thePowersGang (John Hodge)
+ */
+/**
+ * \file iocache.h
+ * \brief I/O Caching Helper Subsystem
+ * 
+ * The IO Cache abstracts caching of disk sectors away from the device
+ * driver to reduce code duplication and allow a central location for
+ * disk cache management that can be flushed simply by the kernel, without
+ * having to ask each driver to do it indivitually.
+ */
+#ifndef _IOCHACHE_H_
+#define _IOCHACHE_H_
+
+// === TYPES ===
+/**
+ * \brief IO Cache Handle
+ */
+typedef struct sIOCache        tIOCache;
+/**
+ * \brief Write Callback
+ * 
+ * Called to write a sector back to the device
+ */
+typedef int    (*tIOCache_WriteCallback)(Uint32 ID, Uint64 Sector, void *Buffer);
+
+// === CONSTANTS ===
+/**
+ * \brief I/O Cache handling modes
+ */
+enum eIOCache_Modess {
+       /**
+        * \brief Writeback
+        * 
+        * Transparently writes data straight to the device when the cache
+        * is written to.
+        */
+       IOCACHE_WRITEBACK,
+       /**
+        * \brief Delay Write
+        * 
+        * Only writes when instructed to (by ::IOCache_Flush) or when a
+        * cached sector is being reallocated.
+        */
+       IOCACHE_DELAYWRITE,
+       /**
+        * \brief Virtual - No Writes
+        * 
+        * Changes to the cache contents are only reflected in memory,
+        * any calls to ::IOCache_Flush will silently return without doing
+        * anything and if a sector is reallocated, all changes will be lost
+        */
+       IOCACHE_VIRTUAL
+};
+
+// === FUNCTIONS ===
+/**
+ * \brief Creates a new IO Cache
+ * \param Write        Function to call to write a sector to the device
+ * \param ID   ID to pass to \a Write
+ * \param SectorSize   Size of a cached sector
+ * \param CacheSize    Maximum number of objects that can be in the cache at one time
+ */
+tIOCache       *IOCache_Create( tIOCache_WriteCallback Write, Uint32 ID, int SectorSize, int CacheSize );
+
+/**
+ * \brief Reads from a cached sector
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Destination for the data read
+ * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
+ */
+ int   IOCache_Read( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Adds a sector to the cache
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Data to cache
+ * \return     1 on success, 0 if the sector is already cached, -1 on error
+ */
+ int   IOCache_Add( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Writes to a cached sector
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \param Sector       Sector's ID number
+ * \param Buffer       Data to write to the cache
+ * \return     1 if the data was read, 0 if the sector is not cached, -1 on error
+ * 
+ * If the sector is in the cache, it is updated.
+ * Wether the Write callback is called depends on the selected caching
+ * behaviour.
+ */
+ int   IOCache_Write( tIOCache *Cache, Uint64 Sector, void *Buffer );
+
+/**
+ * \brief Flush altered sectors out to the device
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * 
+ * This will call the cache's write callback on each altered sector
+ * to flush the write cache.
+ */
+void   IOCache_Flush( tIOCache *Cache );
+
+/**
+ * \brief Flushes the cache and then removes it
+ * \param Cache        Cache handle returned by ::IOCache_Create
+ * \note After this is called \a Cache is no longer valid
+ * 
+ * IOCache_Destroy writes all changed sectors to the device and then
+ * deallocates the cache for other systems to use.
+ */
+void   IOCache_Destroy( tIOCache *Cache );
+
+#endif
index 31ad97a..7608bc8 100644 (file)
@@ -1,8 +1,11 @@
+/*
+ * Acess2
+ * - Common Driver Interface
+ */
 /**
- AcessOS Version 1
- \file tpl_drv_common.h
- \brief Common Driver Interface Definitions
-*/
+ * \file tpl_drv_common.h
+ * \brief Common Driver Interface Definitions
+ */
 #ifndef _TPL_COMMON_H
 #define _TPL_COMMON_H
 
@@ -18,7 +21,7 @@ enum eTplDrv_IOCtl {
        /// \brief Get driver version - (int *ver)
        DRV_IOCTL_VERSION,
        /// \brief Get a IOCtl from a symbolic name
-       DRV_IOCTL_LOOKUP,
+       DRV_IOCTL_LOOKUP
 };
 
 /**
@@ -39,6 +42,17 @@ enum eTplDrv_Type {
 };
 
 // === FUNCTIONS ===
+/**
+ * \fn int GetIOCtlId(int Class, char *Name)
+ * \brief Transforms a symbolic name into an ID
+ * \param Class        ::eTplDrv_Type type to use
+ * \param Name Symbolic name to resolve
+ * 
+ * This function is designed to be used by device drivers to implement
+ * ::eTplDrv_IOCtl.DRV_IOCTL_LOOKUP easily given that they conform to
+ * the standard interfaces (::eTplDrv_Type except DRV_TYPE_MISC) and do
+ * not add their own call numbers.
+ */
 extern int     GetIOCtlId(int Class, char *Name);
 
 #endif
index 77f8295..1f33003 100644 (file)
@@ -21,9 +21,15 @@ enum eTplKeyboard_IOCtl {
        KB_IOCTL_SETCALLBACK\r
 };\r
 \r
-typedef void (*tKeybardCallback)(Uint32);\r
+/**\r
+ * \brief Callback type for KB_IOCTL_SETCALLBACK\r
+ */\r
+typedef void (*tKeybardCallback)(Uint32 Key);\r
 \r
-enum {\r
+/**\r
+ * \brief Symbolic key codes\r
+ */\r
+enum eTplKeyboard_KeyCodes {\r
        KEY_ESC = 0x1B,\r
        \r
        KEY_NP_MASK = 0x80,     //End of ASCII Range\r
index b84a97e..0272078 100644 (file)
@@ -44,9 +44,8 @@ enum eTplVideo_IOCtl {
 };\r
 \r
 /**\r
- \struct sVideo_IOCtl_Mode\r
- \brief Mode Structure used in IOCtl Calls\r
-*/\r
+ * \brief Mode Structure used in IOCtl Calls\r
+ */\r
 struct sVideo_IOCtl_Mode {\r
        short   id;             //!< Mide ID\r
        Uint16  width;  //!< Width\r
@@ -55,45 +54,76 @@ struct sVideo_IOCtl_Mode {
        Uint8   flags;  //!< Mode Flags\r
 };\r
 typedef struct sVideo_IOCtl_Mode       tVideo_IOCtl_Mode;      //!< Mode Type\r
+\r
+//! \name Video Mode flags\r
+//! \{\r
 /**\r
  * \brief Text Mode Flag\r
  * \note A text mode should have the ::sVideo_IOCtl_Mode.bpp set to 12\r
  */\r
 #define VIDEO_FLAG_TEXT        0x1\r
-#define VIDEO_FLAG_SLOW        0x2     //!< Non-accelerated mode\r
+/**\r
+ * \brief Slow (non-accellerated mode)\r
+ */\r
+#define VIDEO_FLAG_SLOW        0x2\r
+//! \}\r
 \r
-typedef struct sVideo_IOCtl_Pos        tVideo_IOCtl_Pos;       //!< Position Type\r
 /**\r
+ * \brief Describes a position in the video framebuffer\r
  */\r
+typedef struct sVideo_IOCtl_Pos        tVideo_IOCtl_Pos;\r
 struct sVideo_IOCtl_Pos {\r
        Sint16  x;      //!< X Coordinate\r
        Sint16  y;      //!< Y Coordinate\r
 };\r
 \r
 /**\r
- * \struct sVT_Char\r
  * \brief Virtual Terminal Representation of a character\r
  */\r
+typedef struct sVT_Char        tVT_Char;\r
 struct sVT_Char {\r
-       Uint32  Ch;\r
+       Uint32  Ch;     //!< UTF-32 Character\r
        union {\r
                struct {\r
-                       Uint16  BGCol;\r
-                       Uint16  FGCol;\r
+                       Uint16  BGCol;  //!< 12-bit Foreground Colour\r
+                       Uint16  FGCol;  //!< 12-bit Background Colour\r
                };\r
-               Uint32  Colour;\r
+               Uint32  Colour; //!< Compound colour for ease of access\r
        };\r
 };\r
-typedef struct sVT_Char        tVT_Char;\r
 \r
+/**\r
+ * \name Basic builtin colour definitions\r
+ * \{\r
+ */\r
 #define        VT_COL_BLACK    0x0000\r
 #define        VT_COL_GREY             0x0888\r
 #define        VT_COL_LTGREY   0x0CCC\r
 #define        VT_COL_WHITE    0x0FFF\r
+/**\r
+ * \}\r
+ */\r
 \r
+//! \brief Defines the width of a rendered character\r
 extern int     giVT_CharWidth;\r
+//! \brief Defines the height of a rendered character\r
 extern int     giVT_CharHeight;\r
+/**\r
+ * \fn void VT_Font_Render(Uint32 Codepoint, void *Buffer, int Pitch, Uint32 BGC, Uint32 FGC)\r
+ * \brief Renders a character to a buffer\r
+ * \param Codepoint    Unicode character to render\r
+ * \param Buffer       Buffer to render to (32-bpp)\r
+ * \param Pitch        Number of DWords per line\r
+ * \param BGC  32-bit Background Colour\r
+ * \param FGC  32-bit Foreground Colour\r
+ */\r
 extern void    VT_Font_Render(Uint32 Codepoint, void *Buffer, int Pitch, Uint32 BGC, Uint32 FGC);\r
+/**\r
+ * \fn Uint32 VT_Colour12to24(Uint16 Col12)\r
+ * \brief Converts a colour from 12bpp to 32bpp\r
+ * \param Col12        12-bpp input colour\r
+ * \return     Expanded 32-bpp (24-bit colour) version of \a Col12\r
+ */\r
 extern Uint32  VT_Colour12to24(Uint16 Col12);\r
 \r
 #endif\r
index 025a526..6fc2491 100644 (file)
@@ -1,36 +1,75 @@
 /* 
- * Acess Micro - VFS Server Ver 1
+ * Acess2
+ * VFS Common Header
+ */
+/**
+ * \file vfs.h
+ * \brief Acess VFS Layer
  */
 #ifndef _VFS_H
 #define _VFS_H
 
 #include <common.h>
 
+//! \name ACL Permissions
+//! \{
+/**
+ * \brief Readable
+ */
 #define VFS_PERM_READ  0x00000001
+/**
+ * \brief Writeable
+ */
 #define VFS_PERM_WRITE 0x00000002
+/**
+ * \brief Append allowed
+ */
 #define VFS_PERM_APPEND        0x00000004
+/**
+ * \brief Executable
+ */
 #define VFS_PERM_EXECUTE       0x00000008
+/**
+ * \brief All permissions granted
+ */
 #define VFS_PERM_ALL   0x7FFFFFFF      // Mask for permissions
+/**
+ * \brief Denies instead of granting permissions
+ * \note Denials take precedence
+ */
 #define VFS_PERM_DENY  0x80000000      // Inverts permissions
+//! \}
 
-typedef struct sVFS_ACL {
+/**
+ * \brief ACL Defintion Structure
+ */
+typedef struct sVFS_ACL
+{
        struct {
-               unsigned Group: 1;      // Group (as opposed to user) flag
-               unsigned ID:    31;     // ID of Group/User (-1 for nobody/world)
+               unsigned Group: 1;      //!< Group (as opposed to user) flag
+               unsigned ID:    31;     //!< ID of Group/User (-1 for nobody/world)
        };
        struct {
-               unsigned Inv:   1;      // Invert Permissions
-               unsigned Perms: 31;     // Permission Flags
+               unsigned Inv:   1;      //!< Invert Permissions
+               unsigned Perms: 31;     //!< Permission Flags
        };
 } tVFS_ACL;
 
-#define VFS_FFLAG_READONLY     0x01
-#define VFS_FFLAG_DIRECTORY    0x02
-#define VFS_FFLAG_SYMLINK      0x04
+/**
+ * \name VFS Node Flags
+ * \{
+ */
+#define VFS_FFLAG_READONLY     0x01    //!< Read-only file
+#define VFS_FFLAG_DIRECTORY    0x02    //!< Directory
+#define VFS_FFLAG_SYMLINK      0x04    //!< Symbolic Link
+/**
+ * \}
+ */
 
-typedef struct sVFS_Node {
-       //char  *Name;  //!< Node's Name (UTF-8)
-       
+/**
+ * \brief VFS Node
+ */
+typedef struct sVFS_Node {     
        Uint64  Inode;  //!< Inode ID
        Uint    ImplInt;        //!< Implementation Usable Integer
        void    *ImplPtr;       //!< Implementation Usable Pointer
@@ -58,16 +97,23 @@ typedef struct sVFS_Node {
        //! Send an IO Control
         int    (*IOCtl)(struct sVFS_Node *Node, int Id, void *Data);
        
+       //! \brief Read from the file
        Uint64  (*Read)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+       //! \brief Write to the file
        Uint64  (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
        
-       //! Find an directory entry by name
+       //! \brief Find an directory entry by name
+       //! \note The node returned must be accessable until ::tVFS_Node.Close is called
        struct sVFS_Node        *(*FindDir)(struct sVFS_Node *Node, char *Name);
-       //! Read from a directory - MUST return a heap address
+       
+       //! \brief Read from a directory
+       //! \note MUST return a heap address
        char    *(*ReadDir)(struct sVFS_Node *Node, int Pos);
-       //! Create a node in a directory
+       
+       //! \brief Create a node in a directory
         int    (*MkNod)(struct sVFS_Node *Node, char *Name, Uint Flags);
-       //! Relink (Rename/Remove) a file/directory
+       
+       //! \brief Relink (Rename/Remove) a file/directory
         int    (*Relink)(struct sVFS_Node *Node, char *OldName, char *NewName);
        
        //!< \todo Complete
@@ -76,34 +122,104 @@ typedef struct sVFS_Node {
 /**
  * \brief VFS Driver (Filesystem) Definition
  */
-typedef struct sVFS_Driver {
+typedef struct sVFS_Driver
+{
+       //! \brief Unique Identifier for this filesystem type
        char    *Name;
+       //! \brief Flags applying to this driver
        Uint    Flags;
+       
+       //! \brief Callback to mount a device
        tVFS_Node       *(*InitDevice)(char *Device, char **Options);
+       //! \brief Callback to unmount a device
        void    (*Unmount)(tVFS_Node *Node);
+       //! \brief Used internally (next driver in the chain)
        struct sVFS_Driver      *Next;
 } tVFS_Driver;
 
 // === GLOBALS ===
+//! \brief Maximum number of elements that can be skipped in one return
 #define        VFS_MAXSKIP     ((void*)1024)
+//! \brief Skip a single entry in readdir
 #define        VFS_SKIP        ((void*)1)
+//! \brief Skip \a n entries in readdir
 #define        VFS_SKIPN(n)    ((void*)(n))
-extern tVFS_Node       NULLNode;
-extern tVFS_ACL        gVFS_ACL_EveryoneRWX;
-extern tVFS_ACL        gVFS_ACL_EveryoneRW;
-extern tVFS_ACL        gVFS_ACL_EveryoneRX;
-extern tVFS_ACL        gVFS_ACL_EveryoneRO;
+
+extern tVFS_Node       NULLNode;       //!< NULL VFS Node (Ignored/Skipped)
+/**
+ * \name Simple ACLs to aid writing drivers
+ * \{
+ */
+extern tVFS_ACL        gVFS_ACL_EveryoneRWX;   //!< Everyone Read/Write/Execute
+extern tVFS_ACL        gVFS_ACL_EveryoneRW;    //!< Everyone Read/Write
+extern tVFS_ACL        gVFS_ACL_EveryoneRX;    //!< Everyone Read/Execute
+extern tVFS_ACL        gVFS_ACL_EveryoneRO;    //!< Everyone Read only
+/**
+ * \}
+ */
 
 // === FUNCTIONS ===
+/**
+ * \fn int VFS_AddDriver(tVFS_Driver *Info)
+ * \brief Registers the driver with the DevFS layer
+ * \param Info Driver information structure
+ */
 extern int     VFS_AddDriver(tVFS_Driver *Info);
+/**
+ * \fn tVFS_Driver *VFS_GetFSByName(char *Name)
+ * \brief Get the information structure of a driver given its name
+ * \param Name Name of filesystem driver to find
+ */
 extern tVFS_Driver     *VFS_GetFSByName(char *Name);
+/**
+ * \fn tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group)
+ * \brief Transforms Unix Permssions into Acess ACLs
+ * \param Mode Unix RWXrwxRWX mask
+ * \param Owner        UID of the file's owner
+ * \param Group        GID of the file's owning group
+ * \return An array of 3 Acess ACLs
+ */
 extern tVFS_ACL        *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group);
 
 // --- Node Cache --
+//! \name Node Cache
+//! \{
+/**
+ * \fn int Inode_GetHandle()
+ * \brief Gets a unique handle to the Node Cache
+ * \return A unique handle for use for the rest of the Inode_* functions
+ */
 extern int     Inode_GetHandle();
+/**
+ * \fn tVFS_Node *Inode_GetCache(int Handle, Uint64 Inode)
+ * \brief Gets an inode from the node cache
+ * \param Handle       A handle returned by Inode_GetHandle()
+ * \param Inode        Value of the Inode field of the ::tVFS_Node you want
+ * \return A pointer to the cached node
+ */
 extern tVFS_Node       *Inode_GetCache(int Handle, Uint64 Inode);
+/**
+ * \fn tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node)
+ * \brief Caches a node in the Node Cache
+ * \param Handle       A handle returned by Inode_GetHandle()
+ * \param Node A pointer to the node to be cached (a copy is taken)
+ * \return A pointer to the node in the node cache
+ */
 extern tVFS_Node       *Inode_CacheNode(int Handle, tVFS_Node *Node);
+/**
+ * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \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
+ */
 extern void    Inode_UncacheNode(int Handle, Uint64 Inode);
+/**
+ * \fn void Inode_ClearCache(int Handle)
+ * \brief Clears the cache for a handle
+ * \param Handle       A handle returned by Inode_GetHandle()
+ */
 extern void    Inode_ClearCache(int Handle);
 
+//! \}
+
 #endif
index 1752497..a8d3b20 100644 (file)
@@ -15,8 +15,8 @@ ARCH = i386
 ARCHDIR = x86
 
 FILESYSTEMS = fat ext2
-DRIVERS = ata_x86 fdd
-MODULES = NE2000 BochsVBE
+DRIVERS = ata_x86
+MODULES = FDD NE2000 BochsVBE
 
 DISTROOT = /mnt/AcessHDD/Acess2
 ACESSDIR = /home/hodgeja/Projects/Acess2
diff --git a/Modules/FDD/Makefile b/Modules/FDD/Makefile
new file mode 100644 (file)
index 0000000..1596553
--- /dev/null
@@ -0,0 +1,7 @@
+#
+#
+
+OBJ = fdd.o
+NAME = FDD
+
+-include ../Makefile.tpl
diff --git a/Modules/FDD/fdd.c b/Modules/FDD/fdd.c
new file mode 100644 (file)
index 0000000..c33b281
--- /dev/null
@@ -0,0 +1,793 @@
+/*\r
+ * AcessOS 0.1\r
+ * Floppy Disk Access Code\r
+ */\r
+#define DEBUG  0\r
+#include <common.h>\r
+#include <modules.h>\r
+#include <fs_devfs.h>\r
+#include <tpl_drv_common.h>\r
+#include <dma.h>\r
+#include <iocache.h>\r
+\r
+#define WARN   0\r
+\r
+// === CONSTANTS ===\r
+// --- Current Version\r
+#define FDD_VERSION     ((0<<8)|(75))\r
+\r
+// --- Options\r
+#define USE_CACHE      1       // Use Sector Cache\r
+#define        CACHE_SIZE      32      // Number of cachable sectors\r
+#define FDD_SEEK_TIMEOUT       10      // Timeout for a seek operation\r
+#define MOTOR_ON_DELAY 500             // Miliseconds\r
+#define MOTOR_OFF_DELAY        2000    // Miliseconds\r
+\r
+// === TYPEDEFS ===\r
+/**\r
+ * \brief Representation of a floppy drive\r
+ */\r
+typedef struct {\r
+        int    type;\r
+       volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off\r
+        int    track[2];\r
+        int    timer;\r
+       tVFS_Node       Node;\r
+} t_floppyDevice;\r
+\r
+/**\r
+ * \brief Cached Sector\r
+ */\r
+typedef struct {\r
+       Uint64  timestamp;\r
+       Uint16  disk;\r
+       Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
+       Uint8   data[512];\r
+} t_floppySector;\r
+\r
+// === CONSTANTS ===\r
+static const char      *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };\r
+static const int       cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
+static const short     cPORTBASE[] = { 0x3F0, 0x370 };\r
+\r
+enum FloppyPorts {\r
+       PORT_STATUSA    = 0x0,\r
+       PORT_STATUSB    = 0x1,\r
+       PORT_DIGOUTPUT  = 0x2,\r
+       PORT_MAINSTATUS = 0x4,\r
+       PORT_DATARATE   = 0x4,\r
+       PORT_DATA               = 0x5,\r
+       PORT_DIGINPUT   = 0x7,\r
+       PORT_CONFIGCTRL = 0x7\r
+};\r
+\r
+enum FloppyCommands {\r
+       FIX_DRIVE_DATA  = 0x03,\r
+       HECK_DRIVE_STATUS       = 0x04,\r
+       CALIBRATE_DRIVE = 0x07,\r
+       CHECK_INTERRUPT_STATUS = 0x08,\r
+       SEEK_TRACK              = 0x0F,\r
+       READ_SECTOR_ID  = 0x4A,\r
+       FORMAT_TRACK    = 0x4D,\r
+       READ_TRACK              = 0x42,\r
+       READ_SECTOR             = 0x66,\r
+       WRITE_SECTOR    = 0xC5,\r
+       WRITE_DELETE_SECTOR     = 0xC9,\r
+       READ_DELETE_SECTOR      = 0xCC,\r
+};\r
+\r
+// === PROTOTYPES ===\r
+// --- Filesystem\r
+ int   FDD_Install(char **Arguments);\r
+char   *FDD_ReadDir(tVFS_Node *Node, int pos);\r
+tVFS_Node      *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
+ int   FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
+// --- Raw Disk Access\r
+ int   FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);\r
+ int   FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);\r
+// --- Helpers\r
+void   FDD_IRQHandler(int Num);\r
+void   FDD_WaitIRQ();\r
+void   FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
+inline void    FDD_AquireSpinlock();\r
+inline void    FDD_FreeSpinlock();\r
+#if USE_CACHE\r
+inline void FDD_AquireCacheSpinlock();\r
+inline void FDD_FreeCacheSpinlock();\r
+#endif\r
+void   FDD_int_SendByte(int base, char byte);\r
+ int   FDD_int_GetByte(int base);\r
+void   FDD_Reset(int id);\r
+void   FDD_Recalibrate(int disk);\r
+ int   FDD_int_SeekTrack(int disk, int head, int track);\r
+void   FDD_int_TimerCallback(int arg);\r
+void   FDD_int_StopMotor(int disk);\r
+void   FDD_int_StartMotor(int disk);\r
+ int   FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, NULL);\r
+t_floppyDevice gFDD_Devices[2];\r
+volatile int   fdd_inUse = 0;\r
+volatile int   fdd_irq6 = 0;\r
+tDevFS_Driver  gFDD_DriverInfo = {\r
+       NULL, "fdd",\r
+       {\r
+       .Size = -1,\r
+       .NumACLs = 1,\r
+       .ACLs = &gVFS_ACL_EveryoneRX,\r
+       .Flags = VFS_FFLAG_DIRECTORY,\r
+       .ReadDir = FDD_ReadDir,\r
+       .FindDir = FDD_FindDir,\r
+       .IOCtl = FDD_IOCtl\r
+       }\r
+};\r
+#if USE_CACHE\r
+int    siFDD_CacheInUse = 0;\r
+int    siFDD_SectorCacheSize = CACHE_SIZE;\r
+t_floppySector sFDD_SectorCache[CACHE_SIZE];\r
+#endif\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int FDD_Install(char **Arguments)\r
+ * \brief Installs floppy driver\r
+ */\r
+int FDD_Install(char **Arguments)\r
+{\r
+       Uint8 data;\r
+       \r
+       // Determine Floppy Types (From CMOS)\r
+       outb(0x70, 0x10);\r
+       data = inb(0x71);\r
+       gFDD_Devices[0].type = data >> 4;\r
+       gFDD_Devices[1].type = data & 0xF;\r
+       gFDD_Devices[0].track[0] = -1;\r
+       gFDD_Devices[1].track[1] = -1;\r
+       \r
+       Log("[FDD ] Detected Disk 0: %s and Disk 1: %s\n", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
+       \r
+       // Clear FDD IRQ Flag\r
+       FDD_SensInt(0x3F0, NULL, NULL);\r
+       // Install IRQ6 Handler\r
+       IRQ_AddHandler(6, FDD_IRQHandler);\r
+       // Reset Primary FDD Controller\r
+       FDD_Reset(0);\r
+       \r
+       // Initialise Root Node\r
+       gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime\r
+               = gFDD_DriverInfo.RootNode.ATime = now();\r
+       \r
+       // Initialise Child Nodes\r
+       gFDD_Devices[0].Node.Inode = 0;\r
+       gFDD_Devices[0].Node.Flags = 0;\r
+       gFDD_Devices[0].Node.NumACLs = 0;\r
+       gFDD_Devices[0].Node.Read = FDD_ReadFS;\r
+       gFDD_Devices[0].Node.Write = NULL;//fdd_writeFS;\r
+       memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));\r
+       \r
+       gFDD_Devices[1].Node.Inode = 1;\r
+       \r
+       // Set Lengths\r
+       gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
+       gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
+       \r
+       // Create Sector Cache\r
+       #if USE_CACHE\r
+       //sFDD_SectorCache = malloc(sizeof(*sFDD_SectorCache)*CACHE_SIZE);\r
+       //siFDD_SectorCacheSize = CACHE_SIZE;\r
+       #else\r
+       if( cFDD_SIZES[data >> 4] ) {\r
+               gFDD_Devices[0].CacheHandle = IOCache_Create(\r
+                       FDD_WriteSector, 0, 512,\r
+                       gFDD_Devices[0].Node.Size / (512*4)\r
+                       );      // Cache is 1/4 the size of the disk\r
+       }\r
+       if( cFDD_SIZES[data & 15] ) {\r
+               gFDD_Devices[1].CacheHandle = IOCache_Create(\r
+                       FDD_WriteSector, 0, 512,\r
+                       gFDD_Devices[1].Node.Size / (512*4)\r
+                       );      // Cache is 1/4 the size of the disk\r
+       }\r
+       #endif\r
+       \r
+       // Register with devfs\r
+       DevFS_AddDevice(&gFDD_DriverInfo);\r
+       \r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
+ * \brief Read Directory\r
+ */\r
+char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
+{\r
+       char    name[2] = "0\0";\r
+       //Update Accessed Time\r
+       //gFDD_DrvInfo.rootNode.atime = now();\r
+       \r
+       //Check for bounds\r
+       if(pos >= 2 || pos < 0)\r
+               return NULL;\r
+       \r
+       if(gFDD_Devices[pos].type == 0)\r
+               return VFS_SKIP;\r
+       \r
+       name[0] += pos;\r
+       \r
+       //Return\r
+       return strdup(name);\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);\r
+ * \brief Find File Routine (for vfs_node)\r
+ */\r
+tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename)\r
+{\r
+        int    i;\r
+       \r
+       ENTER("sfilename", filename);\r
+       \r
+       // Sanity check string\r
+       if(filename == NULL) {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Check string length (should be 1)\r
+       if(filename[0] == '\0' || filename[1] != '\0') {\r
+               LEAVE('n');\r
+               return NULL;\r
+       }\r
+       \r
+       // Get First character\r
+       i = filename[0] - '0';\r
+       \r
+       // Check for 1st disk and if it is present return\r
+       if(i == 0 && gFDD_Devices[0].type != 0) {\r
+               LEAVE('p', &gFDD_Devices[0].Node);\r
+               return &gFDD_Devices[0].Node;\r
+       }\r
+       \r
+       // Check for 2nd disk and if it is present return\r
+       if(i == 1 && gFDD_Devices[1].type != 0) {\r
+               LEAVE('p', &gFDD_Devices[1].Node);\r
+               return &gFDD_Devices[1].Node;\r
+       }\r
+       \r
+       // Else return null\r
+       LEAVE('n');\r
+       return NULL;\r
+}\r
+\r
+/**\r
+ * \fn int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
+ * \brief Stub ioctl function\r
+ */\r
+int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
+{\r
+       switch(id)\r
+       {\r
+       case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;\r
+       case DRV_IOCTL_IDENT:   memcpy(data, "FDD\0", 4);       return 1;\r
+       case DRV_IOCTL_VERSION: return FDD_VERSION;\r
+       default:        return 0;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn Uint64 fdd_readFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+ * \brief Read Data from a disk\r
+*/\r
+Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+       int i = 0;\r
+       int     disk;\r
+       Uint32  buf[128];\r
+       \r
+       ENTER("xoff xlen pbuffer", off, len, buffer);\r
+       \r
+       if(node == NULL) {\r
+               LEAVE('i', -1);\r
+               return -1;\r
+       }\r
+       \r
+       if(node->Inode != 0 && node->Inode != 1) {\r
+               LEAVE('i', -1);\r
+               return -1;\r
+       }\r
+       \r
+       disk = node->Inode;\r
+       \r
+       // Update Accessed Time\r
+       node->ATime = now();\r
+       \r
+       if((off & 0x1FF) || (len & 0x1FF))\r
+       {\r
+               // Un-Aligned Offset/Length\r
+                int    startOff = off>>9;\r
+                int    sectOff = off&0x1FF;\r
+                int    sectors = (len+0x1FF)>>9;\r
+       \r
+               LOG("Non-aligned Read");\r
+               \r
+               //Read Starting Sector\r
+               if(!FDD_ReadSector(disk, startOff, buf))\r
+                       return 0;\r
+               memcpy(buffer, (char*)(buf+sectOff), len>512-sectOff?512-sectOff:len);\r
+               \r
+               //If the data size is one sector or less\r
+               if(len <= 512-sectOff) {\r
+                       LEAVE('X', len);\r
+                       return len;     //Return\r
+               }\r
+               buffer += 512-sectOff;\r
+       \r
+               //Read Middle Sectors\r
+               for(i=1;i<sectors-1;i++)        {\r
+                       if(!FDD_ReadSector(disk, startOff+i, buf)) {\r
+                               LEAVE('i', -1);\r
+                               return -1;\r
+                       }\r
+                       memcpy(buffer, buf, 512);\r
+                       buffer += 512;\r
+               }\r
+       \r
+               //Read End Sectors\r
+               if(!FDD_ReadSector(disk, startOff+i, buf))\r
+                       return 0;\r
+               memcpy(buffer, buf, (len&0x1FF)-sectOff);\r
+               
+               LEAVE('X', len);\r
+               return len;\r
+       }\r
+       else\r
+       {\r
+                int    count = len >> 9;\r
+                int    sector = off >> 9;\r
+               LOG("Aligned Read");\r
+               //Aligned Offset and Length - Simple Code\r
+               for(i=0;i<count;i++)\r
+               {\r
+                       FDD_ReadSector(disk, sector, buf);\r
+                       memcpy(buffer, buf, 512);\r
+                       buffer += 512;\r
+                       sector++;\r
+               }
+               LEAVE('i', len);\r
+               return len;\r
+       }\r
+}\r
+\r
+/**\r
+ * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+ * \fn Read a sector from disk\r
+*/\r
+int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+{\r
+        int    cyl, head, sec;\r
+        int    spt, base;\r
+        int    i;\r
+        int    lba = SectorAddr;\r
+       \r
+       ENTER("idisk Xlba pbuf", disk, lba, buf);\r
+       \r
+       #if USE_CACHE\r
+       FDD_AquireCacheSpinlock();\r
+       for( i = 0; i < siFDD_SectorCacheSize; i++ )\r
+       {\r
+               if(sFDD_SectorCache[i].timestamp == 0)  continue;\r
+               if(sFDD_SectorCache[i].disk == Disk\r
+               && sFDD_SectorCache[i].sector == lba) {\r
+                       LOG("Found %i in cache %i", lba, i);\r
+                       memcpy(Buffer, sFDD_SectorCache[i].data, 512);\r
+                       sFDD_SectorCache[i].timestamp = now();\r
+                       FDD_FreeCacheSpinlock();\r
+                       LEAVE('i', 1);\r
+                       return 1;\r
+               }\r
+       }\r
+       LOG("Read %i from Disk", lba);\r
+       FDD_FreeCacheSpinlock();\r
+       #else\r
+       if( IOCache_Read( gFDD_Devices[Disk].Cache, SectorAddr, Buffer ) == 1 ) {\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       #endif\r
+       \r
+       base = cPORTBASE[Disk>>1];\r
+       \r
+       LOG("Calculating Disk Dimensions");\r
+       //Get CHS position\r
+       if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1) {\r
+               LEAVE('i', -1);\r
+               return -1;\r
+       }\r
+       \r
+       // Remove Old Timer\r
+       Time_RemoveTimer(gFDD_Devices[Disk].timer);\r
+       // Check if Motor is on\r
+       if(gFDD_Devices[Disk].motorState == 0) {\r
+               FDD_int_StartMotor(Disk);\r
+       }\r
+       \r
+       LOG("Wait for Motor Spinup");\r
+       \r
+       // Wait for spinup\r
+       while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();\r
+       \r
+       LOG("C:%i,H:%i,S:%i", cyl, head, sec);\r
+       LOG("Acquire Spinlock");\r
+       \r
+       FDD_AquireSpinlock();\r
+       \r
+       // Seek to track\r
+       outb(base+CALIBRATE_DRIVE, 0);\r
+       i = 0;\r
+       while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )        Threads_Yield();\r
+       //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ\r
+       \r
+       LOG("Setting DMA for read");\r
+       \r
+       //Read Data from DMA\r
+       DMA_SetChannel(2, 512, 1);      // Read 512 Bytes\r
+       \r
+       LOG("Sending read command");\r
+       \r
+       //Threads_Wait(100);    // Wait for Head to settle\r
+       Time_Delay(100);\r
+       FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6\r
+       FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
+       FDD_int_SendByte(base, (Uint8)cyl);\r
+       FDD_int_SendByte(base, (Uint8)head);\r
+       FDD_int_SendByte(base, (Uint8)sec);\r
+       FDD_int_SendByte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})\r
+       FDD_int_SendByte(base, spt);    // SPT\r
+       FDD_int_SendByte(base, 0x1B);   // Gap Length (27 is default)\r
+       FDD_int_SendByte(base, 0xFF);   // Data Length\r
+       \r
+       // Wait for IRQ\r
+       LOG("Waiting for Data to be read");\r
+       FDD_WaitIRQ();\r
+       \r
+       // Read Data from DMA\r
+       LOG(" FDD_ReadSector: Reading Data");\r
+       DMA_ReadData(2, 512, Buffer);\r
+       \r
+       // Clear Input Buffer\r
+       LOG("Clearing Input Buffer");\r
+       FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
+       FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
+       \r
+       LOG("Realeasing Spinlock and Setting motor to stop");\r
+       // Release Spinlock\r
+       FDD_FreeSpinlock();\r
+       \r
+       //Set timer to turn off motor affter a gap\r
+       gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk);   //One Shot Timer
+\r
+       #if USE_CACHE\r
+       {\r
+               FDD_AquireCacheSpinlock();\r
+               int oldest = 0;\r
+               for(i=0;i<siFDD_SectorCacheSize;i++)\r
+               {\r
+                       if(sFDD_SectorCache[i].timestamp == 0) {\r
+                               oldest = i;\r
+                               break;\r
+                       }\r
+                       if(sFDD_SectorCache[i].timestamp < sFDD_SectorCache[oldest].timestamp)\r
+                               oldest = i;\r
+               }\r
+               sFDD_SectorCache[oldest].timestamp = now();\r
+               sFDD_SectorCache[oldest].disk = Disk;\r
+               sFDD_SectorCache[oldest].sector = lba;\r
+               memcpy(sFDD_SectorCache[oldest].data, Buffer, 512);\r
+               FDD_FreeCacheSpinlock();\r
+       }\r
+       #else\r
+       IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );\r
+       #endif\r
+
+       LEAVE('i', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn int FDD_int_SeekTrack(int disk, int track)\r
+ * \brief Seek disk to selected track\r
+ */\r
+int FDD_int_SeekTrack(int disk, int head, int track)\r
+{\r
+       Uint8   sr0, cyl;\r
+        int    base;\r
+       \r
+       base = cPORTBASE[disk>>1];\r
+       \r
+       // Check if seeking is needed\r
+       if(gFDD_Devices[disk].track[head] == track)\r
+               return 1;\r
+       \r
+       // - Seek Head 0\r
+       FDD_int_SendByte(base, SEEK_TRACK);\r
+       FDD_int_SendByte(base, (head<<2)|(disk&1));\r
+       FDD_int_SendByte(base, track);  // Send Seek command\r
+       FDD_WaitIRQ();\r
+       FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ\r
+       if((sr0 & 0xF0) != 0x20) {
+               LOG("sr0 = 0x%x", sr0);
+               return 0;       //Check Status
+       }\r
+       if(cyl != track)        return 0;\r
+       \r
+       // Set Track in structure\r
+       gFDD_Devices[disk].track[head] = track;\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
+ * \brief Get Dimensions of a disk\r
+ */\r
+int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)\r
+{\r
+       switch(type) {\r
+       case 0:\r
+               return 0;\r
+       \r
+       // 360Kb 5.25"\r
+       case 1:\r
+               *spt = 9;\r
+               *s = (lba % 9) + 1;\r
+               *c = lba / 18;\r
+               *h = (lba / 9) & 1;\r
+               break;\r
+       \r
+       // 1220Kb 5.25"\r
+       case 2:\r
+               *spt = 15;\r
+               *s = (lba % 15) + 1;\r
+               *c = lba / 30;\r
+               *h = (lba / 15) & 1;\r
+               break;\r
+       \r
+       // 720Kb 3.5"\r
+       case 3:\r
+               *spt = 9;\r
+               *s = (lba % 9) + 1;\r
+               *c = lba / 18;\r
+               *h = (lba / 9) & 1;\r
+               break;\r
+       \r
+       // 1440Kb 3.5"\r
+       case 4:\r
+               *spt = 18;\r
+               *s = (lba % 18) + 1;\r
+               *c = lba / 36;\r
+               *h = (lba / 18) & 1;\r
+               break;\r
+               \r
+       // 2880Kb 3.5"\r
+       case 5:\r
+               *spt = 36;\r
+               *s = (lba % 36) + 1;\r
+               *c = lba / 72;\r
+               *h = (lba / 32) & 1;\r
+               break;\r
+               \r
+       default:\r
+               return -2;\r
+       }\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \fn void FDD_IRQHandler(int Num)\r
+ * \brief Handles IRQ6\r
+ */\r
+void FDD_IRQHandler(int Num)\r
+{\r
+    fdd_irq6 = 1;\r
+}\r
+\r
+/**\r
+ * \fn FDD_WaitIRQ()\r
+ * \brief Wait for an IRQ6\r
+ */\r
+void FDD_WaitIRQ()\r
+{\r
+       // Wait for IRQ\r
+       while(!fdd_irq6)        Threads_Yield();\r
+       fdd_irq6 = 0;\r
+}\r
+\r
+void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
+{\r
+       FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);\r
+       if(sr0) *sr0 = FDD_int_GetByte(base);\r
+       else    FDD_int_GetByte(base);\r
+       if(cyl) *cyl = FDD_int_GetByte(base);\r
+       else    FDD_int_GetByte(base);\r
+}\r
+\r
+void FDD_AquireSpinlock()\r
+{\r
+       while(fdd_inUse)\r
+               Threads_Yield();\r
+       fdd_inUse = 1;\r
+}\r
+\r
+inline void FDD_FreeSpinlock()\r
+{\r
+       fdd_inUse = 0;\r
+}\r
+\r
+#if USE_CACHE\r
+inline void FDD_AquireCacheSpinlock()\r
+{\r
+       while(siFDD_CacheInUse) Threads_Yield();\r
+       siFDD_CacheInUse = 1;\r
+}\r
+inline void FDD_FreeCacheSpinlock()\r
+{\r
+       siFDD_CacheInUse = 0;\r
+}\r
+#endif\r
+\r
+/**\r
+ * void FDD_int_SendByte(int base, char byte)\r
+ * \brief Sends a command to the controller\r
+ */\r
+void FDD_int_SendByte(int base, char byte)\r
+{\r
+    volatile int state;\r
+    int timeout = 128;\r
+    for( ; timeout--; )\r
+    {\r
+        state = inb(base + PORT_MAINSTATUS);\r
+        if ((state & 0xC0) == 0x80)\r
+        {\r
+            outb(base + PORT_DATA, byte);\r
+            return;\r
+        }\r
+        inb(0x80);     //Delay\r
+    }\r
+       #if WARN\r
+               Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
+       #endif\r
+}\r
+\r
+/**\r
+ * int FDD_int_GetByte(int base, char byte)\r
+ * \brief Receive data from fdd controller\r
+ */\r
+int FDD_int_GetByte(int base)\r
+{\r
+    volatile int state;\r
+    int timeout;\r
+    for( timeout = 128; timeout--; )\r
+    {\r
+        state = inb((base + PORT_MAINSTATUS));\r
+        if ((state & 0xd0) == 0xd0)\r
+               return inb(base + PORT_DATA);\r
+        inb(0x80);\r
+    }\r
+    return -1;\r
+}\r
+\r
+/**\r
+ * \brief Recalibrate the specified disk\r
+ */\r
+void FDD_Recalibrate(int disk)\r
+{\r
+       ENTER("idisk", disk);\r
+       \r
+       LOG("Starting Motor");\r
+       FDD_int_StartMotor(disk);\r
+       // Wait for Spinup\r
+       while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();\r
+       \r
+       LOG("Sending Calibrate Command");\r
+       FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
+       FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);\r
+       \r
+       LOG("Waiting for IRQ");\r
+       FDD_WaitIRQ();\r
+       FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);\r
+       \r
+       LOG("Stopping Motor");\r
+       FDD_int_StopMotor(disk);\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \brief Reset the specified FDD controller\r
+ */\r
+void FDD_Reset(int id)\r
+{\r
+       int base = cPORTBASE[id];\r
+       \r
+       ENTER("iID", id);\r
+       \r
+       outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC\r
+       outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)\r
+       \r
+       LOG("Awaiting IRQ");\r
+       \r
+       FDD_WaitIRQ();\r
+       FDD_SensInt(base, NULL, NULL);\r
+       \r
+       LOG("Setting Driver Info");\r
+       outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s\r
+       FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
+       FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)\r
+       FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1\r
+       while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track\r
+       while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track\r
+       \r
+       LOG("Recalibrating Disk");\r
+       FDD_Recalibrate((id<<1)|0);\r
+       FDD_Recalibrate((id<<1)|1);
+\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn void FDD_int_TimerCallback()\r
+ * \brief Called by timer\r
+ */\r
+void FDD_int_TimerCallback(int arg)\r
+{\r
+       ENTER("iarg", arg);\r
+       if(gFDD_Devices[arg].motorState == 1)\r
+               gFDD_Devices[arg].motorState = 2;\r
+       Time_RemoveTimer(gFDD_Devices[arg].timer);\r
+       gFDD_Devices[arg].timer = -1;\r
+       LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \fn void FDD_int_StartMotor(char disk)\r
+ * \brief Starts FDD Motor\r
+ */\r
+void FDD_int_StartMotor(int disk)\r
+{\r
+       Uint8   state;\r
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
+       state |= 1 << (4+disk);\r
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
+       gFDD_Devices[disk].motorState = 1;\r
+       gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)disk);\r
+}\r
+\r
+/**\r
+ * \fn void FDD_int_StopMotor(int disk)\r
+ * \brief Stops FDD Motor\r
+ */\r
+void FDD_int_StopMotor(int disk)\r
+{\r
+       Uint8   state;\r
+       state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
+       state &= ~( 1 << (4+disk) );\r
+       outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
+    gFDD_Devices[disk].motorState = 0;\r
+}\r
+\r
+/**\r
+ * \fn void ModuleUnload()\r
+ * \brief Prepare the module for removal\r
+ */\r
+void ModuleUnload()\r
+{\r
+       int i;\r
+       FDD_AquireSpinlock();\r
+       for(i=0;i<4;i++) {\r
+               Time_RemoveTimer(gFDD_Devices[i].timer);\r
+               FDD_int_StopMotor(i);\r
+       }\r
+       //IRQ_Clear(6);\r
+}\r
index 4174344..64cf4b5 100644 (file)
@@ -24,7 +24,7 @@ clean:
 $(BIN): $(OBJ)
        @echo --- $(LD) -o $@
        @$(LD) -T ../link.ld -shared -o $@ $(OBJ)
-       @echo --- $(LD) -o ../$(NAME).o.$(ARCH)
+       @echo --- $(LD) -o $(KOBJ)
        @$(CC) -Wl,-r -nostdlib -o $(KOBJ) $(OBJ)
 
 %.o.$(ARCH): %.c Makefile ../Makefile.tpl ../../Makefile.cfg 

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