3 * - By John Hodge (thePowersGang)
13 #include <api_drv_disk.h>
16 #define FDD_VERSION VER2(1,10)
21 int FDD_Install(char **Arguments);
22 int FDD_RegisterFS(void);
24 int FDD_ReadDir(tVFS_Node *Node, int pos, char dest[FILENAME_MAX]);
25 tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, const char *Name, Uint Flags);
26 int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
27 size_t FDD_ReadFS(tVFS_Node *node, off_t Offset, size_t Len, void *buffer, Uint Flags);
29 int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer);
32 MODULE_DEFINE(0, FDD_VERSION, Storage_FDDv2, FDD_Install, NULL, "x86_ISADMA", NULL);
33 tDrive gaFDD_Disks[MAX_DISKS];
34 tVFS_Node gaFDD_DiskNodes[MAX_DISKS];
35 tVFS_NodeType gFDD_RootNodeType = {
36 .TypeName = "FDD Root Node",
37 .ReadDir = FDD_ReadDir,
38 .FindDir = FDD_FindDir,
41 tVFS_NodeType gFDD_DevNodeType = {
42 .TypeName = "FDD Device",
44 .Write = NULL // FDD_WriteFS?
46 tDevFS_Driver gFDD_DriverInfo = {
51 .ACLs = &gVFS_ACL_EveryoneRX,
52 .Flags = VFS_FFLAG_DIRECTORY,
53 .Type = &gFDD_RootNodeType
58 int FDD_Install(char **Arguments)
66 // NOTE: CMOS only reports 2 disks
67 if( (data & 0xF0) == 0x40 )
68 gaFDD_Disks[0].bValid = gaFDD_Disks[0].bInserted = 1;
69 if( (data & 0x0F) == 0x04 )
70 gaFDD_Disks[1].bValid = gaFDD_Disks[1].bInserted = 1;
72 if( gaFDD_Disks[0].bValid == 0 && gaFDD_Disks[1].bValid == 0 )
73 return MODULE_ERR_NOTNEEDED;
76 // Initialise controller
85 * \brief Register the FDD driver with DevFS
87 int FDD_RegisterFS(void)
89 gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
90 = gFDD_DriverInfo.RootNode.ATime = now();
92 for( int i = 0; i < MAX_DISKS; i ++ )
94 if( !gaFDD_Disks[i].bValid ) continue ;
96 // Initialise Child Nodes
97 gaFDD_DiskNodes[i].Inode = i;
98 gaFDD_DiskNodes[i].Flags = 0;
99 gaFDD_DiskNodes[i].NumACLs = 0;
100 gaFDD_DiskNodes[i].Type = &gFDD_DevNodeType;
101 gaFDD_DiskNodes[i].Size = 1440*1024; // TODO: Non 1.44 disks
104 DevFS_AddDevice( &gFDD_DriverInfo );
109 * \brief Get the name of the \a Pos th item in the driver root
110 * \param Node Root node (unused)
111 * \param Pos Position
112 * \return Heap string of node name
114 int FDD_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
116 if(Pos < 0 || Pos >= MAX_DISKS )
118 if(!gaFDD_Disks[Pos].bValid)
127 * \brief Get a node by name
128 * \param Node Root node (unused)
129 * \param Name Drive name
130 * \return Pointer to node structure
132 tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
135 if( '0' > Name[0] || Name[0] > '9' ) return NULL;
136 if( Name[1] != '\0' ) return NULL;
139 if( pos >= MAX_DISKS ) return NULL;
141 return &gaFDD_DiskNodes[pos];
144 static const char *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
146 * \brief Driver root IOCtl Handler
147 * \param Node Root node (unused)
149 * \param Data IOCtl specific data pointer
151 int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
155 BASE_IOCTLS(DRV_TYPE_DISK, "FDDv2", FDD_VERSION, casIOCTLS);
157 case DISK_IOCTL_GETBLOCKSIZE: return 512;
165 * \brief Read from a disk
166 * \param Node Disk node
167 * \param Offset Byte offset in disk
168 * \param Length Number of bytes to read
169 * \param Buffer Destination buffer
170 * \return Number of bytes read
172 size_t FDD_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
174 int disk = Node->Inode;
179 ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
181 if( Offset > Node->Size ) LEAVE_RET('i', 0);
182 if( Length > Node->Size ) Length = Node->Size;
183 if( Offset + Length > Node->Size )
184 Length = Node->Size - Offset;
185 if( Length == 0 ) return 0;
189 track = Offset / BYTES_PER_TRACK;
190 Offset %= BYTES_PER_TRACK;
192 // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK)
197 if(rem_len > BYTES_PER_TRACK - Offset)
198 len = BYTES_PER_TRACK - Offset;
201 FDD_int_ReadWriteWithinTrack(disk, track, 0, Offset, len, dest);
209 while( rem_len > BYTES_PER_TRACK )
211 FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, BYTES_PER_TRACK, dest);
212 dest += BYTES_PER_TRACK;
213 rem_len -= BYTES_PER_TRACK;
217 FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, rem_len, dest);
225 * \brief Read from a track
227 int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer)
229 if( Offset > BYTES_PER_TRACK || Length > BYTES_PER_TRACK )
231 if( Offset + Length > BYTES_PER_TRACK )
237 ENTER("iDisk iTrack bbWrite xOffset xLength pBuffer",
238 Disk, Track, bWrite, Offset, Length, Buffer);
240 Mutex_Acquire( &gaFDD_Disks[Disk].Mutex );
242 // If the cache doesn't exist, create it
243 if( !gaFDD_Disks[Disk].TrackData[Track] )
245 gaFDD_Disks[Disk].TrackData[Track] = malloc( BYTES_PER_TRACK );
246 // Don't bother reading if this is a whole track write
247 if( !(bWrite && Offset == 0 && Length == BYTES_PER_TRACK) )
249 LOG("Reading track");
250 FDD_int_ReadWriteTrack(Disk, Track, 0, gaFDD_Disks[Disk].TrackData[Track]);
257 // Write to cache then commit cache to disk
258 char *dest = gaFDD_Disks[Disk].TrackData[Track];
259 LOG("Write to cache");
260 memcpy( dest + Offset, Buffer, Length );
261 FDD_int_ReadWriteTrack(Disk, Track, 1, gaFDD_Disks[Disk].TrackData[Track]);
266 char *src = gaFDD_Disks[Disk].TrackData[Track];
267 LOG("Read from cache");
268 memcpy(Buffer, src + Offset, Length);
271 Mutex_Release( &gaFDD_Disks[Disk].Mutex );