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>
31 #include <proto/expat_au.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_UFH3(LONG
, UnitProcEntry
,
57 AROS_UFHA(STRPTR
, argstr
, A0
),
58 AROS_UFHA(ULONG
, arglen
, D0
),
59 AROS_UFHA(struct Library
*, SysBase
, A6
)
64 int UnitProcEntry (void) {
67 struct DiskImageMsg
*msg
;
68 struct DiskImageUnit
*unit
;
69 struct DeathMessage
*dm
;
71 dbug(("UnitProcEntry()\n"));
73 proc
= (struct Process
*)FindTask(NULL
);
74 WaitPort(&proc
->pr_MsgPort
);
75 msg
= (struct DiskImageMsg
*)GetMsg(&proc
->pr_MsgPort
);
76 if (!msg
->dim_Unit
|| msg
->dim_Command
!= DICMD_STARTUP
) {
83 dm
->dm_ReturnCode
= UnitProcMain(unit
);
84 dm
->dm_Result2
= IoErr();
87 ReplyMsg(&dm
->dm_Msg
);
88 return dm
->dm_ReturnCode
;
94 int UnitProcMain (struct DiskImageUnit
*unit
) {
95 struct DiskImageBase
*libBase
= unit
->LibBase
;
96 struct Library
*SysBase
= libBase
->SysBase
;
97 struct Library
*UtilityBase
= libBase
->UtilityBase
;
99 struct DiskImageMsg
*msg
;
100 struct TagItem
*ti
, *tstate
;
103 CONST_STRPTR filename
, plugin_name
;
104 struct ChangeInt
*handler
;
105 BOOL disk_change
= FALSE
;
107 dbug(("UnitProcMain()\n"));
109 unit
->IOPort
= CreateMsgPort();
110 unit
->MsgPort
= CreateMsgPort();
111 if (!unit
->IOPort
|| !unit
->MsgPort
) {
116 unit
->Prefs
= AllocPrefsDictionary();
122 dbug(("replying to start msg\n"));
123 ReplyMsg(&unit
->DiskImageMsg
->dim_Msg
);
126 ObtainSemaphore(libBase
->PluginSemaphore
);
127 if (IsListEmpty(libBase
->Plugins
)) {
128 InitLocaleInfo(SysBase
, &libBase
->LocaleInfo
, "diskimagedevice.catalog");
129 LoadPlugins(libBase
);
131 ReleaseSemaphore(libBase
->PluginSemaphore
);
135 unit
->DeviceType
= DictGetIntegerForKey(unit
->Prefs
, "DeviceType", DG_DIRECT_ACCESS
);
136 unit
->Flags
= DictGetIntegerForKey(unit
->Prefs
, "Flags", DGF_REMOVABLE
);
137 filename
= DictGetStringForKey(unit
->Prefs
, "DiskImageFile", NULL
);
138 plugin_name
= DictGetStringForKey(unit
->Prefs
, "Plugin", NULL
);
140 struct DiskImagePlugin
*plugin
= NULL
;
141 ObtainSemaphoreShared(libBase
->PluginSemaphore
);
143 plugin
= (struct DiskImagePlugin
*)FindName(libBase
->Plugins
, plugin_name
);
145 if (!plugin_name
|| plugin
) {
147 window
= SetProcWindow((APTR
)-1);
148 InsertDisk(unit
, ZERO
, filename
, plugin
, NULL
, 0);
149 SetProcWindow(window
);
151 ReleaseSemaphore(libBase
->PluginSemaphore
);
154 sigmask
= (1UL << unit
->IOPort
->mp_SigBit
)|(1UL << unit
->MsgPort
->mp_SigBit
);
155 dbug(("entering main loop\n"));
159 while ((msg
= (struct DiskImageMsg
*)GetMsg(unit
->MsgPort
))) {
160 switch (msg
->dim_Command
) {
166 if ((tstate
= msg
->dim_Tags
)) {
167 BPTR curr_dir
= ZERO
;
168 struct DiskImagePlugin
*plugin
= NULL
;
170 unit
->Error
= NO_ERROR
;
171 unit
->ErrorString
= NULL
;
173 ObtainSemaphoreShared(libBase
->PluginSemaphore
);
174 while (!unit
->Error
&& (ti
= NextTagItem(&tstate
))) {
175 switch (ti
->ti_Tag
) {
177 unit
->ErrorPtr
= (LONG
*)ti
->ti_Data
;
178 if (unit
->ErrorPtr
) {
179 *unit
->ErrorPtr
= NO_ERROR
;
183 case DITAG_ErrorString
:
184 unit
->ErrorString
= (STRPTR
)ti
->ti_Data
;
185 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
186 unit
->ErrorString
[0] = 0;
190 case DITAG_ErrorStringLength
:
191 unit
->ErrorStringLength
= ti
->ti_Data
;
192 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
193 unit
->ErrorString
[0] = 0;
198 unit
->Screen
= (struct Screen
*)ti
->ti_Data
;
202 unit
->Password
= (CONST_STRPTR
)ti
->ti_Data
;
205 case DITAG_CurrentDir
:
206 curr_dir
= (BPTR
)ti
->ti_Data
;
210 if (!ti
->ti_Data
) break;
211 plugin
= (void *)FindName(libBase
->Plugins
, (STRPTR
)ti
->ti_Data
);
213 SetDiskImageError(NULL
, unit
, ERROR_OBJECT_NOT_FOUND
, 0);
218 case DITAG_Filename
: {
219 APTR image_data
= unit
->ImageData
;
222 filename
= (CONST_STRPTR
)ti
->ti_Data
;
224 InsertDisk(unit
, curr_dir
, filename
, plugin
, fullpath
, sizeof(fullpath
));
226 if (image_data
|| unit
->ImageData
) {
228 if (unit
->ImageData
) {
229 DictSetObjectForKey(unit
->Prefs
,
230 AllocPrefsString(fullpath
),
233 DictRemoveObjForKey(unit
->Prefs
,
236 if (unit
->ImageData
&& plugin
) {
237 DictSetObjectForKey(unit
->Prefs
,
238 AllocPrefsString(plugin
->Node
.ln_Name
),
241 DictRemoveObjForKey(unit
->Prefs
,
244 WriteUnitPrefs(unit
, TRUE
);
249 case DITAG_WriteProtect
:
250 unit
->WriteProtect
= ti
->ti_Data
? TRUE
: FALSE
;
253 case DITAG_GetImageName
:
255 *(STRPTR
*)ti
->ti_Data
= NULL
;
258 *(STRPTR
*)ti
->ti_Data
= ASPrintf("%s", unit
->Name
);
260 SetDiskImageError(NULL
, unit
, ERROR_NO_FREE_STORE
, 0);
265 case DITAG_GetWriteProtect
:
266 *(BOOL
*)ti
->ti_Data
= unit
->WriteProtect
;
269 case DITAG_DiskImageType
:
271 *(ULONG
*)ti
->ti_Data
= DITYPE_RAW
;
273 *(ULONG
*)ti
->ti_Data
= DITYPE_NONE
;
276 case DITAG_SetDeviceType
:
277 if (unit
->DeviceType
!= ti
->ti_Data
) {
278 unit
->DeviceType
= ti
->ti_Data
;
279 DictSetObjectForKey(unit
->Prefs
,
280 AllocPrefsInteger(unit
->DeviceType
),
282 WriteUnitPrefs(unit
, TRUE
);
286 case DITAG_GetDeviceType
:
287 *(UBYTE
*)ti
->ti_Data
= unit
->DeviceType
;
291 if (unit
->Flags
!= ti
->ti_Data
) {
292 unit
->Flags
= ti
->ti_Data
;
293 DictSetObjectForKey(unit
->Prefs
,
294 AllocPrefsInteger(unit
->Flags
),
296 WriteUnitPrefs(unit
, TRUE
);
301 *(UBYTE
*)ti
->ti_Data
= unit
->Flags
;
305 ReleaseSemaphore(libBase
->PluginSemaphore
);
308 unit
->Password
= NULL
;
312 ReplyMsg(&msg
->dim_Msg
);
319 while ((iotd
= GetIOMsg(unit
))) {
320 switch (iotd
->iotd_Req
.io_Command
) {
322 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
323 err
= TDERR_DiskChanged
;
327 iotd
->iotd_Req
.io_Actual
= 0;
328 err
= TDRead(unit
, &iotd
->iotd_Req
);
333 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
334 err
= TDERR_DiskChanged
;
339 iotd
->iotd_Req
.io_Actual
= 0;
340 err
= TDWrite(unit
, &iotd
->iotd_Req
);
343 case NSCMD_ETD_READ64
:
344 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
345 err
= TDERR_DiskChanged
;
348 case NSCMD_TD_READ64
:
350 err
= TDRead(unit
, &iotd
->iotd_Req
);
353 case NSCMD_ETD_WRITE64
:
354 case NSCMD_ETD_FORMAT64
:
355 if (iotd
->iotd_Count
< unit
->ChangeCnt
) {
356 err
= TDERR_DiskChanged
;
359 case NSCMD_TD_WRITE64
:
360 case NSCMD_TD_FORMAT64
:
363 err
= TDWrite(unit
, &iotd
->iotd_Req
);
368 iotd
->iotd_Req
.io_Actual
= unit
->ChangeCnt
;
373 iotd
->iotd_Req
.io_Actual
= unit
->ImageData
? 0 : 1;
378 iotd
->iotd_Req
.io_Actual
= unit
->WriteProtect
;
382 err
= TDGeometry(unit
, &iotd
->iotd_Req
);
387 if (unit
->ImageData
) {
395 unit
->ObsoleteChangeInt
= (struct Interrupt
*)iotd
->iotd_Req
.io_Data
;
398 case TD_ADDCHANGEINT
:
399 handler
= AllocMem(sizeof(*handler
), MEMF_CLEAR
);
401 iotd
->iotd_Req
.io_Error
= 0;
402 handler
->ci_Interrupt
= (struct Interrupt
*)iotd
->iotd_Req
.io_Data
;
403 AddTail(unit
->ChangeInts
, (struct Node
*)&handler
->ci_Node
);
405 iotd
->iotd_Req
.io_Error
= TDERR_NoMem
;
410 case TD_REMCHANGEINT
:
412 handler
= (struct ChangeInt
*)unit
->ChangeInts
->lh_Head
;
413 while (handler
->ci_Node
.mln_Succ
) {
414 if (handler
->ci_Interrupt
== (struct Interrupt
*)iotd
->iotd_Req
.io_Data
) {
415 Remove((struct Node
*)&handler
->ci_Node
);
416 FreeMem(handler
, sizeof(*handler
));
419 handler
= (struct ChangeInt
*)handler
->ci_Node
.mln_Succ
;
424 err
= DoSCSICmd(&iotd
->iotd_Req
, (struct SCSICmd
*)iotd
->iotd_Req
.io_Data
);
433 iotd
->iotd_Req
.io_Error
= err
;
434 ReplyMsg(&iotd
->iotd_Req
.io_Message
);
440 static void ReadUnitPrefs (struct DiskImageUnit
*unit
) {
442 SNPrintf(filename
, sizeof(filename
), "ENV:DiskImage/unit_%ld.xml", unit
->UnitNum
);
443 if (!ReadPrefs(unit
->Prefs
, filename
)) {
444 SNPrintf(filename
, sizeof(filename
), "ENVARC:DiskImage/unit_%ld.xml", unit
->UnitNum
);
445 ReadPrefs(unit
->Prefs
, filename
);
449 static void WriteUnitPrefs (struct DiskImageUnit
*unit
, BOOL envarc
) {
452 UnLock(CreateDir("ENVARC:DiskImage"));
453 SNPrintf(filename
, sizeof(filename
), "ENVARC:DiskImage/unit_%ld.xml", unit
->UnitNum
);
454 WritePrefs(unit
->Prefs
, filename
);
456 UnLock(CreateDir("ENV:DiskImage"));
457 SNPrintf(filename
, sizeof(filename
), "ENV:DiskImage/unit_%ld.xml", unit
->UnitNum
);
458 WritePrefs(unit
->Prefs
, filename
);
461 static inline struct IOExtTD
*GetIOMsg (struct DiskImageUnit
*unit
) {
462 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
463 struct IOExtTD
*iotd
;
464 ObtainSemaphore(unit
->IOSemaphore
);
465 iotd
= (struct IOExtTD
*)GetMsg(unit
->IOPort
);
466 ReleaseSemaphore(unit
->IOSemaphore
);
470 static void Cleanup (struct DiskImageUnit
*unit
) {
471 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
473 FreePrefsObject(unit
->Prefs
);
474 DeleteMsgPort(unit
->IOPort
);
475 DeleteMsgPort(unit
->MsgPort
);
476 unit
->IOPort
= unit
->MsgPort
= NULL
;
479 LONG
DOS2IOErr (APTR Self
, LONG error
) {
482 case ERROR_SEEK_ERROR
:
483 ret
= TDERR_SeekError
;
485 case ERROR_DISK_WRITE_PROTECTED
:
486 case ERROR_WRITE_PROTECTED
:
487 ret
= TDERR_WriteProt
;
490 ret
= TDERR_DiskChanged
;
492 case ERROR_NO_FREE_STORE
:
496 ret
= TDERR_NotSpecified
;
502 static LONG
TDGeometry (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
503 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
504 struct DriveGeometry
*dg
= (struct DriveGeometry
*)io
->io_Data
;
508 if (io
->io_Length
< sizeof(struct DriveGeometry
)) {
509 return IOERR_BADLENGTH
;
512 memset(dg
, 0, io
->io_Length
);
513 dg
->dg_SectorSize
= 512;
514 dg
->dg_CylSectors
= 1;
516 dg
->dg_TrackSectors
= 1;
517 dg
->dg_BufMemType
= MEMF_ANY
;
518 dg
->dg_DeviceType
= unit
->DeviceType
;
519 dg
->dg_Flags
= unit
->Flags
;
521 if (!unit
->ImageData
|| !plugin
) {
522 io
->io_Actual
= sizeof(struct DriveGeometry
);
523 return IOERR_SUCCESS
;
526 error
= Plugin_Geometry(plugin
, unit
->ImageData
, dg
);
527 if (error
== IOERR_SUCCESS
) {
528 io
->io_Actual
= sizeof(struct DriveGeometry
);
533 static LONG
TDRead (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
534 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
535 if (!unit
->ImageData
|| !plugin
) {
536 return TDERR_DiskChanged
;
538 return Plugin_Read(plugin
, unit
->ImageData
, io
);
541 static LONG
TDWrite (struct DiskImageUnit
*unit
, struct IOStdReq
*io
) {
542 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
543 if (!unit
->ImageData
|| !plugin
) {
544 return TDERR_DiskChanged
;
546 if (unit
->WriteProtect
|| !plugin
->plugin_Write
) {
547 return TDERR_WriteProt
;
549 return Plugin_Write(plugin
, unit
->ImageData
, io
);
552 static void InsertDisk (struct DiskImageUnit
*unit
, BPTR dir
, CONST_STRPTR filename
,
553 struct DiskImagePlugin
*plugin
, STRPTR fullpath
, ULONG fullpath_size
)
555 struct Library
*DOSBase
= unit
->LibBase
->DOSBase
;
557 curr_dir
= CurrentDir(dir
);
558 unit
->Name
= ASPrintf("%s", FilePart(filename
));
559 file
= Open(filename
, MODE_OLDFILE
);
560 if (unit
->Name
&& file
) {
561 if (fullpath
&& fullpath_size
) {
562 NameFromFH(file
, fullpath
, fullpath_size
);
565 unit
->Plugin
= plugin
;
566 unit
->ImageData
= Plugin_OpenImage(plugin
, unit
, file
, filename
);
568 unit
->ImageData
= OpenImage(NULL
, unit
, file
, filename
);
571 const LONG error
= !file
? IoErr() : ERROR_NO_FREE_STORE
;
572 SetDiskImageError(NULL
, unit
, error
, 0);
577 if (!unit
->ImageData
) {
580 CurrentDir(curr_dir
);
583 static void RemoveDisk (struct DiskImageUnit
*unit
) {
584 struct Library
*SysBase
= unit
->LibBase
->SysBase
;
586 if (unit
->Plugin
&& unit
->ImageData
) {
587 Plugin_CloseImage(unit
->Plugin
, unit
->ImageData
);
592 RemoveTempFile(NULL
, unit
);
598 static void DiskChange (struct DiskImageUnit
*unit
) {
599 struct DiskImageBase
*libBase
= unit
->LibBase
;
600 struct Library
*SysBase
= libBase
->SysBase
;
601 struct Library
*UtilityBase
= libBase
->UtilityBase
;
602 struct ChangeInt
*handler
;
607 if (unit
->ObsoleteChangeInt
) {
608 Cause(unit
->ObsoleteChangeInt
);
611 handler
= (struct ChangeInt
*)unit
->ChangeInts
->lh_Head
;
612 while (handler
->ci_Node
.mln_Succ
) {
613 Cause(handler
->ci_Interrupt
);
614 handler
= (struct ChangeInt
*)handler
->ci_Node
.mln_Succ
;
617 ObtainSemaphoreShared(libBase
->DiskChangeSemaphore
);
618 hook
= (struct Hook
*)libBase
->DiskChangeHooks
->lh_Head
;
619 while (hook
->h_MinNode
.mln_Succ
) {
620 CallHookPkt(hook
, &unit
->UnitNum
, hook
->h_Data
);
621 hook
= (struct Hook
*)hook
->h_MinNode
.mln_Succ
;
623 ReleaseSemaphore(libBase
->DiskChangeSemaphore
);
626 void SetDiskImageErrorA (APTR Self
, struct DiskImageUnit
*unit
, LONG error
,
627 LONG error_string
, CONST_APTR error_args
)
629 struct DiskImageBase
*libBase
= unit
->LibBase
;
630 if (error
!= NO_ERROR
) {
632 if (unit
->ErrorPtr
) {
633 *unit
->ErrorPtr
= error
;
636 if (unit
->ErrorString
&& unit
->ErrorStringLength
) {
637 if (error_string
!= NO_ERROR_STRING
) {
638 VSNPrintf(unit
->ErrorString
, unit
->ErrorStringLength
,
639 GetString(&libBase
->LocaleInfo
, error_string
), error_args
);
640 } else if (error
!= NO_ERROR
) {
641 struct Library
*DOSBase
= libBase
->DOSBase
;
642 Fault(error
, NULL
, unit
->ErrorString
, unit
->ErrorStringLength
);
647 VARARGS68K
void SetDiskImageError (APTR Self
, struct DiskImageUnit
*unit
, LONG error
,
648 LONG error_string
, ...)
651 VA_START(args
, error_string
);
652 SetDiskImageErrorA(Self
, unit
, error
, error_string
, VA_ARG(args
, CONST_APTR
));