1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "diskimage_device.h"
28 #include <libraries/iffparse.h>
33 #include <proto/expat.h>
36 #include <SDI_stdarg.h>
39 struct MinNode ci_Node
;
40 struct Interrupt
*ci_Interrupt
;
43 static void ReadUnitPrefs (struct DiskImageUnit
*unit
);
44 static void WriteUnitPrefs (struct DiskImageUnit
*unit
, BOOL envarc
);
45 static inline struct IOExtTD
*GetIOMsg (struct DiskImageUnit
*unit
);
46 static void Cleanup (struct DiskImageUnit
*unit
);
47 static LONG
TDGeometry (struct DiskImageUnit
*unit
, struct IOStdReq
*io
);
48 static LONG
TDRead (struct DiskImageUnit
*unit
, struct IOStdReq
*io
);
49 static LONG
TDWrite (struct DiskImageUnit
*unit
, struct IOStdReq
*io
);
50 static void InsertDisk (struct DiskImageUnit
*unit
, BPTR dir
, CONST_STRPTR filename
,
51 struct DiskImagePlugin
*plugin
, STRPTR fullpath
, ULONG fullpath_size
);
52 static void RemoveDisk (struct DiskImageUnit
*unit
);
53 static void DiskChange (struct DiskImageUnit
*unit
);
56 AROS_PROCH(UnitProcEntry
, argstr
, arglen
, SysBase
)
60 int UnitProcEntry (void) {
63 struct DiskImageMsg
*msg
;
64 struct DiskImageUnit
*unit
;
65 struct DeathMessage
*dm
;
67 dbug(("UnitProcEntry()\n"));
69 proc
= (struct Process
*)FindTask(NULL
);
70 WaitPort(&proc
->pr_MsgPort
);
71 msg
= (struct DiskImageMsg
*)GetMsg(&proc
->pr_MsgPort
);
72 if (!msg
->dim_Unit
|| msg
->dim_Command
!= DICMD_STARTUP
) {
79 dm
->dm_ReturnCode
= UnitProcMain(unit
);
80 dm
->dm_Result2
= IoErr();
83 ReplyMsg(&dm
->dm_Msg
);
84 return dm
->dm_ReturnCode
;
90 int UnitProcMain (struct DiskImageUnit
*unit
) {
91 struct DiskImageBase
*libBase
= unit
->LibBase
;
92 struct Library
*SysBase
= libBase
->SysBase
;
93 struct Library
*UtilityBase
= libBase
->UtilityBase
;
95 struct DiskImageMsg
*msg
;
96 struct TagItem
*ti
, *tstate
;
99 CONST_STRPTR filename
, plugin_name
;
100 struct ChangeInt
*handler
;
101 BOOL disk_change
= FALSE
;
103 dbug(("UnitProcMain()\n"));
105 unit
->IOPort
= CreateMsgPort();
106 unit
->MsgPort
= CreateMsgPort();
107 if (!unit
->IOPort
|| !unit
->MsgPort
) {
112 unit
->Prefs
= AllocPrefsDictionary();
118 dbug(("replying to start msg\n"));
119 ReplyMsg(&unit
->DiskImageMsg
->dim_Msg
);
122 ObtainSemaphore(libBase
->PluginSemaphore
);
123 if (IsListEmpty(libBase
->Plugins
)) {
124 InitLocaleInfo(SysBase
, &libBase
->LocaleInfo
, "diskimagedevice.catalog");
125 LoadPlugins(libBase
);
127 ReleaseSemaphore(libBase
->PluginSemaphore
);
131 unit
->DeviceType
= DictGetIntegerForKey(unit
->Prefs
, "DeviceType", DG_DIRECT_ACCESS
);
132 unit
->Flags
= DictGetIntegerForKey(unit
->Prefs
, "Flags", DGF_REMOVABLE
);
133 filename
= DictGetStringForKey(unit
->Prefs
, "DiskImageFile", NULL
);
134 plugin_name
= DictGetStringForKey(unit
->Prefs
, "Plugin", NULL
);
136 struct DiskImagePlugin
*plugin
= NULL
;
137 ObtainSemaphoreShared(libBase
->PluginSemaphore
);
139 plugin
= (struct DiskImagePlugin
*)FindName(libBase
->Plugins
, plugin_name
);
141 if (!plugin_name
|| plugin
) {
143 window
= SetProcWindow((APTR
)-1);
144 InsertDisk(unit
, ZERO
, filename
, plugin
, NULL
, 0);
145 SetProcWindow(window
);
147 ReleaseSemaphore(libBase
->PluginSemaphore
);
150 sigmask
= (1UL << unit
->IOPort
->mp_SigBit
)|(1UL << unit
->MsgPort
->mp_SigBit
);
151 dbug(("entering main loop\n"));
155 while ((msg
= (struct DiskImageMsg
*)GetMsg(unit
->MsgPort
))) {
156 switch (msg
->dim_Command
) {
162 if ((tstate
= (struct TagItem
*)msg
->dim_Tags
)) {
163 BPTR curr_dir
= ZERO
;
164 struct DiskImagePlugin
*plugin
= NULL
;
166 unit
->Error
= NO_ERROR
;
167 unit
->ErrorString
= NULL
;
169 ObtainSemaphoreShared(libBase
->PluginSemaphore
);
170 while (!unit
->Error
&& (ti
= NextTagItem(&tstate
))) {
171 switch (ti
->ti_Tag
) {
173 unit
->ErrorPtr
= (LONG
*)ti
->ti_Data
;
174 if (unit
->ErrorPtr
) {
175 *unit
->ErrorPtr
= NO_ERROR
;
179 case DITAG_ErrorString
:
180 unit
->ErrorString
= (STRPTR
)ti
->ti_Data
;
181 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
182 unit
->ErrorString
[0] = 0;
186 case DITAG_ErrorStringLength
:
187 unit
->ErrorStringLength
= ti
->ti_Data
;
188 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
189 unit
->ErrorString
[0] = 0;
194 unit
->Screen
= (struct Screen
*)ti
->ti_Data
;
198 unit
->Password
= (CONST_STRPTR
)ti
->ti_Data
;
201 case DITAG_CurrentDir
:
202 curr_dir
= (BPTR
)ti
->ti_Data
;
206 if (!ti
->ti_Data
) break;
207 plugin
= (void *)FindName(libBase
->Plugins
, (STRPTR
)ti
->ti_Data
);
209 SetDiskImageError(NULL
, unit
, ERROR_OBJECT_NOT_FOUND
, 0);
214 case DITAG_Filename
: {
215 APTR image_data
= unit
->ImageData
;
218 filename
= (CONST_STRPTR
)ti
->ti_Data
;
220 InsertDisk(unit
, curr_dir
, filename
, plugin
, fullpath
, sizeof(fullpath
));
222 if (image_data
|| unit
->ImageData
) {
224 if (unit
->ImageData
) {
225 DictSetObjectForKey(unit
->Prefs
,
226 AllocPrefsString(fullpath
),
229 DictRemoveObjForKey(unit
->Prefs
,
232 if (unit
->ImageData
&& plugin
) {
233 DictSetObjectForKey(unit
->Prefs
,
234 AllocPrefsString(plugin
->Node
.ln_Name
),
237 DictRemoveObjForKey(unit
->Prefs
,
240 WriteUnitPrefs(unit
, TRUE
);
245 case DITAG_WriteProtect
:
246 unit
->WriteProtect
= ti
->ti_Data
? TRUE
: FALSE
;
249 case DITAG_GetImageName
:
251 *(STRPTR
*)ti
->ti_Data
= NULL
;
254 *(STRPTR
*)ti
->ti_Data
= ASPrintf("%s", unit
->Name
);
256 SetDiskImageError(NULL
, unit
, ERROR_NO_FREE_STORE
, 0);
261 case DITAG_GetWriteProtect
:
262 *(BOOL
*)ti
->ti_Data
= unit
->WriteProtect
;
265 case DITAG_DiskImageType
:
267 *(ULONG
*)ti
->ti_Data
= DITYPE_RAW
;
269 *(ULONG
*)ti
->ti_Data
= DITYPE_NONE
;
272 case DITAG_SetDeviceType
:
273 if (unit
->DeviceType
!= ti
->ti_Data
) {
274 unit
->DeviceType
= ti
->ti_Data
;
275 DictSetObjectForKey(unit
->Prefs
,
276 AllocPrefsInteger(unit
->DeviceType
),
278 WriteUnitPrefs(unit
, TRUE
);
282 case DITAG_GetDeviceType
:
283 *(UBYTE
*)ti
->ti_Data
= unit
->DeviceType
;
287 if (unit
->Flags
!= ti
->ti_Data
) {
288 unit
->Flags
= ti
->ti_Data
;
289 DictSetObjectForKey(unit
->Prefs
,
290 AllocPrefsInteger(unit
->Flags
),
292 WriteUnitPrefs(unit
, TRUE
);
297 *(UBYTE
*)ti
->ti_Data
= unit
->Flags
;
301 ReleaseSemaphore(libBase
->PluginSemaphore
);
304 unit
->Password
= NULL
;
308 ReplyMsg(&msg
->dim_Msg
);
315 while ((iotd
= GetIOMsg(unit
))) {
316 switch (iotd
->iotd_Req
.io_Command
) {
318 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
319 err
= TDERR_DiskChanged
;
323 iotd
->iotd_Req
.io_Actual
= 0;
324 err
= TDRead(unit
, &iotd
->iotd_Req
);
329 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
330 err
= TDERR_DiskChanged
;
335 iotd
->iotd_Req
.io_Actual
= 0;
336 err
= TDWrite(unit
, &iotd
->iotd_Req
);
339 case NSCMD_ETD_READ64
:
340 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
341 err
= TDERR_DiskChanged
;
344 case NSCMD_TD_READ64
:
346 err
= TDRead(unit
, &iotd
->iotd_Req
);
349 case NSCMD_ETD_WRITE64
:
350 case NSCMD_ETD_FORMAT64
:
351 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
352 err
= TDERR_DiskChanged
;
355 case NSCMD_TD_WRITE64
:
356 case NSCMD_TD_FORMAT64
:
359 err
= TDWrite(unit
, &iotd
->iotd_Req
);
364 iotd
->iotd_Req
.io_Actual
= unit
->ChangeCnt
;
369 iotd
->iotd_Req
.io_Actual
= unit
->ImageData
? 0 : 1;
374 iotd
->iotd_Req
.io_Actual
= unit
->WriteProtect
;
378 err
= TDGeometry(unit
, &iotd
->iotd_Req
);
383 if (unit
->ImageData
) {
391 unit
->ObsoleteChangeInt
= (struct Interrupt
*)iotd
->iotd_Req
.io_Data
;
394 case TD_ADDCHANGEINT
:
395 handler
= AllocMem(sizeof(*handler
), MEMF_CLEAR
);
397 iotd
->iotd_Req
.io_Error
= 0;
398 handler
->ci_Interrupt
= (struct Interrupt
*)iotd
->iotd_Req
.io_Data
;
399 AddTail(unit
->ChangeInts
, (struct Node
*)&handler
->ci_Node
);
401 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
406 case TD_REMCHANGEINT
:
408 handler
= (struct ChangeInt
*)unit
->ChangeInts
->lh_Head
;
409 while (handler
->ci_Node
.mln_Succ
) {
410 if (handler
->ci_Interrupt
== (struct Interrupt
*)iotd
->iotd_Req
.io_Data
) {
411 Remove((struct Node
*)&handler
->ci_Node
);
412 FreeMem(handler
, sizeof(*handler
));
415 handler
= (struct ChangeInt
*)handler
->ci_Node
.mln_Succ
;
420 err
= DoSCSICmd(&iotd
->iotd_Req
, (struct SCSICmd
*)iotd
->iotd_Req
.io_Data
);
429 iotd
->iotd_Req
.io_Error
= err
;
430 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
436 static void ReadUnitPrefs (struct DiskImageUnit
*unit
) {
438 SNPrintf(filename
, sizeof(filename
), "ENV:DiskImage/unit_%ld.xml", unit
->UnitNum
);
439 if (!ReadPrefs(unit
->Prefs
, filename
)) {
440 SNPrintf(filename
, sizeof(filename
), "ENVARC:DiskImage/unit_%ld.xml", unit
->UnitNum
);
441 ReadPrefs(unit
->Prefs
, filename
);
445 static void WriteUnitPrefs (struct DiskImageUnit
*unit
, BOOL envarc
) {
448 UnLock(CreateDir("ENVARC:DiskImage"));
449 SNPrintf(filename
, sizeof(filename
), "ENVARC:DiskImage/unit_%ld.xml", unit
->UnitNum
);
450 WritePrefs(unit
->Prefs
, filename
);
452 UnLock(CreateDir("ENV:DiskImage"));
453 SNPrintf(filename
, sizeof(filename
), "ENV:DiskImage/unit_%ld.xml", unit
->UnitNum
);
454 WritePrefs(unit
->Prefs
, filename
);
457 static inline struct IOExtTD
*GetIOMsg (struct DiskImageUnit
*unit
) {
458 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
459 struct IOExtTD
*iotd
;
460 ObtainSemaphore(unit
->IOSemaphore
);
461 iotd
= (struct IOExtTD
*)GetMsg(unit
->IOPort
);
462 ReleaseSemaphore(unit
->IOSemaphore
);
466 static void Cleanup (struct DiskImageUnit
*unit
) {
467 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
469 FreePrefsObject(unit
->Prefs
);
470 DeleteMsgPort(unit
->IOPort
);
471 DeleteMsgPort(unit
->MsgPort
);
472 unit
->IOPort
= unit
->MsgPort
= NULL
;
475 LONG
DOS2IOErr (APTR Self
, LONG error
) {
478 case ERROR_SEEK_ERROR
:
479 ret
= TDERR_SeekError
;
481 case ERROR_DISK_WRITE_PROTECTED
:
482 case ERROR_WRITE_PROTECTED
:
483 ret
= TDERR_WriteProt
;
486 ret
= TDERR_DiskChanged
;
488 case ERROR_NO_FREE_STORE
:
492 ret
= TDERR_NotSpecified
;
498 static LONG
TDGeometry (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
499 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
500 struct DriveGeometry
*dg
= (struct DriveGeometry
*)io
->io_Data
;
504 if (io
->io_Length
< sizeof(struct DriveGeometry
)) {
505 return IOERR_BADLENGTH
;
508 memset(dg
, 0, io
->io_Length
);
509 dg
->dg_SectorSize
= 512;
510 dg
->dg_CylSectors
= 1;
512 dg
->dg_TrackSectors
= 1;
513 dg
->dg_BufMemType
= MEMF_ANY
;
514 dg
->dg_DeviceType
= unit
->DeviceType
;
515 dg
->dg_Flags
= unit
->Flags
;
517 if (!unit
->ImageData
|| !plugin
) {
518 io
->io_Actual
= sizeof(struct DriveGeometry
);
519 return IOERR_SUCCESS
;
522 error
= Plugin_Geometry(plugin
, unit
->ImageData
, dg
);
523 if (error
== IOERR_SUCCESS
) {
524 io
->io_Actual
= sizeof(struct DriveGeometry
);
529 static LONG
TDRead (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
530 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
531 if (!unit
->ImageData
|| !plugin
) {
532 return TDERR_DiskChanged
;
534 return Plugin_Read(plugin
, unit
->ImageData
, io
);
537 static LONG
TDWrite (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
538 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
539 if (!unit
->ImageData
|| !plugin
) {
540 return TDERR_DiskChanged
;
542 if (unit
->WriteProtect
|| !plugin
->plugin_Write
) {
543 return TDERR_WriteProt
;
545 return Plugin_Write(plugin
, unit
->ImageData
, io
);
548 static void InsertDisk (struct DiskImageUnit
*unit
, BPTR dir
, CONST_STRPTR filename
,
549 struct DiskImagePlugin
*plugin
, STRPTR fullpath
, ULONG fullpath_size
)
551 struct Library
*DOSBase
= unit
->LibBase
->DOSBase
;
553 curr_dir
= CurrentDir(dir
);
554 unit
->Name
= ASPrintf("%s", FilePart(filename
));
555 file
= Open(filename
, MODE_OLDFILE
);
556 if (unit
->Name
&& file
) {
557 if (fullpath
&& fullpath_size
) {
558 NameFromFH(file
, fullpath
, fullpath_size
);
561 unit
->Plugin
= plugin
;
562 unit
->ImageData
= Plugin_OpenImage(plugin
, unit
, file
, filename
);
564 unit
->ImageData
= OpenImage(NULL
, unit
, file
, filename
);
567 const LONG error
= !file
? IoErr() : ERROR_NO_FREE_STORE
;
568 SetDiskImageError(NULL
, unit
, error
, 0);
573 if (!unit
->ImageData
) {
576 CurrentDir(curr_dir
);
579 static void RemoveDisk (struct DiskImageUnit
*unit
) {
580 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
582 if (unit
->Plugin
&& unit
->ImageData
) {
583 Plugin_CloseImage(unit
->Plugin
, unit
->ImageData
);
588 RemoveTempFile(NULL
, unit
);
594 static void DiskChange (struct DiskImageUnit
*unit
) {
595 struct DiskImageBase
*libBase
= unit
->LibBase
;
596 struct Library
*SysBase
= libBase
->SysBase
;
597 struct Library
*UtilityBase
= libBase
->UtilityBase
;
598 struct ChangeInt
*handler
;
603 if (unit
->ObsoleteChangeInt
) {
604 Cause(unit
->ObsoleteChangeInt
);
607 handler
= (struct ChangeInt
*)unit
->ChangeInts
->lh_Head
;
608 while (handler
->ci_Node
.mln_Succ
) {
609 Cause(handler
->ci_Interrupt
);
610 handler
= (struct ChangeInt
*)handler
->ci_Node
.mln_Succ
;
613 ObtainSemaphoreShared(libBase
->DiskChangeSemaphore
);
614 hook
= (struct Hook
*)libBase
->DiskChangeHooks
->lh_Head
;
615 while (hook
->h_MinNode
.mln_Succ
) {
616 CallHookPkt(hook
, &unit
->UnitNum
, hook
->h_Data
);
617 hook
= (struct Hook
*)hook
->h_MinNode
.mln_Succ
;
619 ReleaseSemaphore(libBase
->DiskChangeSemaphore
);
623 void SetDiskImageErrorA (APTR Self
, struct DiskImageUnit
*unit
, LONG error
,
624 LONG error_string
, VA_LIST error_args
)
626 void SetDiskImageErrorA (APTR Self
, struct DiskImageUnit
*unit
, LONG error
,
627 LONG error_string
, CONST_APTR error_args
)
630 struct DiskImageBase
*libBase
= unit
->LibBase
;
631 if (error
!= NO_ERROR
) {
633 if (unit
->ErrorPtr
) {
634 *unit
->ErrorPtr
= error
;
637 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
638 if (error_string
!= NO_ERROR_STRING
) {
639 VSNPrintf(unit
->ErrorString
, unit
->ErrorStringLength
,
640 GetString(&libBase
->LocaleInfo
, error_string
), error_args
);
641 } else if (error
!= NO_ERROR
) {
642 struct Library
*DOSBase
= libBase
->DOSBase
;
643 Fault(error
, NULL
, unit
->ErrorString
, unit
->ErrorStringLength
);
648 VARARGS68K
void SetDiskImageError (APTR Self
, struct DiskImageUnit
*unit
, LONG error
,
649 LONG error_string
, ...)
652 VA_START(args
, error_string
);
654 SetDiskImageErrorA(Self
, unit
, error
, error_string
, args
);
656 SetDiskImageErrorA(Self
, unit
, error
, error_string
, VA_ARG(args
, CONST_APTR
));