Kernel/ARMv7 - Fixed not using ASIDs
[tpg/acess2.git] / 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 char    *FDD_ReadDir(tVFS_Node *Node, int pos);
25 tVFS_Node       *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
26  int    FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
27 Uint64  FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
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 tDevFS_Driver   gFDD_DriverInfo = {
36         NULL, "fdd",
37         {
38         .Size = -1,
39         .NumACLs = 1,
40         .ACLs = &gVFS_ACL_EveryoneRX,
41         .Flags = VFS_FFLAG_DIRECTORY,
42         .ReadDir = FDD_ReadDir,
43         .FindDir = FDD_FindDir,
44         .IOCtl = FDD_IOCtl
45         }
46         };
47
48 // === CODE ===
49 int FDD_Install(char **Arguments)
50 {
51         // Query CMOS memory
52         {
53                 Uint8   data;
54                 outb(0x70, 0x10);
55                 data = inb(0x71);
56                 
57                 // NOTE: CMOS only reports 2 disks
58                 if( (data & 0xF0) == 0x40 )
59                         gaFDD_Disks[0].bValid = gaFDD_Disks[0].bInserted = 1;
60                 if( (data & 0x0F) == 0x04 )
61                         gaFDD_Disks[1].bValid = gaFDD_Disks[1].bInserted = 1;
62                 
63                 if( gaFDD_Disks[0].bValid == 0 && gaFDD_Disks[1].bValid == 0 )
64                         return MODULE_ERR_NOTNEEDED;
65         }
66         
67         // Initialise controller
68         FDD_SetupIO();
69
70         FDD_RegisterFS();
71
72         return 0;
73 }
74
75 /**
76  * \brief Register the FDD driver with DevFS
77  */
78 int FDD_RegisterFS(void)
79 {
80         gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
81                 = gFDD_DriverInfo.RootNode.ATime = now();
82
83         for( int i = 0; i < MAX_DISKS; i ++ )
84         {
85                 if( !gaFDD_Disks[i].bValid )    continue ;
86         
87                 // Initialise Child Nodes
88                 gaFDD_DiskNodes[i].Inode = i;
89                 gaFDD_DiskNodes[i].Flags = 0;
90                 gaFDD_DiskNodes[i].NumACLs = 0;
91                 gaFDD_DiskNodes[i].Read = FDD_ReadFS;
92                 gaFDD_DiskNodes[i].Write = NULL;//FDD_WriteFS;
93                 gaFDD_DiskNodes[i].Size = 1440*1024;    // TODO: Non 1.44 disks
94         }
95         
96         DevFS_AddDevice( &gFDD_DriverInfo );
97         return 0;
98 }
99
100 /**
101  * \brief Get the name of the \a Pos th item in the driver root
102  * \param Node  Root node (unused)
103  * \param Pos   Position
104  * \return Heap string of node name
105  */
106 char *FDD_ReadDir(tVFS_Node *Node, int Pos)
107 {
108         char    ret_tpl[2];
109         if(Pos < 0 || Pos > MAX_DISKS )
110                 return NULL;
111         if(gaFDD_Disks[Pos].bValid)
112                 return VFS_SKIP;
113         
114         ret_tpl[0] = '0' + Pos;
115         ret_tpl[1] = '\0';
116         return strdup(ret_tpl);
117 }
118
119 /**
120  * \brief Get a node by name
121  * \param Node  Root node (unused)
122  * \param Name  Drive name
123  * \return Pointer to node structure
124  */
125 tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *Name)
126 {
127          int    pos;
128         if( '0' > Name[0] || Name[0] > '9' )    return NULL;
129         if( Name[1] != '\0' )   return NULL;
130         
131         pos = Name[0] - '0';
132         
133         return &gaFDD_DiskNodes[pos];
134 }
135
136 static const char       *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
137 /**
138  * \brief Driver root IOCtl Handler
139  * \param Node  Root node (unused)
140  * \param ID    IOCtl ID
141  * \param Data  IOCtl specific data pointer
142  */
143 int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data)
144 {
145         switch(ID)
146         {
147         BASE_IOCTLS(DRV_TYPE_DISK, "FDDv2", FDD_VERSION, casIOCTLS);
148         
149         case DISK_IOCTL_GETBLOCKSIZE:   return 512;
150         
151         default:
152                 return -1;
153         }
154 }
155
156 /**
157  * \brief Read from a disk
158  * \param Node  Disk node
159  * \param Offset        Byte offset in disk
160  * \param Length        Number of bytes to read
161  * \param Buffer        Destination buffer
162  * \return Number of bytes read
163  */
164 Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
165 {
166          int    disk = Node->Inode;
167          int    track;
168          int    rem_len;
169         char    *dest = Buffer;
170
171         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
172
173         if( Offset > Node->Size )       LEAVE_RET('i', 0);
174         if( Length > Node->Size )       Length = Node->Size;
175         if( Offset + Length > Node->Size )
176                 Length = Node->Size - Offset;
177         if( Length == 0 )       return 0;
178
179         rem_len = Length;
180
181         track = Offset / BYTES_PER_TRACK;
182         Offset %= BYTES_PER_TRACK;      
183
184         if( Offset )
185         {
186                  int    len;
187                 if(rem_len > BYTES_PER_TRACK - Offset)
188                         len = BYTES_PER_TRACK - Offset;
189                 else
190                         len = rem_len;
191                 FDD_int_ReadWriteWithinTrack(disk, track, 0, Offset, len, dest);
192                 dest += len;
193                 rem_len -= len;
194                 track ++;
195         }
196
197         if( rem_len > 0)
198         {
199                 while( rem_len > BYTES_PER_TRACK )
200                 {
201                         FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, BYTES_PER_TRACK, dest);
202                         dest += BYTES_PER_TRACK;
203                                 rem_len -= BYTES_PER_TRACK;
204                         track ++;
205                 }
206
207                 FDD_int_ReadWriteWithinTrack(disk, track, 0, 0, rem_len, dest);
208         }
209         
210         LEAVE('X', Length);
211         return Length;
212 }
213
214 /**
215  * \brief Read from a track
216  */
217 int FDD_int_ReadWriteWithinTrack(int Disk, int Track, int bWrite, size_t Offset, size_t Length, void *Buffer)
218 {
219         if( Offset > BYTES_PER_TRACK || Length > BYTES_PER_TRACK )
220                 return 1;
221         if( Offset + Length > BYTES_PER_TRACK )
222                 return 1;
223
224         if( Length == 0 )
225                 return 0;
226         
227         ENTER("iDisk iTrack bbWrite xOffset xLength pBuffer",
228                 Disk, Track, bWrite, Offset, Length, Buffer);
229         
230         Mutex_Acquire( &gaFDD_Disks[Disk].Mutex );
231
232         // If the cache doesn't exist, create it
233         if( !gaFDD_Disks[Disk].TrackData[Track] )
234         {
235                 gaFDD_Disks[Disk].TrackData[Track] = malloc( BYTES_PER_TRACK );
236                 // Don't bother reading if this is a whole track write
237                 if( !(bWrite && Offset == 0 && Length == BYTES_PER_TRACK) )
238                 {
239                         LOG("Reading track");
240                         FDD_int_ReadWriteTrack(Disk, Track, 0, gaFDD_Disks[Disk].TrackData[Track]);
241                 }
242         }
243         
244         // Read/Write
245         if( bWrite )
246         {
247                 // Write to cache then commit cache to disk
248                 char    *dest = gaFDD_Disks[Disk].TrackData[Track];
249                 LOG("Write to cache");
250                 memcpy( dest + Offset, Buffer, Length );
251                 FDD_int_ReadWriteTrack(Disk, Track, 1, gaFDD_Disks[Disk].TrackData[Track]);
252         }
253         else
254         {
255                 // Read from cache
256                 char    *src = gaFDD_Disks[Disk].TrackData[Track];
257                 LOG("Read from cache");
258                 memcpy(Buffer, src + Offset, Length);
259         }
260         
261         Mutex_Release( &gaFDD_Disks[Disk].Mutex );
262
263         LEAVE('i', 0);
264         return 0;
265 }

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