Various Changes
[tpg/acess2.git] / Kernel / drv / fdd.c
1 /*\r
2  * AcessOS 0.1\r
3  * Floppy Disk Access Code\r
4  */\r
5 #define DEBUG   1\r
6 #include <common.h>\r
7 #include <modules.h>\r
8 #include <fs_devfs.h>\r
9 #include <tpl_drv_common.h>\r
10 #include <dma.h>\r
11 \r
12 #define WARN    0\r
13 \r
14 // Version Information\r
15 #define FDD_VER_MAJ      0\r
16 #define FDD_VER_MIN     75\r
17 \r
18 #define USE_CACHE       1       // Use Sector Cache\r
19 #define CACHE_SIZE      32      // Number of cachable sectors\r
20 #define FDD_SEEK_TIMEOUT        10      // Timeout for a seek operation\r
21 #define MOTOR_ON_DELAY  500             // Miliseconds\r
22 #define MOTOR_OFF_DELAY 2000    // Miliseconds\r
23 \r
24 // === TYPEDEFS ===\r
25 typedef struct {\r
26          int    type;\r
27         volatile int    motorState;     //2 - On, 1 - Spinup, 0 - Off\r
28          int    track[2];\r
29          int    timer;\r
30         char    Name[2];\r
31         tVFS_Node       Node;\r
32 } t_floppyDevice;\r
33 \r
34 typedef struct {\r
35         Uint64  timestamp;\r
36         Uint16  disk;\r
37         Uint16  sector; // Allows 32Mb of addressable space (Plenty for FDD)\r
38         char    data[512];\r
39 } t_floppySector;\r
40 \r
41 // === CONSTANTS ===\r
42 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
43 static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
44 static const short      cPORTBASE[] = {0x3F0, 0x370 };\r
45 \r
46 enum FloppyPorts {\r
47         PORT_STATUSA    = 0x0,\r
48         PORT_STATUSB    = 0x1,\r
49         PORT_DIGOUTPUT  = 0x2,\r
50         PORT_MAINSTATUS = 0x4,\r
51         PORT_DATARATE   = 0x4,\r
52         PORT_DATA               = 0x5,\r
53         PORT_DIGINPUT   = 0x7,\r
54         PORT_CONFIGCTRL = 0x7\r
55 };\r
56 \r
57 enum FloppyCommands {\r
58         FIX_DRIVE_DATA  = 0x03,\r
59         HECK_DRIVE_STATUS       = 0x04,\r
60         CALIBRATE_DRIVE = 0x07,\r
61         CHECK_INTERRUPT_STATUS = 0x08,\r
62         SEEK_TRACK              = 0x0F,\r
63         READ_SECTOR_ID  = 0x4A,\r
64         FORMAT_TRACK    = 0x4D,\r
65         READ_TRACK              = 0x42,\r
66         READ_SECTOR             = 0x66,\r
67         WRITE_SECTOR    = 0xC5,\r
68         WRITE_DELETE_SECTOR     = 0xC9,\r
69         READ_DELETE_SECTOR      = 0xCC,\r
70 };\r
71 \r
72 // === PROTOTYPES ===\r
73 char    *FDD_ReadDir(tVFS_Node *Node, int pos);\r
74 tVFS_Node       *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
75 static int      fdd_readSector(int disk, int lba, void *buf);\r
76 void    FDD_WaitIRQ();\r
77 void    FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
78 static void     FDD_AquireSpinlock();\r
79 static void     inline FDD_FreeSpinlock();\r
80 #if USE_CACHE\r
81 static inline void FDD_AquireCacheSpinlock();\r
82 static inline void FDD_FreeCacheSpinlock();\r
83 #endif\r
84 static void     sendbyte(int base, char byte);\r
85 static int      getbyte(int base);\r
86 static int      seekTrack(int disk, int head, int track);\r
87 static void     stop_motor(int disk);\r
88 static void     start_motor(int disk);\r
89 static int      get_dims(int type, int lba, int *c, int *h, int *s, int *spt);\r
90  int    FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
91 Uint64  FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
92  int    FDD_Install(char **Arguments);\r
93 \r
94 // === GLOBALS ===\r
95 MODULE_DEFINE(0, 0x004B, FDD, FDD_Install, NULL, NULL);\r
96 static t_floppyDevice   fdd_devices[2];\r
97 static volatile int     fdd_inUse = 0;\r
98 static volatile int     fdd_irq6 = 0;\r
99 tDevFS_Driver   gFDD_DriverInfo = {\r
100         NULL, "fdd",\r
101         {\r
102         .Size = -1,\r
103         .NumACLs = 1,\r
104         .ACLs = &gVFS_ACL_EveryoneRX,\r
105         .Flags = VFS_FFLAG_DIRECTORY,\r
106         .ReadDir = FDD_ReadDir,\r
107         .FindDir = FDD_FindDir,\r
108         .IOCtl = FDD_IOCtl\r
109         }\r
110 };\r
111 #if USE_CACHE\r
112 static int      siFDD_CacheInUse = 0;\r
113 static int      siFDD_SectorCacheSize = CACHE_SIZE;\r
114 static t_floppySector   sFDD_SectorCache[CACHE_SIZE];\r
115 #endif\r
116 \r
117 // === CODE ===\r
118 /**\r
119  * \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
120  * \brief Read Directory\r
121  */\r
122 char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
123 {\r
124         //Update Accessed Time\r
125         //gFDD_DrvInfo.rootNode.atime = now();\r
126         \r
127         //Check for bounds\r
128         if(pos >= 2 || pos < 0)\r
129                 return NULL;\r
130         \r
131         if(fdd_devices[pos].type == 0)\r
132                 return VFS_SKIP;\r
133         \r
134         //Return\r
135         return fdd_devices[pos].Name;\r
136 }\r
137 \r
138 /**\r
139  * \fn tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename);\r
140  * \brief Find File Routine (for vfs_node)\r
141  */\r
142 tVFS_Node *FDD_FindDir(tVFS_Node *Node, char *filename)\r
143 {\r
144         int i;\r
145         \r
146         ENTER("sfilename", filename);\r
147         \r
148         if(filename == NULL)    return NULL;\r
149         \r
150         //Check string length (should be 1)\r
151         if(filename[0] == '\0') return NULL;\r
152         if(filename[1] != '\0') return NULL;\r
153         \r
154         //Get First char\r
155         i = filename[0] - '0';\r
156         \r
157         // Check for 1st disk and if it is present return\r
158         if(i == 0 && fdd_devices[0].type != 0)\r
159                 return &fdd_devices[0].Node;\r
160         \r
161         // Check for 2nd disk and if it is present return\r
162         if(i == 1 && fdd_devices[1].type != 0)\r
163                 return &fdd_devices[1].Node;\r
164         \r
165         // Else return null\r
166         return NULL;\r
167 }\r
168 \r
169 /**\r
170  * \fn Uint64 fdd_readFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
171  * \brief Read Data from a disk\r
172 */\r
173 Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer)\r
174 {\r
175         int i = 0;\r
176         int     disk;\r
177         Uint32  buf[128];\r
178         \r
179         ENTER("xoff xlen pbuffer", off, len, buffer);\r
180         \r
181         if(node == NULL) {\r
182                 LEAVE('i', -1);\r
183                 return -1;\r
184         }\r
185         \r
186         if(node->Inode != 0 && node->Inode != 1) {\r
187                 LEAVE('i', -1);\r
188                 return -1;\r
189         }\r
190         \r
191         disk = node->Inode;\r
192         \r
193         // Update Accessed Time\r
194         node->ATime = now();\r
195         \r
196         if((off & 0x1FF) || (len & 0x1FF))\r
197         {\r
198                 // Un-Aligned Offset/Length\r
199                  int    startOff = off>>9;\r
200                  int    sectOff = off&0x1FF;\r
201                  int    sectors = (len+0x1FF)>>9;\r
202         \r
203                 LOG("Non-aligned Read");\r
204                 \r
205                 //Read Starting Sector\r
206                 if(!fdd_readSector(disk, startOff, buf))\r
207                         return 0;\r
208                 memcpy(buffer, (char*)(buf+sectOff), len>512-sectOff?512-sectOff:len);\r
209                 \r
210                 //If the data size is one sector or less\r
211                 if(len <= 512-sectOff) {\r
212                         LEAVE('X', len);\r
213                         return len;     //Return\r
214                 }\r
215                 buffer += 512-sectOff;\r
216         \r
217                 //Read Middle Sectors\r
218                 for(i=1;i<sectors-1;i++)        {\r
219                         if(!fdd_readSector(disk, startOff+i, buf)) {\r
220                                 LEAVE('i', -1);\r
221                                 return -1;\r
222                         }\r
223                         memcpy(buffer, buf, 512);\r
224                         buffer += 512;\r
225                 }\r
226         \r
227                 //Read End Sectors\r
228                 if(!fdd_readSector(disk, startOff+i, buf))\r
229                         return 0;\r
230                 memcpy(buffer, buf, (len&0x1FF)-sectOff);\r
231                 
232                 LEAVE('X', len);\r
233                 return len;\r
234         }\r
235         else\r
236         {\r
237                  int    count = len >> 9;\r
238                  int    sector = off >> 9;\r
239                 LOG("Aligned Read");\r
240                 //Aligned Offset and Length - Simple Code\r
241                 for(i=0;i<count;i++)\r
242                 {\r
243                         fdd_readSector(disk, sector, buf);\r
244                         memcpy(buffer, buf, 512);\r
245                         buffer += 512;\r
246                         sector++;\r
247                 }
248                 LEAVE('i', len);\r
249                 return len;\r
250         }\r
251 }\r
252 \r
253 /**\r
254  * \fn static int fdd_readSector(int disk, int lba, void *buf)\r
255  * \fn Read a sector from disk\r
256 */\r
257 int fdd_readSector(int disk, int lba, void *buf)\r
258 {\r
259          int    cyl, head, sec;\r
260          int    spt, base;\r
261          int    i;\r
262         \r
263         ENTER("idisk xlba pbuf", disk, lba, buf);\r
264         \r
265         #if USE_CACHE\r
266         FDD_AquireCacheSpinlock();\r
267         for(i=0;i<siFDD_SectorCacheSize;i++)\r
268         {\r
269                 if(sFDD_SectorCache[i].timestamp == 0)  continue;\r
270                 if(sFDD_SectorCache[i].disk == disk\r
271                 && sFDD_SectorCache[i].sector == lba) {\r
272                         LOG("Found %i in cache %i", lba, i);\r
273                         memcpy(buf, sFDD_SectorCache[i].data, 512);\r
274                         sFDD_SectorCache[i].timestamp = now();\r
275                         FDD_FreeCacheSpinlock();\r
276                         LEAVE('i', 1);\r
277                         return 1;\r
278                 }\r
279         }\r
280         LOG("Read %i from Disk", lba);\r
281         FDD_FreeCacheSpinlock();\r
282         #endif\r
283         \r
284         base = cPORTBASE[disk>>1];\r
285         \r
286         LOG("Calculating Disk Dimensions");\r
287         //Get CHS position\r
288         if(get_dims(fdd_devices[disk].type, lba, &cyl, &head, &sec, &spt) != 1) {\r
289                 LEAVE('i', -1);\r
290                 return -1;\r
291         }\r
292         \r
293         // Remove Old Timer\r
294         Time_RemoveTimer(fdd_devices[disk].timer);\r
295         // Check if Motor is on\r
296         if(fdd_devices[disk].motorState == 0) {\r
297                 start_motor(disk);\r
298         }\r
299         \r
300         LOG("Wait for Motor Spinup");\r
301         \r
302         // Wait for spinup\r
303         while(fdd_devices[disk].motorState == 1)        Threads_Yield();\r
304         \r
305         LOG("C:%i,H:%i,S:%i", cyl, head, sec);\r
306         LOG("Acquire Spinlock");\r
307         \r
308         FDD_AquireSpinlock();\r
309         \r
310         // Seek to track\r
311         outb(base+CALIBRATE_DRIVE, 0);\r
312         i = 0;\r
313         while(seekTrack(disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )        Threads_Yield();\r
314         //FDD_SensInt(base, NULL, NULL);        // Wait for IRQ\r
315         \r
316         LOG("Setting DMA for read");\r
317         \r
318         //Read Data from DMA\r
319         DMA_SetChannel(2, 512, 1);      // Read 512 Bytes\r
320         \r
321         LOG("Sending read command");\r
322         \r
323         //Threads_Wait(100);    // Wait for Head to settle\r
324         Time_Delay(100);\r
325         sendbyte(base, READ_SECTOR);    // Was 0xE6\r
326         sendbyte(base, (head << 2) | (disk&1));\r
327         sendbyte(base, (Uint8)cyl);\r
328         sendbyte(base, (Uint8)head);\r
329         sendbyte(base, (Uint8)sec);\r
330         sendbyte(base, 0x02);   // Bytes Per Sector (Real BPS=128*2^{val})\r
331         sendbyte(base, spt);    // SPT\r
332         sendbyte(base, 0x1B);   // Gap Length (27 is default)\r
333         sendbyte(base, 0xFF);   // Data Length\r
334         \r
335         // Wait for IRQ\r
336         LOG("Waiting for Data to be read");\r
337         FDD_WaitIRQ();\r
338         \r
339         // Read Data from DMA\r
340         LOG(" fdd_readSector: Reading Data");\r
341         DMA_ReadData(2, 512, buf);\r
342         \r
343         // Clear Input Buffer\r
344         LOG("Clearing Input Buffer");\r
345         getbyte(base); getbyte(base); getbyte(base);\r
346         getbyte(base); getbyte(base); getbyte(base); getbyte(base);\r
347         \r
348         LOG("Realeasing Spinlock and Setting motor to stop");\r
349         // Release Spinlock\r
350         FDD_FreeSpinlock();\r
351         \r
352         //Set timer to turn off motor affter a gap\r
353         fdd_devices[disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, stop_motor, (void*)disk);   //One Shot Timer
354 \r
355         #if USE_CACHE\r
356         {\r
357                 FDD_AquireCacheSpinlock();\r
358                 int oldest = 0;\r
359                 for(i=0;i<siFDD_SectorCacheSize;i++)\r
360                 {\r
361                         if(sFDD_SectorCache[i].timestamp == 0) {\r
362                                 oldest = i;\r
363                                 break;\r
364                         }\r
365                         if(sFDD_SectorCache[i].timestamp < sFDD_SectorCache[oldest].timestamp)\r
366                                 oldest = i;\r
367                 }\r
368                 sFDD_SectorCache[oldest].timestamp = now();\r
369                 sFDD_SectorCache[oldest].disk = disk;\r
370                 sFDD_SectorCache[oldest].sector = lba;\r
371                 memcpy(sFDD_SectorCache[oldest].data, buf, 512);\r
372                 FDD_FreeCacheSpinlock();\r
373         }\r
374         #endif\r
375
376         LEAVE('i', 1);\r
377         return 1;\r
378 }\r
379 \r
380 /**\r
381  * \fn static int seekTrack(int disk, int track)\r
382  * \brief Seek disk to selected track\r
383  */\r
384 static int seekTrack(int disk, int head, int track)\r
385 {\r
386         Uint8   sr0, cyl;\r
387          int    base;\r
388         \r
389         base = cPORTBASE[disk>>1];\r
390         \r
391         // Check if seeking is needed\r
392         if(fdd_devices[disk].track[head] == track)\r
393                 return 1;\r
394         \r
395         // - Seek Head 0\r
396         sendbyte(base, SEEK_TRACK);\r
397         sendbyte(base, (head<<2)|(disk&1));\r
398         sendbyte(base, track);  // Send Seek command\r
399         FDD_WaitIRQ();\r
400         FDD_SensInt(base, &sr0, &cyl);  // Wait for IRQ\r
401         if((sr0 & 0xF0) != 0x20) {
402                 LOG("sr0 = 0x%x", sr0);
403                 return 0;       //Check Status
404         }\r
405         if(cyl != track)        return 0;\r
406         \r
407         // Set Track in structure\r
408         fdd_devices[disk].track[head] = track;\r
409         return 1;\r
410 }\r
411 \r
412 /**\r
413  * \fn static int get_dims(int type, int lba, int *c, int *h, int *s, int *spt)\r
414  * \brief Get Dimensions of a disk\r
415  */\r
416 static int get_dims(int type, int lba, int *c, int *h, int *s, int *spt)\r
417 {\r
418         switch(type) {\r
419         case 0:\r
420                 return 0;\r
421         \r
422         // 360Kb 5.25"\r
423         case 1:\r
424                 *spt = 9;\r
425                 *s = (lba % 9) + 1;\r
426                 *c = lba / 18;\r
427                 *h = (lba / 9) & 1;\r
428                 break;\r
429         \r
430         // 1220Kb 5.25"\r
431         case 2:\r
432                 *spt = 15;\r
433                 *s = (lba % 15) + 1;\r
434                 *c = lba / 30;\r
435                 *h = (lba / 15) & 1;\r
436                 break;\r
437         \r
438         // 720Kb 3.5"\r
439         case 3:\r
440                 *spt = 9;\r
441                 *s = (lba % 9) + 1;\r
442                 *c = lba / 18;\r
443                 *h = (lba / 9) & 1;\r
444                 break;\r
445         \r
446         // 1440Kb 3.5"\r
447         case 4:\r
448                 *spt = 18;\r
449                 *s = (lba % 18) + 1;\r
450                 *c = lba / 36;\r
451                 *h = (lba / 18) & 1;\r
452                 break;\r
453                 \r
454         // 2880Kb 3.5"\r
455         case 5:\r
456                 *spt = 36;\r
457                 *s = (lba % 36) + 1;\r
458                 *c = lba / 72;\r
459                 *h = (lba / 32) & 1;\r
460                 break;\r
461                 \r
462         default:\r
463                 return -2;\r
464         }\r
465         return 1;\r
466 }\r
467 \r
468 /**\r
469  * \fn int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
470  * \brief Stub ioctl function\r
471  */\r
472 int FDD_IOCtl(tVFS_Node *node, int id, void *data)\r
473 {\r
474         switch(id)\r
475         {\r
476         case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;\r
477         case DRV_IOCTL_IDENT:   memcpy(data, "FDD\0", 4);       return 1;\r
478         case DRV_IOCTL_VERSION: return (FDD_VER_MAJ<<8)|FDD_VER_MIN;\r
479         default:        return 0;\r
480         }\r
481 }\r
482 \r
483 /**\r
484  * \fn void fdd_handler(int unused)\r
485  * \brief Handles IRQ6\r
486  */\r
487 void fdd_handler(int unused)\r
488 {\r
489     fdd_irq6 = 1;\r
490 }\r
491 \r
492 /**\r
493  * \fn FDD_WaitIRQ()\r
494  * \brief Wait for an IRQ6\r
495  */\r
496 void FDD_WaitIRQ()\r
497 {\r
498         // Wait for IRQ\r
499         while(!fdd_irq6)        Threads_Yield();\r
500         fdd_irq6 = 0;\r
501 }\r
502 \r
503 void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
504 {\r
505         sendbyte(base, CHECK_INTERRUPT_STATUS);\r
506         if(sr0) *sr0 = getbyte(base);\r
507         else    getbyte(base);\r
508         if(cyl) *cyl = getbyte(base);\r
509         else    getbyte(base);\r
510 }\r
511 \r
512 void FDD_AquireSpinlock()\r
513 {\r
514         while(fdd_inUse)\r
515                 Threads_Yield();\r
516         fdd_inUse = 1;\r
517 }\r
518 \r
519 inline void FDD_FreeSpinlock()\r
520 {\r
521         fdd_inUse = 0;\r
522 }\r
523 \r
524 #if USE_CACHE\r
525 inline void FDD_AquireCacheSpinlock()\r
526 {\r
527         while(siFDD_CacheInUse) Threads_Yield();\r
528         siFDD_CacheInUse = 1;\r
529 }\r
530 inline void FDD_FreeCacheSpinlock()\r
531 {\r
532         siFDD_CacheInUse = 0;\r
533 }\r
534 #endif\r
535 \r
536 /**\r
537  * void sendbyte(int base, char byte)\r
538  * \brief Sends a command to the controller\r
539  */\r
540 static void sendbyte(int base, char byte)\r
541 {\r
542     volatile int state;\r
543     int timeout = 128;\r
544     for( ; timeout--; )\r
545     {\r
546         state = inb(base + PORT_MAINSTATUS);\r
547         if ((state & 0xC0) == 0x80)\r
548         {\r
549             outb(base + PORT_DATA, byte);\r
550             return;\r
551         }\r
552         inb(0x80);      //Delay\r
553     }\r
554         #if WARN\r
555                 Warning("FDD_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
556         #endif\r
557 }\r
558 \r
559 /**\r
560  * int getbyte(int base, char byte)\r
561  * \brief Receive data from fdd controller\r
562  */\r
563 static int getbyte(int base)\r
564 {\r
565     volatile int state;\r
566     int timeout;\r
567     for( timeout = 128; timeout--; )\r
568     {\r
569         state = inb((base + PORT_MAINSTATUS));\r
570         if ((state & 0xd0) == 0xd0)\r
571                 return inb(base + PORT_DATA);\r
572         inb(0x80);\r
573     }\r
574     return -1;\r
575 }\r
576 \r
577 void FDD_Recalibrate(int disk)\r
578 {\r
579         ENTER("idisk", disk);\r
580         \r
581         LOG("Starting Motor");\r
582         start_motor(disk);\r
583         // Wait for Spinup\r
584         while(fdd_devices[disk].motorState == 1)        Threads_Yield();\r
585         \r
586         LOG("Sending Calibrate Command");\r
587         sendbyte(cPORTBASE[disk>>1], CALIBRATE_DRIVE);\r
588         sendbyte(cPORTBASE[disk>>1], disk&1);\r
589         \r
590         LOG("Waiting for IRQ");\r
591         FDD_WaitIRQ();\r
592         FDD_SensInt(cPORTBASE[disk>>1], NULL, NULL);\r
593         \r
594         LOG("Stopping Motor");\r
595         stop_motor(disk);\r
596         LEAVE('-');\r
597 }\r
598 \r
599 void FDD_Reset(int id)\r
600 {\r
601         int base = cPORTBASE[id];\r
602         \r
603         ENTER("iID", id);\r
604         \r
605         outb(base + PORT_DIGOUTPUT, 0); // Stop Motors & Disable FDC\r
606         outb(base + PORT_DIGOUTPUT, 0x0C);      // Re-enable FDC (DMA and Enable)\r
607         \r
608         LOG("Awaiting IRQ");\r
609         \r
610         FDD_WaitIRQ();\r
611         FDD_SensInt(base, NULL, NULL);\r
612         \r
613         LOG("Setting Driver Info");\r
614         outb(base + PORT_DATARATE, 0);  // Set data rate to 500K/s\r
615         sendbyte(base, FIX_DRIVE_DATA); // Step and Head Load Times\r
616         sendbyte(base, 0xDF);   // Step Rate Time, Head Unload Time (Nibble each)\r
617         sendbyte(base, 0x02);   // Head Load Time >> 1\r
618         while(seekTrack(0, 0, 1) == 0); // set track\r
619         while(seekTrack(0, 1, 1) == 0); // set track\r
620         \r
621         LOG("Recalibrating Disk");\r
622         FDD_Recalibrate((id<<1)|0);\r
623         FDD_Recalibrate((id<<1)|1);
624 \r
625         LEAVE('-');\r
626 }\r
627 \r
628 /**\r
629  * \fn void fdd_timer()\r
630  * \brief Called by timer\r
631  */\r
632 static void fdd_timer(int arg)\r
633 {\r
634         ENTER("iarg", arg);\r
635         if(fdd_devices[arg].motorState == 1)\r
636                 fdd_devices[arg].motorState = 2;\r
637         Time_RemoveTimer(fdd_devices[arg].timer);\r
638         fdd_devices[arg].timer = -1;\r
639         LEAVE('-');\r
640 }\r
641 \r
642 /**\r
643  * \fn void start_motor(char disk)\r
644  * \brief Starts FDD Motor\r
645  */\r
646 static void start_motor(int disk)\r
647 {\r
648         Uint8   state;\r
649         state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
650         state |= 1 << (4+disk);\r
651         outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
652         fdd_devices[disk].motorState = 1;\r
653         fdd_devices[disk].timer = Time_CreateTimer(MOTOR_ON_DELAY, fdd_timer, (void*)disk);     //One Shot Timer\r
654 }\r
655 \r
656 /**\r
657  * \fn void stop_motor(int disk)\r
658  * \brief Stops FDD Motor\r
659  */\r
660 static void stop_motor(int disk)\r
661 {\r
662         Uint8   state;\r
663         state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
664         state &= ~( 1 << (4+disk) );\r
665         outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
666     fdd_devices[disk].motorState = 0;\r
667 }\r
668 \r
669 /**\r
670  * \fn int FDD_Install(char **Arguments)\r
671  * \brief Installs floppy driver\r
672  */\r
673 int FDD_Install(char **Arguments)\r
674 {\r
675         Uint8 data;\r
676         \r
677         // Determine Floppy Types (From CMOS)\r
678         outb(0x70, 0x10);\r
679         data = inb(0x71);\r
680         fdd_devices[0].type = data >> 4;\r
681         fdd_devices[1].type = data & 0xF;\r
682         fdd_devices[0].track[0] = -1;\r
683         fdd_devices[1].track[1] = -1;\r
684         \r
685         // Clear FDD IRQ Flag\r
686         FDD_SensInt(0x3F0, NULL, NULL);\r
687         // Install IRQ6 Handler\r
688         IRQ_AddHandler(6, fdd_handler);\r
689         // Reset Primary FDD Controller\r
690         FDD_Reset(0);\r
691         \r
692         Log("[FDD ] Detected Disk 0: %s and Disk 1: %s\n", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
693         \r
694         // Initialise Root Node\r
695         gFDD_DriverInfo.RootNode.CTime = gFDD_DriverInfo.RootNode.MTime\r
696                 = gFDD_DriverInfo.RootNode.ATime = now();\r
697         \r
698         // Initialise Child Nodes\r
699         fdd_devices[0].Name[0] = '0';   fdd_devices[0].Name[1] = '\0';\r
700         fdd_devices[0].Node.Inode = 0;\r
701         fdd_devices[0].Node.Flags = 0;\r
702         fdd_devices[0].Node.NumACLs = 0;\r
703         fdd_devices[0].Node.Read = FDD_ReadFS;\r
704         fdd_devices[0].Node.Write = NULL;//fdd_writeFS;\r
705         memcpy(&fdd_devices[1].Node, &fdd_devices[0].Node, sizeof(tVFS_Node));\r
706         fdd_devices[1].Name[0] = '1';\r
707         fdd_devices[1].Node.Inode = 1;\r
708         \r
709         // Set Lengths\r
710         fdd_devices[0].Node.Size = cFDD_SIZES[data >> 4];\r
711         fdd_devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
712         \r
713         // Create Sector Cache\r
714         #if USE_CACHE\r
715         //sFDD_SectorCache = malloc(sizeof(*sFDD_SectorCache)*CACHE_SIZE);\r
716         //siFDD_SectorCacheSize = CACHE_SIZE;\r
717         #endif\r
718         \r
719         // Register with devfs\r
720         DevFS_AddDevice(&gFDD_DriverInfo);\r
721         \r
722         return 0;\r
723 }\r
724 \r
725 /**\r
726  * \fn void ModuleUnload()\r
727  * \brief Prepare the module for removal\r
728  */\r
729 void ModuleUnload()\r
730 {\r
731         int i;\r
732         FDD_AquireSpinlock();\r
733         for(i=0;i<4;i++) {\r
734                 Time_RemoveTimer(fdd_devices[i].timer);\r
735                 stop_motor(i);\r
736         }\r
737         //IRQ_Clear(6);\r
738 }\r

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