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)))
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
+++ /dev/null
-/*\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
--- /dev/null
+/*
+ * 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);
+}
#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)
DevFS_AddDevice( &gVT_DrvInfo );
// Set kernel output to VT0
- //Debug_SetKTerminal("/Devices/VTerm/0");
+ Debug_SetKTerminal("/Devices/VTerm/0");
return 0;
}
* 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
--- /dev/null
+/*
+ * 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
+/*
+ * 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
/// \brief Get driver version - (int *ver)
DRV_IOCTL_VERSION,
/// \brief Get a IOCtl from a symbolic name
- DRV_IOCTL_LOOKUP,
+ DRV_IOCTL_LOOKUP
};
/**
};
// === 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
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
};\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
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
/*
- * 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
//! 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
/**
* \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
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
--- /dev/null
+#
+#
+
+OBJ = fdd.o
+NAME = FDD
+
+-include ../Makefile.tpl
--- /dev/null
+/*\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
$(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