Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / diskimage / device / init.c
blob3cca2c59360661f18b42ca56ba1ccd386da8c139
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
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 #define __NOLIBBASE__
28 #include "diskimage_device.h"
29 #include "progress.h"
30 #include <exec/exec.h>
31 #include <proto/exec.h>
32 #include <proto/expat.h>
34 #include "rev/diskimage.device_rev.h"
36 #define LIBNAME "diskimage.device"
37 CONST TEXT USED_VAR verstag[] = VERSTAG;
39 struct Library *SysBase;
40 struct Library *DOSBase;
41 struct Library *IntuitionBase;
43 static void FreeBaseVars (struct DiskImageBase *libBase);
44 static struct DiskImageUnit *InitUnit (struct DiskImageBase *libBase, ULONG unit_number);
45 static void FreeUnit (struct DiskImageBase *libBase, struct DiskImageUnit *unit);
47 /* FOR RTF_AUTOINIT:
48 This routine gets called after the device has been allocated.
49 The device pointer is in D0. The AmigaDOS segment list is in a0.
50 If it returns the device pointer, then the device will be linked
51 into the device list. If it returns NULL, then the device
52 will be unloaded.
54 IMPORTANT:
55 If you don't use the "RTF_AUTOINIT" feature, there is an additional
56 caveat. If you allocate memory in your Open function, remember that
57 allocating memory can cause an Expunge... including an expunge of your
58 device. This must not be fatal. The easy solution is don't add your
59 device to the list until after it is ready for action.
61 This call is single-threaded by exec; please read the description for
62 "dev_open" below. */
64 /* The ROMTAG Init Function */
65 #ifdef __AROS__
66 static AROS_UFH3(struct DiskImageBase *, LibInit,
67 AROS_UFHA(struct DiskImageBase *, libBase, D0),
68 AROS_UFHA(BPTR, seglist, A0),
69 AROS_UFHA(struct Library *, exec_base, A6)
72 AROS_USERFUNC_INIT
73 #else
74 static struct DiskImageBase *LibInit (REG(d0, struct DiskImageBase *libBase),
75 REG(a0, BPTR seglist), REG(a6, struct Library *exec_base))
77 #endif
78 libBase->LibNode.lib_Node.ln_Type = NT_DEVICE;
79 libBase->LibNode.lib_Node.ln_Pri = 0;
80 libBase->LibNode.lib_Node.ln_Name = LIBNAME;
81 libBase->LibNode.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
82 libBase->LibNode.lib_Version = VERSION;
83 libBase->LibNode.lib_Revision = REVISION;
84 libBase->LibNode.lib_IdString = VSTRING;
85 libBase->SysBase = exec_base;
86 SysBase = exec_base;
88 /* Save pointer to our loaded code (the SegList) */
89 libBase->SegList = seglist;
91 if ((DOSBase = libBase->DOSBase = OpenLibrary("dos.library", MIN_OS_VERSION)) &&
92 (libBase->UtilityBase = OpenLibrary("utility.library", MIN_OS_VERSION)) &&
93 (IntuitionBase = libBase->IntuitionBase = OpenLibrary("intuition.library", MIN_OS_VERSION)))
95 if ((libBase->UnitSemaphore = CreateSemaphore()) &&
96 (libBase->PluginSemaphore = CreateSemaphore()) &&
97 (libBase->DiskChangeSemaphore = CreateSemaphore()) &&
98 (libBase->Units = CreateList(TRUE)) &&
99 (libBase->Plugins = CreateList(TRUE)) &&
100 (libBase->ReloadPluginsHooks = CreateList(TRUE)) &&
101 (libBase->DiskChangeHooks = CreateList(TRUE)))
103 return libBase;
107 FreeBaseVars(libBase);
108 DeleteLibrary((struct Library *)libBase);
109 return NULL;
110 #ifdef __AROS__
111 AROS_USERFUNC_EXIT
112 #endif
115 static void FreeBaseVars (struct DiskImageBase *libBase) {
116 struct Library *SysBase = libBase->SysBase;
117 DeleteList(libBase->DiskChangeHooks);
118 DeleteList(libBase->ReloadPluginsHooks);
119 DeleteList(libBase->Plugins);
120 DeleteList(libBase->Units);
121 DeleteSemaphore(libBase->DiskChangeSemaphore);
122 DeleteSemaphore(libBase->PluginSemaphore);
123 DeleteSemaphore(libBase->UnitSemaphore);
124 if (libBase->IntuitionBase) CloseLibrary(libBase->IntuitionBase);
125 if (libBase->UtilityBase) CloseLibrary(libBase->UtilityBase);
126 if (libBase->DOSBase) CloseLibrary(libBase->DOSBase);
129 /* Here begins the system interface commands. When the user calls
130 OpenDevice/CloseDevice/RemDevice, this eventually gets translated
131 into a call to the following routines (Open/Close/Expunge).
132 Exec has already put our device pointer in a6 for us.
134 IMPORTANT:
135 These calls are guaranteed to be single-threaded; only one task
136 will execute your Open/Close/Expunge at a time.
138 For Kickstart V33/34, the single-threading method involves "Forbid".
139 There is a good chance this will change. Anything inside your
140 Open/Close/Expunge that causes a direct or indirect Wait() will break
141 the Forbid(). If the Forbid() is broken, some other task might
142 manage to enter your Open/Close/Expunge code at the same time.
143 Take care!
145 Since exec has turned off task switching while in these routines
146 (via Forbid/Permit), we should not take too long in them. */
148 /* dev_open() sets the io_Error field on an error. If it was successful,
149 we should also set up the io_Unit and ln_Type fields.
150 Exec takes care of setting up io_Device. */
152 /* Open the library */
153 #ifdef __AROS__
154 static AROS_LH3(LONG, LibOpen,
155 AROS_LHA(struct IORequest *, io, A1),
156 AROS_LHA(ULONG, unit_number, D0),
157 AROS_LHA(ULONG, flags, D1),
158 struct DiskImageBase *, libBase, 1, DiskImage
161 AROS_LIBFUNC_INIT
162 #else
163 static LONG LibOpen(REG(a1, struct IORequest *io), REG(d0, ULONG unit_number), REG(d1, ULONG flags),
164 REG(a6, struct DiskImageBase *libBase))
166 #endif
167 struct Library *SysBase = libBase->SysBase;
168 struct Library *DOSBase = libBase->DOSBase;
169 struct DiskImageUnit *unit;
171 /* Subtle point: any AllocMem() call can cause a call to this device's
172 expunge vector. If lib_OpenCnt is zero, the device might get expunged. */
174 ObtainSemaphore(libBase->UnitSemaphore);
176 io->io_Device = (struct Device *)libBase;
177 io->io_Unit = NULL;
178 io->io_Error = IOERR_SUCCESS;
180 #ifndef __AROS__
181 if (libBase->LibNode.lib_OpenCnt++ == 0) {
182 ObtainSemaphore(libBase->PluginSemaphore);
183 InitLocaleInfo(SysBase, &libBase->LocaleInfo, "diskimagedevice.catalog");
184 LoadPlugins(libBase);
185 ReleaseSemaphore(libBase->PluginSemaphore);
187 #endif
189 if (unit_number == ~0) {
190 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
192 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
193 ReleaseSemaphore(libBase->UnitSemaphore);
195 return IOERR_SUCCESS;
198 unit = (struct DiskImageUnit *)libBase->Units->lh_Head;
199 while (unit->Node.ln_Succ) {
200 if (unit->UnitNum == unit_number) {
201 unit->OpenCnt++;
203 io->io_Unit = (struct Unit *)unit;
204 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
206 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
207 ReleaseSemaphore(libBase->UnitSemaphore);
209 return IOERR_SUCCESS;
211 unit = (struct DiskImageUnit *)unit->Node.ln_Succ;
214 unit = InitUnit(libBase, unit_number);
215 if (unit) {
216 BPTR stdin, stdout;
218 stdin = Open("NIL:", MODE_OLDFILE);
219 stdout = Open("NIL:", MODE_NEWFILE);
221 if (stdin && stdout) {
222 unit->UnitProc = CreateNewProcTags(
223 NP_Name, unit->Node.ln_Name,
224 NP_StackSize, 32768,
225 NP_Input, stdin,
226 NP_Output, stdout,
227 NP_CurrentDir, ZERO,
228 NP_Entry, UnitProcEntry,
229 NP_Priority, 4,
230 TAG_END);
233 if (unit->UnitProc) {
234 struct MsgPort *replyport = unit->ReplyPort;
235 struct DiskImageMsg *msg = unit->DiskImageMsg;
236 struct MsgPort *port;
238 replyport->mp_SigTask = FindTask(NULL);
239 replyport->mp_Flags = PA_SIGNAL;
240 msg->dim_Unit = unit;
241 msg->dim_Command = DICMD_STARTUP;
242 msg->dim_Tags = NULL;
244 port = GetProcMsgPort(unit->UnitProc);
245 PutMsg(port, &msg->dim_Msg);
246 WaitPort(replyport);
248 replyport->mp_Flags = PA_IGNORE;
249 replyport->mp_SigTask = NULL;
251 /* Check that it's not DeathMessage */
252 if (GetMsg(replyport) == &msg->dim_Msg) {
253 AddTail(libBase->Units, &unit->Node);
254 io->io_Unit = (struct Unit *)unit;
255 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
257 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
258 ReleaseSemaphore(libBase->UnitSemaphore);
260 return IOERR_SUCCESS;
261 } else {
262 unit->UnitProc = NULL;
264 } else {
265 Close(stdin);
266 Close(stdout);
269 FreeUnit(libBase, unit);
272 /* IMPORTANT: Mark IORequest as "complete" */
273 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
275 /* IMPORTANT: trash io_Device on open failure */
276 io->io_Device = NULL;
278 if (io->io_Error == IOERR_SUCCESS) io->io_Error = TDERR_NotSpecified;
280 libBase->LibNode.lib_OpenCnt--; /* End of expunge protection */
282 ReleaseSemaphore(libBase->UnitSemaphore);
284 return io->io_Error;
286 #ifdef __AROS__
287 AROS_LIBFUNC_EXIT
288 #endif
291 /* There are two different things that might be returned from the dev_close()
292 routine. If the device wishes to be unloaded, then dev_close() must return
293 the segment list (as given to dev_init()). Otherwise dev_close() MUST
294 return NULL. */
296 /* Close the library */
297 #ifdef __AROS__
298 static AROS_LH1(BPTR, LibClose,
299 AROS_LHA(struct IORequest *, io, A1),
300 struct DiskImageBase *, libBase, 2, DiskImage
303 AROS_LIBFUNC_INIT
304 #else
305 static BPTR LibClose(REG(a1, struct IORequest *io), REG(a6, struct DiskImageBase *libBase))
307 #endif
308 struct Library *SysBase = libBase->SysBase;
309 struct DiskImageUnit *unit = (struct DiskImageUnit *)io->io_Unit;
311 ObtainSemaphore(libBase->UnitSemaphore);
313 /* IMPORTANT: make sure the IORequest is not used again
314 with a -1 in io_Device, any BeginIO() attempt will
315 immediatly halt (which is better than a subtle corruption
316 that will lead to hard-to-trace crashes!!! */
317 io->io_Unit = (struct Unit *)-1;
318 io->io_Device = (struct Device *)-1;
320 /* see if the unit is still in use */
321 if(unit && --unit->OpenCnt == 0) {
322 struct MsgPort *replyport = unit->ReplyPort;
323 struct DiskImageMsg *msg = unit->DiskImageMsg;
325 Remove(&unit->Node);
327 replyport->mp_SigTask = FindTask(NULL);
328 replyport->mp_Flags = PA_SIGNAL;
329 msg->dim_Command = DICMD_DIE;
330 msg->dim_Tags = NULL;
332 PutMsg(unit->MsgPort, &msg->dim_Msg);
333 WaitPort(replyport);
334 GetMsg(replyport);
336 replyport->mp_Flags = PA_IGNORE;
337 replyport->mp_SigTask = NULL;
339 FreeUnit(libBase, unit);
342 /* mark us as having one fewer openers */
343 if (--libBase->LibNode.lib_OpenCnt == 0) {
344 ObtainSemaphore(libBase->PluginSemaphore);
345 FreePlugins(libBase);
346 FreeLocaleInfo(SysBase, &libBase->LocaleInfo);
347 ReleaseSemaphore(libBase->PluginSemaphore);
350 ReleaseSemaphore(libBase->UnitSemaphore);
352 return ZERO;
353 #ifdef __AROS__
354 AROS_LIBFUNC_EXIT
355 #endif
358 static struct DiskImageUnit *InitUnit (struct DiskImageBase *libBase, ULONG unit_number) {
359 struct DiskImageUnit *unit;
360 struct Library *SysBase = libBase->SysBase;
362 unit = AllocVec(sizeof(*unit), MEMF_CLEAR);
363 if (!unit) {
364 return NULL;
367 unit->OpenCnt = 1;
368 unit->UnitNum = unit_number;
369 unit->LibBase = libBase;
371 if ((unit->Node.ln_Name = ASPrintf("diskimage.device unit %ld", unit_number)) &&
372 (unit->IOSemaphore = CreateSemaphore()) &&
373 (unit->MsgSemaphore = CreateSemaphore()) &&
374 (unit->ReplyPort = CreatePortNoSignal()) &&
375 (unit->DiskImageMsg = (struct DiskImageMsg *)CreateMsg(sizeof(*unit->DiskImageMsg))) &&
376 (unit->DeathMsg = (struct DeathMessage *)CreateMsg(sizeof(*unit->DeathMsg))) &&
377 (unit->ChangeInts = CreateList(TRUE)))
379 unit->DiskImageMsg->dim_Msg.mn_Node.ln_Name = unit->Node.ln_Name;
380 unit->DeathMsg->dm_Msg.mn_Node.ln_Name = unit->Node.ln_Name;
381 unit->DiskImageMsg->dim_Msg.mn_ReplyPort = unit->ReplyPort;
382 unit->DeathMsg->dm_Msg.mn_ReplyPort = unit->ReplyPort;
383 return unit;
386 FreeUnit(libBase, unit);
387 return NULL;
390 static void FreeUnit (struct DiskImageBase *libBase, struct DiskImageUnit *unit) {
391 struct Library *SysBase = libBase->SysBase;
392 if (unit) {
393 DeleteList(unit->ChangeInts);
394 DeleteMsg(&unit->DeathMsg->dm_Msg);
395 DeleteMsg(&unit->DiskImageMsg->dim_Msg);
396 DeletePortNoSignal(unit->ReplyPort);
397 DeleteSemaphore(unit->MsgSemaphore);
398 DeleteSemaphore(unit->IOSemaphore);
399 FreeVec(unit->Node.ln_Name);
400 FreeVec(unit);
404 /* dev_expunge() is called by the memory allocator when the system is low on
405 memory.
407 There are two different things that might be returned from the dev_expunge()
408 routine. If the device is no longer open then dev_expunge() may return the
409 segment list (as given to dev_init()). Otherwise dev_expunge() may set the
410 delayed expunge flag and return NULL.
412 One other important note: because dev_expunge() is called from the memory
413 allocator, it may NEVER Wait() or otherwise take long time to complete. */
415 /* Expunge the library */
416 #ifdef __AROS__
417 static AROS_LH0(BPTR, LibExpunge,
418 struct DiskImageBase *, libBase, 3, DiskImage
421 AROS_LIBFUNC_INIT
422 #else
423 static BPTR LibExpunge(REG(a6, struct DiskImageBase *libBase))
425 #endif
426 struct Library *SysBase = libBase->SysBase;
427 BPTR result = 0;
429 /* see if anyone has us open */
430 if (libBase->LibNode.lib_OpenCnt > 0) {
431 /* it is still open. set the delayed expunge flag */
432 libBase->LibNode.lib_Flags |= LIBF_DELEXP;
433 } else {
434 /* go ahead and get rid of us. */
435 result = libBase->SegList;
437 /* unlink from device list */
438 Remove((struct Node *)libBase); /* Remove first (before FreeMem) */
440 /* ...device specific closings here... */
441 FreeBaseVars(libBase);
443 /* free our memory */
444 DeleteLibrary((struct Library *)libBase);
447 return result;
448 #ifdef __AROS__
449 AROS_LIBFUNC_EXIT
450 #endif
453 #ifdef __AROS__
454 static AROS_LH0(APTR, LibReserved,
455 struct DiskImageBase *, libBase, 4, DiskImage
458 AROS_LIBFUNC_INIT
459 return NULL;
460 AROS_LIBFUNC_EXIT
462 #else
463 static APTR LibReserved (void) {
464 return NULL;
466 #endif
468 #ifdef __AROS__
469 #ifdef ABIV1
470 #define LIB_ENTRY(a,b) AROS_SLIB_ENTRY(a, DiskImage, b)
471 #else
472 #define LIB_ENTRY(a,b) AROS_SLIB_ENTRY(a, DiskImage)
473 #endif
474 #else
475 #define LIB_ENTRY(a,b) a
476 #endif
478 const CONST_APTR LibVectors[] = {
479 (APTR)LIB_ENTRY(LibOpen, 1),
480 (APTR)LIB_ENTRY(LibClose, 2),
481 (APTR)LIB_ENTRY(LibExpunge, 3),
482 (APTR)LIB_ENTRY(LibReserved, 4),
483 (APTR)LIB_ENTRY(LibBeginIO, 5),
484 (APTR)LIB_ENTRY(LibAbortIO, 6),
485 (APTR)LIB_ENTRY(MountImage, 7),
486 (APTR)LIB_ENTRY(UnitInfo, 8),
487 (APTR)LIB_ENTRY(WriteProtect, 9),
488 (APTR)LIB_ENTRY(UnitControlA, 10),
489 (APTR)LIB_ENTRY(ReloadPlugins, 11),
490 (APTR)LIB_ENTRY(DoHookPlugins, 12),
491 (APTR)LIB_ENTRY(AddDiskChangeHook, 13),
492 (APTR)LIB_ENTRY(AddReloadPluginsHook, 14),
493 (APTR)-1
496 const IPTR LibInitTab[] = {
497 sizeof(struct DiskImageBase),
498 (IPTR)LibVectors,
499 (IPTR)NULL,
500 (IPTR)LibInit
503 const struct Resident USED_VAR ROMTag = {
504 RTC_MATCHWORD,
505 (struct Resident *)&ROMTag,
506 (APTR)(&ROMTag + 1),
507 RTF_AUTOINIT, /* Add RTF_COLDSTART if you want to be resident */
508 VERSION,
509 NT_DEVICE, /* Make this NT_DEVICE if needed */
510 0, /* PRI, usually not needed unless you're resident */
511 (STRPTR)LIBNAME,
512 (STRPTR)VSTRING,
513 (APTR)LibInitTab