2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
6 /****************************************************************************************/
13 /* #define DUMP_DATA */
15 #include <aros/debug.h>
16 #include <aros/symbolsets.h>
17 #include <devices/trackdisk.h>
18 #include <devices/newstyle.h>
19 #include <exec/errors.h>
20 #include <exec/rawfmt.h>
21 #include <proto/dos.h>
22 #include <proto/exec.h>
23 #include <proto/hostlib.h>
25 #include LC_LIBDEFS_FILE
27 /****************************************************************************************/
29 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR hdskBase
)
31 HostLibBase
= OpenResource("hostlib.resource");
32 D(bug("hostdisk: HostLibBase: 0x%p\n", HostLibBase
));
36 InitSemaphore(&hdskBase
->sigsem
);
37 NEWLIST(&hdskBase
->units
);
39 D(bug("hostdisk: in libinit func. Returning %x (success) :-)\n", hdskBase
));
43 static int HostDisk_Cleanup(struct HostDiskBase
*hdskBase
)
45 D(bug("hostdisk: Expunge(0x%p)\n", hdskBase
));
51 HostLib_DropInterface((APTR
*)hdskBase
->iface
);
53 if (hdskBase
->KernelHandle
)
54 HostLib_Close(hdskBase
->KernelHandle
, NULL
);
59 /****************************************************************************************/
61 static void unitentry(struct IOExtTD
*iotd
);
63 static void freeUnit(struct unit
*unit
)
65 if (unit
->flags
& UNIT_FREENAME
)
66 FreeVec(unit
->n
.ln_Name
);
68 FreeMem(unit
, sizeof(struct unit
));
71 /****************************************************************************************/
73 extern const char GM_UNIQUENAME(LibName
)[];
75 static int GM_UNIQUENAME(Open
)(LIBBASETYPEPTR hdskBase
, struct IOExtTD
*iotd
, IPTR unitnum
, ULONG flags
)
83 ULONG len
= strlen(hdskBase
->DiskDevice
) + 5;
85 unitname
= AllocVec(len
, MEMF_ANY
);
89 unitflags
= UNIT_FREENAME
;
90 NewRawDoFmt(hdskBase
->DiskDevice
, (VOID_FUNC
)RAWFMTFUNC_STRING
, unitname
, unitnum
+ hdskBase
->unitBase
);
93 unitname
= (STRPTR
)unitnum
;
95 D(bug("hostdisk: open unit %s\n", unitname
));
97 ObtainSemaphore(&hdskBase
->sigsem
);
99 unit
= (struct unit
*)FindName(&hdskBase
->units
, unitname
);
104 ReleaseSemaphore(&hdskBase
->sigsem
);
106 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
107 iotd
->iotd_Req
.io_Error
= 0;
108 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
110 DOPEN(bug("hostdisk: in libopen func. Yep. Unit is already open\n"));
114 DOPEN(bug("hostdisk: in libopen func. No, it is not. So creating new unit ...\n"));
116 unit
= (struct unit
*)AllocMem(sizeof(struct unit
), MEMF_PUBLIC
| MEMF_CLEAR
);
120 ULONG p
= strlen(GM_UNIQUENAME(LibName
));
121 char taskName
[p
+ strlen(unitname
) + 2];
122 struct Task
*unitTask
;
124 DOPEN(bug("hostdisk: in libopen func. Allocation of unit memory okay. Setting up unit and calling CreateNewProc ...\n"));
126 CopyMem(GM_UNIQUENAME(LibName
), taskName
, p
);
128 strcpy(&taskName
[p
+ 1], unitname
);
130 unit
->n
.ln_Name
= unitname
;
132 unit
->hdskBase
= hdskBase
;
133 unit
->flags
= unitflags
;
134 NEWLIST((struct List
*)&unit
->changeints
);
136 iotd
->iotd_Req
.io_Unit
= (struct Unit
*)unit
;
137 SetSignal(0, SIGF_SINGLE
);
138 unitTask
= NewCreateTask(TASKTAG_PC
, unitentry
,
139 TASKTAG_NAME
, taskName
,
143 DOPEN(bug("hostdisk: in libopen func. NewCreateTask() called. Task = 0x%p\n", unitTask
));
147 DOPEN(bug("hostdisk: in libopen func. Waiting for signal from unit task...\n"));
150 DOPEN(bug("hostdisk: in libopen func. Unit error %u, flags 0x%02X\n", iotd
->iotd_Req
.io_Error
, unit
->flags
));
151 if (!iotd
->iotd_Req
.io_Error
)
153 AddTail((struct List
*)&hdskBase
->units
, &unit
->n
);
154 ReleaseSemaphore(&hdskBase
->sigsem
);
159 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
164 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
166 ReleaseSemaphore(&hdskBase
->sigsem
);
171 /****************************************************************************************/
173 static int GM_UNIQUENAME(Close
)(LIBBASETYPEPTR hdskBase
, struct IOExtTD
*iotd
)
175 struct unit
*unit
= (struct unit
*)iotd
->iotd_Req
.io_Unit
;
177 D(bug("hostdisk: close unit %s\n", unit
->n
.ln_Name
));
179 ObtainSemaphore(&hdskBase
->sigsem
);
181 if (!--unit
->usecount
)
185 /* The task will free its unit structure itself */
186 Signal(unit
->port
->mp_SigTask
, SIGBREAKF_CTRL_C
);
189 ReleaseSemaphore(&hdskBase
->sigsem
);
194 /****************************************************************************************/
196 ADD2INITLIB(GM_UNIQUENAME(Init
), -5)
197 ADD2EXPUNGELIB(HostDisk_Cleanup
, -5);
198 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
199 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
201 /****************************************************************************************/
203 static const UWORD NSDSupported
[] = {
237 AROS_LH1(void, beginio
,
238 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
239 struct HostDiskBase
*, hdskBase
, 5, Hostdisk
)
243 struct NSDeviceQueryResult
*nsdq
;
245 DCMD(bug("hostdisk: command %u\n", iotd
->iotd_Req
.io_Command
));
246 switch(iotd
->iotd_Req
.io_Command
)
252 /* Ignore but don't fail */
253 iotd
->iotd_Req
.io_Error
= 0;
264 case NSCMD_TD_READ64
:
265 case NSCMD_TD_WRITE64
:
266 case NSCMD_TD_FORMAT64
:
267 case NSCMD_TD_SEEK64
:
270 case TD_ADDCHANGEINT
:
271 case TD_REMCHANGEINT
:
275 /* Forward to unit thread */
276 PutMsg(((struct unit
*)iotd
->iotd_Req
.io_Unit
)->port
, &iotd
->iotd_Req
.io_Message
);
278 iotd
->iotd_Req
.io_Flags
&= ~IOF_QUICK
;
282 New Style Devices query. Introduce self as trackdisk and provide list of
285 case NSCMD_DEVICEQUERY
:
286 nsdq
= iotd
->iotd_Req
.io_Data
;
288 nsdq
->DevQueryFormat
= 0;
289 nsdq
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
290 nsdq
->DeviceType
= NSDEVTYPE_TRACKDISK
;
291 nsdq
->DeviceSubType
= 0;
292 nsdq
->SupportedCommands
= (UWORD
*)NSDSupported
;
294 iotd
->iotd_Req
.io_Actual
= sizeof(struct NSDeviceQueryResult
);
295 iotd
->iotd_Req
.io_Error
= 0;
299 New Style Devices report here the 'NSTY' - only if such value is
300 returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should
303 case TD_GETDRIVETYPE
:
304 iotd
->iotd_Req
.io_Actual
= DRIVE_NEWSTYLE
;
305 iotd
->iotd_Req
.io_Error
= 0;
310 DCMD(bug("hostdisk: command not supported\n"));
311 iotd
->iotd_Req
.io_Error
= IOERR_NOCMD
;
314 } /* switch(iotd->iotd_Req.io_Command) */
316 /* WaitIO will look into this */
317 iotd
->iotd_Req
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
320 if(!(iotd
->iotd_Req
.io_Flags
&IOF_QUICK
))
321 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
326 /****************************************************************************************/
328 AROS_LH1(LONG
, abortio
,
329 AROS_LHA(struct IOExtTD
*, iotd
, A1
),
330 struct HostDiskBase
*, hdskBase
, 6, Hostdisk
)
337 /****************************************************************************************/
339 static LONG
read(struct unit
*unit
, struct IOExtTD
*iotd
)
345 buf
= iotd
->iotd_Req
.io_Data
;
346 size
= iotd
->iotd_Req
.io_Length
;
348 iotd
->iotd_Req
.io_Actual
= 0;
351 subsize
= Host_Read(unit
, buf
, size
, &ioerr
);
354 DREAD(bug("hostdisk.device/read: Host_Read() returned 0. Returning IOERR_BADLENGTH\n"));
355 return IOERR_BADLENGTH
;
359 DREAD(bug("hostdisk.device/read: Host_Read() returned -1. Returning error number %d\n", ioerr
));
363 iotd
->iotd_Req
.io_Actual
+= subsize
;
369 buf
= iotd
->iotd_Req
.io_Data
;
370 bug("hostdisk/read: returning 0. First 4 buffer bytes = [%c%c%c%c]\n", buf
[0], buf
[1], buf
[2], buf
[3]);
376 /****************************************************************************************/
378 static LONG
write(struct unit
*unit
, struct IOExtTD
*iotd
)
384 if (unit
->flags
& UNIT_READONLY
)
385 return TDERR_WriteProt
;
387 buf
= iotd
->iotd_Req
.io_Data
;
388 size
= iotd
->iotd_Req
.io_Length
;
390 iotd
->iotd_Req
.io_Actual
= 0;
393 subsize
= Host_Write(unit
, buf
, size
, &ioerr
);
398 iotd
->iotd_Req
.io_Actual
+= subsize
;
406 /**************************************************************************/
408 static void addchangeint(struct unit
*unit
, struct IOExtTD
*iotd
)
411 AddTail((struct List
*)&unit
->changeints
, (struct Node
*)iotd
);
415 /**************************************************************************/
417 static void remchangeint(struct unit
*unit
, struct IOExtTD
*iotd
)
420 Remove((struct Node
*)iotd
);
424 /**************************************************************************/
426 static ULONG
getgeometry(struct unit
*Unit
, struct DriveGeometry
*dg
)
429 * First set some common defaults.
430 * We can work with image file, which is LBA-oriented by nature.
431 * LBA addressing can be represented by flattened geometry, where Heads == TrackSectors == 1,
432 * i. e. one cylinder == one block (sector).
433 * Sector size is assumed to be 512 bytes (a common size for hard disk drives)
434 * Host-specific code can override this if possible.
436 * This gives us a limitation: we can's handle disks longer than 2TB.
437 * It's general AmigaOS limitation, currently inherited by all Amiga family
438 * of operating systems, this is determined by maximum block number that can
439 * fit into ULONG. In order to overcome this we need 64-bit block number.
440 * Perhaps we should completely go LBA in such a case.
442 dg
->dg_SectorSize
= 512;
444 dg
->dg_TrackSectors
= 1;
445 dg
->dg_CylSectors
= 1; /* Heads * TrackSectors */
446 dg
->dg_BufMemType
= MEMF_PUBLIC
;
447 dg
->dg_DeviceType
= DG_DIRECT_ACCESS
;
450 /* Call host-specific processing */
451 return Host_GetGeometry(Unit
, dg
);
454 /**************************************************************************/
456 void eject(struct unit
*unit
, BOOL eject
)
458 struct IOExtTD
*iotd
;
464 unit
->file
= INVALID_HANDLE_VALUE
;
468 err
= Host_Open(unit
);
475 ForeachNode(&unit
->changeints
, iotd
)
477 Cause((struct Interrupt
*)iotd
->iotd_Req
.io_Data
);
481 /****************************************************************************************/
483 static void unitentry(struct IOExtTD
*iotd
)
486 struct Task
*me
= FindTask(NULL
);
487 struct Task
*parent
= me
->tc_UnionETask
.tc_ETask
->et_Parent
;
488 struct unit
*unit
= (struct unit
*)iotd
->iotd_Req
.io_Unit
;
490 D(bug("%s: just started\n", me
->tc_Node
.ln_Name
));
492 unit
->port
= CreateMsgPort();
495 Signal(parent
, SIGF_SINGLE
);
499 D(bug("%s: Trying to open \"%s\" ...\n", me
->tc_Node
.ln_Name
, unit
->n
.ln_Name
));
501 err
= Host_Open(unit
);
504 D(bug("%s: open failed :-(\n", me
->tc_Node
.ln_Name
));
506 iotd
->iotd_Req
.io_Error
= err
;
508 Signal(parent
, SIGF_SINGLE
);
512 D(bug("%s: open okay :-)\n", me
->tc_Node
.ln_Name
));
514 iotd
->iotd_Req
.io_Error
= 0;
515 Signal(parent
, SIGF_SINGLE
);
517 D(bug("%s: Now entering main loop\n", me
->tc_Node
.ln_Name
));
521 ULONG portsig
= 1 << unit
->port
->mp_SigBit
;
522 ULONG sigs
= Wait(portsig
| SIGBREAKF_CTRL_C
);
526 while((iotd
= (struct IOExtTD
*)GetMsg(unit
->port
)) != NULL
)
528 switch(iotd
->iotd_Req
.io_Command
)
531 * In fact these two commands make a little sense, but they exist,
532 * so we honestly process them.
535 DCMD(bug("%s: received CMD_SEEK.\n", me
->tc_Node
.ln_Name
));
536 err
= Host_Seek(unit
, iotd
->iotd_Req
.io_Offset
);
540 case NSCMD_TD_SEEK64
:
541 DCMD(bug("%s: received CMD_SEEK64.\n", me
->tc_Node
.ln_Name
));
542 err
= Host_Seek64(unit
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Actual
);
546 DCMD(bug("%s: received CMD_READ.\n", me
->tc_Node
.ln_Name
));
547 DREAD(bug("hostdisk/CMD_READ: offset = %u (0x%08X) size = %d\n", iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
549 err
= Host_Seek(unit
, iotd
->iotd_Req
.io_Offset
);
551 err
= read(unit
, iotd
);
552 DREAD(else bug("CMD_READ: Seek failed\n");)
556 case NSCMD_TD_READ64
:
557 DREAD(bug("hostdisk/TD_READ64: offset = 0x%08X%08X size = %d\n",
558 iotd
->iotd_Req
.io_Actual
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
560 err
= Host_Seek64(unit
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Actual
);
562 err
= read(unit
, iotd
);
563 DREAD(else bug("CMD_READ64: Seek failed\n");)
568 DCMD(bug("%s: received %s\n", me
->tc_Node
.ln_Name
, (iotd
->iotd_Req
.io_Command
== CMD_WRITE
) ? "CMD_WRITE" : "TD_FORMAT"));
569 DWRITE(bug("hostdisk/CMD_WRITE: offset = %u (0x%08X) size = %d\n", iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
571 err
= Host_Seek(unit
, iotd
->iotd_Req
.io_Offset
);
573 err
= write(unit
, iotd
);
578 case NSCMD_TD_WRITE64
:
579 case NSCMD_TD_FORMAT64
:
580 DCMD(bug("%s: received TD_WRITE64\n", me
->tc_Node
.ln_Name
));
581 DWRITE(bug("hostdisk/TD_WRITE64: offset = 0x%08X%08X size = %d\n",
582 iotd
->iotd_Req
.io_Actual
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Length
));
584 err
= Host_Seek64(unit
, iotd
->iotd_Req
.io_Offset
, iotd
->iotd_Req
.io_Actual
);
586 err
= write(unit
, iotd
);
591 iotd
->iotd_Req
.io_Actual
= unit
->changecount
;
596 iotd
->iotd_Req
.io_Actual
= (unit
->file
== INVALID_HANDLE_VALUE
);
599 case TD_ADDCHANGEINT
:
600 addchangeint(unit
, iotd
);
604 case TD_REMCHANGEINT
:
605 remchangeint(unit
, iotd
);
610 DCMD(bug("%s: received TD_GETGEOMETRY\n", me
->tc_Node
.ln_Name
));
612 err
= getgeometry(unit
, (struct DriveGeometry
*)iotd
->iotd_Req
.io_Data
);
616 eject(unit
, iotd
->iotd_Req
.io_Length
);
621 iotd
->iotd_Req
.io_Actual
= (unit
->flags
& UNIT_READONLY
) ? TRUE
: FALSE
;
625 } /* switch(iotd->iotd_Req.io_Command) */
627 iotd
->iotd_Req
.io_Error
= err
;
628 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
630 } /* while((iotd = (struct IOExtTD *)GetMsg(&unit->port)) != NULL) */
634 /* Process quit signal after our MsgPort is empty */
635 if (sigs
& SIGBREAKF_CTRL_C
)
637 D(bug("%s: Received EXIT signal.\n", me
->tc_Node
.ln_Name
));
648 /****************************************************************************************/