Fixed my network drivers to work with ABIv1 (apart from prism2.device, which
[AROS.git] / workbench / devs / diskimage / device / init.c
blob817d2e5e76c47b28257cac52cb7a9bedf50c125d
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>
33 #ifdef __AROS__
34 # include <proto/expat_au.h>
35 #else
36 # include <proto/expat.h>
37 #endif
39 #include "rev/diskimage.device_rev.h"
41 #define LIBNAME "diskimage.device"
42 CONST TEXT USED_VAR verstag[] = VERSTAG;
44 struct Library *SysBase;
45 struct Library *DOSBase;
46 struct Library *IntuitionBase;
47 struct Library *aroscbase;
49 static void FreeBaseVars (struct DiskImageBase *libBase);
50 static struct DiskImageUnit *InitUnit (struct DiskImageBase *libBase, ULONG unit_number);
51 static void FreeUnit (struct DiskImageBase *libBase, struct DiskImageUnit *unit);
53 /* FOR RTF_AUTOINIT:
54 This routine gets called after the device has been allocated.
55 The device pointer is in D0. The AmigaDOS segment list is in a0.
56 If it returns the device pointer, then the device will be linked
57 into the device list. If it returns NULL, then the device
58 will be unloaded.
60 IMPORTANT:
61 If you don't use the "RTF_AUTOINIT" feature, there is an additional
62 caveat. If you allocate memory in your Open function, remember that
63 allocating memory can cause an Expunge... including an expunge of your
64 device. This must not be fatal. The easy solution is don't add your
65 device to the list until after it is ready for action.
67 This call is single-threaded by exec; please read the description for
68 "dev_open" below. */
70 /* The ROMTAG Init Function */
71 #ifdef __AROS__
72 static AROS_UFH3(struct DiskImageBase *, LibInit,
73 AROS_UFHA(struct DiskImageBase *, libBase, D0),
74 AROS_UFHA(BPTR, seglist, A0),
75 AROS_UFHA(struct Library *, exec_base, A6)
78 AROS_USERFUNC_INIT
79 #else
80 static struct DiskImageBase *LibInit (REG(d0, struct DiskImageBase *libBase),
81 REG(a0, BPTR seglist), REG(a6, struct Library *exec_base))
83 #endif
84 libBase->LibNode.lib_Node.ln_Type = NT_DEVICE;
85 libBase->LibNode.lib_Node.ln_Pri = 0;
86 libBase->LibNode.lib_Node.ln_Name = LIBNAME;
87 libBase->LibNode.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
88 libBase->LibNode.lib_Version = VERSION;
89 libBase->LibNode.lib_Revision = REVISION;
90 libBase->LibNode.lib_IdString = VSTRING;
91 libBase->SysBase = exec_base;
92 SysBase = exec_base;
94 /* Save pointer to our loaded code (the SegList) */
95 libBase->SegList = seglist;
97 if ((DOSBase = libBase->DOSBase = OpenLibrary("dos.library", MIN_OS_VERSION)) &&
98 (libBase->UtilityBase = OpenLibrary("utility.library", MIN_OS_VERSION)) &&
99 #ifdef __AROS__
100 (aroscbase = libBase->aroscbase = OpenLibrary("arosc.library", 41)) &&
101 #endif
102 (IntuitionBase = libBase->IntuitionBase = OpenLibrary("intuition.library", MIN_OS_VERSION)))
104 if ((libBase->UnitSemaphore = CreateSemaphore()) &&
105 (libBase->PluginSemaphore = CreateSemaphore()) &&
106 (libBase->DiskChangeSemaphore = CreateSemaphore()) &&
107 (libBase->Units = CreateList(TRUE)) &&
108 (libBase->Plugins = CreateList(TRUE)) &&
109 (libBase->ReloadPluginsHooks = CreateList(TRUE)) &&
110 (libBase->DiskChangeHooks = CreateList(TRUE)))
112 return libBase;
116 FreeBaseVars(libBase);
117 DeleteLibrary((struct Library *)libBase);
118 return NULL;
119 #ifdef __AROS__
120 AROS_USERFUNC_EXIT
121 #endif
124 static void FreeBaseVars (struct DiskImageBase *libBase) {
125 struct Library *SysBase = libBase->SysBase;
126 DeleteList(libBase->DiskChangeHooks);
127 DeleteList(libBase->ReloadPluginsHooks);
128 DeleteList(libBase->Plugins);
129 DeleteList(libBase->Units);
130 DeleteSemaphore(libBase->DiskChangeSemaphore);
131 DeleteSemaphore(libBase->PluginSemaphore);
132 DeleteSemaphore(libBase->UnitSemaphore);
133 if (libBase->IntuitionBase) CloseLibrary(libBase->IntuitionBase);
134 #ifdef __AROS__
135 if (libBase->aroscbase) CloseLibrary(libBase->aroscbase);
136 #endif
137 if (libBase->UtilityBase) CloseLibrary(libBase->UtilityBase);
138 if (libBase->DOSBase) CloseLibrary(libBase->DOSBase);
141 /* Here begins the system interface commands. When the user calls
142 OpenDevice/CloseDevice/RemDevice, this eventually gets translated
143 into a call to the following routines (Open/Close/Expunge).
144 Exec has already put our device pointer in a6 for us.
146 IMPORTANT:
147 These calls are guaranteed to be single-threaded; only one task
148 will execute your Open/Close/Expunge at a time.
150 For Kickstart V33/34, the single-threading method involves "Forbid".
151 There is a good chance this will change. Anything inside your
152 Open/Close/Expunge that causes a direct or indirect Wait() will break
153 the Forbid(). If the Forbid() is broken, some other task might
154 manage to enter your Open/Close/Expunge code at the same time.
155 Take care!
157 Since exec has turned off task switching while in these routines
158 (via Forbid/Permit), we should not take too long in them. */
160 /* dev_open() sets the io_Error field on an error. If it was successful,
161 we should also set up the io_Unit and ln_Type fields.
162 Exec takes care of setting up io_Device. */
164 /* Open the library */
165 #ifdef __AROS__
166 static AROS_LH3(LONG, LibOpen,
167 AROS_LHA(struct IORequest *, io, A1),
168 AROS_LHA(ULONG, unit_number, D0),
169 AROS_LHA(ULONG, flags, D1),
170 struct DiskImageBase *, libBase, 1, DiskImage
173 AROS_LIBFUNC_INIT
174 #else
175 static LONG LibOpen(REG(a1, struct IORequest *io), REG(d0, ULONG unit_number), REG(d1, ULONG flags),
176 REG(a6, struct DiskImageBase *libBase))
178 #endif
179 struct Library *SysBase = libBase->SysBase;
180 struct Library *DOSBase = libBase->DOSBase;
181 struct DiskImageUnit *unit;
183 /* Subtle point: any AllocMem() call can cause a call to this device's
184 expunge vector. If lib_OpenCnt is zero, the device might get expunged. */
186 ObtainSemaphore(libBase->UnitSemaphore);
188 io->io_Device = (struct Device *)libBase;
189 io->io_Unit = NULL;
190 io->io_Error = IOERR_SUCCESS;
192 #ifndef __AROS__
193 if (libBase->LibNode.lib_OpenCnt++ == 0) {
194 ObtainSemaphore(libBase->PluginSemaphore);
195 InitLocaleInfo(SysBase, &libBase->LocaleInfo, "diskimagedevice.catalog");
196 LoadPlugins(libBase);
197 ReleaseSemaphore(libBase->PluginSemaphore);
199 #endif
201 if (unit_number == ~0) {
202 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
204 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
205 ReleaseSemaphore(libBase->UnitSemaphore);
207 return IOERR_SUCCESS;
210 unit = (struct DiskImageUnit *)libBase->Units->lh_Head;
211 while (unit->Node.ln_Succ) {
212 if (unit->UnitNum == unit_number) {
213 unit->OpenCnt++;
215 io->io_Unit = (struct Unit *)unit;
216 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
218 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
219 ReleaseSemaphore(libBase->UnitSemaphore);
221 return IOERR_SUCCESS;
223 unit = (struct DiskImageUnit *)unit->Node.ln_Succ;
226 unit = InitUnit(libBase, unit_number);
227 if (unit) {
228 BPTR stdin, stdout;
230 stdin = Open("NIL:", MODE_OLDFILE);
231 stdout = Open("NIL:", MODE_NEWFILE);
233 if (stdin && stdout) {
234 unit->UnitProc = CreateNewProcTags(
235 NP_Name, unit->Node.ln_Name,
236 NP_StackSize, 32768,
237 NP_Input, stdin,
238 NP_Output, stdout,
239 NP_CurrentDir, ZERO,
240 NP_Entry, UnitProcEntry,
241 NP_Priority, 4,
242 TAG_END);
245 if (unit->UnitProc) {
246 struct MsgPort *replyport = unit->ReplyPort;
247 struct DiskImageMsg *msg = unit->DiskImageMsg;
248 struct MsgPort *port;
250 replyport->mp_SigTask = FindTask(NULL);
251 replyport->mp_Flags = PA_SIGNAL;
252 msg->dim_Unit = unit;
253 msg->dim_Command = DICMD_STARTUP;
254 msg->dim_Tags = NULL;
256 port = GetProcMsgPort(unit->UnitProc);
257 PutMsg(port, &msg->dim_Msg);
258 WaitPort(replyport);
260 replyport->mp_Flags = PA_IGNORE;
261 replyport->mp_SigTask = NULL;
263 /* Check that it's not DeathMessage */
264 if (GetMsg(replyport) == &msg->dim_Msg) {
265 AddTail(libBase->Units, &unit->Node);
266 io->io_Unit = (struct Unit *)unit;
267 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
269 libBase->LibNode.lib_Flags &= ~LIBF_DELEXP;
270 ReleaseSemaphore(libBase->UnitSemaphore);
272 return IOERR_SUCCESS;
273 } else {
274 unit->UnitProc = NULL;
276 } else {
277 Close(stdin);
278 Close(stdout);
281 FreeUnit(libBase, unit);
284 /* IMPORTANT: Mark IORequest as "complete" */
285 io->io_Message.mn_Node.ln_Type = NT_REPLYMSG;
287 /* IMPORTANT: trash io_Device on open failure */
288 io->io_Device = NULL;
290 if (io->io_Error == IOERR_SUCCESS) io->io_Error = TDERR_NotSpecified;
292 libBase->LibNode.lib_OpenCnt--; /* End of expunge protection */
294 ReleaseSemaphore(libBase->UnitSemaphore);
296 return io->io_Error;
298 #ifdef __AROS__
299 AROS_LIBFUNC_EXIT
300 #endif
303 /* There are two different things that might be returned from the dev_close()
304 routine. If the device wishes to be unloaded, then dev_close() must return
305 the segment list (as given to dev_init()). Otherwise dev_close() MUST
306 return NULL. */
308 /* Close the library */
309 #ifdef __AROS__
310 static AROS_LH1(BPTR, LibClose,
311 AROS_LHA(struct IORequest *, io, A1),
312 struct DiskImageBase *, libBase, 2, DiskImage
315 AROS_LIBFUNC_INIT
316 #else
317 static BPTR LibClose(REG(a1, struct IORequest *io), REG(a6, struct DiskImageBase *libBase))
319 #endif
320 struct Library *SysBase = libBase->SysBase;
321 struct DiskImageUnit *unit = (struct DiskImageUnit *)io->io_Unit;
323 ObtainSemaphore(libBase->UnitSemaphore);
325 /* IMPORTANT: make sure the IORequest is not used again
326 with a -1 in io_Device, any BeginIO() attempt will
327 immediatly halt (which is better than a subtle corruption
328 that will lead to hard-to-trace crashes!!! */
329 io->io_Unit = (struct Unit *)-1;
330 io->io_Device = (struct Device *)-1;
332 /* see if the unit is still in use */
333 if(unit && --unit->OpenCnt == 0) {
334 struct MsgPort *replyport = unit->ReplyPort;
335 struct DiskImageMsg *msg = unit->DiskImageMsg;
337 Remove(&unit->Node);
339 replyport->mp_SigTask = FindTask(NULL);
340 replyport->mp_Flags = PA_SIGNAL;
341 msg->dim_Command = DICMD_DIE;
342 msg->dim_Tags = NULL;
344 PutMsg(unit->MsgPort, &msg->dim_Msg);
345 WaitPort(replyport);
346 GetMsg(replyport);
348 replyport->mp_Flags = PA_IGNORE;
349 replyport->mp_SigTask = NULL;
351 FreeUnit(libBase, unit);
354 /* mark us as having one fewer openers */
355 if (--libBase->LibNode.lib_OpenCnt == 0) {
356 ObtainSemaphore(libBase->PluginSemaphore);
357 FreePlugins(libBase);
358 FreeLocaleInfo(SysBase, &libBase->LocaleInfo);
359 ReleaseSemaphore(libBase->PluginSemaphore);
362 ReleaseSemaphore(libBase->UnitSemaphore);
364 return ZERO;
365 #ifdef __AROS__
366 AROS_LIBFUNC_EXIT
367 #endif
370 static struct DiskImageUnit *InitUnit (struct DiskImageBase *libBase, ULONG unit_number) {
371 struct DiskImageUnit *unit;
372 struct Library *SysBase = libBase->SysBase;
374 unit = AllocVec(sizeof(*unit), MEMF_CLEAR);
375 if (!unit) {
376 return NULL;
379 unit->OpenCnt = 1;
380 unit->UnitNum = unit_number;
381 unit->LibBase = libBase;
383 if ((unit->Node.ln_Name = ASPrintf("diskimage.device unit %ld", unit_number)) &&
384 (unit->IOSemaphore = CreateSemaphore()) &&
385 (unit->MsgSemaphore = CreateSemaphore()) &&
386 (unit->ReplyPort = CreatePortNoSignal()) &&
387 (unit->DiskImageMsg = (struct DiskImageMsg *)CreateMsg(sizeof(*unit->DiskImageMsg))) &&
388 (unit->DeathMsg = (struct DeathMessage *)CreateMsg(sizeof(*unit->DeathMsg))) &&
389 (unit->ChangeInts = CreateList(TRUE)))
391 unit->DiskImageMsg->dim_Msg.mn_Node.ln_Name = unit->Node.ln_Name;
392 unit->DeathMsg->dm_Msg.mn_Node.ln_Name = unit->Node.ln_Name;
393 unit->DiskImageMsg->dim_Msg.mn_ReplyPort = unit->ReplyPort;
394 unit->DeathMsg->dm_Msg.mn_ReplyPort = unit->ReplyPort;
395 return unit;
398 FreeUnit(libBase, unit);
399 return NULL;
402 static void FreeUnit (struct DiskImageBase *libBase, struct DiskImageUnit *unit) {
403 struct Library *SysBase = libBase->SysBase;
404 if (unit) {
405 DeleteList(unit->ChangeInts);
406 DeleteMsg(&unit->DeathMsg->dm_Msg);
407 DeleteMsg(&unit->DiskImageMsg->dim_Msg);
408 DeletePortNoSignal(unit->ReplyPort);
409 DeleteSemaphore(unit->MsgSemaphore);
410 DeleteSemaphore(unit->IOSemaphore);
411 FreeVec(unit->Node.ln_Name);
412 FreeVec(unit);
416 /* dev_expunge() is called by the memory allocator when the system is low on
417 memory.
419 There are two different things that might be returned from the dev_expunge()
420 routine. If the device is no longer open then dev_expunge() may return the
421 segment list (as given to dev_init()). Otherwise dev_expunge() may set the
422 delayed expunge flag and return NULL.
424 One other important note: because dev_expunge() is called from the memory
425 allocator, it may NEVER Wait() or otherwise take long time to complete. */
427 /* Expunge the library */
428 #ifdef __AROS__
429 static AROS_LH0(BPTR, LibExpunge,
430 struct DiskImageBase *, libBase, 3, DiskImage
433 AROS_LIBFUNC_INIT
434 #else
435 static BPTR LibExpunge(REG(a6, struct DiskImageBase *libBase))
437 #endif
438 struct Library *SysBase = libBase->SysBase;
439 BPTR result = 0;
441 /* see if anyone has us open */
442 if (libBase->LibNode.lib_OpenCnt > 0) {
443 /* it is still open. set the delayed expunge flag */
444 libBase->LibNode.lib_Flags |= LIBF_DELEXP;
445 } else {
446 /* go ahead and get rid of us. */
447 result = libBase->SegList;
449 /* unlink from device list */
450 Remove((struct Node *)libBase); /* Remove first (before FreeMem) */
452 /* ...device specific closings here... */
453 FreeBaseVars(libBase);
455 /* free our memory */
456 DeleteLibrary((struct Library *)libBase);
459 return result;
460 #ifdef __AROS__
461 AROS_LIBFUNC_EXIT
462 #endif
465 #ifdef __AROS__
466 static AROS_LH0(APTR, LibReserved,
467 struct DiskImageBase *, libBase, 4, DiskImage
470 AROS_LIBFUNC_INIT
471 return NULL;
472 AROS_LIBFUNC_EXIT
474 #else
475 static APTR LibReserved (void) {
476 return NULL;
478 #endif
480 #ifdef __AROS__
481 #ifdef ABIV1
482 #define LIB_ENTRY(a,b) AROS_SLIB_ENTRY(a, DiskImage, b)
483 #else
484 #define LIB_ENTRY(a,b) AROS_SLIB_ENTRY(a, DiskImage)
485 #endif
486 #else
487 #define LIB_ENTRY(a,b) a
488 #endif
490 const CONST_APTR LibVectors[] = {
491 (APTR)LIB_ENTRY(LibOpen, 1),
492 (APTR)LIB_ENTRY(LibClose, 2),
493 (APTR)LIB_ENTRY(LibExpunge, 3),
494 (APTR)LIB_ENTRY(LibReserved, 4),
495 (APTR)LIB_ENTRY(LibBeginIO, 5),
496 (APTR)LIB_ENTRY(LibAbortIO, 6),
497 (APTR)LIB_ENTRY(MountImage, 7),
498 (APTR)LIB_ENTRY(UnitInfo, 8),
499 (APTR)LIB_ENTRY(WriteProtect, 9),
500 (APTR)LIB_ENTRY(UnitControlA, 10),
501 (APTR)LIB_ENTRY(ReloadPlugins, 11),
502 (APTR)LIB_ENTRY(DoHookPlugins, 12),
503 (APTR)LIB_ENTRY(AddDiskChangeHook, 13),
504 (APTR)LIB_ENTRY(AddReloadPluginsHook, 14),
505 (APTR)-1
508 const IPTR LibInitTab[] = {
509 sizeof(struct DiskImageBase),
510 (IPTR)LibVectors,
511 (IPTR)NULL,
512 (IPTR)LibInit
515 const struct Resident USED_VAR ROMTag = {
516 RTC_MATCHWORD,
517 (struct Resident *)&ROMTag,
518 (APTR)(&ROMTag + 1),
519 RTF_AUTOINIT, /* Add RTF_COLDSTART if you want to be resident */
520 VERSION,
521 NT_DEVICE, /* Make this NT_DEVICE if needed */
522 0, /* PRI, usually not needed unless you're resident */
523 (STRPTR)LIBNAME,
524 (STRPTR)VSTRING,
525 (APTR)LibInitTab