2 * fat.handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007 The AROS Development Team
7 * This program is free software; you can redistribute it and/or modify it
8 * under the same terms as AROS itself.
13 #define USE_INLINE_STDARG
15 #include <exec/types.h>
16 #include <exec/execbase.h>
17 #include <exec/libraries.h>
18 #include <exec/errors.h>
21 #include <dos/dosextens.h>
22 #include <dos/dostags.h>
23 #include <dos/filehandler.h>
24 #include <devices/trackdisk.h>
25 #include <devices/inputevent.h>
27 #include <proto/exec.h>
28 #include <proto/dos.h>
30 #include <string.h> /* for memset() */
33 #include "fat_protos.h"
36 #define ID_BUSY 0x42555359
40 void FillDiskInfo (struct InfoData
*id
) {
41 struct DosEnvec
*de
= BADDR(glob
->fssm
->fssm_Environ
);
43 id
->id_NumSoftErrors
= 0;
44 id
->id_UnitNumber
= glob
->fssm
->fssm_Unit
;
45 id
->id_DiskState
= ID_VALIDATED
;
48 CountFreeClusters(glob
->sb
);
50 id
->id_NumBlocks
= glob
->sb
->total_sectors
;
51 id
->id_NumBlocksUsed
= glob
->sb
->total_sectors
- ((glob
->sb
->free_clusters
* glob
->sb
->clustersize
) >> glob
->sb
->sectorsize_bits
);
52 id
->id_BytesPerBlock
= glob
->sb
->sectorsize
;
54 id
->id_DiskType
= (glob
->sb
->type
== 12) ? ID_FAT12_DISK
:
55 (glob
->sb
->type
== 16) ? ID_FAT16_DISK
:
56 (glob
->sb
->type
== 32) ? ID_FAT32_DISK
:
59 id
->id_VolumeNode
= MKBADDR(glob
->sb
->doslist
);
60 id
->id_InUse
= glob
->sb
->doslist
->dol_misc
.dol_volume
.dol_LockList
? DOSTRUE
: DOSFALSE
;
64 id
->id_NumBlocks
= de
->de_Surfaces
* de
->de_BlocksPerTrack
* (de
->de_HighCyl
+1 - de
->de_LowCyl
) / de
->de_SectorPerBlock
;
65 id
->id_NumBlocksUsed
= id
->id_NumBlocks
;
66 id
->id_BytesPerBlock
= de
->de_SizeBlock
<< 2;
68 id
->id_DiskState
= ID_VALIDATED
;
70 if (glob
->disk_inhibited
)
71 id
->id_DiskType
= ID_BUSY
;
72 else if (glob
->disk_inserted
)
73 id
->id_DiskType
= ID_NOT_REALLY_DOS
; //ID_UNREADABLE_DISK;
75 id
->id_DiskType
= ID_NO_DISK_PRESENT
;
77 id
->id_VolumeNode
= NULL
;
78 id
->id_InUse
= DOSFALSE
;
82 LONG
InitDevice(struct FileSysStartupMsg
*fssm
, LONG blocksize
) {
83 glob
->blocksize
= blocksize
;
84 glob
->cache
= cache_new(64, 256, blocksize
, 0);
89 void SendVolumePacket(struct DosList
*vol
, ULONG action
) {
90 struct DosPacket
*dospacket
;
92 dospacket
= AllocDosObject(DOS_STDPKT
, TAG_DONE
);
93 dospacket
->dp_Type
= ACTION_DISK_CHANGE
;
94 dospacket
->dp_Arg1
= ID_FAT_DISK
;
95 dospacket
->dp_Arg2
= (ULONG
) vol
;
96 dospacket
->dp_Arg3
= action
;
97 dospacket
->dp_Port
= NULL
;
99 PutMsg(glob
->ourport
, dospacket
->dp_Link
);
102 void DoDiskInsert(void) {
105 if (glob
->sb
== NULL
&& (sb
= AllocVecPooled(glob
->mempool
, sizeof(struct FSSuper
)))) {
106 memset(sb
, 0, sizeof(struct FSSuper
));
108 if (ReadFATSuper(sb
) == 0) {
112 struct FSSuper
*ptr
= glob
->sblist
, *prev
= NULL
;
114 while (ptr
!= NULL
) {
115 if (CompareFATSuper(sb
, ptr
) == 0)
123 kprintf("\tFound FAT FS Super Block in spare list, freeing obsolete old one\n");
125 sb
->doslist
= ptr
->doslist
;
127 sb
->doslist
->dol_Name
= (BSTR
)MKBADDR(&sb
->volume
.name
);
130 prev
->next
= ptr
->next
;
132 glob
->sblist
= ptr
->next
;
135 FreeVecPooled(glob
->mempool
, ptr
);
142 struct DosList
*newvol
;
144 kprintf("\tCreating new volume.\n");
146 if ((newvol
= AllocVecPooled(glob
->mempool
, sizeof(struct DosList
)))) {
147 newvol
->dol_Next
= NULL
;
148 newvol
->dol_Type
= DLT_VOLUME
;
149 newvol
->dol_Task
= glob
->ourport
;
150 newvol
->dol_Lock
= NULL
;
152 CopyMem(&sb
->volume
.create_time
, &newvol
->dol_misc
.dol_volume
.dol_VolumeDate
, sizeof(struct DateStamp
));
154 newvol
->dol_misc
.dol_volume
.dol_LockList
= NULL
;
156 newvol
->dol_misc
.dol_volume
.dol_DiskType
= (sb
->type
== 12) ? ID_FAT12_DISK
:
157 (sb
->type
== 16) ? ID_FAT16_DISK
:
158 (sb
->type
== 32) ? ID_FAT32_DISK
:
161 #ifdef AROS_FAST_BPTR
162 /* ReadFATSuper() sets a null byte * after the string, so
163 * this should be fine */
164 newvol
->dol_Name
= (BSTR
)MKBADDR(&(sb
->volume
.name
[1]));
166 newvol
->dol_Name
= (BSTR
)MKBADDR(&sb
->volume
.name
);
169 sb
->doslist
= newvol
;
171 SendVolumePacket(newvol
, ACTION_VOLUME_ADD
);
176 SendEvent(IECLASS_DISKINSERTED
);
180 kprintf("\tDisk successfully initialised\n");
185 FreeVecPooled(glob
->mempool
, sb
);
188 SendEvent(IECLASS_DISKINSERTED
);
193 void DoDiskRemove(void) {
196 struct FSSuper
*sb
= glob
->sb
;
200 if (sb
->doslist
->dol_misc
.dol_volume
.dol_LockList
== NULL
) { /* check if the device can be removed */
201 kprintf("\tRemoving disk completely\n");
203 SendVolumePacket(sb
->doslist
, ACTION_VOLUME_REMOVE
);
207 FreeVecPooled(glob
->mempool
, sb
);
210 sb
->next
= glob
->sblist
;
213 kprintf("\tMoved in-memory super block to spare list. Waiting for locks to be freed\n");
215 SendEvent(IECLASS_DISKREMOVED
);
220 void ProcessDiskChange(void) {
221 kprintf("\nGot disk change request\n");
223 if (glob
->disk_inhibited
) {
224 kprintf("Disk is inhibited, ignoring disk change\n");
228 glob
->diskioreq
->iotd_Req
.io_Command
= TD_CHANGESTATE
;
229 glob
->diskioreq
->iotd_Req
.io_Data
= NULL
;
230 glob
->diskioreq
->iotd_Req
.io_Length
= 0;
231 glob
->diskioreq
->iotd_Req
.io_Flags
= IOF_QUICK
;
232 DoIO((struct IORequest
*) glob
->diskioreq
);
234 if (glob
->diskioreq
->iotd_Req
.io_Error
== 0 && glob
->diskioreq
->iotd_Req
.io_Actual
== 0) {
235 /* Disk has been inserted. */
236 kprintf("\tDisk has been inserted\n");
237 glob
->disk_inserted
= TRUE
;
241 /* Disk has been removed. */
242 kprintf("\tDisk has been removed\n");
243 glob
->disk_inserted
= FALSE
;