3 * Support routines for the device handler.
7 * ----------------------------------------------------------------------
8 * This code is (C) Copyright 1993,1994 by Frank Munkert.
9 * (C) Copyright 2002-2011 The AROS Development Team
10 * All rights reserved.
11 * This software may be freely distributed and redistributed for
12 * non-commercial purposes, provided this notice is included.
13 * ----------------------------------------------------------------------
16 * 18-Dec-11 twilen - SCANINTERVAL=-1: Use media change interrupt.
17 * 11-Aug-10 sonic - Fixed for 64-bit compatibility
18 * 08-Apr-07 sonic - removed redundant "TRACKDISK" option
19 * 31-Mar-07 sonic - merged together 2 versions of Get_Startup(), changed
20 * startup mechanism under AmigaOS/MorphOS
22 * - added character set translation support for Joliet
23 * 20-Jul-02 sheutlin - made 2 Versions of Get_Startup() because AROS
24 * doesn't understand startup fields (yet)
25 * - put last part of Get_Startup() into an own function
26 * (OpenCDRom()) and optimized it a little bit
27 * 12-Oct-94 fmu Get_Startup() modified.
28 * 17-May-94 fmu New option MAYBELOWERCASE (=ML).
29 * 09-Apr-94 fmu Larger buffer for startup strings.
30 * 02-Jan-94 fmu New options XPOS and YPOS.
31 * 11-Dec-93 fmu Memory type can now be chosen by the user:
32 * new options CHIP, DMA and ANY.
33 * 11-Dec-93 fmu The assembly code stubs for the debugging process
34 * are no longer necessary; the debugger code is now
35 * called with CreateNewProcTags().
36 * 21-Nov-93 fmu New option SCANINTERVAL.
37 * 14-Nov-93 fmu Added Handle_Control_Packet for 'cdcontrol' program.
38 * 10-Nov-93 fmu New options SHOWVERSION and HFSFIRST.
39 * 23-Oct-93 fmu MacHFS options added.
40 * 15-Oct-93 fmu Adapted to new VOLUME structure.
41 * 07-Jul-02 sheutlin various changes when porting to AROS
42 * - global variables are now in struct Global global
43 * - "Version" is defined somewhere else (struct Resident)
44 * - replaced memcpy by CopyMem
48 * Extract information from Mountlist "Startup" field.
51 #define USE_INLINE_STDARG
53 #include <proto/exec.h>
54 #include <proto/dos.h>
60 #include <exec/resident.h>
61 #include <exec/types.h>
62 #include <dos/dostags.h>
63 #include <dos/rdargs.h>
65 #include "aros_stuff.h"
70 #include "cdcontrol.h"
74 int OpenCDRom(struct CDVDBase
*global
) {
76 global
->g_cd
= Open_CDROM
81 global
->g_memory_type
,
82 global
->g_std_buffers
,
83 global
->g_file_buffers
87 global
->g_disk_inserted
=
89 Test_Unit_Ready (global
->g_cd
) ||
90 Test_Unit_Ready (global
->g_cd
)
95 global
->g_retry_mode
&&
96 global
->g_cdrom_errno
!= CDROMERR_NO_MEMORY
&&
97 global
->g_cdrom_errno
!= CDROMERR_MSGPORT
&&
98 global
->g_cdrom_errno
!= CDROMERR_IOREQ
103 switch (global
->g_cdrom_errno
)
105 case CDROMERR_NO_MEMORY
:
108 "Out of memory: cannot allocate buffers\n"
109 "(Try changing BufMemType option.)"
112 case CDROMERR_MSGPORT
:
113 Display_Error ("Cannot open the message port.");
116 Display_Error ("Cannot open the I/O request structure.");
118 case CDROMERR_DEVICE
:
121 "Cannot open \"%s\" unit %ld",
122 (IPTR
)global
->g_device
, global
->g_unit
125 case CDROMERR_BLOCKSIZE
:
126 Display_Error ("Cannot access CDROM drive: illegal blocksize.");
134 int Get_Startup(struct CDVDBase
*global
,struct FileSysStartupMsg
*fssm
) {
155 STRPTR Args
[ARGCOUNT
] = {0};
157 UBYTE LocalBuffer
[250];
158 struct RDArgs
*ArgsPtr
;
159 int result
= FALSE
,len
,i
;
162 if (fssm
!= (struct FileSysStartupMsg
*)-1)
164 len
= AROS_BSTR_strlen(fssm
->fssm_Device
);
165 if (len
<sizeof(global
->g_device
))
167 de
= (struct DosEnvec
*)BADDR(fssm
->fssm_Environ
);
168 CopyMem(AROS_BSTR_ADDR(fssm
->fssm_Device
), global
->g_device
, len
);
169 global
->g_device
[len
] = 0;
170 global
->g_unit
= fssm
->fssm_Unit
;
171 global
->g_std_buffers
= de
->de_NumBuffers
;
172 global
->g_file_buffers
= de
->de_NumBuffers
;
173 global
->g_memory_type
= de
->de_BufMemType
;
174 // global->g_memory_type = MEMF_ANY;
176 global
->g_retry_mode
= FALSE
;
177 global
->g_map_to_lowercase
= FALSE
;
178 global
->g_maybe_map_to_lowercase
= TRUE
;
179 global
->g_use_rock_ridge
= TRUE
;
180 global
->g_use_joliet
= TRUE
;
181 global
->g_show_version_numbers
= FALSE
;
182 global
->g_hfs_first
= FALSE
;
183 strcpy(global
->g_data_fork_extension
, "dfork");
184 strcpy(global
->g_resource_fork_extension
, "rfork");
185 global
->g_convert_hfs_filenames
= FALSE
;
186 global
->g_convert_hfs_spaces
= FALSE
;
187 global
->g_scan_interval
= 3;
188 global
->g_play_cdda_command
[0] = 0;
189 global
->g_xpos
= NO_ICON_POSITION
;
190 global
->g_ypos
= NO_ICON_POSITION
;
192 if (de
->de_Control
) {
193 /* Get the contents of the control field. */
194 len
= AROS_BSTR_strlen(de
->de_Control
);
195 if (len
> sizeof (LocalBuffer
) - 1)
196 len
= sizeof (LocalBuffer
) - 1;
197 CopyMem (AROS_BSTR_ADDR(de
->de_Control
), LocalBuffer
, len
);
199 /* Provide null-termination. */
200 LocalBuffer
[len
] = 0;
202 /* Remove leading quotes. */
203 for (i
= 0 ; i
< len
; i
++) {
204 if (LocalBuffer
[i
] != ' ') {
205 if (LocalBuffer
[i
] == '\"')
206 LocalBuffer
[i
] = ' ';
212 /* Remove trailing quotes. */
213 for (i
= len
- 1 ; i
>= 0 ; i
--) {
214 if (LocalBuffer
[i
] != ' '){
215 if (LocalBuffer
[i
] == '\"')
216 LocalBuffer
[i
] = ' ';
221 /* Replace "+" by spaces, except "++" which is replaced by "+". */
223 for (i
= 0 ; i
< len
; i
++) {
224 if (LocalBuffer
[i
] == '+') {
225 if (i
+1 < len
&& LocalBuffer
[i
+1] == '+') {
231 *Index
++ = LocalBuffer
[i
];
234 /* Provide termination. */
237 BUG(dbprintf("Control string: %s", LocalBuffer
);)
239 ArgsPtr
= (struct RDArgs
*)AllocDosObject(DOS_RDARGS
, NULL
);
242 /* Don't prompt for input! */
243 ArgsPtr
-> RDA_Flags
|= RDAF_NOPROMPT
;
245 /* Set up for local parsing. */
246 ArgsPtr
->RDA_Source
.CS_Buffer
= LocalBuffer
;
247 ArgsPtr
->RDA_Source
.CS_Length
= strlen ((char *) LocalBuffer
);
248 ArgsPtr
->RDA_Source
.CS_CurChr
= 0;
250 /* Read the arguments. */
251 if (ReadArgs ((UBYTE
*)
252 "RETRY/S,L=LOWERCASE/S,ML=MAYBELOWERCASE/S,"
253 "R=ROCKRIDGE/S,J=JOLIET/S,"
254 "MI=MACTOISO/S,CS=CONVERTSPACES/S,"
255 "SV=SHOWVERSION/S,HF=HFSFIRST/S,"
256 "FB=FILEBUFFERS/K/N,"
257 "DE=DATAEXT/K,RE=RESOURCEEXT/K,"
258 "SI=SCANINTERVAL/K/N,PC=PLAYCDDA/K,"
259 "X=XPOS/K/N,Y=YPOS/K/N,",
260 (IPTR
*) Args
, ArgsPtr
)) {
263 global
->g_retry_mode
= (Args
[ARG_RETRY
] != NULL
);
264 global
->g_map_to_lowercase
= (Args
[ARG_LOWERCASE
] != NULL
);
265 global
->g_maybe_map_to_lowercase
= (Args
[ARG_MAYBELOWERCASE
] != NULL
);
267 if (global
->g_map_to_lowercase
&& global
->g_maybe_map_to_lowercase
) {
268 Display_Error ("Options L and ML are mutually exclusive!");
272 global
->g_use_rock_ridge
= (Args
[ARG_ROCKRIDGE
] != NULL
);
273 global
->g_use_joliet
= (Args
[ARG_JOLIET
] != NULL
);
274 global
->g_show_version_numbers
= (Args
[ARG_SHOWVERSION
] != NULL
);
275 global
->g_hfs_first
= (Args
[ARG_HFSFIRST
] != NULL
);
277 if (Args
[ARG_FILEBUFFERS
]) {
278 global
->g_file_buffers
= *(long *) (Args
[ARG_FILEBUFFERS
]);
279 if (global
->g_file_buffers
<= 0) {
280 Display_Error ("Illegal number of file buffers: %ld", global
->g_std_buffers
);
285 if (Args
[ARG_DATAEXT
])
286 strcpy (global
->g_data_fork_extension
, (char *) Args
[ARG_DATAEXT
]);
288 if (Args
[ARG_RESOURCEEXT
])
289 strcpy (global
->g_resource_fork_extension
, (char *) Args
[ARG_RESOURCEEXT
]);
291 global
->g_convert_hfs_filenames
= (Args
[ARG_MACTOISO
] != NULL
);
292 global
->g_convert_hfs_spaces
= (Args
[ARG_CONVERTSPACES
] != NULL
);
294 if (Args
[ARG_SCANINTERVAL
]) {
295 global
->g_scan_interval
= *(long *) (Args
[ARG_SCANINTERVAL
]);
298 if (Args
[ARG_PLAYCDDA
]) {
299 len
= strlen((char *) (Args
[ARG_PLAYCDDA
]));
301 if (len
>= sizeof (global
->g_play_cdda_command
)) {
302 Display_Error ("PLAYCDDA command name too long");
305 strcpy (global
->g_play_cdda_command
, (char *) (Args
[ARG_PLAYCDDA
]));
309 global
->g_xpos
= *(LONG
*) (Args
[ARG_XPOS
]);
311 global
->g_ypos
= *(LONG
*) (Args
[ARG_YPOS
]);
315 Fault(IoErr (), (UBYTE
*) "", LocalBuffer
, sizeof (LocalBuffer
));
316 Display_Error ("Error while parsing \"Control\" field in Mountlist:\n%s",
317 (IPTR
)LocalBuffer
+ 2);
320 FreeDosObject (DOS_RDARGS
, ArgsPtr
);
322 Display_Error ("Out of memory");
325 BUG(dbprintf(global
, "Use RockRidge: %ld\n", global
->g_use_rock_ridge
);)
326 BUG(dbprintf(global
, "Use joliet: %ld\n", global
->g_use_joliet
);)
327 BUG(dbprintf(global
, "Force lowercase: %ld\n", global
->g_map_to_lowercase
);)
328 BUG(dbprintf(global
, "Allow lowercase: %ld\n", global
->g_maybe_map_to_lowercase
);)
332 return OpenCDRom(global
);
337 int Handle_Control_Packet (struct CDVDBase
*global
, ULONG p_type
, IPTR p_par1
, IPTR p_par2
)
340 case CDCMD_LOWERCASE
:
341 global
->g_map_to_lowercase
= p_par1
;
344 global
->g_convert_hfs_filenames
= p_par1
;
346 case CDCMD_CONVERTSPACES
:
347 global
->g_convert_hfs_spaces
= p_par1
;
349 case CDCMD_SHOWVERSION
:
350 global
->g_show_version_numbers
= p_par1
;
353 global
->g_hfs_first
= p_par1
;
356 strcpy (global
->g_data_fork_extension
, (char *) p_par1
);
358 case CDCMD_RESOURCEEXT
:
359 strcpy (global
->g_resource_fork_extension
, (char *) p_par1
);
367 char *typetostr (int ty
)
370 case ACTION_DIE
: return("DIE");
371 case ACTION_FINDUPDATE
: return("OPEN-RW");
372 case ACTION_FINDINPUT
: return("OPEN-OLD");
373 case ACTION_FINDOUTPUT
: return("OPEN-NEW");
374 case ACTION_READ
: return("READ");
375 case ACTION_WRITE
: return("WRITE");
376 case ACTION_END
: return("CLOSE");
377 case ACTION_SEEK
: return("SEEK");
378 case ACTION_EXAMINE_NEXT
: return("EXAMINE NEXT");
379 case ACTION_EXAMINE_OBJECT
: return("EXAMINE OBJ");
380 case ACTION_INFO
: return("INFO");
381 case ACTION_DISK_INFO
: return("DISK INFO");
382 case ACTION_PARENT
: return("PARENTDIR");
383 case ACTION_DELETE_OBJECT
: return("DELETE");
384 case ACTION_CREATE_DIR
: return("CREATEDIR");
385 case ACTION_LOCATE_OBJECT
: return("LOCK");
386 case ACTION_COPY_DIR
: return("DUPLOCK");
387 case ACTION_FREE_LOCK
: return("FREELOCK");
388 case ACTION_SET_PROTECT
: return("SETPROTECT");
389 case ACTION_SET_COMMENT
: return("SETCOMMENT");
390 case ACTION_RENAME_OBJECT
: return("RENAME");
391 case ACTION_INHIBIT
: return("INHIBIT");
392 case ACTION_RENAME_DISK
: return("RENAME DISK");
393 case ACTION_MORE_CACHE
: return("MORE CACHE");
394 case ACTION_WAIT_CHAR
: return("WAIT FOR CHAR");
395 case ACTION_FLUSH
: return("FLUSH");
396 case ACTION_SCREEN_MODE
: return("SCREENMODE");
397 case ACTION_IS_FILESYSTEM
: return("IS_FILESYSTEM");
398 case ACTION_SAME_LOCK
: return("SAME_LOCK");
399 case ACTION_COPY_DIR_FH
: return("COPY_DIR_FH");
400 case ACTION_PARENT_FH
: return("PARENT_FH");
401 case ACTION_EXAMINE_FH
: return("EXAMINE_FH");
402 case ACTION_FH_FROM_LOCK
: return("FH_FROM_LOCK");
403 case ACTION_CURRENT_VOLUME
: return("CURRENT_VOLUME");
404 case ACTION_READ_LINK
: return("READ LINK");
405 case ACTION_MAKE_LINK
: return("MAKE LINK");
406 case ACTION_USER
: return("USER");
407 default: return("---------UNKNOWN-------");
411 #if !(defined(__AROS__) || defined(__MORPHOS__))
414 * DEBUGGING CODE. You cannot make DOS library calls that access other
415 * devices from within a DOS device driver because they use the same
416 * message port as the driver. If you need to make such calls you must
417 * create a port and construct the DOS messages yourself. I do not
418 * do this. To get debugging info out another PROCESS is created to which
419 * debugging messages can be sent.
421 * You want the priority of the debug process to be larger than the
422 * priority of your DOS handler. This is so if your DOS handler crashes
423 * you have a better idea of where it died from the debugging messages
424 * (remember that the two processes are asyncronous from each other).
428 * BTW, the DOS library used by debugmain() was actually opened by
429 * the device driver. Note: DummyMsg cannot be on debugmain()'s stack
430 * since debugmain() goes away on the final handshake.
433 void SAVEDS
debugmain (void)
441 global
->Dbport
= CreateMsgPort ();
442 fh
= (void *) Open ((UBYTE
*) "con:0/0/640/200/debugwindow", 1006);
443 PutMsg(global
->Dback
, &global
->DummyMsg
);
446 out
= (void *) Open ((UBYTE
*) "PAR:", 1006);
448 out
= (void *) Open ((UBYTE
*) "ram:cd.log", 1006);
452 WaitPort(global
->Dbport
);
453 msg
= GetMsg(global
->Dbport
);
454 len
= msg
->mn_Length
;
457 --len
; /* Fix length up */
458 Write((BPTR
) fh
, msg
+1, len
);
460 Write((BPTR
) out
, msg
+1, len
);
462 FreeMem(msg
,sizeof(MSG
)+len
+1);
468 DeleteMsgPort(global
->Dbport
);
469 PutMsg(global
->Dback
,&global
->DummyMsg
); /* Kill handshake */
472 void dbinit (struct CDVDBase
*global
)
474 TASK
*task
= FindTask(NULL
);
476 if (CreateNewProcTags (
479 NP_Priority
, task
->tc_Node
.ln_Pri
+1,
482 WaitPort(global
->Dback
); /* handshake startup */
483 GetMsg(global
->Dback
); /* remove dummy msg */
484 dbprintf("Debugger running:" HANDLER_VERSION
"%s, %s\n",
485 #define asString(x) #x
487 "SAS/C" asString(__VERSION__
) "." asString(__REVISION__
),
488 #elif defined(__GNUC__)
489 "GNU C " __VERSION__
,
501 if (global
->Dbport
) {
502 killmsg
.mn_Length
= 0; /* 0 means die */
503 PutMsg(global
->Dbport
,&killmsg
);
504 WaitPort(global
->Dback
); /* He's dead jim! */
505 GetMsg(global
->Dback
);
508 * Since the debug process is running at a greater priority, I
509 * am pretty sure that it is guarenteed to be completely removed
510 * before this task gets control again. Still, it doesn't hurt...
513 Delay(100); /* ensure he's dead */
517 void dbprintf (struct CDVDBase
*global
, char *format
, ...)
523 va_start (arg
, format
);
524 if (global
->Dbport
&& !global
->DBDisable
) {
525 vsprintf (buf
, format
, arg
);
526 msg
= AllocMem(sizeof(MSG
)+strlen(buf
)+1, MEMF_PUBLIC
|MEMF_CLEAR
);
527 msg
->mn_Length
= strlen(buf
)+1; /* Length NEVER 0 */
528 strcpy((char *) (msg
+1), buf
);
529 PutMsg(global
->Dbport
,msg
);
534 /* This hack is intended to suppress linking DOS access functions from libnix.
535 Libnix v1.2 is written badly and vsprintf() uses the same code as vfprintf()
536 whicn in turn relies on fputc(). This causes linker to add whole
537 dos.library-based I/O stuff to the code together with BREAK checking
538 functions. One of bad effects of this is that the handler can't be linked at
539 all due to lack of exit() function (i think even if it would link it is
540 unlikely to work properly) */
546 #endif /* !(__AROS__ || __MORPHOS__) */