2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
6 /****************************************************************************************/
13 #define DISKSIZE (NUM_HEADS * NUM_CYL * NUM_SECS * BLOCKSIZE)
14 #define NUM_TRACKS (NUM_CYL * NUM_HEADS)
16 /****************************************************************************************/
18 #include <devices/trackdisk.h>
19 #include <devices/newstyle.h>
20 #include <exec/resident.h>
21 #include <exec/errors.h>
22 #include <exec/memory.h>
23 #include <exec/initializers.h>
24 #include <proto/exec.h>
25 #include <dos/dosextens.h>
26 #include <dos/dostags.h>
27 #include <proto/dos.h>
28 #include <aros/macros.h>
29 #include <aros/libcall.h>
30 #include <aros/symbolsets.h>
33 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
34 #include "ramdrive_device_gcc.h"
38 #include <aros/debug.h>
40 #include LC_LIBDEFS_FILE
42 /****************************************************************************************/
44 #define NEWSTYLE_DEVICE 1
48 static const UWORD SupportedCommands
[] =
83 /****************************************************************************************/
85 static void FormatOFS(UBYTE
*mem
, ULONG number
, struct unit
*unit
);
87 /****************************************************************************************/
89 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR ramdrivebase
)
91 D(bug("ramdrive_device: in libinit func\n"));
93 InitSemaphore(&ramdrivebase
->sigsem
);
94 NEWLIST((struct List
*)&ramdrivebase
->units
);
95 memset( &ramdrivebase
->port
, 0, sizeof( ramdrivebase
->port
) );
96 ramdrivebase
->port
.mp_Node
.ln_Type
= NT_MSGPORT
;
97 ramdrivebase
->port
.mp_Flags
= PA_SIGNAL
;
98 ramdrivebase
->port
.mp_SigBit
= SIGB_SINGLE
;
99 NEWLIST((struct List
*)&ramdrivebase
->port
.mp_MsgList
);
101 D(bug("ramdrive_device: in libinit func. Returning %x (success) :-)\n", ramdrivebase
));
105 /****************************************************************************************/
107 AROS_UFP3(LONG
, unitentry
,
108 AROS_UFPA(STRPTR
, argstr
, A0
),
109 AROS_UFPA(ULONG
, arglen
, D0
),
110 AROS_UFPA(struct ExecBase
*, SysBase
, A6
));
112 /****************************************************************************************/
114 static int GM_UNIQUENAME(Open
)
116 LIBBASETYPEPTR ramdrivebase
,
117 struct IOExtTD
*iotd
,
122 static const struct TagItem tags
[] =
124 { NP_Name
, (IPTR
)"Ram Drive Unit Process"},
128 { NP_CurrentDir
, 0 },
132 { NP_Entry
, (IPTR
)unitentry
},
137 D(bug("ramdrive_device: in libopen func.\n"));
139 if (iotd
->iotd_Req
.io_Message
.mn_Length
< sizeof(struct IOExtTD
))
141 D(bug("ramdrive.device/open: IORequest structure passed to OpenDevice is too small!\n"));
142 iotd
->iotd_Req
.io_Error
= IOERR_OPENFAIL
;
146 D(bug("ramdrive_device: in libopen func. Looking if unit is already open\n"));
148 ObtainSemaphore(&ramdrivebase
->sigsem
);
150 for(unit
= (struct unit
*)ramdrivebase
->units
.mlh_Head
;
151 unit
->msg
.mn_Node
.ln_Succ
!= NULL
;
152 unit
= (struct unit
*)unit
->msg
.mn_Node
.ln_Succ
)
153 if(unit
->unitnum
== unitnum
)
156 ReleaseSemaphore(&ramdrivebase
->sigsem
);
158 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
159 iotd
->iotd_Req
.io_Error
= 0;
160 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
162 D(bug("ramdrive_device: in libopen func. Yep. Unit is already open\n"));
167 D(bug("ramdrive_device: in libopen func. No, it is not. So creating new unit ...\n"));
169 unit
= (struct unit
*)AllocMem(sizeof(struct unit
), MEMF_PUBLIC
);
172 D(bug("ramdrive_device: in libopen func. Allocation of unit memory okay. Setting up unit and calling CreateNewProc ...\n"));
175 unit
->ramdrivebase
= ramdrivebase
;
176 unit
->unitnum
= unitnum
;
177 unit
->msg
.mn_ReplyPort
= &ramdrivebase
->port
;
178 unit
->msg
.mn_Length
= sizeof(struct unit
);
179 unit
->port
.mp_Node
.ln_Type
= NT_MSGPORT
;
180 unit
->port
.mp_Flags
= PA_IGNORE
;
181 unit
->port
.mp_SigTask
= CreateNewProc((struct TagItem
*)tags
);
183 D(bug("ramdrive_device: in libopen func. CreateNewProc called. Proc = %x\n", unit
->port
.mp_SigTask
));
185 if(unit
->port
.mp_SigTask
!= NULL
)
187 NEWLIST((struct List
*)&unit
->port
.mp_MsgList
);
189 /* setup replyport to point to active task */
190 ramdrivebase
->port
.mp_SigTask
= FindTask(NULL
);
191 SetSignal(0, SIGF_SINGLE
);
193 D(bug("ramdrive_device: in libopen func. Sending startup msg\n"));
194 PutMsg(&((struct Process
*)unit
->port
.mp_SigTask
)->pr_MsgPort
, &unit
->msg
);
196 D(bug("ramdrive_device: in libopen func. Waiting for replymsg\n"));
197 WaitPort(&ramdrivebase
->port
);
198 (void)GetMsg(&ramdrivebase
->port
);
199 D(bug("ramdrive_device: in libopen func. Received replymsg\n"));
203 AddTail((struct List
*)&ramdrivebase
->units
, &unit
->msg
.mn_Node
);
204 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
206 iotd
->iotd_Req
.io_Error
= 0;
207 ReleaseSemaphore(&ramdrivebase
->sigsem
);
210 iotd
->iotd_Req
.io_Error
= TDERR_NotSpecified
;
212 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
213 FreeMem(unit
, sizeof(struct unit
));
215 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
217 ReleaseSemaphore(&ramdrivebase
->sigsem
);
222 /****************************************************************************************/
224 static int GM_UNIQUENAME(Close
)
226 LIBBASETYPEPTR ramdrivebase
,
232 ObtainSemaphore(&ramdrivebase
->sigsem
);
233 unit
= (struct unit
*)iotd
->iotd_Req
.io_Unit
;
234 if(!--unit
->usecount
)
236 Remove(&unit
->msg
.mn_Node
);
237 ramdrivebase
->port
.mp_SigTask
= FindTask(NULL
);
238 SetSignal(0, SIGF_SINGLE
);
239 PutMsg(&unit
->port
, &unit
->msg
);
240 WaitPort(&ramdrivebase
->port
);
241 (void)GetMsg(&ramdrivebase
->port
);
242 FreeMem(unit
, sizeof(struct unit
));
244 ReleaseSemaphore(&ramdrivebase
->sigsem
);
249 /****************************************************************************************/
251 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
252 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
253 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
255 /****************************************************************************************/
257 AROS_LH1(void, beginio
,
258 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
259 struct ramdrivebase
*, ramdrivebase
, 5, Ramdrive
)
263 switch(iotd
->iotd_Req
.io_Command
)
266 case NSCMD_DEVICEQUERY
:
267 if(iotd
->iotd_Req
.io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
269 iotd
->iotd_Req
.io_Error
= IOERR_BADLENGTH
;
273 struct NSDeviceQueryResult
*d
;
275 d
= (struct NSDeviceQueryResult
*)iotd
->iotd_Req
.io_Data
;
277 d
->DevQueryFormat
= 0;
278 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
279 d
->DeviceType
= NSDEVTYPE_TRACKDISK
;
280 d
->DeviceSubType
= 0;
281 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
283 iotd
->iotd_Req
.io_Actual
= sizeof(struct NSDeviceQueryResult
);
284 iotd
->iotd_Req
.io_Error
= 0;
291 /* result: io_Actual = disk change counter */
294 /* result: io_Actual = disk presence indicator (0 = disk is in drive) */
297 /* result: io_Actual = disk protection status (0 = not protected) */
299 iotd
->iotd_Req
.io_Actual
= 0;
300 iotd
->iotd_Req
.io_Error
= 0;
308 case TD_ADDCHANGEINT
:
309 case TD_REMCHANGEINT
:
310 /* Ignore but don't fail */
311 iotd
->iotd_Req
.io_Error
= 0;
314 case TD_GETDRIVETYPE
:
315 iotd
->iotd_Req
.io_Actual
= DRIVE3_5
;
316 iotd
->iotd_Req
.io_Error
= 0;
319 case TD_GETNUMTRACKS
:
320 iotd
->iotd_Req
.io_Actual
= NUM_TRACKS
;
321 iotd
->iotd_Req
.io_Error
= 0;
326 struct IOExtTD
*flushed_iotd
;
327 struct unit
*u
=(struct unit
*)iotd
->iotd_Req
.io_Unit
;
329 while((flushed_iotd
= (struct IOExtTD
*)GetMsg(&u
->port
)))
331 flushed_iotd
->iotd_Req
.io_Error
= IOERR_ABORTED
;
332 ReplyMsg(&flushed_iotd
->iotd_Req
.io_Message
);
353 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
355 /* Forward to unit thread */
356 PutMsg(&((struct unit
*)iotd
->iotd_Req
.io_Unit
)->port
,
357 &iotd
->iotd_Req
.io_Message
);
362 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
365 } /* switch(iotd->iotd_Req.io_Command) */
367 /* WaitIO will look into this */
368 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
371 if(!(iotd
->iotd_Req
.io_Flags
&IOF_QUICK
))
372 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
377 /****************************************************************************************/
379 AROS_LH1(LONG
, abortio
,
380 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
381 struct ramdrivebase
*, ramdrivebase
, 6, Ramdrive
)
390 /****************************************************************************************/
392 AROS_LH0(STRPTR
, killrad0
,
393 struct ramdrivebase
*, ramdrivebase
, 7, Ramdrive
)
397 /* FIXME: KillRAD0 not implemented yet */
404 /****************************************************************************************/
406 AROS_LH1(STRPTR
, killrad
,
407 AROS_LHA(ULONG
, unit
, D0
),
408 struct ramdrivebase
*, ramdrivebase
, 8, Ramdrive
)
412 /* FIXME: KillRAD not implemented yet */
419 /****************************************************************************************/
421 #define ramdrivebase unit->ramdrivebase
423 /****************************************************************************************/
425 static LONG
read(struct unit
*unit
, struct IOExtTD
*iotd
)
430 D(bug("ramdrive_device/read: offset = %d size = %d\n", iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
432 if(iotd
->iotd_SecLabel
)
434 D(bug("ramdrive_device/read: iotd->iotd_SecLabel is != NULL -> returning IOERR_NOCMD\n"));
438 buf
= iotd
->iotd_Req
.io_Data
;
439 offset
= iotd
->iotd_Req
.io_Offset
;
440 size
= iotd
->iotd_Req
.io_Length
;
442 unit
->headpos
= offset
;
444 if (offset
+ size
> DISKSIZE
)
446 D(bug("ramdrive_device/read: Seek to offset %d failed. Returning TDERR_SeekError\n", offset
));
447 return TDERR_SeekError
;
450 CopyMem(&unit
->mem
[offset
], buf
, size
);
452 iotd
->iotd_Req
.io_Actual
= size
;
455 buf
= iotd
->iotd_Req
.io_Data
;
456 D(bug("ramdrive_device/read: returning 0. First 4 buffer bytes = [%c%c%c%c]\n", buf
[0], buf
[1], buf
[2], buf
[3]));
462 /****************************************************************************************/
464 static LONG
write(struct unit
*unit
, struct IOExtTD
*iotd
)
469 if(iotd
->iotd_SecLabel
)
472 buf
= iotd
->iotd_Req
.io_Data
;
473 offset
= iotd
->iotd_Req
.io_Offset
;
474 size
= iotd
->iotd_Req
.io_Length
;
476 unit
->headpos
= offset
;
478 if (offset
+ size
> DISKSIZE
)
480 D(bug("ramdrive_device/write: Seek to offset %d failed. Returning TDERR_SeekError\n", offset
));
481 return TDERR_SeekError
;
484 iotd
->iotd_Req
.io_Actual
= size
;
486 CopyMem(buf
, &unit
->mem
[offset
], size
);
491 /****************************************************************************************/
493 AROS_UFH3(LONG
, unitentry
,
494 AROS_UFHA(STRPTR
, argstr
, A0
),
495 AROS_UFHA(ULONG
, arglen
, D0
),
496 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
502 struct IOExtTD
*iotd
;
505 D(bug("ramdrive_device/unitentry: just started\n"));
507 me
= (struct Process
*)FindTask(NULL
);
509 WaitPort(&me
->pr_MsgPort
);
510 unit
= (struct unit
*)GetMsg(&me
->pr_MsgPort
);
511 unit
->port
.mp_SigBit
= AllocSignal(-1);
512 unit
->port
.mp_Flags
= PA_SIGNAL
;
514 D(bug("ramdrive_device/unitentry: Trying to allocate memory disk\n"));
516 unit
->mem
= AllocVec(DISKSIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
519 D(bug("ramdrive_device/unitentry: Memory allocation failed :-( Replying startup msg.\n"));
522 ReplyMsg(&unit
->msg
);
526 D(bug("ramdrive_device/unitentry: Memory allocation okay :-) Replying startup msg.\n"));
528 FormatOFS(unit
->mem
, unit
->unitnum
, unit
);
530 ReplyMsg(&unit
->msg
);
532 D(bug("ramdrive_device/unitentry: Now entering main loop\n"));
536 while((iotd
= (struct IOExtTD
*)GetMsg(&unit
->port
)) != NULL
)
538 if(&iotd
->iotd_Req
.io_Message
== &unit
->msg
)
540 D(bug("ramdrive_device/unitentry: Recevied EXIT message.\n"));
544 ReplyMsg(&unit
->msg
);
548 switch(iotd
->iotd_Req
.io_Command
)
553 ** same as CMD_READ, but offset does not have to be multiple of
561 D(bug("ramdrive_device/unitentry: received CMD_READ.\n"));
562 err
= read(unit
, iotd
);
568 ** same as CMD_WRITE, but offset does not have to be multiple of
578 D(bug("ramdrive_device/unitentry: received %s\n", (iotd
->iotd_Req
.io_Command
== CMD_WRITE
) ? "CMD_WRITE" : "TD_FORMAT"));
579 err
= write(unit
, iotd
);
585 ** DOS wants the previous state in io_Actual.
586 ** We return "!io_Actual"
589 iotd
->iotd_Req
.io_Actual
= (iotd
->iotd_Req
.io_Actual
== 1) ? 0 : 1;
595 unit
->headpos
= iotd
->iotd_Req
.io_Actual
;
599 } /* switch(iotd->iotd_Req.io_Command) */
601 iotd
->iotd_Req
.io_Error
= err
;
602 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
604 } /* while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL) */
606 WaitPort(&unit
->port
);
613 /****************************************************************************************/
615 /* The following routines are based on TurboDevice by Thomas Dreibholz */
617 /****************************************************************************************/
619 static ULONG
CalcRootBlock(void)
621 return NUM_CYL
* NUM_HEADS
* NUM_SECS
/ 2;
624 /****************************************************************************************/
626 static ULONG
CalcBitMap(void)
628 return CalcRootBlock() + 1;
631 /****************************************************************************************/
633 VOID
RootBlockCheckSum(UBYTE
*buf
)
635 LONG checksum
, *long_ptr
;
638 long_ptr
= (ULONG
*)buf
;
641 for(i
= 0; i
< TD_SECTOR
/ 4; i
++)
643 checksum
+= AROS_BE2LONG(long_ptr
[i
]);
645 long_ptr
[5] = AROS_LONG2BE(-checksum
);
648 /****************************************************************************************/
650 VOID
CalcBitMapCheckSum(UBYTE
*buf
)
653 LONG
*long_ptr
= (LONG
*)buf
;
655 for(i
= 1, checksum
= 0; i
< TD_SECTOR
/ 4; i
++)
657 checksum
+= AROS_BE2LONG(long_ptr
[i
]);
659 long_ptr
[0] = AROS_LONG2BE(-checksum
);
662 /****************************************************************************************/
664 VOID
InstallRootBlock(UBYTE
*buf
, STRPTR diskname
, ULONG bitmap
,
671 long_ptr
= (ULONG
*)buf
;
672 long_ptr
[0] = AROS_LONG2BE(2);
673 long_ptr
[3] = AROS_LONG2BE(72);
674 long_ptr
[78] = AROS_LONG2BE(-1);
675 long_ptr
[79] = AROS_LONG2BE(bitmap
);
676 long_ptr
[127] = AROS_LONG2BE(1);
680 long_ptr
[121] = AROS_LONG2BE(ds
.ds_Days
);
681 long_ptr
[122] = AROS_LONG2BE(ds
.ds_Minute
);
682 long_ptr
[123] = AROS_LONG2BE(ds
.ds_Tick
);
684 long_ptr
[105] = AROS_LONG2BE(ds
.ds_Days
);
685 long_ptr
[106] = AROS_LONG2BE(ds
.ds_Minute
);
686 long_ptr
[107] = AROS_LONG2BE(ds
.ds_Tick
);
688 buf
[432] = (UBYTE
)strlen(diskname
);
690 for(i
= 0; i
< strlen(diskname
); i
++)
692 buf
[433+i
] = diskname
[i
];
695 RootBlockCheckSum(buf
);
698 /****************************************************************************************/
700 static ULONG
CalcBlocks(void)
702 return NUM_CYL
* NUM_HEADS
* NUM_SECS
- 1;
705 /****************************************************************************************/
707 static void AllocBitMapBlock(LONG block
, UBYTE
*buf
)
709 ULONG
*long_ptr
= (ULONG
*)buf
;
711 LONG old_long
, new_long
;
713 longword
= (block
- 2) / 32;
714 bit
= block
- 2 - longword
* 32;
715 old_long
= AROS_BE2LONG(long_ptr
[longword
+ 1]);
716 new_long
= old_long
& (0xFFFFFFFF - (1L << bit
));
718 long_ptr
[longword
+ 1] = AROS_LONG2BE(new_long
);
721 /****************************************************************************************/
723 static void FreeBitMapBlock(LONG block
, UBYTE
*buf
)
725 ULONG
*long_ptr
= (ULONG
*)buf
;
727 LONG old_long
, new_long
;
729 longword
= (block
- 2) / 32;
730 bit
= block
- 2 - longword
* 32;
731 old_long
= AROS_BE2LONG(long_ptr
[longword
+ 1]);
732 new_long
= old_long
| (1L << bit
);
734 long_ptr
[longword
+ 1] = AROS_LONG2BE(new_long
);
737 /****************************************************************************************/
739 static void FormatOFS(UBYTE
*mem
, ULONG number
, struct unit
*unit
)
753 cmem
= mem
+ (a
* TD_SECTOR
);
754 strcpy(Name
, "RAM_#");
755 Name
[4] = '0' + number
;
757 InstallRootBlock(cmem
, Name
, b
, unit
);
758 cmem
= mem
+ (b
* TD_SECTOR
);
760 for(c
= 2; c
<= d
; c
++)
762 FreeBitMapBlock(c
, cmem
);
765 AllocBitMapBlock(a
, cmem
);
766 AllocBitMapBlock(b
, cmem
);
768 CalcBitMapCheckSum(cmem
);
771 /****************************************************************************************/
775 /****************************************************************************************/