Kernel - Added 'Flags' param to VFS Read/Write/FindDir
[tpg/acess2.git] / KernelLand / Modules / Storage / FDDv2 / main.c
1 /*
2  * Acess2 82077AA FDC
3  * - By John Hodge (thePowersGang)
4  *
5  * fdc.c
6  * - Core file
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <modules.h>
11 #include <fs_devfs.h>
12 #include "common.h"
13 #include <api_drv_disk.h>
14
15 // === CONSTANTS ===
16 #define FDD_VERSION     VER2(1,10)
17
18 // === STRUCTURES ===
19
20 // === PROTOTYPES ===
21  int    FDD_Install(char **Arguments);
22  int    FDD_RegisterFS(void);
23 // --- VFS
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);
28 // --- Helpers
29  int    FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer);
30
31 // === GLOBALS ===
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,
39         .IOCtl = FDD_IOCtl
40         };
41 tVFS_NodeType   gFDD_DevNodeType = {
42         .TypeName = "FDD Device",
43         .Read = FDD_ReadFS,
44         .Write = NULL   // FDD_WriteFS?
45         };
46 tDevFS_Driver   gFDD_DriverInfo = {
47         NULL, "fdd",
48         {
49         .Size = -1,
50         .NumACLs = 1,
51         .ACLs = &gVFS_ACL_EveryoneRX,
52         .Flags = VFS_FFLAG_DIRECTORY,
53         .Type = &gFDD_RootNodeType
54         }
55         };
56
57 // === CODE ===
58 int FDD_Install(char **Arguments)
59 {
60         // Query CMOS memory
61         {
62                 Uint8   data;
63                 outb(0x70, 0x10);
64                 data = inb(0x71);
65                 
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;
71                 
72                 if( gaFDD_Disks[0].bValid == 0 && gaFDD_Disks[1].bValid == 0 )
73                         return MODULE_ERR_NOTNEEDED;
74         }
75         
76         // Initialise controller
77         FDD_SetupIO();
78
79         FDD_RegisterFS();
80
81         return 0;
82 }
83
84 /**
85  * \brief Register the FDD driver with DevFS
86  */
87 int FDD_RegisterFS(void)
88 {
89         gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
90                 = gFDD_DriverInfo.RootNode.ATime = now();
91
92         for( int i = 0; i < MAX_DISKS; i ++ )
93         {
94                 if( !gaFDD_Disks[i].bValid )    continue ;
95         
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
102         }
103         
104         DevFS_AddDevice( &gFDD_DriverInfo );
105         return 0;
106 }
107
108 /**
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
113  */
114 int FDD_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
115 {
116         if(Pos < 0 || Pos >= MAX_DISKS )
117                 return -ENOENT;
118         if(!gaFDD_Disks[Pos].bValid)
119                 return 1;
120         
121         Dest[0] = '0' + Pos;
122         Dest[1] = '\0';
123         return 0;
124 }
125
126 /**
127  * \brief Get a node by name
128  * \param Node  Root node (unused)
129  * \param Name  Drive name
130  * \return Pointer to node structure
131  */
132 tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
133 {
134          int    pos;
135         if( '0' > Name[0] || Name[0] > '9' )    return NULL;
136         if( Name[1] != '\0' )   return NULL;
137         
138         pos = Name[0] - '0';
139         if( pos >= MAX_DISKS )  return NULL;
140         
141         return &gaFDD_DiskNodes[pos];
142 }
143
144 static const char       *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
145 /**
146  * \brief Driver root IOCtl Handler
147  * \param Node  Root node (unused)
148  * \param ID    IOCtl ID
149  * \param Data  IOCtl specific data pointer
150  */
151 int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
152 {
153         switch(ID)
154         {
155         BASE_IOCTLS(DRV_TYPE_DISK, "FDDv2", FDD_VERSION, casIOCTLS);
156         
157         case DISK_IOCTL_GETBLOCKSIZE:   return 512;
158         
159         default:
160                 return -1;
161         }
162 }
163
164 /**
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
171  */
172 size_t FDD_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags)
173 {
174          int    disk = Node->Inode;
175          int    track;
176          int    rem_len;
177         char    *dest = Buffer;
178
179         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
180
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;
186
187         rem_len = Length;
188
189         track = Offset / BYTES_PER_TRACK;
190         Offset %= BYTES_PER_TRACK;
191
192         // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK)
193
194         if( Offset )
195         {
196                  int    len;
197                 if(rem_len > BYTES_PER_TRACK - Offset)
198                         len = BYTES_PER_TRACK - Offset;
199                 else
200                         len = rem_len;
201                 FDD_int_ReadWriteWithinTrack(disk, track, 0, Offset, len, dest);
202                 dest += len;
203                 rem_len -= len;
204                 track ++;
205         }
206
207         if( rem_len > 0)
208         {
209                 while( rem_len > BYTES_PER_TRACK )
210                 {
211                         FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, BYTES_PER_TRACK, dest);
212                         dest += BYTES_PER_TRACK;
213                                 rem_len -= BYTES_PER_TRACK;
214                         track ++;
215                 }
216
217                 FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, rem_len, dest);
218         }
219         
220         LEAVE('X', Length);
221         return Length;
222 }
223
224 /**
225  * \brief Read from a track
226  */
227 int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer)
228 {
229         if( Offset > BYTES_PER_TRACK || Length > BYTES_PER_TRACK )
230                 return 1;
231         if( Offset + Length > BYTES_PER_TRACK )
232                 return 1;
233
234         if( Length == 0 )
235                 return 0;
236         
237         ENTER("iDisk iTrack bbWrite xOffset xLength pBuffer",
238                 Disk, Track, bWrite, Offset, Length, Buffer);
239         
240         Mutex_Acquire( &gaFDD_Disks[Disk].Mutex );
241
242         // If the cache doesn't exist, create it
243         if( !gaFDD_Disks[Disk].TrackData[Track] )
244         {
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) )
248                 {
249                         LOG("Reading track");
250                         FDD_int_ReadWriteTrack(Disk, Track, 0, gaFDD_Disks[Disk].TrackData[Track]);
251                 }
252         }
253         
254         // Read/Write
255         if( bWrite )
256         {
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]);
262         }
263         else
264         {
265                 // Read from cache
266                 char    *src = gaFDD_Disks[Disk].TrackData[Track];
267                 LOG("Read from cache");
268                 memcpy(Buffer, src + Offset, Length);
269         }
270         
271         Mutex_Release( &gaFDD_Disks[Disk].Mutex );
272
273         LEAVE('i', 0);
274         return 0;
275 }

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