Improving the debug capabilities of the heap code, changed VFS to use const char...
[tpg/acess2.git] / Modules / Storage / FDD / fdd.c
1 /*
2  * AcessOS 0.1
3  * Floppy Disk Access Code
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <modules.h>
8 #include <fs_devfs.h>
9 #include <tpl_drv_disk.h>
10 #include <dma.h>
11 #include <iocache.h>
12
13 #define WARN    0
14
15 // === CONSTANTS ===
16 // --- Current Version
17 #define FDD_VERSION      ((0<<8)|(75))
18
19 // --- Options
20 #define FDD_SEEK_TIMEOUT        10      // Timeout for a seek operation
21 #define MOTOR_ON_DELAY  500             // Miliseconds
22 #define MOTOR_OFF_DELAY 2000    // Miliseconds
23 #define FDD_MAX_READWRITE_ATTEMPTS      16
24
25 // === TYPEDEFS ===
26 /**
27  * \brief Representation of a floppy drive
28  */
29 typedef struct sFloppyDrive
30 {
31          int    type;
32         volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off
33          int    track[2];
34          int    timer;
35         tVFS_Node       Node;
36         #if !USE_CACHE
37         tIOCache        *CacheHandle;
38         #endif
39 } t_floppyDevice;
40
41 /**
42  * \brief Cached Sector
43  */
44 typedef struct {
45         Uint64  timestamp;
46         Uint16  disk;
47         Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)
48         Uint8   data[512];
49 } t_floppySector;
50
51 // === CONSTANTS ===
52 static const char       *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };
53 static const int        cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };
54 static const short      cPORTBASE[] = { 0x3F0, 0x370 };
55 #if DEBUG
56 static const char       *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};
57 #endif
58
59 enum FloppyPorts {
60         PORT_STATUSA    = 0x0,
61         PORT_STATUSB    = 0x1,
62         PORT_DIGOUTPUT  = 0x2,
63         PORT_MAINSTATUS = 0x4,
64         PORT_DATARATE   = 0x4,
65         PORT_DATA               = 0x5,
66         PORT_DIGINPUT   = 0x7,
67         PORT_CONFIGCTRL = 0x7
68 };
69
70 enum FloppyCommands {
71         FIX_DRIVE_DATA  = 0x03,
72         HECK_DRIVE_STATUS       = 0x04,
73         CALIBRATE_DRIVE = 0x07,
74         CHECK_INTERRUPT_STATUS = 0x08,
75         SEEK_TRACK              = 0x0F,
76         READ_SECTOR_ID  = 0x4A,
77         FORMAT_TRACK    = 0x4D,
78         READ_TRACK              = 0x42,
79         READ_SECTOR             = 0x66,
80         WRITE_SECTOR    = 0xC5,
81         WRITE_DELETE_SECTOR     = 0xC9,
82         READ_DELETE_SECTOR      = 0xCC,
83 };
84
85 // === PROTOTYPES ===
86 // --- Filesystem
87  int    FDD_Install(char **Arguments);
88 void    FDD_UnloadModule();
89 // --- VFS Methods
90 char    *FDD_ReadDir(tVFS_Node *Node, int pos);
91 tVFS_Node       *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
92  int    FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
93 Uint64  FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);
94 // --- Functions for IOCache/DrvUtil
95 Uint    FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);
96 // --- Raw Disk Access
97  int    FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);
98  int    FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);
99 // --- Helpers
100 void    FDD_IRQHandler(int Num);
101 inline void     FDD_WaitIRQ();
102 void    FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);
103 void    FDD_int_SendByte(int base, char byte);
104  int    FDD_int_GetByte(int base);
105 void    FDD_Reset(int id);
106 void    FDD_Recalibrate(int disk);
107  int    FDD_int_SeekTrack(int disk, int head, int track);
108 void    FDD_int_TimerCallback(void *Arg);
109 void    FDD_int_StopMotor(void *Arg);
110 void    FDD_int_StartMotor(int Disk);
111  int    FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);
112
113 // === GLOBALS ===
114 MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL);
115 t_floppyDevice  gFDD_Devices[2];
116 tSpinlock       glFDD;
117 volatile int    gbFDD_IrqFired = 0;
118 tDevFS_Driver   gFDD_DriverInfo = {
119         NULL, "fdd",
120         {
121         .Size = -1,
122         .NumACLs = 1,
123         .ACLs = &gVFS_ACL_EveryoneRX,
124         .Flags = VFS_FFLAG_DIRECTORY,
125         .ReadDir = FDD_ReadDir,
126         .FindDir = FDD_FindDir,
127         .IOCtl = FDD_IOCtl
128         }
129 };
130
131 // === CODE ===
132 /**
133  * \fn int FDD_Install(char **Arguments)
134  * \brief Installs floppy driver
135  */
136 int FDD_Install(char **Arguments)
137 {
138         Uint8 data;
139         char    **args = Arguments;
140         
141         // Determine Floppy Types (From CMOS)
142         outb(0x70, 0x10);
143         data = inb(0x71);
144         gFDD_Devices[0].type = data >> 4;
145         gFDD_Devices[1].type = data & 0xF;
146         gFDD_Devices[0].track[0] = -1;
147         gFDD_Devices[1].track[1] = -1;
148         
149         if(args) {
150                 for(;*args;args++)
151                 {
152                         if(strcmp(*args, "disable")==0)
153                                 return MODULE_ERR_NOTNEEDED;
154                 }
155         }
156         
157         Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);
158         
159         if( data == 0 ) {
160                 return MODULE_ERR_NOTNEEDED;
161         }
162         
163         // Clear FDD IRQ Flag
164         FDD_SensInt(0x3F0, NULL, NULL);
165         // Install IRQ6 Handler
166         IRQ_AddHandler(6, FDD_IRQHandler);
167         // Reset Primary FDD Controller
168         FDD_Reset(0);
169         
170         // Initialise Root Node
171         gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime
172                 = gFDD_DriverInfo.RootNode.ATime = now();
173         
174         // Initialise Child Nodes
175         gFDD_Devices[0].Node.Inode = 0;
176         gFDD_Devices[0].Node.Flags = 0;
177         gFDD_Devices[0].Node.NumACLs = 0;
178         gFDD_Devices[0].Node.Read = FDD_ReadFS;
179         gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;
180         memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));
181         
182         gFDD_Devices[1].Node.Inode = 1;
183         
184         // Set Lengths
185         gFDD_Devices[0].Node.Size = cFDD_SIZES[data >> 4];
186         gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];
187         
188         // Create Sector Cache
189         if( cFDD_SIZES[data >> 4] )
190         {
191                 gFDD_Devices[0].CacheHandle = IOCache_Create(
192                         FDD_WriteSector, 0, 512,
193                         gFDD_Devices[0].Node.Size / (512*4)
194                         );      // Cache is 1/4 the size of the disk
195         }
196         if( cFDD_SIZES[data & 15] )
197         {
198                 gFDD_Devices[1].CacheHandle = IOCache_Create(
199                         FDD_WriteSector, 0, 512,
200                         gFDD_Devices[1].Node.Size / (512*4)
201                         );      // Cache is 1/4 the size of the disk
202         }
203         
204         // Register with devfs
205         DevFS_AddDevice(&gFDD_DriverInfo);
206         
207         return MODULE_ERR_OK;
208 }
209
210 /**
211  * \brief Prepare the module for removal
212  */
213 void FDD_UnloadModule()
214 {
215          int    i;
216         //DevFS_DelDevice( &gFDD_DriverInfo );
217         LOCK(&glFDD);
218         for(i=0;i<4;i++) {
219                 Time_RemoveTimer(gFDD_Devices[i].timer);
220                 FDD_int_StopMotor((void *)(Uint)i);
221         }
222         RELEASE(&glFDD);
223         //IRQ_Clear(6);
224 }
225
226 /**
227  * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)
228  * \brief Read Directory
229  */
230 char *FDD_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
231 {
232         char    name[2] = "0\0";
233
234         if(Pos >= 2 || Pos < 0) return NULL;
235         
236         if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;
237         
238         name[0] += Pos;
239         
240         return strdup(name);
241 }
242
243 /**
244  * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, const char *filename);
245  * \brief Find File Routine (for vfs_node)
246  */
247 tVFS_Node *FDD_FindDir(tVFS_Node *UNUSED(Node), const char *Filename)
248 {
249          int    i;
250         
251         ENTER("sFilename", Filename);
252         
253         // Sanity check string
254         if(Filename == NULL) {
255                 LEAVE('n');
256                 return NULL;
257         }
258         
259         // Check string length (should be 1)
260         if(Filename[0] == '\0' || Filename[1] != '\0') {
261                 LEAVE('n');
262                 return NULL;
263         }
264         
265         // Get First character
266         i = Filename[0] - '0';
267         
268         // Check for 1st disk and if it is present return
269         if(i == 0 && gFDD_Devices[0].type != 0) {
270                 LEAVE('p', &gFDD_Devices[0].Node);
271                 return &gFDD_Devices[0].Node;
272         }
273         
274         // Check for 2nd disk and if it is present return
275         if(i == 1 && gFDD_Devices[1].type != 0) {
276                 LEAVE('p', &gFDD_Devices[1].Node);
277                 return &gFDD_Devices[1].Node;
278         }
279         
280         // Else return null
281         LEAVE('n');
282         return NULL;
283 }
284
285 static const char       *casIOCTLS[] = {DRV_IOCTLNAMES,DRV_DISK_IOCTLNAMES,NULL};
286 /**
287  * \fn int FDD_IOCtl(tVFS_Node *Node, int id, void *data)
288  * \brief Stub ioctl function
289  */
290 int FDD_IOCtl(tVFS_Node *UNUSED(Node), int ID, void *Data)
291 {
292         switch(ID)
293         {
294         BASE_IOCTLS(DRV_TYPE_DISK, "FDD", FDD_VERSION, casIOCTLS);
295         
296         case DISK_IOCTL_GETBLOCKSIZE:   return 512;     
297         
298         default:
299                 return 0;
300         }
301 }
302
303 /**
304  * \fn Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
305  * \brief Read Data from a disk
306 */
307 Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
308 {
309          int    ret;
310         
311         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
312         
313         if(Node == NULL) {
314                 LEAVE('i', -1);
315                 return -1;
316         }
317         
318         if(Node->Inode != 0 && Node->Inode != 1) {
319                 LEAVE('i', -1);
320                 return -1;
321         }
322         
323         ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);
324         LEAVE('i', ret);
325         return ret;
326 }
327
328 /**
329  * \brief Reads \a Count contiguous sectors from a disk
330  * \param SectorAddr    Address of the first sector
331  * \param Count Number of sectors to read
332  * \param Buffer        Destination Buffer
333  * \param Disk  Disk Number
334  * \return Number of sectors read
335  * \note Used as a ::DrvUtil_ReadBlock helper
336  */
337 Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk)
338 {
339         Uint    ret = 0;
340         while(Count --)
341         {
342                 if( FDD_ReadSector(Disk, SectorAddr, Buffer) != 1 )
343                         return ret;
344                 
345                 Buffer = (void*)( (tVAddr)Buffer + 512 );
346                 SectorAddr ++;
347                 ret ++;
348         }
349         return ret;
350 }
351
352 int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)
353 {
354          int    cyl, head, sec;
355          int    spt, base;
356          int    i;
357          int    lba = SectorAddr;
358         Uint8   st0, st1, st2, rcy, rhe, rse, bps;      //      Status Values
359         
360         ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
361         
362         base = cPORTBASE[Disk >> 1];
363         
364         LOG("Calculating Disk Dimensions");
365         // Get CHS position
366         if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)
367         {
368                 LEAVE('i', -1);
369                 return -1;
370         }
371         LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);
372         
373         LOCK(&glFDD);   // Lock to stop the motor stopping on us
374         Time_RemoveTimer(gFDD_Devices[Disk].timer);     // Remove Old Timer
375         // Start motor if needed
376         if(gFDD_Devices[Disk].motorState != 2)  FDD_int_StartMotor(Disk);
377         RELEASE(&glFDD);
378         
379         LOG("Wait for the motor to spin up");
380         
381         // Wait for spinup
382         while(gFDD_Devices[Disk].motorState == 1)       Threads_Yield();
383         
384         LOG("Acquire Spinlock");
385         LOCK(&glFDD);
386         
387         // Seek to track
388         outb(base + CALIBRATE_DRIVE, 0);
389         i = 0;
390         while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )
391                 Threads_Yield();
392         if( i > FDD_SEEK_TIMEOUT ) {
393                 RELEASE(&glFDD);
394                 LEAVE('i', 0);
395                 return 0;
396         }
397         //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ
398                 
399         // Read Data from DMA
400         LOG("Setting DMA for read");
401         DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2
402         
403         LOG("Sending command");
404         
405         //Threads_Wait(100);    // Wait for Head to settle
406         Time_Delay(100);
407         
408         for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )
409         {
410                 if( Write )
411                         FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6
412                 else
413                         FDD_int_SendByte(base, READ_SECTOR);    // Was 0xE6
414                 FDD_int_SendByte(base, (head << 2) | (Disk&1));
415                 FDD_int_SendByte(base, (Uint8)cyl);
416                 FDD_int_SendByte(base, (Uint8)head);
417                 FDD_int_SendByte(base, (Uint8)sec);
418                 FDD_int_SendByte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})
419                 FDD_int_SendByte(base, spt);    // SPT
420                 FDD_int_SendByte(base, 0x1B);   // Gap Length (27 is default)
421                 FDD_int_SendByte(base, 0xFF);   // Data Length
422                 
423                 // Wait for IRQ
424                 if( Write ) {
425                         LOG("Writing Data");
426                         DMA_WriteData(2, 512, Buffer);
427                         LOG("Waiting for Data to be written");
428                         FDD_WaitIRQ();
429                 }
430                 else {
431                         LOG("Waiting for data to be read");
432                         FDD_WaitIRQ();
433                         LOG("Reading Data");
434                         DMA_ReadData(2, 512, Buffer);
435                 }
436                 
437                 // Clear Input Buffer
438                 LOG("Clearing Input Buffer");
439                 // Status Values
440                 st0 = FDD_int_GetByte(base);
441                 st1 = FDD_int_GetByte(base);
442                 st2 = FDD_int_GetByte(base);
443                 
444                 // Cylinder, Head and Sector (mutilated in some way
445                 rcy = FDD_int_GetByte(base);
446                 rhe = FDD_int_GetByte(base);
447                 rse = FDD_int_GetByte(base);
448                 // Should be the BPS set above (0x02)
449                 bps = FDD_int_GetByte(base);
450                 
451                 // Check Status
452                 // - Error Code
453                 if(st0 & 0xC0) {
454                         LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);
455                         continue;
456             }
457             // - Status Flags
458             if(st0 & 0x08) {    LOG("Drive not ready"); continue;       }
459             if(st1 & 0x80) {    LOG("End of Cylinder"); continue;       }
460                 if(st1 & 0x20) {        LOG("CRC Error");       continue;       }
461                 if(st1 & 0x10) {        LOG("Controller Timeout");      continue;       }
462                 if(st1 & 0x04) {        LOG("No Data Found");   continue;       }
463                 if(st1 & 0x01 || st2 & 0x01) {
464                         LOG("No Address mark found");
465                         continue;
466                 }
467             if(st2 & 0x40) {    LOG("Deleted address mark");    continue;       }
468                 if(st2 & 0x20) {        LOG("CRC error in data");       continue;       }
469                 if(st2 & 0x10) {        LOG("Wrong Cylinder");  continue;       }
470                 if(st2 & 0x04) {        LOG("uPD765 sector not found"); continue;       }
471                 if(st2 & 0x02) {        LOG("Bad Cylinder");    continue;       }
472                 
473                 if(bps != 0x2) {
474                         LOG("Returned BPS = 0x%02x, not 0x02", bps);
475                         continue;
476                 }
477                 
478                 if(st1 & 0x02) {
479                         LOG("Floppy not writable");
480                         i = FDD_MAX_READWRITE_ATTEMPTS+1;
481                         break;
482                 }
483                 
484                 // Success!
485                 break;
486         }
487         
488         // Release Spinlock
489         LOG("Realeasing Spinlock and setting motor to stop");
490         RELEASE(&glFDD);
491         
492         if(i == FDD_MAX_READWRITE_ATTEMPTS) {
493                 Log_Warning("FDD", "Exceeded %i attempts in %s the disk",
494                         FDD_MAX_READWRITE_ATTEMPTS,
495                         (Write ? "writing to" : "reading from")
496                         );
497         }
498         
499         // Don't turn the motor off now, wait for a while
500         gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)(tVAddr)Disk);
501
502         if( i < FDD_MAX_READWRITE_ATTEMPTS ) {
503                 LEAVE('i', 0);
504                 return 0;
505         }
506         else {
507                 LEAVE('i', 1);
508                 return 1;
509         }
510 }
511
512 /**
513  * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
514  * \brief Read a sector from disk
515  * \todo Make real-hardware safe (account for read errors)
516 */
517 int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)
518 {
519          int    ret;
520         
521         ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);
522         
523         if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {
524                 LEAVE('i', 1);
525                 return 1;
526         }
527         
528         // Pass to general function
529         ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
530
531         if( ret == 0 ) {
532                 IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
533                 LEAVE('i', 1);
534                 return 1;
535         }
536         else {
537                 LOG("Reading failed");
538                 LEAVE('i', 0);
539                 return 0;
540         }
541 }
542
543 /**
544  * \fn int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
545  * \brief Write a sector to the floppy disk
546  * \note Not Implemented
547  */
548 int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer)
549 {
550         Warning("[FDD  ] Read Only at the moment");
551         return -1;
552 }
553
554 /**
555  * \fn int FDD_int_SeekTrack(int disk, int track)
556  * \brief Seek disk to selected track
557  */
558 int FDD_int_SeekTrack(int disk, int head, int track)
559 {
560         Uint8   sr0, cyl;
561          int    base;
562         
563         base = cPORTBASE[disk>>1];
564         
565         // Check if seeking is needed
566         if(gFDD_Devices[disk].track[head] == track)
567                 return 1;
568         
569         // - Seek Head 0
570         FDD_int_SendByte(base, SEEK_TRACK);
571         FDD_int_SendByte(base, (head<<2)|(disk&1));
572         FDD_int_SendByte(base, track);  // Send Seek command
573         FDD_WaitIRQ();
574         FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ
575         if((sr0 & 0xF0) != 0x20) {
576                 LOG("sr0 = 0x%x", sr0);
577                 return 0;       //Check Status
578         }
579         if(cyl != track)        return 0;
580         
581         // Set Track in structure
582         gFDD_Devices[disk].track[head] = track;
583         return 1;
584 }
585
586 /**
587  * \fn int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
588  * \brief Get Dimensions of a disk
589  */
590 int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt)
591 {
592         switch(type) {
593         case 0:
594                 return 0;
595         
596         // 360Kb 5.25"
597         case 1:
598                 *spt = 9;
599                 *s = (lba % 9) + 1;
600                 *c = lba / 18;
601                 *h = (lba / 9) & 1;
602                 break;
603         
604         // 1220Kb 5.25"
605         case 2:
606                 *spt = 15;
607                 *s = (lba % 15) + 1;
608                 *c = lba / 30;
609                 *h = (lba / 15) & 1;
610                 break;
611         
612         // 720Kb 3.5"
613         case 3:
614                 *spt = 9;
615                 *s = (lba % 9) + 1;
616                 *c = lba / 18;
617                 *h = (lba / 9) & 1;
618                 break;
619         
620         // 1440Kb 3.5"
621         case 4:
622                 *spt = 18;
623                 *s = (lba % 18) + 1;
624                 *c = lba / 36;
625                 *h = (lba / 18) & 1;
626                 //Log("1440k - lba=%i(0x%x), *s=%i,*c=%i,*h=%i", lba, lba, *s, *c, *h);
627                 break;
628                 
629         // 2880Kb 3.5"
630         case 5:
631                 *spt = 36;
632                 *s = (lba % 36) + 1;
633                 *c = lba / 72;
634                 *h = (lba / 32) & 1;
635                 break;
636                 
637         default:
638                 return -2;
639         }
640         return 1;
641 }
642
643 /**
644  * \fn void FDD_IRQHandler(int Num)
645  * \brief Handles IRQ6
646  */
647 void FDD_IRQHandler(int Num)
648 {
649         gbFDD_IrqFired = 1;
650 }
651
652 /**
653  * \fn FDD_WaitIRQ()
654  * \brief Wait for an IRQ6
655  */
656 inline void FDD_WaitIRQ()
657 {
658         // Wait for IRQ
659         while(!gbFDD_IrqFired)  Threads_Yield();
660         gbFDD_IrqFired = 0;
661 }
662
663 void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)
664 {
665         FDD_int_SendByte(base, CHECK_INTERRUPT_STATUS);
666         if(sr0) *sr0 = FDD_int_GetByte(base);
667         else    FDD_int_GetByte(base);
668         if(cyl) *cyl = FDD_int_GetByte(base);
669         else    FDD_int_GetByte(base);
670 }
671
672 /**
673  * void FDD_int_SendByte(int base, char byte)
674  * \brief Sends a command to the controller
675  */
676 void FDD_int_SendByte(int base, char byte)
677 {
678         volatile int state;
679         int timeout = 128;
680         for( ; timeout--; )
681         {
682             state = inb(base + PORT_MAINSTATUS);
683             if ((state & 0xC0) == 0x80)
684             {
685                 outb(base + PORT_DATA, byte);
686                 return;
687             }
688             inb(0x80);  //Delay
689         }
690         
691         #if WARN
692         Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);
693         #endif
694 }
695
696 /**
697  * int FDD_int_GetByte(int base, char byte)
698  * \brief Receive data from fdd controller
699  */
700 int FDD_int_GetByte(int base)
701 {
702         volatile int state;
703         int timeout;
704         for( timeout = 128; timeout--; )
705         {
706             state = inb((base + PORT_MAINSTATUS));
707             if ((state & 0xd0) == 0xd0)
708                     return inb(base + PORT_DATA);
709             inb(0x80);
710         }
711         return -1;
712 }
713
714 /**
715  * \brief Recalibrate the specified disk
716  */
717 void FDD_Recalibrate(int disk)
718 {
719         ENTER("idisk", disk);
720         
721         LOG("Starting Motor");
722         FDD_int_StartMotor(disk);
723         // Wait for Spinup
724         while(gFDD_Devices[disk].motorState == 1)       Threads_Yield();
725         
726         LOG("Sending Calibrate Command");
727         FDD_int_SendByte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);
728         FDD_int_SendByte(cPORTBASE[disk>>1], disk&1);
729         
730         LOG("Waiting for IRQ");
731         FDD_WaitIRQ();
732         FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);
733         
734         LOG("Stopping Motor");
735         gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)(Uint)disk);
736         LEAVE('-');
737 }
738
739 /**
740  * \brief Reset the specified FDD controller
741  */
742 void FDD_Reset(int id)
743 {
744         int base = cPORTBASE[id];
745         
746         ENTER("iID", id);
747         
748         outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC
749         outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)
750         
751         LOG("Awaiting IRQ");
752         
753         FDD_WaitIRQ();
754         FDD_SensInt(base, NULL, NULL);
755         
756         LOG("Setting Driver Info");
757         outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s
758         FDD_int_SendByte(base, FIX_DRIVE_DATA); // Step and Head Load Times
759         FDD_int_SendByte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)
760         FDD_int_SendByte(base, 0x02);   // Head Load Time >> 1
761         while(FDD_int_SeekTrack(0, 0, 1) == 0); // set track
762         while(FDD_int_SeekTrack(0, 1, 1) == 0); // set track
763         
764         LOG("Recalibrating Disk");
765         FDD_Recalibrate((id<<1)|0);
766         FDD_Recalibrate((id<<1)|1);
767
768         LEAVE('-');
769 }
770
771 /**
772  * \fn void FDD_int_TimerCallback()
773  * \brief Called by timer
774  */
775 void FDD_int_TimerCallback(void *Arg)
776 {
777          int    disk = (Uint)Arg;
778         ENTER("iarg", disk);
779         if(gFDD_Devices[disk].motorState == 1)
780                 gFDD_Devices[disk].motorState = 2;
781         Time_RemoveTimer(gFDD_Devices[disk].timer);
782         gFDD_Devices[disk].timer = -1;
783         LEAVE('-');
784 }
785
786 /**
787  * \fn void FDD_int_StartMotor(char disk)
788  * \brief Starts FDD Motor
789  */
790 void FDD_int_StartMotor(int disk)
791 {
792         Uint8   state;
793         state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
794         state |= 1 << (4+disk);
795         outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
796         gFDD_Devices[disk].motorState = 1;
797         gFDD_Devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, FDD_int_TimerCallback, (void*)(Uint)disk);
798 }
799
800 /**
801  * \fn void FDD_int_StopMotor(int disk)
802  * \brief Stops FDD Motor
803  */
804 void FDD_int_StopMotor(void *Arg)
805 {
806         Uint8   state, disk = (Uint)Arg;
807         if( IS_LOCKED(&glFDD) ) return ;
808         ENTER("iDisk", disk);
809         
810         state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );
811         state &= ~( 1 << (4+disk) );
812         outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );
813         gFDD_Devices[disk].motorState = 0;
814         LEAVE('-');
815 }

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