2 Copyright © 1995-2007, 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 ramdrivebase
->port
.mp_Node
.ln_Type
= NT_MSGPORT
;
96 ramdrivebase
->port
.mp_Flags
= PA_SIGNAL
;
97 ramdrivebase
->port
.mp_SigBit
= SIGB_SINGLE
;
98 NEWLIST((struct List
*)&ramdrivebase
->port
.mp_MsgList
);
100 D(bug("ramdrive_device: in libinit func. Returning %x (success) :-)\n", ramdrivebase
));
104 /****************************************************************************************/
106 AROS_UFP3(LONG
, unitentry
,
107 AROS_UFPA(STRPTR
, argstr
, A0
),
108 AROS_UFPA(ULONG
, arglen
, D0
),
109 AROS_UFPA(struct ExecBase
*, SysBase
, A6
));
111 /****************************************************************************************/
113 static int GM_UNIQUENAME(Open
)
115 LIBBASETYPEPTR ramdrivebase
,
116 struct IOExtTD
*iotd
,
121 static const struct TagItem tags
[] =
123 { NP_Name
, (IPTR
)"Ram Drive Unit Process"},
127 { NP_CurrentDir
, 0 },
131 { NP_Entry
, (IPTR
)unitentry
},
136 D(bug("ramdrive_device: in libopen func.\n"));
138 if (iotd
->iotd_Req
.io_Message
.mn_Length
< sizeof(struct IOExtTD
))
140 D(bug("ramdrive.device/open: IORequest structure passed to OpenDevice is too small!\n"));
141 iotd
->iotd_Req
.io_Error
= IOERR_OPENFAIL
;
145 D(bug("ramdrive_device: in libopen func. Looking if unit is already open\n"));
147 ObtainSemaphore(&ramdrivebase
->sigsem
);
149 for(unit
= (struct unit
*)ramdrivebase
->units
.mlh_Head
;
150 unit
->msg
.mn_Node
.ln_Succ
!= NULL
;
151 unit
= (struct unit
*)unit
->msg
.mn_Node
.ln_Succ
)
152 if(unit
->unitnum
== unitnum
)
155 ReleaseSemaphore(&ramdrivebase
->sigsem
);
157 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
158 iotd
->iotd_Req
.io_Error
= 0;
159 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
161 D(bug("ramdrive_device: in libopen func. Yep. Unit is already open\n"));
166 D(bug("ramdrive_device: in libopen func. No, it is not. So creating new unit ...\n"));
168 unit
= (struct unit
*)AllocMem(sizeof(struct unit
), MEMF_PUBLIC
);
171 D(bug("ramdrive_device: in libopen func. Allocation of unit memory okay. Setting up unit and calling CreateNewProc ...\n"));
174 unit
->ramdrivebase
= ramdrivebase
;
175 unit
->unitnum
= unitnum
;
176 unit
->msg
.mn_ReplyPort
= &ramdrivebase
->port
;
177 unit
->msg
.mn_Length
= sizeof(struct unit
);
178 unit
->port
.mp_Node
.ln_Type
= NT_MSGPORT
;
179 unit
->port
.mp_Flags
= PA_IGNORE
;
180 unit
->port
.mp_SigTask
= CreateNewProc((struct TagItem
*)tags
);
182 D(bug("ramdrive_device: in libopen func. CreateNewProc called. Proc = %x\n", unit
->port
.mp_SigTask
));
184 if(unit
->port
.mp_SigTask
!= NULL
)
186 NEWLIST((struct List
*)&unit
->port
.mp_MsgList
);
188 /* setup replyport to point to active task */
189 ramdrivebase
->port
.mp_SigTask
= FindTask(NULL
);
190 SetSignal(0, SIGF_SINGLE
);
192 D(bug("ramdrive_device: in libopen func. Sending startup msg\n"));
193 PutMsg(&((struct Process
*)unit
->port
.mp_SigTask
)->pr_MsgPort
, &unit
->msg
);
195 D(bug("ramdrive_device: in libopen func. Waiting for replymsg\n"));
196 WaitPort(&ramdrivebase
->port
);
197 (void)GetMsg(&ramdrivebase
->port
);
198 D(bug("ramdrive_device: in libopen func. Received replymsg\n"));
202 AddTail((struct List
*)&ramdrivebase
->units
, &unit
->msg
.mn_Node
);
203 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
205 iotd
->iotd_Req
.io_Error
= 0;
206 ReleaseSemaphore(&ramdrivebase
->sigsem
);
209 iotd
->iotd_Req
.io_Error
= TDERR_NotSpecified
;
211 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
212 FreeMem(unit
, sizeof(struct unit
));
214 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
216 ReleaseSemaphore(&ramdrivebase
->sigsem
);
221 /****************************************************************************************/
223 static int GM_UNIQUENAME(Close
)
225 LIBBASETYPEPTR ramdrivebase
,
231 ObtainSemaphore(&ramdrivebase
->sigsem
);
232 unit
= (struct unit
*)iotd
->iotd_Req
.io_Unit
;
233 if(!--unit
->usecount
)
235 Remove(&unit
->msg
.mn_Node
);
236 ramdrivebase
->port
.mp_SigTask
= FindTask(NULL
);
237 SetSignal(0, SIGF_SINGLE
);
238 PutMsg(&unit
->port
, &unit
->msg
);
239 WaitPort(&ramdrivebase
->port
);
240 (void)GetMsg(&ramdrivebase
->port
);
241 FreeMem(unit
, sizeof(struct unit
));
243 ReleaseSemaphore(&ramdrivebase
->sigsem
);
248 /****************************************************************************************/
250 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
251 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
252 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
254 /****************************************************************************************/
256 AROS_LH1(void, beginio
,
257 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
258 struct ramdrivebase
*, ramdrivebase
, 5, Ramdrive
)
262 switch(iotd
->iotd_Req
.io_Command
)
265 case NSCMD_DEVICEQUERY
:
266 if(iotd
->iotd_Req
.io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
268 iotd
->iotd_Req
.io_Error
= IOERR_BADLENGTH
;
272 struct NSDeviceQueryResult
*d
;
274 d
= (struct NSDeviceQueryResult
*)iotd
->iotd_Req
.io_Data
;
276 d
->DevQueryFormat
= 0;
277 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
278 d
->DeviceType
= NSDEVTYPE_TRACKDISK
;
279 d
->DeviceSubType
= 0;
280 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
282 iotd
->iotd_Req
.io_Actual
= sizeof(struct NSDeviceQueryResult
);
283 iotd
->iotd_Req
.io_Error
= 0;
290 /* result: io_Actual = disk change counter */
293 /* result: io_Actual = disk presence indicator (0 = disk is in drive) */
296 /* result: io_Actual = disk protection status (0 = not protected) */
298 iotd
->iotd_Req
.io_Actual
= 0;
299 iotd
->iotd_Req
.io_Error
= 0;
307 case TD_ADDCHANGEINT
:
308 case TD_REMCHANGEINT
:
309 /* Ignore but don't fail */
310 iotd
->iotd_Req
.io_Error
= 0;
313 case TD_GETDRIVETYPE
:
314 iotd
->iotd_Req
.io_Actual
= DRIVE3_5
;
315 iotd
->iotd_Req
.io_Error
= 0;
318 case TD_GETNUMTRACKS
:
319 iotd
->iotd_Req
.io_Actual
= NUM_TRACKS
;
320 iotd
->iotd_Req
.io_Error
= 0;
325 struct IOExtTD
*flushed_iotd
;
326 struct unit
*u
=(struct unit
*)iotd
->iotd_Req
.io_Unit
;
328 while((flushed_iotd
= (struct IOExtTD
*)GetMsg(&u
->port
)))
330 flushed_iotd
->iotd_Req
.io_Error
= IOERR_ABORTED
;
331 ReplyMsg(&flushed_iotd
->iotd_Req
.io_Message
);
352 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
354 /* Forward to unit thread */
355 PutMsg(&((struct unit
*)iotd
->iotd_Req
.io_Unit
)->port
,
356 &iotd
->iotd_Req
.io_Message
);
361 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
364 } /* switch(iotd->iotd_Req.io_Command) */
366 /* WaitIO will look into this */
367 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
370 if(!(iotd
->iotd_Req
.io_Flags
&IOF_QUICK
))
371 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
376 /****************************************************************************************/
378 AROS_LH1(LONG
, abortio
,
379 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
380 struct ramdrivebase
*, ramdrivebase
, 6, Ramdrive
)
389 /****************************************************************************************/
391 AROS_LH0(STRPTR
, killrad0
,
392 struct ramdrivebase
*, ramdrivebase
, 7, Ramdrive
)
396 /* FIXME: KillRAD0 not implemented yet */
403 /****************************************************************************************/
405 AROS_LH1(STRPTR
, killrad
,
406 AROS_LHA(ULONG
, unit
, D0
),
407 struct ramdrivebase
*, ramdrivebase
, 8, Ramdrive
)
411 /* FIXME: KillRAD not implemented yet */
418 /****************************************************************************************/
420 #define ramdrivebase unit->ramdrivebase
422 /****************************************************************************************/
424 static LONG
read(struct unit
*unit
, struct IOExtTD
*iotd
)
429 D(bug("ramdrive_device/read: offset = %d size = %d\n", iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
431 if(iotd
->iotd_SecLabel
)
433 D(bug("ramdrive_device/read: iotd->iotd_SecLabel is != NULL -> returning IOERR_NOCMD\n"));
437 buf
= iotd
->iotd_Req
.io_Data
;
438 offset
= iotd
->iotd_Req
.io_Offset
;
439 size
= iotd
->iotd_Req
.io_Length
;
441 unit
->headpos
= offset
;
443 if (offset
+ size
> DISKSIZE
)
445 D(bug("ramdrive_device/read: Seek to offset %d failed. Returning TDERR_SeekError\n", offset
));
446 return TDERR_SeekError
;
449 CopyMem(&unit
->mem
[offset
], buf
, size
);
451 iotd
->iotd_Req
.io_Actual
= size
;
454 buf
= iotd
->iotd_Req
.io_Data
;
455 D(bug("ramdrive_device/read: returning 0. First 4 buffer bytes = [%c%c%c%c]\n", buf
[0], buf
[1], buf
[2], buf
[3]));
461 /****************************************************************************************/
463 static LONG
write(struct unit
*unit
, struct IOExtTD
*iotd
)
468 if(iotd
->iotd_SecLabel
)
471 buf
= iotd
->iotd_Req
.io_Data
;
472 offset
= iotd
->iotd_Req
.io_Offset
;
473 size
= iotd
->iotd_Req
.io_Length
;
475 unit
->headpos
= offset
;
477 if (offset
+ size
> DISKSIZE
)
479 D(bug("ramdrive_device/write: Seek to offset %d failed. Returning TDERR_SeekError\n", offset
));
480 return TDERR_SeekError
;
483 iotd
->iotd_Req
.io_Actual
= size
;
485 CopyMem(buf
, &unit
->mem
[offset
], size
);
490 /****************************************************************************************/
492 AROS_UFH3(LONG
, unitentry
,
493 AROS_UFHA(STRPTR
, argstr
, A0
),
494 AROS_UFHA(ULONG
, arglen
, D0
),
495 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
501 struct IOExtTD
*iotd
;
504 D(bug("ramdrive_device/unitentry: just started\n"));
506 me
= (struct Process
*)FindTask(NULL
);
508 WaitPort(&me
->pr_MsgPort
);
509 unit
= (struct unit
*)GetMsg(&me
->pr_MsgPort
);
510 unit
->port
.mp_SigBit
= AllocSignal(-1);
511 unit
->port
.mp_Flags
= PA_SIGNAL
;
513 D(bug("ramdrive_device/unitentry: Trying to allocate memory disk\n"));
515 unit
->mem
= AllocVec(DISKSIZE
, MEMF_PUBLIC
| MEMF_CLEAR
);
518 D(bug("ramdrive_device/unitentry: Memory allocation failed :-( Replying startup msg.\n"));
521 ReplyMsg(&unit
->msg
);
525 D(bug("ramdrive_device/unitentry: Memory allocation okay :-) Replying startup msg.\n"));
527 FormatOFS(unit
->mem
, unit
->unitnum
, unit
);
529 ReplyMsg(&unit
->msg
);
531 D(bug("ramdrive_device/unitentry: Now entering main loop\n"));
535 while((iotd
= (struct IOExtTD
*)GetMsg(&unit
->port
)) != NULL
)
537 if(&iotd
->iotd_Req
.io_Message
== &unit
->msg
)
539 D(bug("ramdrive_device/unitentry: Recevied EXIT message.\n"));
543 ReplyMsg(&unit
->msg
);
547 switch(iotd
->iotd_Req
.io_Command
)
552 ** same as CMD_READ, but offset does not have to be multiple of
560 D(bug("ramdrive_device/unitentry: received CMD_READ.\n"));
561 err
= read(unit
, iotd
);
567 ** same as CMD_WRITE, but offset does not have to be multiple of
577 D(bug("ramdrive_device/unitentry: received %s\n", (iotd
->iotd_Req
.io_Command
== CMD_WRITE
) ? "CMD_WRITE" : "TD_FORMAT"));
578 err
= write(unit
, iotd
);
584 ** DOS wants the previous state in io_Actual.
585 ** We return "!io_Actual"
588 iotd
->iotd_Req
.io_Actual
= (iotd
->iotd_Req
.io_Actual
== 1) ? 0 : 1;
594 unit
->headpos
= iotd
->iotd_Req
.io_Actual
;
598 } /* switch(iotd->iotd_Req.io_Command) */
600 iotd
->iotd_Req
.io_Error
= err
;
601 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
603 } /* while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL) */
605 WaitPort(&unit
->port
);
612 /****************************************************************************************/
614 /* The following routines are based on TurboDevice by Thomas Dreibholz */
616 /****************************************************************************************/
618 static ULONG
CalcRootBlock(void)
620 return NUM_CYL
* NUM_HEADS
* NUM_SECS
/ 2;
623 /****************************************************************************************/
625 static ULONG
CalcBitMap(void)
627 return CalcRootBlock() + 1;
630 /****************************************************************************************/
632 VOID
RootBlockCheckSum(UBYTE
*buf
)
634 LONG checksum
, *long_ptr
;
637 long_ptr
= (ULONG
*)buf
;
640 for(i
= 0; i
< TD_SECTOR
/ 4; i
++)
642 checksum
+= AROS_BE2LONG(long_ptr
[i
]);
644 long_ptr
[5] = AROS_LONG2BE(-checksum
);
647 /****************************************************************************************/
649 VOID
CalcBitMapCheckSum(UBYTE
*buf
)
652 LONG
*long_ptr
= (LONG
*)buf
;
654 for(i
= 1, checksum
= 0; i
< TD_SECTOR
/ 4; i
++)
656 checksum
+= AROS_BE2LONG(long_ptr
[i
]);
658 long_ptr
[0] = AROS_LONG2BE(-checksum
);
661 /****************************************************************************************/
663 VOID
InstallRootBlock(UBYTE
*buf
, STRPTR diskname
, ULONG bitmap
,
670 long_ptr
= (ULONG
*)buf
;
671 long_ptr
[0] = AROS_LONG2BE(2);
672 long_ptr
[3] = AROS_LONG2BE(72);
673 long_ptr
[78] = AROS_LONG2BE(-1);
674 long_ptr
[79] = AROS_LONG2BE(bitmap
);
675 long_ptr
[127] = AROS_LONG2BE(1);
679 long_ptr
[121] = AROS_LONG2BE(ds
.ds_Days
);
680 long_ptr
[122] = AROS_LONG2BE(ds
.ds_Minute
);
681 long_ptr
[123] = AROS_LONG2BE(ds
.ds_Tick
);
683 long_ptr
[105] = AROS_LONG2BE(ds
.ds_Days
);
684 long_ptr
[106] = AROS_LONG2BE(ds
.ds_Minute
);
685 long_ptr
[107] = AROS_LONG2BE(ds
.ds_Tick
);
687 buf
[432] = (UBYTE
)strlen(diskname
);
689 for(i
= 0; i
< strlen(diskname
); i
++)
691 buf
[433+i
] = diskname
[i
];
694 RootBlockCheckSum(buf
);
697 /****************************************************************************************/
699 static ULONG
CalcBlocks(void)
701 return NUM_CYL
* NUM_HEADS
* NUM_SECS
- 1;
704 /****************************************************************************************/
706 static void AllocBitMapBlock(LONG block
, UBYTE
*buf
)
708 ULONG
*long_ptr
= (ULONG
*)buf
;
710 LONG old_long
, new_long
;
712 longword
= (block
- 2) / 32;
713 bit
= block
- 2 - longword
* 32;
714 old_long
= AROS_BE2LONG(long_ptr
[longword
+ 1]);
715 new_long
= old_long
& (0xFFFFFFFF - (1L << bit
));
717 long_ptr
[longword
+ 1] = AROS_LONG2BE(new_long
);
720 /****************************************************************************************/
722 static void FreeBitMapBlock(LONG block
, UBYTE
*buf
)
724 ULONG
*long_ptr
= (ULONG
*)buf
;
726 LONG old_long
, new_long
;
728 longword
= (block
- 2) / 32;
729 bit
= block
- 2 - longword
* 32;
730 old_long
= AROS_BE2LONG(long_ptr
[longword
+ 1]);
731 new_long
= old_long
| (1L << bit
);
733 long_ptr
[longword
+ 1] = AROS_LONG2BE(new_long
);
736 /****************************************************************************************/
738 static void FormatOFS(UBYTE
*mem
, ULONG number
, struct unit
*unit
)
752 cmem
= mem
+ (a
* TD_SECTOR
);
753 strcpy(Name
, "RAM_#");
754 Name
[4] = '0' + number
;
756 InstallRootBlock(cmem
, Name
, b
, unit
);
757 cmem
= mem
+ (b
* TD_SECTOR
);
759 for(c
= 2; c
<= d
; c
++)
761 FreeBitMapBlock(c
, cmem
);
764 AllocBitMapBlock(a
, cmem
);
765 AllocBitMapBlock(b
, cmem
);
767 CalcBitMapCheckSum(cmem
);
770 /****************************************************************************************/
774 /****************************************************************************************/