3 * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
4 * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
6 * ----------------------------------------------------------------------
7 * This code is (C) Copyright 1993,1994 by Frank Munkert.
8 * (C) Copyright 2002-2013 The AROS Development Team
10 * This software may be freely distributed and redistributed for
11 * non-commercial purposes, provided this notice is included.
12 * ----------------------------------------------------------------------
15 * 08-Nov-13 neil - Only delay 2 seconds upon exiting if debugging is
17 * 18-Dec-11 twilen - Added media change interrupt support (SCANINTERVAL=-1).
18 * 11-Aug-10 sonic - Fixed for 64-bit compatibility
19 * 04-Jun-10 neil - No longer removes device node and seglist when
20 * exiting. It isn't our job.
21 * - Delay returning ACTION_DIE packet until handler is
23 * 20-Mar-09 sonic - Fixed ID_CDFS_DISK redefinition warning when building with new
25 * 18-Mar-09 sonic - Numerous BSTR handling adjustments, now can be compiled as a
26 * packet-type handler for AROS
27 * 27-Aug-07 sonic - Register_Volume_Node() now takes separate pointer to a volume name.
28 * - Now reports correct DOS type for volumes ('CDFS').
29 * 29-May-07 sonic - Replies FileSysStartupMsg and loads character
30 * set translation table before mounting volume
31 * - Does not unmount volume any more in case of
33 * 15-May-07 sonic - Fixed CDDA handling
34 * 06-May-07 sonic - Added support for protection bits and file comments
35 * - Fixed memory trashing when file name length is greater than AmigaOS
37 * 08-Apr-07 sonic - removed redundant "TRACKDISK" option
38 * 01-Apr-07 sonic - seglist unloading is much more safe
39 * - removed unneeded search in Remove_Volume_Node()
40 * 31-Mar-07 sonic - ACTION_SAME_LOCK now returns 100% correct values
41 * - removed Make_FSSM()
42 * - removed many #ifdef's
44 * 09-Apr-06 sonic - fixed binary-compatible BCPL file name string handling
45 * - code style improved, removed many #ifdef's.
46 * - now works if compiled for binary-compatible flavour
47 * 07-Jul-02 sheutlin various changes/fixes when porting to AROS
48 * - all global variables are now in the structure global
49 * - changed types in lowercase to uppercase (ulong, ...)
50 * - replaced BTOC() by dos/dos.h/BADDR()
51 * - replaced CTOB() by dos/dos.h/MKBADDR()
52 * - fixed various warnings
53 * - replaced (unsigned) long by (U)LONG
54 * - replaced short by WORD
55 * - removed GetHead(), NextNode() (was unused)
56 * - changed Create_Volume_Node() to use
57 * MakeDosEntry()/AddDosEntry()
58 * - changed Remove_Volume_Node() to use
59 * RemDosEntry()/FreeDosEntry() now
60 * - removed dosalloc()/dosfree() and replaced these calls
61 * by AllocVec()/FreeVec()
62 * - put packet handling into own function to split
63 * code into init-main-deinit
64 * - replaced memcpy by CopyMem
65 * - changed SAME_LOCK returning LOCK_SAME/LOCK_DIFFERENT
66 * - replaced DOS_[TRUE|FALSE] by dos/dos.h/DOS[TRUE|FALSE]
67 * - optimisations here and there
68 * - removed static definitions
69 * 03-Nov-94 fmu Truncate file names to 30 characters.
70 * 12-Oct-94 fmu Return startup packet even if the scsi device cannot
71 * be opened immediately.
72 * 01-Sep-94 fmu - Added ACTION_EXAMINE_FH.
73 * - Added ACTION_PARENT_FH.
74 * - Added ACTION_MAKE_LINK (-> error message).
75 * - Automatically remove volume if all locks on the
76 * the volume have been freed.
77 * 17-May-94 fmu New option MAYBELOWERCASE (=ML).
78 * 20-Apr-94 fmu Improved implementation of ACTION_INHIBIT.
79 * 17-Apr-94 fmu Fixed bug concerning TRACKDISK disk change recognition.
80 * 12-Apr-94 fmu Adapted ACTION_CURRENT_VOLUME to new filehandle
82 * 09-Apr-94 fmu Volume management: locks and filehandles will not
83 * be forgotten if a CDROM is removed from the drive.
84 * 06-Feb-94 dmb - Full support for ACTION_INHIBIT
85 * - Change Check_Disk() for trackdisk support
86 * 05-Jan-93 fmu - Retry displaying CD-DA icon if WB is not open.
87 * - id_UnitNumber of InfoData set to SCSI unit number.
88 * - Added Make_FSSM().
89 * 01-Jan-93 fmu Support for symbolic links on RockRidge disks.
90 * 11-Dec-93 fmu - ACTION_FLUSH always returns DOSTRUE.
91 * - ISO volume names are mapped to lowercase if
92 * the option LOWERCASE has been selected.
93 * 26-Nov-93 fmu Some packets are now handled even if no disk
95 * 21-Nov-93 fmu - User programmable diskchange check interval.
96 * - Better support for ACTION_INHIBIT.
97 * - Handles filenames with ';'.
98 * 15-Nov-93 fmu Missing return value for 'handler' inserted.
99 * 14-Nov-93 fmu Added ACTION_USER packet for 'cdcontrol' program.
100 * 15-Oct-93 fmu Adapted to new VOLUME structure.
101 * 10-Oct-93 fmu - Creates volume node for 'no DOS' disks.
102 * - Volume node now contains the correct volume
104 * 09-Oct-93 fmu - New format for mountlist startup field.
106 * - Debug process assembly tag adapted to small
108 * - Get_Startup moved to file devsupp.c.
109 * 03-Oct-93 fmu - New buffering options 'S' and 'C'.
110 * - Fixed bug in cdlock.
111 * - Fixed bug in ACTION_CURRENT_VOLUME.
112 * 27-Sep-93 fmu Added ACTION_SAME_LOCK
113 * 25-Sep-93 fmu - Send 'disk inserted' / 'disk removed' event via
114 * input.device if disk has been changed.
115 * - Corrected bug in ACTION_DISK_INFO.
116 * 24-Sep-93 fmu - Added fast memory option 'F'.
117 * - Added ACTION_IS_FILESYSTEM.
118 * - Added 'write protected' error for write actions.
119 * - Added ACTION_CURRENT_VOLUME.
120 * - Unload handler code after ACTION_DIE.
121 * - Immediately terminate program if called from CLI.
122 * - Added library version number.
123 * - Set volume label to "Unnamed" for disks without name.
124 * 16-Sep-93 fmu Added code to detect whether a lock stems from the
125 * current volume or from another volume which has
126 * been removed from the drive.
130 * Debugging routines are disabled by simply attempting to open the
131 * file "debugoff", turned on again with "debugon". No prefix may be
132 * attached to these names (you must be CD'd to TEST:).
134 * See Documentation for a detailed discussion.
137 #include <proto/dos.h>
138 #include <proto/exec.h>
139 #include <proto/utility.h>
147 #include "cdcontrol.h"
154 #include "aros_stuff.h"
157 #define ID_CDFS_DISK 0x43444653
160 LONG
handler(struct ExecBase
*);
161 static LOCK
*cdlock(CDROM_OBJ
*, int);
162 static void cdunlock (LOCK
*);
163 static CDROM_OBJ
*getlockfile(struct CDVDBase
*global
, IPTR
);
164 static void returnpacket(struct CDVDBase
*global
, struct DosPacket
*);
165 static int packetsqueued (struct CDVDBase
*global
);
166 static int Check_For_Volume_Name_Prefix (struct CDVDBase
*global
, char *);
167 static void Fill_FileInfoBlock (struct CDVDBase
*global
, FIB
*, CDROM_INFO
*, VOLUME
*);
168 static void Mount (struct CDVDBase
*global
);
169 static void Unmount (struct CDVDBase
*global
);
170 static int Mount_Check (struct CDVDBase
*global
);
171 static void Check_Disk (struct CDVDBase
*global
);
172 static void Send_Timer_Request (struct CDVDBase
*global
);
173 static void Cleanup_Timer_Device (struct CDVDBase
*global
);
174 static int Open_Timer_Device (struct CDVDBase
*global
);
175 static void Send_Event (struct CDVDBase
*global
, int);
176 /* BPTR Make_FSSM (void); */
177 static void Remove_Volume_Node (struct CDVDBase
*global
, struct DeviceList
*);
178 static LONG
handlemessage(struct CDVDBase
*global
, ULONG
);
181 #define MAX_NAME_LEN 107
182 #define MAX_COMMENT_LEN 79
183 #define btos(bstr, buf) strcpy(buf, bstr)
185 #define MAX_NAME_LEN 106
186 #define MAX_COMMENT_LEN 78
188 static void btos(BSTR
, char *);
196 char __version__
[] = "\0$VER: CDVDFS 1.8 (8.11.2013)";
198 LONG SAVEDS
Main(void)
200 return handler(*(struct ExecBase
**)4L);
204 static struct CDVDBase
*AllocCDVDBase(struct ExecBase
*SysBase
)
206 struct CDVDBase
*cdvd
= NULL
;
208 cdvd
= AllocMem(sizeof(*cdvd
), MEMF_CLEAR
| MEMF_PUBLIC
);
212 cdvd
->g_iconname
= "CD-DA";
217 static void FreeCDVDBase(struct CDVDBase
*cdvd
)
219 FreeMem(cdvd
, sizeof(*cdvd
));
222 LONG
handler(struct ExecBase
*SysBase
)
224 register PACKET
*packet
;
228 struct CDVDBase
*global
= AllocCDVDBase(SysBase
);
230 D(bug("[CDVDFS] In handler, cdvd=%p\n", global
));
231 global
->playing
= FALSE
;
234 * Initialize all global variables. SysBase MUST be initialized before
235 * we can make Exec calls. The DOS library is opened for the debug
238 global
->DosProc
= (PROC
*) FindTask(NULL
);
239 DOSBase
= (APTR
)OpenLibrary("dos.library",37);
240 UtilityBase
= (APTR
)OpenLibrary("utility.library",37);
243 global
->Dback
= CreateMsgPort();
245 #if !defined(NDEBUG) || defined(DEBUG_SECTORS)
246 D(bug("[CDVDFS] Initializing debugging code\n"));
247 global
->DBDisable
= 0; /* Init. globals */
248 global
->Dbport
= NULL
;
251 * Initialize debugging code
254 if (DOSBase
&& global
->Dback
)
257 global
->DevList
= NULL
;
258 global
->PrefsProc
= NULL
;
259 global
->uniCodeset
= NULL
;
261 WaitPort(&global
->DosProc
->pr_MsgPort
); /* Get Startup Packet */
262 msg
= GetMsg(&global
->DosProc
->pr_MsgPort
);
263 packet
= (PACKET
*)msg
->mn_Node
.ln_Name
;
266 * Loading DosNode->dn_Task causes DOS *NOT* to startup a new
267 * instance of the device driver for every reference. E.G. if
268 * you were writing a CON device you would want this field to
272 global
->DosNode
= (DEVNODE
*)BADDR(packet
->dp_Arg3
);
274 D(bug("[CDVDFS] Fixing up DosNode %p\n", global
->DosNode
));
276 * Set dn_Task field which tells DOS not to startup a new
277 * process on every reference.
279 global
->DosNode
->dn_Task
= &global
->DosProc
->pr_MsgPort
;
283 if (UtilityBase
&& DOSBase
&& global
->Dback
&&
284 Get_Startup (global
, (struct FileSysStartupMsg
*)(BADDR(packet
->dp_Arg2
))))
286 D(bug("[CDVDFS] On track, globals at %p\n", global
));
287 packet
->dp_Res1
= DOSTRUE
;
291 * Load dn_Startup field with a BPTR to a FileSysStartupMsg.
292 * (According to the official documentation, this is not
293 * required. Some debugging tools, however, depend on it.)
296 /* global->DosNode->dn_Startup = Make_FSSM (global); */
298 } else { /* couldn't open dos.library */
299 D(bug("[CDVDFS] Off track, globals at %p\n", global
));
301 packet
->dp_Res1
= DOSFALSE
;
302 packet
->dp_Res2
= 333; /* any error code */
303 global
->DosNode
->dn_Task
= BNULL
;
304 returnpacket(global
, packet
);
307 BUG2(dbuninit(global
);)
308 Close_Intui (global
);
310 DeleteMsgPort(global
->Dback
);
312 CloseLibrary((struct Library
*)UtilityBase
);
313 CloseLibrary ((struct Library
*)DOSBase
);
315 return 0; /* exit process */
318 global
->g_inhibited
= 0;
320 BUG2(dbprintf (global
, "g_cd = %08lx\n", global
->g_cd
);)
321 BUG(dbprintf(global
, "%d std buffers, %d file buffers\n",
322 global
->g_std_buffers
, global
->g_file_buffers
);)
324 global
->g_changeint_signumber
= AllocSignal(-1);
325 global
->g_changeint_sigbit
= 1L << global
->g_changeint_signumber
;
326 /* Initialize timer: */
327 global
->g_timer_sigbit
= 0;
328 if (Open_Timer_Device (global
)) {
329 Send_Timer_Request (global
);
330 global
->g_scan_time
= global
->g_scan_interval
;
334 global
->g_vol_name
= AllocVec(128, MEMF_PUBLIC
| MEMF_CLEAR
);
335 global
->g_dos_sigbit
= 1L << global
->DosProc
->pr_MsgPort
.mp_SigBit
;
336 returnpacket(global
, packet
);
338 global
->g_disk_inserted
= 0;
341 /* Mount volume (if any disk is inserted): */
342 Mount_Check (global
);
346 * Here begins the endless loop, waiting for requests over our
347 * message port and executing them. Since requests are sent over
348 * our message port, this precludes being able to call DOS functions
349 * ourselves (that is why the debugging routines are a separate process)
353 signals
= Wait(global
->g_dos_sigbit
| global
->g_timer_sigbit
| global
->g_app_sigbit
| global
->g_changeint_sigbit
);
354 } while (handlemessage(global
, signals
));
355 BUG(dbprintf(global
, "Terminating the handler\n");)
356 /* remove timer device and any pending timer requests: */
357 if (global
->g_timer_sigbit
)
358 Cleanup_Timer_Device (global
);
363 FreeVec(global
->g_vol_name
);
366 Cleanup_CDROM (global
->g_cd
);
368 if (global
->g_changeint_signumber
!= -1)
369 FreeSignal(global
->g_changeint_signumber
);
371 Close_Intui (global
);
374 * Delay returning a successful ACTION_DIE packet until now, to avoid
375 * inconveniences such as having the trackdisk device disappear before
376 * we close it (e.g. when using a USB drive).
378 returnpacket(global
, global
->g_death_packet
);
381 * Remove processes, closedown, fall off the end of the world
382 * (which is how you kill yourself if a PROCESS. A TASK would have
383 * had to RemTask(NULL) itself).
385 Prefs_Uninit(global
);
387 BUG2(dbuninit(global
);)
388 DeleteMsgPort(global
->Dback
);
391 CloseLibrary(CodesetsBase
);
392 CloseLibrary((struct Library
*)UtilityBase
);
393 CloseLibrary((struct Library
*)DOSBase
);
395 FreeCDVDBase(global
);
399 LONG
handlemessage(struct CDVDBase
*global
, ULONG signals
) {
400 register PACKET
*packet
;
407 if (signals
& global
->g_changeint_sigbit
)
409 if (global
->g_cd
&& !global
->g_inhibited
)
412 if (signals
& global
->g_timer_sigbit
)
414 GetMsg (global
->g_timer_mp
);
416 /* retry opening the SCSI device (every 2 seconds): */
417 if (!global
->g_cd
&& (global
->g_time
& 1))
419 BUG(dbprintf(global
, "Device is closed, attempting to open\n");)
420 Get_Startup(global
, (struct FileSysStartupMsg
*)-1);
424 /* icon retry (every second): */
425 if (global
->g_retry_show_cdda_icon
)
427 BUG(dbprintf(global
, "Showing CDDA icon\n");)
428 Show_CDDA_Icon (global
);
430 /* diskchange check: */
431 if (global
->g_scan_interval
> 0)
433 if (global
->g_scan_time
== 1)
435 if (!global
->g_inhibited
)
437 global
->g_scan_time
= global
->g_scan_interval
;
440 global
->g_scan_time
--;
443 Send_Timer_Request (global
);
445 if (signals
& global
->g_app_sigbit
)
448 BUG(dbprintf(global
, "CDDA icon double-clicked\n");)
449 while ((msg
= GetMsg (global
->g_app_port
)))
451 struct TagItem PlayTags
[] = {
459 if (global
->g_play_cdda_command
[0]) {
460 PlayTags
[0].ti_Data
= (IPTR
)Open ("NIL:", MODE_OLDFILE
);
461 System(global
->g_play_cdda_command
, PlayTags
);
467 res
= Stop_Play_Audio (global
->g_cd
);
469 res
= Start_Play_Audio (global
->g_cd
);
471 Display_Error ("Cannot perform play audio command!");
473 global
->playing
= !global
->playing
;
477 if (!(signals
& global
->g_dos_sigbit
))
479 while ((msg
= GetMsg(&global
->DosProc
->pr_MsgPort
)))
481 packet
= (PACKET
*)msg
->mn_Node
.ln_Name
;
482 packet
->dp_Res1
= DOSTRUE
;
487 "[CDVDFS]\tPacket: %3ld %08lx %08lx %08lx %10s ",
492 typetostr(packet
->dp_Type
)
496 switch (packet
->dp_Type
)
498 /* packets we will handle even if the SCSI device is not yet open: */
501 /* packets we cannot handle because the SCSI device is not yet open: */
503 packet
->dp_Res1
= DOSFALSE
;
505 some return codes cause the WB to pop a requester; we don't
506 want this, though. Therefore we use this "exotic" return code:
508 packet
->dp_Res2
= ERROR_INVALID_COMPONENT_NAME
;
509 BUG(dbprintf(global
, "ERR=%ld\n", (LONG
) packet
->dp_Res2
);)
510 returnpacket(global
, packet
);
514 else if (global
->g_inhibited
)
516 switch (packet
->dp_Type
)
518 /* packets we will handle even if the handler is inhibited: */
521 case ACTION_MORE_CACHE
:
522 case ACTION_DISK_INFO
:
524 /* packets we cannot handle because the handler is inhibited: */
526 packet
->dp_Res1
= DOSFALSE
;
527 packet
->dp_Res2
= ERROR_NOT_A_DOS_DISK
;
528 BUG(dbprintf(global
, "ERR=%ld\n", (LONG
) packet
->dp_Res2
);)
529 returnpacket(global
, packet
);
533 else if (global
->DevList
== NULL
)
535 switch (packet
->dp_Type
)
537 /* packets we will handle even if no disk is inserted: */
540 case ACTION_IS_FILESYSTEM
:
542 case ACTION_MORE_CACHE
:
543 case ACTION_DISK_INFO
:
545 case ACTION_FREE_LOCK
:
547 /* packets we cannot handle because no disk is inserted: */
549 packet
->dp_Res1
= DOSFALSE
;
551 (global
->g_disk_inserted
?
552 ERROR_NOT_A_DOS_DISK
:
555 BUG(dbprintf(global
, "ERR=%ld\n", (LONG
) packet
->dp_Res2
);)
556 returnpacket(global
, packet
);
561 switch(packet
->dp_Type
)
563 case ACTION_DIE
: /* attempt to die? */
564 notdone
= 0; /* try to die */
566 case ACTION_USER
: /* Mode,Par1,Par2 Bool */
567 error
= Handle_Control_Packet
575 case ACTION_FINDINPUT
: /* FileHandle,Lock,Name Bool */
577 if (!(error
= Mount_Check (global
)))
580 CDROM_OBJ
*parentdir
= getlockfile(global
, packet
->dp_Arg2
);
583 if (parentdir
->volume
!= global
->g_volume
)
585 /* old lock from another disk: */
586 error
= ERROR_DEVICE_NOT_MOUNTED
;
589 btos((BSTR
)packet
->dp_Arg3
,buf
);
590 BUG(dbprintf(global
, "'%s' ", buf
);)
591 offs
= Check_For_Volume_Name_Prefix (global
, buf
);
592 if ((obj
= Open_Object (parentdir
, buf
+ offs
)))
596 error
= ERROR_IS_SOFT_LINK
;
599 if (obj
->directory_f
)
601 error
= ERROR_OBJECT_WRONG_TYPE
;
607 if (global
->iso_errno
== ISOERR_ILLEGAL_NAME
)
609 error
= ERROR_INVALID_COMPONENT_NAME
;
612 else if (global
->iso_errno
== ISOERR_NOT_FOUND
)
613 error
= ERROR_OBJECT_NOT_FOUND
;
614 else if (global
->iso_errno
== ISOERR_NO_MEMORY
)
616 error
= ERROR_NO_FREE_STORE
;
619 else if (global
->iso_errno
== ISOERR_IS_SYMLINK
)
621 error
= ERROR_IS_SOFT_LINK
;
632 global
->g_volume
->file_handles
++;
633 ((FH
*)BADDR(packet
->dp_Arg1
))->fh_Arg1
= (IPTR
)obj
;
634 Register_File_Handle (obj
);
640 case ACTION_READ
: /* FHArg1,CPTRBuffer,Length ActLength */
642 CDROM_OBJ
*obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
643 char *ptr
= (char *) packet
->dp_Arg2
;
644 LONG length
= packet
->dp_Arg3
;
647 if (obj
->volume
!= global
->g_volume
)
649 /* old lock from another disk: */
650 error
= ERROR_DEVICE_NOT_MOUNTED
;
653 actual
= Read_From_File (obj
, ptr
, length
);
654 packet
->dp_Res1
= actual
;
657 case ACTION_END
: /* FHArg1 Bool:TRUE */
659 CDROM_OBJ
*obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
661 if (obj
->volume
!= global
->g_volume
)
663 /* old lock from another disk: */
664 error
= ERROR_DEVICE_NOT_MOUNTED
;
667 Unregister_File_Handle (obj
);
669 global
->g_volume
->file_handles
--;
672 case ACTION_SEEK
: /* FHArg1,Position,Mode OldPosition */
674 CDROM_OBJ
*obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
675 LONG offset
= packet
->dp_Arg2
;
676 int mode
= packet
->dp_Arg3
;
678 if (obj
->volume
!= global
->g_volume
)
680 /* old lock from another disk: */
681 error
= ERROR_DEVICE_NOT_MOUNTED
;
684 packet
->dp_Res1
= obj
->pos
;
685 if (!Seek_Position (obj
, offset
, mode
))
687 error
= ERROR_SEEK_ERROR
;
688 packet
->dp_Res1
= -1;
692 case ACTION_EXAMINE_NEXT
: /* Lock,Fib Bool */
694 FIB
*fib
= (FIB
*)BADDR (packet
->dp_Arg2
);
695 CDROM_OBJ
*dir
= getlockfile (global
, packet
->dp_Arg1
);
698 if (dir
->volume
!= global
->g_volume
)
700 /* old lock from another disk: */
701 error
= ERROR_DEVICE_NOT_MOUNTED
;
704 if (!dir
->directory_f
)
706 error
= ERROR_OBJECT_WRONG_TYPE
;
709 if (Examine_Next (dir
, &info
, (ULONG
*) &fib
->fib_DiskKey
))
712 Fill_FileInfoBlock (global
, fib
, &info
, dir
->volume
);
716 error
= ERROR_NO_MORE_ENTRIES
;
720 case ACTION_EXAMINE_FH
: /* FHArg1,Fib Bool */
721 case ACTION_EXAMINE_OBJECT
: /* Lock,Fib Bool */
723 FIB
*fib
= (FIB
*)BADDR(packet
->dp_Arg2
);
727 if (packet
->dp_Type
== ACTION_EXAMINE_FH
)
728 obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
730 obj
= getlockfile (global
, packet
->dp_Arg1
);
731 if (obj
->volume
!= global
->g_volume
)
733 /* old lock from another disk: */
734 error
= ERROR_DEVICE_NOT_MOUNTED
;
737 fib
->fib_DiskKey
= 0;
739 if (!CDROM_Info (obj
, &info
))
742 Fill_FileInfoBlock (global
, fib
, &info
, obj
->volume
);
745 case ACTION_INFO
: /* Lock, InfoData Bool:TRUE */
746 tmp
= (void *)BADDR(packet
->dp_Arg2
);
749 case ACTION_DISK_INFO
: /* InfoData Bool:TRUE */
752 register INFODATA
*id
;
754 id
= (INFODATA
*)(error
? tmp
: (void *)BADDR (packet
->dp_Arg1
));
756 memset (id
, 0, sizeof(*id
));
757 id
->id_UnitNumber
= global
->g_unit
;
758 if (global
->g_inhibited
) {
759 id
->id_DiskType
= 0x42555359 /* "BUSY" */;
761 int errcode
= Mount_Check (global
);
762 if (errcode
== ERROR_NO_DISK
) {
763 id
->id_DiskType
= ID_NO_DISK_PRESENT
;
764 } else if (!errcode
) {
765 id
->id_DiskType
= ID_DOS_DISK
;
766 id
->id_NumBlocks
= Volume_Size (global
->g_volume
);
767 id
->id_BytesPerBlock
= Block_Size (global
->g_volume
);
768 id
->id_VolumeNode
= MKBADDR(global
->DevList
);
770 /* For example empty CD-R */
771 id
->id_DiskType
= ID_UNREADABLE_DISK
;
772 id
->id_NumBlocks
= 0;
773 id
->id_BytesPerBlock
= 2048;
775 id
->id_DiskState
= ID_WRITE_PROTECTED
;
777 id
->id_NumBlocksUsed
= id
->id_NumBlocks
;
781 case ACTION_IS_FILESYSTEM
: /* - Bool */
782 packet
->dp_Res1
= DOSTRUE
;
784 case ACTION_PARENT_FH
: /* FHArg1 ParentLock */
785 case ACTION_PARENT
: /* Lock ParentLock */
787 if (!(error
= Mount_Check (global
)))
794 if (packet
->dp_Type
== ACTION_PARENT_FH
)
795 obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
797 obj
= getlockfile (global
, packet
->dp_Arg1
);
798 if (obj
->volume
!= global
->g_volume
)
800 /* old lock from another disk: */
801 error
= ERROR_DEVICE_NOT_MOUNTED
;
804 if (Is_Top_Level_Object (obj
))
806 packet
->dp_Res1
= packet
->dp_Res2
= 0;
810 parent
= Find_Parent (obj
);
813 if (global
->iso_errno
== ISOERR_NO_MEMORY
)
814 error
= ERROR_NO_FREE_STORE
;
816 error
= ERROR_OBJECT_NOT_FOUND
;
820 packet
->dp_Res1
= (IPTR
)MKBADDR(cdlock (parent
, ACCESS_READ
));
825 error
= ERROR_OBJECT_NOT_FOUND
;
829 case ACTION_LOCATE_OBJECT
: /* Lock,Name,Mode Lock */
831 if (!(error
= Mount_Check (global
)))
833 CDROM_OBJ
*parentdir
= getlockfile (global
, packet
->dp_Arg1
);
837 if (parentdir
->volume
!= global
->g_volume
)
839 /* old lock from another disk: */
840 error
= ERROR_DEVICE_NOT_MOUNTED
;
843 btos ((BSTR
)packet
->dp_Arg2
, buf
);
845 dbprintf (global
, "'%s' %ld ", buf
, packet
->dp_Arg3
);
846 if (strcmp(buf
,"debugoff") == 0)
847 global
->DBDisable
= 1;
848 if (strcmp(buf
,"debugon") == 0)
849 global
->DBDisable
= 0;
851 offs
= Check_For_Volume_Name_Prefix (global
, buf
);
855 obj
= Clone_Object (parentdir
);
857 obj
= Open_Top_Level_Directory (global
->g_volume
);
860 obj
= Open_Object (parentdir
, buf
+ offs
);
864 error
= ERROR_IS_SOFT_LINK
;
866 packet
->dp_Res1
= (IPTR
)MKBADDR(cdlock (obj
, packet
->dp_Arg3
));
870 if (global
->iso_errno
== ISOERR_SCSI_ERROR
)
871 error
= ERROR_SEEK_ERROR
;
872 else if (global
->iso_errno
== ISOERR_ILLEGAL_NAME
)
873 error
= ERROR_INVALID_COMPONENT_NAME
;
874 else if (global
->iso_errno
== ISOERR_NOT_FOUND
)
875 error
= ERROR_OBJECT_NOT_FOUND
;
876 else if (global
->iso_errno
== ISOERR_NO_MEMORY
)
877 error
= ERROR_NO_FREE_STORE
;
878 else if (global
->iso_errno
== ISOERR_IS_SYMLINK
)
879 error
= ERROR_IS_SOFT_LINK
;
886 case ACTION_COPY_DIR
: /* Lock, Lock */
890 CDROM_OBJ
*obj
= getlockfile (global
, packet
->dp_Arg1
);
893 if (obj
->volume
!= global
->g_volume
)
895 /* old lock from another disk: */
896 error
= ERROR_DEVICE_NOT_MOUNTED
;
899 new = Clone_Object (obj
);
901 error
= ERROR_NO_FREE_STORE
;
903 packet
->dp_Res1
= (IPTR
)MKBADDR(cdlock (new, ACCESS_READ
));
909 case ACTION_FREE_LOCK
: /* Lock Bool */
911 cdunlock((LOCK
*)BADDR(packet
->dp_Arg1
));
913 case ACTION_CURRENT_VOLUME
: /* FHArg1 DevList */
915 CDROM_OBJ
*obj
= (CDROM_OBJ
*) packet
->dp_Arg1
;
917 packet
->dp_Res1
= (IPTR
)MKBADDR(Find_Dev_List (obj
));
919 packet
->dp_Res1
= (IPTR
)MKBADDR(global
->DevList
);
922 case ACTION_INHIBIT
: /* Bool Bool */
923 if (packet
->dp_Arg1
!= DOSFALSE
)
925 /* true means forbid access */
926 global
->g_inhibited
++;
929 Hide_CDDA_Icon (global
);
930 global
->g_cd
->t_changeint2
= -2;
934 /* false means access allowed */
935 if (global
->g_inhibited
)
936 global
->g_inhibited
--;
937 if (global
->g_inhibited
== 0)
939 global
->g_disk_inserted
= FALSE
;
945 * FINDINPUT and FINDOUTPUT normally should return the
946 * 'write protected' error. If the field 'Name', however,
947 * designates the root (e.g. CD0:), then the 'wrong type'
948 * error should be returned. Otherwise, AmigaDOS would do
949 * some funny things (such as saying 'Volume CD0: is write-
950 * protected') if you try to mount the handler with the
951 * field 'Mount' set to 1.
953 case ACTION_FINDOUTPUT
: /* Handle Lock Name Bool */
954 case ACTION_FINDUPDATE
: /* Handle Lock Name Bool */
958 btos((BSTR
)packet
->dp_Arg3
,buf
);
959 BUG(dbprintf(global
, "'%s' ", buf
);)
960 if ((pos
= Check_For_Volume_Name_Prefix (global
, buf
)) && buf
[pos
] == 0)
961 error
= ERROR_OBJECT_WRONG_TYPE
;
963 error
= ERROR_DISK_WRITE_PROTECTED
;
966 case ACTION_SAME_LOCK
: /* Lock Lock Bool */
968 CDROM_OBJ
*obj1
= getlockfile(global
, packet
->dp_Arg1
),
969 *obj2
= getlockfile(global
, packet
->dp_Arg2
);
970 if (Same_Objects (obj1
, obj2
))
971 packet
->dp_Res1
= DOSTRUE
;
973 packet
->dp_Res1
= DOSFALSE
;
976 case ACTION_READ_LINK
: /* Lock Name Buf Length NumChar */
979 CDROM_OBJ
*parentdir
= getlockfile (global
, packet
->dp_Arg1
);
980 char *outbuf
= (char *) packet
->dp_Arg3
;
981 t_ulong maxlength
= packet
->dp_Arg4
;
986 if (parentdir
->volume
!= global
->g_volume
)
988 /* old lock from another disk: */
989 error
= ERROR_DEVICE_NOT_MOUNTED
;
992 BUG(dbprintf (global
, "'%s' len=%lu ", packet
->dp_Arg2
, maxlength
);)
993 offs
= Check_For_Volume_Name_Prefix (global
, (char *) packet
->dp_Arg2
);
994 obj
= Open_Object (parentdir
, (char *) packet
->dp_Arg2
+ offs
);
997 res
= Get_Link_Name (obj
, buf
, sizeof (buf
));
1001 strlen (global
->g_vol_name
+1) + 1
1005 strncpy (outbuf
, "illegal_link", maxlength
- 1);
1009 strcpy (outbuf
, global
->g_vol_name
+1);
1012 strcat (outbuf
, buf
);
1014 outbuf
[maxlength
- 1] = 0;
1016 packet
->dp_Res1
= strlen (outbuf
);
1020 if (global
->iso_errno
== ISOERR_ILLEGAL_NAME
)
1021 error
= ERROR_INVALID_COMPONENT_NAME
;
1022 else if (global
->iso_errno
== ISOERR_NOT_FOUND
)
1023 error
= ERROR_OBJECT_NOT_FOUND
;
1024 else if (global
->iso_errno
== ISOERR_NO_MEMORY
)
1025 error
= ERROR_NO_FREE_STORE
;
1026 else if (global
->iso_errno
== ISOERR_IS_SYMLINK
)
1027 error
= ERROR_IS_SOFT_LINK
;
1033 case ACTION_MAKE_LINK
:
1034 case ACTION_RENAME_DISK
:
1036 case ACTION_SET_PROTECT
:
1037 case ACTION_DELETE_OBJECT
:
1038 case ACTION_RENAME_OBJECT
:
1039 case ACTION_CREATE_DIR
:
1040 case ACTION_SET_COMMENT
:
1041 case ACTION_SET_DATE
:
1042 case ACTION_SET_FILE_SIZE
:
1043 error
= ERROR_DISK_WRITE_PROTECTED
;
1045 case ACTION_FLUSH
: /* writeout bufs, disk motor off */
1048 * A few other packet types which we do not support
1050 case ACTION_MORE_CACHE
: /* #BufsToAdd Bool */
1051 case ACTION_WAIT_CHAR
: /* Timeout, ticks Bool */
1052 case ACTION_SCREEN_MODE
:/* Bool(-1:RAW 0:CON) OldState */
1054 error
= ERROR_ACTION_NOT_KNOWN
;
1061 BUG(dbprintf(global
, "ERR=%ld\n", error
);)
1062 packet
->dp_Res1
= DOSFALSE
;
1063 packet
->dp_Res2
= error
;
1067 BUG(dbprintf(global
, "RES=%06lx\n", packet
->dp_Res1
));
1069 if (packet
->dp_Type
!= ACTION_DIE
)
1070 returnpacket(global
, packet
);
1072 global
->g_death_packet
= packet
;
1077 BUG(dbprintf(global
, "Can we remove ourselves? ");)
1078 BUG(Delay(100);) /* I wanna even see the debug message! */
1083 packetsqueued(global
) ||
1087 global
->g_volume
->locks
|| global
->g_volume
->file_handles
1094 BUG(dbprintf(global
, " .. not yet!\n");)
1095 return TRUE
; /* sorry... can't exit */
1099 BUG(dbprintf(global
, " .. yes!\n");)
1105 * PACKET ROUTINES. Dos Packets are in a rather strange format as you
1106 * can see by this and how the PACKET structure is extracted in the
1107 * GetMsg() of the main routine.
1110 static void returnpacket(struct CDVDBase
*global
, struct DosPacket
*packet
)
1112 register struct Message
*mess
;
1113 register struct MsgPort
*replyport
;
1115 replyport
= packet
->dp_Port
;
1116 mess
= packet
->dp_Link
;
1117 packet
->dp_Port
= &global
->DosProc
->pr_MsgPort
;
1118 mess
->mn_Node
.ln_Name
= (char *)packet
;
1119 mess
->mn_Node
.ln_Succ
= NULL
;
1120 mess
->mn_Node
.ln_Pred
= NULL
;
1121 PutMsg(replyport
, mess
);
1125 * Are there any packets queued to our device?
1128 int packetsqueued (struct CDVDBase
*global
)
1130 return ((void *)global
->DosProc
->pr_MsgPort
.mp_MsgList
.lh_Head
!=
1131 (void *)&global
->DosProc
->pr_MsgPort
.mp_MsgList
.lh_Tail
);
1134 #ifndef USE_FAST_BSTR
1136 * Convert a BSTR into a normal string.. copying the string into buf.
1137 * I use normal strings for internal storage, and convert back and forth
1140 static void btos(BSTR bstr
, char *buf
)
1142 UBYTE
*src
= BADDR(bstr
);
1145 CopyMem(src
, buf
, len
);
1151 * The lock function. The file has already been checked to see if it
1152 * is lockable given the mode.
1155 static LOCK
*cdlock(CDROM_OBJ
*cdfile
, int mode
)
1157 struct CDVDBase
*global
= cdfile
->global
;
1158 LOCK
*lock
= AllocVec(sizeof(LOCK
), MEMF_PUBLIC
| MEMF_CLEAR
);
1160 cdfile
->volume
->locks
++;
1161 lock
->fl_Key
= (LONG
) Location (cdfile
);
1162 lock
->fl_Link
= (BPTR
) cdfile
;
1163 lock
->fl_Access
= ACCESS_READ
;
1164 lock
->fl_Task
= &global
->DosProc
->pr_MsgPort
;
1165 lock
->fl_Volume
= (BPTR
)MKBADDR(global
->DevList
);
1166 Register_Lock (lock
);
1170 static void cdunlock (LOCK
*lock
)
1172 CDROM_OBJ
*obj
= (CDROM_OBJ
*) lock
->fl_Link
;
1173 struct CDVDBase
*global
= obj
->global
;
1175 Unregister_Lock (lock
);
1176 --obj
->volume
->locks
;
1178 /* if all locks and filehandles have been removed, and if the volume
1179 * is not the current volume, then the volume node may be removed:
1181 if (obj
->volume
!= global
->g_volume
&&
1182 obj
->volume
->locks
== 0 && obj
->volume
->file_handles
== 0) {
1183 VOLUME
*vol
= obj
->volume
;
1186 Remove_Volume_Node (global
, vol
->devlist
);
1190 Send_Event (global
, FALSE
);
1194 FreeVec(lock
); /* free lock */
1198 * GETLOCKFILE(bptrlock)
1200 * Return the CDROM_OBJ (file or directory) associated with the
1201 * given lock, which is passed as a BPTR.
1203 * According to the DOS spec, the only way a NULL lock will ever be
1204 * passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
1205 * In anycase, If a NULL lock is passed to me I simply assume it means
1206 * the root directory of the CDROM.
1209 CDROM_OBJ
*getlockfile (struct CDVDBase
*global
, IPTR lock
)
1211 LOCK
*rl
= (LOCK
*)BADDR (lock
);
1214 return (CDROM_OBJ
*) rl
->fl_Link
;
1215 return global
->g_top_level_obj
;
1219 * If p_pathname contains a ':' character, return the position of the first
1220 * character after ':'
1221 * Otherwise, return 0.
1224 int Check_For_Volume_Name_Prefix (struct CDVDBase
*global
, char *p_pathname
)
1226 char *pos
= strchr (p_pathname
, ':');
1228 return pos
? (pos
- p_pathname
) + 1 : 0;
1232 * Fills a FileInfoBlock with the information contained in the
1233 * directory record of a CD-ROM directory or file.
1236 static void Fill_FileInfoBlock (struct CDVDBase
*global
, FIB
*p_fib
, CDROM_INFO
*p_info
, VOLUME
*p_volume
)
1238 char *src
= p_info
->name
;
1239 char *dest
= p_fib
->fib_FileName
;
1240 int len
= p_info
->name_length
;
1242 if (len
> MAX_NAME_LEN
)
1244 if (p_info
->symlink_f
)
1245 p_fib
->fib_DirEntryType
= ST_SOFTLINK
;
1247 p_fib
->fib_DirEntryType
= p_info
->directory_f
? ST_USERDIR
: ST_FILE
;
1249 if (len
== 1 && *src
== ':')
1251 /* root of file system: */
1252 p_fib
->fib_DirEntryType
= ST_ROOT
;
1253 /* file name == volume name: */
1254 len
= global
->g_vol_name
[0];
1256 strncpy(dest
, global
->g_vol_name
+1, len
);
1260 /* copy file name: */
1261 if (!global
->g_show_version_numbers
)
1264 for (i
=0; i
<len
; i
++)
1266 if (src
[i
] == ';') {
1273 strncpy(dest
, src
, len
);
1275 if ((global
->g_map_to_lowercase
&& p_volume
->protocol
== PRO_ISO
) ||
1276 (global
->g_maybe_map_to_lowercase
&& !p_volume
->mixed_char_filenames
))
1278 /* convert ISO filename to lowercase: */
1281 for (i
=0; i
<len
; i
++, cp
++)
1282 *cp
= ToLower (*cp
);
1285 /* terminate string */
1287 /* I don't know exactly why I have to set fib_EntryType, but other
1288 * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
1291 p_fib
->fib_EntryType
= p_fib
->fib_DirEntryType
;
1293 p_fib
->fib_Protection
= p_info
->protection
;
1294 p_fib
->fib_Size
= p_info
->file_length
;
1295 p_fib
->fib_NumBlocks
= p_info
->file_length
>> 11;
1296 p_fib
->fib_Date
.ds_Days
= p_info
->date
/ (24 * 60 * 60);
1297 p_fib
->fib_Date
.ds_Minute
= (p_info
->date
% (24 * 60 * 60)) / 60;
1298 p_fib
->fib_Date
.ds_Tick
= (p_info
->date
% 60) * TICKS_PER_SECOND
;
1300 dest
= p_fib
->fib_Comment
;
1301 len
= p_info
->comment_length
;
1302 if (len
> MAX_COMMENT_LEN
)
1303 len
= MAX_COMMENT_LEN
;
1305 strncpy(dest
, p_info
->comment
, len
);
1310 * Create Volume node and add to the device list. This will
1311 * cause the WORKBENCH to recognize us as a disk. If we don't
1312 * create a Volume node, Wb will not recognize us.
1315 static void Create_Volume_Node (struct CDVDBase
*global
, LONG p_disk_type
, ULONG p_volume_date
) {
1316 struct DeviceList
*dl
;
1318 BUG(dbprintf(global
, "Inserted volume name: %s\n", global
->g_vol_name
+ 1));
1319 dl
= Find_Volume_Node (global
, global
->g_vol_name
+ 1);
1322 BUG(dbprintf(global
, "[Reusing old volume node]");)
1324 global
->DevList
= dl
;
1325 dl
->dl_Task
= &global
->DosProc
->pr_MsgPort
;
1330 global
->DevList
= dl
= (struct DeviceList
*)MakeDosEntry(global
->g_vol_name
+1, DLT_VOLUME
);
1331 dl
->dl_Task
= &global
->DosProc
->pr_MsgPort
;
1332 dl
->dl_DiskType
= p_disk_type
;
1333 dl
->dl_VolumeDate
.ds_Days
= p_volume_date
/ (24 * 60 * 60);
1334 dl
->dl_VolumeDate
.ds_Minute
= (p_volume_date
% (24 * 60 * 60)) / 60;
1335 dl
->dl_VolumeDate
.ds_Tick
= (p_volume_date
% 60) * TICKS_PER_SECOND
;
1336 BUG(dbprintf(global
, "Name to add: <0x%08lX> %b\n", dl
->dl_Name
, dl
->dl_Name
));
1337 AddDosEntry((struct DosList
*)dl
);
1338 BUG(dbprintf(global
, "Added name: <0x%08lX> %b\n", dl
->dl_Name
, dl
->dl_Name
));
1339 /* Under MorphOS AddDosEntry() can modify volume name in case if such a volume
1340 is already present in the DosList. In this case it reallocates the name string,
1341 appends "_%d" to it and modifies dl_Name. In this case we can lose our
1342 volume node if a user removes a disc while some locks are pending and then
1343 puts it back, because we wouldn't be able to find it by name in our list.
1344 A typical case is using CDVDFS under MorphOS along with built-in MorphOS
1346 Register_Volume_Node (global
, dl
, global
->g_vol_name
+ 1);
1354 static void Mount (struct CDVDBase
*global
)
1358 if (Has_Audio_Tracks (global
->g_cd
)) {
1359 Show_CDDA_Icon (global
);
1360 global
->g_cd
->t_changeint2
= global
->g_cd
->t_changeint
;
1363 global
->g_volume
= Open_Volume (global
->g_cd
, global
->g_use_rock_ridge
, global
->g_use_joliet
);
1364 if (!global
->g_volume
) {
1365 BUG(dbprintf (global
, "!!! cannot open VOLUME (iso_errno=%d) !!!\n", global
->iso_errno
);)
1368 global
->g_disk_inserted
= TRUE
;
1369 global
->g_cd
->t_changeint2
= global
->g_cd
->t_changeint
;
1370 global
->g_top_level_obj
= Open_Top_Level_Directory (global
->g_volume
);
1371 if (!global
->g_top_level_obj
) {
1372 BUG(dbprintf (global
, "!!! cannot open top level directory !!!\n");)
1377 BUG(dbprintf (global
, "***mounting*** ");)
1378 Volume_ID (global
->g_volume
, buf
, sizeof (buf
)-1);
1379 global
->g_vol_name
[0] = strlen (buf
);
1380 CopyMem(buf
, global
->g_vol_name
+1, strlen (buf
));
1382 if (!(global
->g_vol_name
[0]))
1383 CopyMem("\7Unnamed", global
->g_vol_name
, 8);
1385 /* AmigaDOS expects the BCPL string g_vol_name to be null-terminated: */
1386 global
->g_vol_name
[(int)(global
->g_vol_name
[0])+1] = 0;
1388 /* convert ISO volume name to lowercase: */
1389 if ((global
->g_map_to_lowercase
&& global
->g_volume
->protocol
== PRO_ISO
) ||
1390 (global
->g_maybe_map_to_lowercase
&& !global
->g_volume
->mixed_char_filenames
)) {
1392 for (i
=0; i
<global
->g_vol_name
[0]; i
++)
1393 global
->g_vol_name
[i
+1] = ToLower (global
->g_vol_name
[i
+1]);
1396 global
->g_volume
->locks
= Reinstall_Locks (global
);
1397 global
->g_volume
->file_handles
= Reinstall_File_Handles (global
);
1399 Create_Volume_Node (global
, ID_CDFS_DISK
, Volume_Creation_Date (global
->g_volume
));
1400 global
->g_volume
->devlist
= global
->DevList
;
1401 global
->g_cd
->t_changeint2
= global
->g_cd
->t_changeint
;
1402 Send_Event (global
, TRUE
);
1405 /* Remove a volume node from the DOS list.
1406 * (Must be nested between Forbid() and Permit()!)
1407 * Since DOS uses singly linked lists, we must (ugg) search it manually to find
1408 * the link before our Volume entry.
1411 static void Remove_Volume_Node (struct CDVDBase
*global
, struct DeviceList
* p_volume
)
1415 Unregister_Volume_Node (global
, p_volume
);
1417 dl
= LockDosList(LDF_WRITE
| LDF_VOLUMES
);
1420 RemDosEntry((struct DosList
*)p_volume
);
1421 FreeDosEntry((struct DosList
*)p_volume
);
1422 UnLockDosList(LDF_WRITE
| LDF_VOLUMES
);
1426 /* Unmount a volume, and optionally unload the handler code.
1429 static void Unmount (struct CDVDBase
*global
)
1431 global
->g_cd
->t_changeint2
= global
->g_cd
->t_changeint
;
1432 Hide_CDDA_Icon (global
);
1434 if (global
->DevList
) {
1436 BUG(dbprintf(global
, "***unmounting*** ");)
1438 Close_Object (global
->g_top_level_obj
);
1440 if (global
->g_volume
->locks
== 0 && global
->g_volume
->file_handles
== 0) {
1441 Remove_Volume_Node (global
, global
->DevList
);
1442 Close_Volume (global
->g_volume
);
1444 BUG(dbprintf(global
, "[there are still %d locks on this volume]",
1445 global
->g_volume
->locks
);)
1446 BUG(dbprintf(global
, "[there are still %d file handles on this volume]",
1447 global
->g_volume
->file_handles
);)
1448 global
->DevList
->dl_Task
= NULL
;
1451 global
->DevList
= NULL
;
1454 Send_Event (global
, FALSE
);
1456 global
->g_volume
= 0;
1458 /* when the handler code exits the corresponding device
1459 * node (e.g. "CD0") will be modified. The handler code
1460 * will be unloaded and the task entry will be set to
1461 * zero, so the next device access will reload and
1462 * restart the handler code.
1467 * Mount_Check returns 0 if a valid disk is inserted in the drive.
1468 * Error code is returned if drive is empty or disk is unknown.
1469 * A check is only performed if previously the drive was empty.
1472 int Mount_Check (struct CDVDBase
*global
)
1474 D(bug("[CDVDFS]\tMount_Check\n"));
1475 if (!global
->g_disk_inserted
) {
1477 * No disk was inserted up to now: we will check whether
1478 * a disk has been inserted by sending the test unit ready
1479 * command. We have to send the command twice because
1480 * the first SCSI command after inserting a new disk is
1483 if (0 == Test_Unit_Ready (global
->g_cd
))
1485 D(bug("[CDVDFS]\tDrive not ready, not mounting\n"));
1486 return ERROR_NO_DISK
;
1489 D(bug("[CDVDFS]\tDrive ready, mounting disc\n"));
1490 global
->g_disk_inserted
= TRUE
;
1492 if (!global
->DevList
)
1493 return ERROR_NO_DISK
;
1495 D(bug("[CDVDFS]\tDisc already mounted.\n"));
1497 if (global
->g_volume
== NULL
|| global
->g_volume
->handler
== NULL
)
1498 return ERROR_NOT_A_DOS_DISK
;
1503 * Open timer device structures:
1506 int Open_Timer_Device (struct CDVDBase
*global
) {
1508 global
->g_timer_mp
= CreateMsgPort();
1509 if (global
->g_timer_mp
)
1511 global
->g_timer_io
= (struct timerequest
*)CreateIORequest
1514 sizeof (struct timerequest
)
1516 if (global
->g_timer_io
)
1523 (struct IORequest
*)global
->g_timer_io
,
1528 global
->g_timer_sigbit
= 1L << global
->g_timer_mp
->mp_SigBit
;
1533 BUG(dbprintf (global
, "cannot open timer device!\n");)
1535 DeleteIORequest ((struct IORequest
*) global
->g_timer_io
);
1539 BUG(dbprintf (global
, "cannot create timer i/o structure!\n");)
1541 DeleteMsgPort (global
->g_timer_mp
);
1545 BUG(dbprintf (global
, "cannot create timer message port!\n");)
1551 * Remove timer device structures:
1554 static void Cleanup_Timer_Device (struct CDVDBase
*global
)
1556 /* remove any pending requests: */
1557 if (!CheckIO ((struct IORequest
*) global
->g_timer_io
))
1558 AbortIO ((struct IORequest
*) global
->g_timer_io
);
1559 WaitIO ((struct IORequest
*) global
->g_timer_io
);
1561 CloseDevice ((struct IORequest
*) global
->g_timer_io
);
1562 DeleteIORequest ((struct IORequest
*) global
->g_timer_io
);
1563 DeleteMsgPort (global
->g_timer_mp
);
1567 * Send timer request
1570 static void Send_Timer_Request (struct CDVDBase
*global
)
1572 global
->g_timer_io
->tr_node
.io_Command
= TR_ADDREQUEST
;
1573 global
->g_timer_io
->tr_time
.tv_secs
= 1;
1574 global
->g_timer_io
->tr_time
.tv_micro
= 0;
1575 SendIO ((struct IORequest
*) global
->g_timer_io
);
1579 * Check whether the disk has been removed or inserted.
1582 static void Check_Disk (struct CDVDBase
*global
)
1587 BUG(dbprintf (global
, "[CDVDFS]\tChecking Disk... ");)
1588 i
= Test_Unit_Ready (global
->g_cd
);
1590 l1
= global
->g_cd
->t_changeint
;
1591 l2
= global
->g_cd
->t_changeint2
;
1592 BUG(if (l1
==l2
&& i
) dbprintf (global
, "no disk change (T %ld)", l1
);)
1595 global
->g_disk_inserted
= TRUE
;
1596 BUG(dbprintf (global
, "disk has been inserted (T %ld)", l1
);)
1597 if (global
->DevList
)
1600 Clear_Sector_Buffers (global
->g_cd
);
1603 BUG(if (l1
==l2
&& !i
) dbprintf (global
, "no disk in drive (T %ld)", l1
);)
1606 global
->g_disk_inserted
= FALSE
;
1607 BUG(dbprintf (global
, "disk has been removed (T %ld)", l1
);)
1608 global
->playing
= FALSE
;
1610 global
->g_cd
->t_changeint2
= global
->g_cd
->t_changeint
;
1612 BUG(dbprintf (global
, "\n");)
1615 /* The following lines will generate a `disk inserted/removed' event, in order
1616 * to get Workbench to rescan the DosList and update the list of
1620 static void Send_Event (struct CDVDBase
*global
, int p_inserted
)
1622 struct IOStdReq
*InputRequest
;
1623 struct MsgPort
*InputPort
;
1624 struct InputEvent InputEvent
;
1627 InputPort
= (struct MsgPort
*) CreateMsgPort ();
1630 InputRequest
= (struct IOStdReq
*)
1631 CreateIORequest (InputPort
, sizeof (struct IOStdReq
));
1634 if (!OpenDevice ((UBYTE
*) "input.device", 0,
1635 (struct IORequest
*) InputRequest
, 0))
1637 memset (&InputEvent
, 0, sizeof (struct InputEvent
));
1639 InputEvent
.ie_Class
= p_inserted
? IECLASS_DISKINSERTED
:
1640 IECLASS_DISKREMOVED
;
1642 InputRequest
->io_Command
= IND_WRITEEVENT
;
1643 InputRequest
->io_Data
= &InputEvent
;
1644 InputRequest
->io_Length
= sizeof (struct InputEvent
);
1646 DoIO ((struct IORequest
*) InputRequest
);
1648 CloseDevice ((struct IORequest
*) InputRequest
);
1650 DeleteIORequest ((struct IORequest
*)InputRequest
);
1652 DeleteMsgPort (InputPort
);