home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 1 / FFMCD01.bin / useful / dist / other / amicdrom / device.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-27  |  36.5 KB  |  1,381 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) CDROM filing system.
  4.  * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  * 
  14.  * 27-Sep-93   fmu   - Added ACTION_SAME_LOCK
  15.  * 25-Sep-93   fmu   - Send 'disk inserted' / 'disk removed' event via
  16.  *                     input.device if disk has been changed.
  17.  *                   - Corrected bug in ACTION_DISK_INFO.
  18.  * 24-Sep-93   fmu   - Added fast memory option 'F'.
  19.  *                   - Added ACTION_IS_FILESYSTEM.
  20.  *                   - Added 'write protected' error for write actions.
  21.  *                   - Added ACTION_CURRENT_VOLUME.
  22.  *                   - Unload handler code after ACTION_DIE.
  23.  *                   - Immediately terminate program if called from CLI.
  24.  *                   - Added library version number.
  25.  *                   - Set volume label to "Unnamed" for disks without name.
  26.  * 16-Sep-93   fmu   Added code to detect whether a lock stems from the
  27.  *                   current volume or from another volume which has
  28.  *                   been removed from the drive.
  29.  */
  30.  
  31. /*
  32.  *  Debugging routines are disabled by simply attempting to open the
  33.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  34.  *  attached to these names (you must be CD'd to TEST:).
  35.  *
  36.  *  See Documentation for a detailed discussion.
  37.  */
  38.  
  39. #include <stdlib.h>
  40. #include <stdarg.h>
  41. #include <string.h>
  42. #include <stdio.h>
  43. #include <ctype.h>
  44.  
  45. #include "device.h"
  46. #include "cdrom.h"
  47. #include "iso9660.h"
  48. #include "intui.h"
  49.  
  50. /*
  51.  *  Since this code might be called several times in a row without being
  52.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  53.  *  for any global/static assignments that might be changed by running the
  54.  *  code.
  55.  */
  56.  
  57. #define CHECK_INTERVAL 3   /* in seconds */
  58.  
  59. PROC    *DosProc;   /*    Our Process                    */
  60. DEVNODE *DosNode;   /*    Our DOS node.. created by DOS for us        */
  61. DEVLIST *DevList;   /*    Device List structure for our volume node   */
  62.  
  63. void    *SysBase;   /*    EXEC library base            */
  64. DOSLIB    *DOSBase;   /*    DOS library base for debug process    */
  65.  
  66. CDROM   *g_cd;
  67. VOLUME  *g_volume;
  68. CDROM_OBJ *g_top_level_obj;
  69. char    *g_vol_name;
  70.  
  71. PORT *g_timer_mp;           /*  timer message port        */
  72. struct timerequest *g_timer_io; /*  timer i/o request        */
  73. ULONG g_timer_sigbit;
  74. ULONG g_dos_sigbit;
  75.  
  76. char    g_device[80];        /* SCSI device name */
  77. short    g_unit;            /* SCSI unit */
  78. short    g_use_rock_ridge;    /* Use Rock Ridge flag 'R' */
  79. short    g_map_to_lowercase;    /* Map to lower case flag 'L' */
  80. int     g_trackdisk;        /* Use trackdisk calls instead of SCSI-direct */
  81. int    g_fastmem;        /* Use fast memory for SCSI buffers */
  82. int    g_files_pending;    /* Number of open file handles */
  83.  
  84. struct MsgPort *DosTask;
  85.  
  86. #ifndef NDEBUG
  87.             /*    DEBUGGING            */
  88. PORT *Dbport;        /*    owned by the debug process    */
  89. PORT *Dback;        /*    owned by the DOS device driver    */
  90. short DBDisable;
  91. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  92. #endif
  93.  
  94. void *dosalloc(ulong);
  95. void dosfree (ulong *);
  96. void btos(LONG, char *);
  97. void *NextNode (NODE *);
  98. void *GetHead (LIST *);
  99. LOCK *cdlock(CDROM_OBJ *, int);
  100. void cdunlock (LOCK *);
  101. CDROM_OBJ *getlockfile (LONG);
  102. char *typetostr (int);
  103. void returnpacket(struct DosPacket *);
  104. int packetsqueued (void);
  105. int Check_For_Volume_Name_Prefix (char *);
  106. void Fill_FileInfoBlock (FIB *, CDROM_INFO *, VOLUME *);
  107. void Copy_ISO_Identifier (char *, char *, int);
  108. void Mount (void);
  109. void Unmount (int);
  110. int Mount_Check (void);
  111. void Check_Disk (void);
  112. void Send_Timer_Request (void);
  113. void Cleanup_Timer_Device (void);
  114. int Open_Timer_Device (void);
  115. int Get_Startup (LONG);
  116. void Send_Event (int);
  117. #ifndef NDEBUG
  118. void dbinit (void);
  119. void dbuninit (void);
  120. void dbprintf (char *, ...);
  121. #endif
  122.  
  123. /*
  124.  *  Don't call the entry point main().  This way, if you make a mistake
  125.  *  with the compile options you'll get a link error.
  126.  */
  127.  
  128. int noname (void)
  129. {
  130.     register PACKET *packet;
  131.     register short   error;
  132.     MSG     *msg;
  133.     ubyte   notdone = 1;
  134.     char    buf[256];
  135.     void    *tmp;
  136.     ULONG   signals;
  137.  
  138.     /*
  139.      *    Initialize all global variables.  SysBase MUST be initialized before
  140.      *    we can make Exec calls.  AbsExecBase is a library symbol
  141.      *    referencing absolute memory location 4.  The DOS library is openned
  142.      *    for the debug process only.
  143.      */
  144.  
  145.     SysBase = AbsExecBase;
  146.     DosProc = (PROC *) FindTask(NULL);
  147.     if (DosProc->pr_CLI)
  148.       return RETURN_FAIL;
  149.     DOSBase = (DOSLIB *) OpenLibrary ((UBYTE *) "dos.library",37);
  150.  
  151.     BUG(DBDisable = 0;)                /*  Init. globals    */
  152.     BUG(Dbport = Dback = NULL;)
  153.     DevList = NULL;
  154.     {
  155.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  156.     msg = GetMsg(&DosProc->pr_MsgPort);
  157.     packet = (PACKET *)msg->mn_Node.ln_Name;
  158.  
  159.     /*
  160.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  161.      *  instance of the device driver for every reference.    E.G. if
  162.      *  you were writing a CON device you would want this field to
  163.      *  be NULL.
  164.      */
  165.  
  166.         DosNode = BTOC(packet->dp_Arg3);
  167.  
  168.     Init_Intui ();
  169.  
  170.     if (DOSBase && Get_Startup (packet->dp_Arg2)) {
  171.         /*
  172.          *    Set dn_Task field which tells DOS not to startup a new
  173.          *    process on every reference.
  174.          */
  175.  
  176.           DosNode->dn_Task = &DosProc->pr_MsgPort;
  177.         packet->dp_Res1 = DOS_TRUE;
  178.          packet->dp_Res2 = 0;
  179.         
  180.         DosTask = DosNode->dn_Task;
  181.  
  182.     } else {                /*    couldn't open dos.library   */
  183.         packet->dp_Res1 = DOS_FALSE;
  184.         returnpacket(packet);
  185.         return;                /*    exit process            */
  186.     }
  187.     returnpacket(packet);
  188.     }
  189.  
  190.     /*
  191.      *    Initialize debugging code
  192.      */
  193.  
  194.     BUG(dbinit();)
  195.  
  196.     /* Initialize timer: */
  197.     if (Open_Timer_Device ())
  198.       Send_Timer_Request ();
  199.     else
  200.       g_timer_sigbit = 0;
  201.  
  202.     /* Mount volume (if any disk is inserted): */
  203.     Mount ();
  204.  
  205.     g_dos_sigbit = 1L << DosProc->pr_MsgPort.mp_SigBit;
  206.  
  207.     g_files_pending = 0;
  208.  
  209.     /*
  210.      *    Here begins the endless loop, waiting for requests over our
  211.      *    message port and executing them.  Since requests are sent over
  212.      *    our message port, this precludes being able to call DOS functions
  213.      *    ourselves (that is why the debugging routines are a separate process)
  214.      */
  215.  
  216. top:
  217.     for (; notdone;) {
  218.     signals = Wait(g_dos_sigbit | g_timer_sigbit);
  219.     if (signals & g_timer_sigbit) {
  220.       GetMsg (g_timer_mp);
  221.       Check_Disk ();
  222.       Send_Timer_Request ();
  223.     }
  224.     if (!(signals & g_dos_sigbit))
  225.       continue;
  226.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  227.         register ubyte *ptr;
  228.         packet = (PACKET *)msg->mn_Node.ln_Name;
  229.         packet->dp_Res1 = DOS_TRUE;
  230.         packet->dp_Res2 = 0;
  231.         error = 0;
  232. #ifndef NDEBUG
  233.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  234.         packet->dp_Type,
  235.         packet->dp_Arg1, packet->dp_Arg2,
  236.         packet->dp_Arg3,
  237.         typetostr(packet->dp_Type)
  238.         );
  239. #endif
  240.  
  241.  
  242.         switch(packet->dp_Type) {
  243.         case ACTION_DIE:        /*    attempt to die?             */
  244.         notdone = 0;        /*    try to die                */
  245.         break;
  246.         case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool    */
  247.         {
  248.             if (Mount_Check ()) {
  249.               CDROM_OBJ *obj;
  250.               CDROM_OBJ *parentdir = getlockfile(packet->dp_Arg2);
  251.               char      *ptr;
  252.               int       offs;
  253.  
  254.               if (parentdir->volume != g_volume) {
  255.                   /* old lock from another disk: */
  256.             error = ERROR_OBJECT_NOT_FOUND;
  257.             goto openbreak;
  258.               }
  259.               
  260.               btos(packet->dp_Arg3,buf);
  261.               BUG(dbprintf("'%s' ", buf);)
  262.               offs = Check_For_Volume_Name_Prefix (buf);
  263.               if (obj = Open_Object (parentdir, buf + offs)) {
  264.             if (obj->directory_f) {
  265.                 error = ERROR_OBJECT_WRONG_TYPE;
  266.                 goto openbreak;
  267.             }
  268.               } else {
  269.             if (iso_errno == ISOERR_ILLEGAL_NAME) {
  270.                 error = ERROR_INVALID_COMPONENT_NAME;
  271.                 goto openbreak;
  272.             } else if (iso_errno == ISOERR_NOT_FOUND)
  273.                   error = ERROR_OBJECT_NOT_FOUND;
  274.             else if (iso_errno == ISOERR_NO_MEMORY) {
  275.               error = ERROR_NO_FREE_STORE;
  276.               goto openbreak;
  277.             } else {
  278.               error = 333;
  279.               goto openbreak;
  280.             }
  281.               }
  282.               if (!error) {
  283.                 g_files_pending++;
  284.               ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long) obj;
  285.               }
  286.             } else
  287.               error = ERROR_NO_DISK;
  288.         }
  289.           openbreak:
  290.         break;
  291.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  292.         {
  293.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  294.             char      *ptr = (char *) packet->dp_Arg2;
  295.             long    length = packet->dp_Arg3;
  296.             int     actual;
  297.  
  298.             if (obj->volume != g_volume) {
  299.               /* old lock from another disk: */
  300.               error = ERROR_OBJECT_NOT_FOUND;
  301.               break;
  302.             }
  303.             actual = Read_From_File (obj, ptr, length);
  304.             packet->dp_Res1 = actual;
  305.         }
  306.         break;
  307.         case ACTION_END:        /*     FHArg1             Bool:TRUE  */
  308.         {
  309.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  310.  
  311.             Close_Object (obj);
  312.             g_files_pending--;
  313.         }
  314.         break;
  315.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  316.             {
  317.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  318.             long offset = packet->dp_Arg2;
  319.             int mode = packet->dp_Arg3;
  320.             
  321.             if (obj->volume != g_volume) {
  322.               /* old lock from another disk: */
  323.               error = ERROR_OBJECT_NOT_FOUND;
  324.               break;
  325.             }
  326.             packet->dp_Res1 = obj->pos;
  327.             if (!Seek_Position (obj, offset, mode)) {
  328.               error = ERROR_SEEK_ERROR;
  329.               packet->dp_Res1 = -1;
  330.             }
  331.         }
  332.         break;
  333.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  334.         {
  335.             FIB       *fib = BTOC (packet->dp_Arg2);
  336.             CDROM_OBJ *dir = getlockfile (packet->dp_Arg1);
  337.             CDROM_INFO info;
  338.  
  339.             if (dir->volume != g_volume) {
  340.               /* old lock from another disk: */
  341.               error = ERROR_OBJECT_NOT_FOUND;
  342.               break;
  343.             }
  344.             if (!dir->directory_f) {
  345.             error = ERROR_OBJECT_WRONG_TYPE;
  346.             break;
  347.             }
  348.             if (Examine_Next (dir, &info,
  349.                           (unsigned long *) &fib->fib_DiskKey)) {
  350.               error = 0;
  351.               Fill_FileInfoBlock (fib, &info, dir->volume);
  352.             } else {
  353.               error = ERROR_NO_MORE_ENTRIES;
  354.             }
  355.             break;
  356.         }
  357.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  358.         {
  359.             FIB *fib = BTOC (packet->dp_Arg2);
  360.                     CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  361.             CDROM_INFO info;
  362.  
  363.             if (obj->volume != g_volume) {
  364.               /* old lock from another disk: */
  365.               error = ERROR_OBJECT_NOT_FOUND;
  366.               break;
  367.             }
  368.             fib->fib_DiskKey = 0;
  369.             error = 0;
  370.             if (!CDROM_Info (obj, &info))
  371.               error = -1;
  372.             else
  373.               Fill_FileInfoBlock (fib, &info, obj->volume);
  374.         }
  375.         break;
  376.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  377.         tmp = BTOC(packet->dp_Arg2);
  378.         error = -1;
  379.         /*  fall through    */
  380.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  381.         {
  382.           if (Mount_Check ()) {
  383.             register INFODATA *id;
  384.  
  385.             (error) ? (id = tmp) : (id = BTOC (packet->dp_Arg1));
  386.             error = 0;
  387.             memset (id, 0, sizeof(*id));
  388.             id->id_DiskState = ID_WRITE_PROTECTED;
  389.             id->id_NumBlocks     = g_volume->pvd.space_size_m;
  390.             id->id_NumBlocksUsed = g_volume->pvd.space_size_m;
  391.             id->id_BytesPerBlock = 2048;
  392.             id->id_DiskType = ID_DOS_DISK;
  393.             id->id_VolumeNode = (long) CTOB (DevList);
  394.             id->id_InUse = 0;
  395.           }
  396.         }
  397.         break;
  398.         case ACTION_IS_FILESYSTEM:   /*  -                      Bool */
  399.           packet->dp_Res1 = DOSTRUE;
  400.           break;
  401.         case ACTION_PARENT:     /*     Lock                ParentLock */
  402.             {
  403.           if (Mount_Check ()) {
  404.             if (packet->dp_Arg1) {
  405.               CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  406.               CDROM_OBJ *parent;
  407.           
  408.               if (obj->volume != g_volume) {
  409.                 /* old lock from another disk: */
  410.                 error = ERROR_OBJECT_NOT_FOUND;
  411.                 break;
  412.               }
  413.               if (Is_Top_Level_Object (obj)) {
  414.                 packet->dp_Res1 = packet->dp_Res2 = 0;
  415.               } else {
  416.                 parent = Find_Parent (obj);
  417.                 if (!parent) {
  418.                   if (iso_errno == ISOERR_NO_MEMORY)
  419.                     error = ERROR_NO_FREE_STORE;
  420.                   else
  421.                     error = ERROR_OBJECT_NOT_FOUND;
  422.                 } else {
  423.                   packet->dp_Res1 = (long)
  424.                 CTOB (cdlock (parent, ACCESS_READ));
  425.                 }
  426.               }
  427.             } else
  428.               error = ERROR_OBJECT_NOT_FOUND;
  429.           } else
  430.             error = ERROR_NO_DISK;
  431.         }
  432.         break;
  433.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  434.         {
  435.           if (Mount_Check ()) {
  436.             CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  437.                     CDROM_OBJ *obj;
  438.             int offs;
  439.  
  440.             if (parentdir->volume != g_volume) {
  441.               /* old lock from another disk: */
  442.               error = ERROR_OBJECT_NOT_FOUND;
  443.               break;
  444.             }
  445.             btos (packet->dp_Arg2, buf);
  446. #ifndef NDEBUG
  447.             dbprintf ("'%s' %ld ", buf, packet->dp_Arg3);
  448.             if (strcmp(buf,"debugoff") == 0)
  449.             DBDisable = 1;
  450.             if (strcmp(buf,"debugon") == 0)
  451.             DBDisable = 0;
  452. #endif
  453.  
  454.             offs = Check_For_Volume_Name_Prefix (buf);
  455.             if (buf[offs]==0) {
  456.               if (parentdir)
  457.                 obj = Clone_Object (parentdir);
  458.               else
  459.                 obj = Open_Top_Level_Directory (g_volume);
  460.             } else
  461.               obj = Open_Object (parentdir, buf + offs);
  462.             
  463.             if (obj) {
  464.               packet->dp_Res1 = (long) CTOB (cdlock (obj, packet->dp_Arg3));
  465.             } else {
  466.               if (iso_errno == ISOERR_SCSI_ERROR) {
  467.                 error = ERROR_OBJECT_NOT_FOUND;
  468.             Unmount (FALSE);
  469.               } else if (iso_errno == ISOERR_ILLEGAL_NAME)
  470.             error = ERROR_INVALID_COMPONENT_NAME;
  471.               else if (iso_errno == ISOERR_NOT_FOUND)
  472.             error = ERROR_OBJECT_NOT_FOUND;
  473.               else if (iso_errno == ISOERR_NO_MEMORY)
  474.                 error = ERROR_NO_FREE_STORE;
  475.               else
  476.                 error = 333;
  477.             }
  478.           } else
  479.             error = ERROR_NO_DISK;
  480.         }
  481.         break;
  482.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  483.             {
  484.           if (packet->dp_Arg1) {
  485.             CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  486.             CDROM_OBJ *new = Clone_Object (obj);
  487.           
  488.             if (!new)
  489.               error = ERROR_NO_FREE_STORE;
  490.             else
  491.               packet->dp_Res1 = (long) CTOB (cdlock (new, ACCESS_READ));
  492.           } else
  493.             packet->dp_Res1 = 0;
  494.         }
  495.         break;
  496.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  497.         if (packet->dp_Arg1);
  498.             cdunlock (BTOC(packet->dp_Arg1));
  499.         break;
  500.         case ACTION_CURRENT_VOLUME: /* -                        DosNode    */
  501.             packet->dp_Res1 = (long) CTOB (DosNode);
  502.             break;
  503.         /*
  504.          *    A few other packet types which we do not support
  505.          */
  506.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  507.         /*  Return success for the hell of it    */
  508.         break;
  509.         /*
  510.          *  FINDINPUT and FINDOUTPUT normally should return the
  511.          *  'write protected' error. If the field 'Name', however,
  512.          *  designates the root (e.g. CD0:), then the 'wrong type'
  513.          *  error should be returned. Otherwise, AmigaDOS would do
  514.          *  some funny things (such as saying 'Volume CD0: is write-
  515.          *  protected') if you try to mount the handler with the
  516.          *  field 'Mount' set to 1.
  517.          */
  518.         case ACTION_FINDOUTPUT: /*   Handle  Lock  Name         Bool       */
  519.         case ACTION_FINDUPDATE: /*   Handle  Lock  Name         Bool       */
  520.         {
  521.           int pos;
  522.           
  523.           btos(packet->dp_Arg3,buf);
  524.           BUG(dbprintf("'%s' ", buf);)
  525.           if ((pos = Check_For_Volume_Name_Prefix (buf)) &&
  526.               buf[pos] == 0)
  527.         error = ERROR_OBJECT_WRONG_TYPE;
  528.           else
  529.         error = ERROR_DISK_WRITE_PROTECTED;
  530.           break;
  531.         }
  532.         case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  533.         {
  534.           CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1),
  535.                     *obj2 = getlockfile(packet->dp_Arg2);
  536.  
  537.               if (obj1->directory_f == obj2->directory_f &&
  538.                   (obj1->dir_record->extent_loc_m ==
  539.            obj2->dir_record->extent_loc_m))
  540.                 packet->dp_Res1 = DOSTRUE;
  541.           else
  542.                 packet->dp_Res1 = DOSFALSE;
  543.  
  544.           break;
  545.         }
  546.         case ACTION_RENAME_DISK:
  547.         case ACTION_WRITE:
  548.         case ACTION_SET_PROTECT:
  549.         case ACTION_DELETE_OBJECT:
  550.         case ACTION_RENAME_OBJECT:
  551.         case ACTION_CREATE_DIR:
  552.         case ACTION_SET_COMMENT:
  553.         case ACTION_SET_DATE:
  554.         case ACTION_SET_FILE_SIZE:
  555.               error = ERROR_DISK_WRITE_PROTECTED;
  556.               break;
  557.         case ACTION_MORE_CACHE: /*     #BufsToAdd            Bool       */
  558.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  559.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  560.         case ACTION_SCREEN_MODE:/*     Bool(-1:RAW 0:CON)        OldState   */
  561.         default:
  562.         error = ERROR_ACTION_NOT_KNOWN;
  563.         break;
  564.         }
  565.         if (packet) {
  566.         if (error) {
  567.             BUG(dbprintf("ERR=%ld\n", error);)
  568.             packet->dp_Res1 = DOS_FALSE;
  569.             packet->dp_Res2 = error;
  570.         } else {
  571.             BUG(dbprintf("RES=%06lx\n", packet->dp_Res1));
  572.         }
  573.         returnpacket(packet);
  574.         }
  575.     }
  576.     }
  577.     BUG(dbprintf("Can we remove ourselves? ");)
  578.     Delay(100);        /*    I wanna even see the debug message! */
  579.     Forbid();
  580.     if (packetsqueued() || g_files_pending ||
  581.         (g_volume && g_volume->locks)) {
  582.     Permit();
  583.     BUG(dbprintf(" ..  not yet!\n");)
  584.     notdone = 1;
  585.     goto top;        /*  sorry... can't exit     */
  586.     } else
  587.     BUG(dbprintf(" ..  yes!\n");)
  588.  
  589.     /* remove timer device and any pending timer requests: */
  590.     if (g_timer_sigbit)
  591.       Cleanup_Timer_Device ();
  592.  
  593.     /* this is getting dangerous. We will unload our very own
  594.      * code via UnLoadSeg() and need to keep the system in
  595.      * Forbid() state in order to avoid getting the free memory
  596.      * reclaimed by other tasks. This means: *NO* Wait() after
  597.      * Unmount(TRUE) ist called!
  598.      */
  599.  
  600.     Unmount (TRUE);
  601.     
  602.     Cleanup_CDROM (g_cd);
  603.  
  604.     Close_Intui ();
  605.  
  606.     /*
  607.      *    Remove debug process, closedown, fall of the end of the world
  608.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  609.      *    had to RemTask(NULL) itself).
  610.      */
  611.  
  612.     BUG(dbuninit();)
  613.     if (DOSBase)
  614.       CloseLibrary ((struct Library *) DOSBase);
  615.     
  616.     return 0;
  617. }
  618.  
  619.  
  620. /*
  621.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  622.  *  can see by this and how the PACKET structure is extracted in the
  623.  *  GetMsg() of the main routine.
  624.  */
  625.  
  626. void returnpacket(struct DosPacket *packet)
  627. {
  628.     register struct Message *mess;
  629.     register struct MsgPort *replyport;
  630.  
  631.     replyport             = packet->dp_Port;
  632.     mess             = packet->dp_Link;
  633.     packet->dp_Port         = &DosProc->pr_MsgPort;
  634.     mess->mn_Node.ln_Name    = (char *)packet;
  635.     mess->mn_Node.ln_Succ    = NULL;
  636.     mess->mn_Node.ln_Pred    = NULL;
  637.     PutMsg(replyport, mess);
  638. }
  639.  
  640. /*
  641.  *  Are there any packets queued to our device?
  642.  */
  643.  
  644. int packetsqueued (void)
  645. {
  646.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  647.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  648. }
  649.  
  650. /*
  651.  *  DOS MEMORY ROUTINES
  652.  *
  653.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  654.  *  a FileLock structure, with additional private information after the
  655.  *  FileLock structure.  The longword before the beginning of the structure
  656.  *  must contain the length of structure + 4.
  657.  *
  658.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  659.  *  copy lock structures.  This means that if you want to be workbench
  660.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  661.  */
  662.  
  663. void *dosalloc(ulong bytes)
  664. {
  665.     register ulong *ptr;
  666.  
  667.     bytes += 4;
  668.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  669.     *ptr = bytes;
  670.     return(ptr+1);
  671. }
  672.  
  673. void dosfree (ulong *ptr)
  674. {
  675.     --ptr;
  676.     FreeMem(ptr, *ptr);
  677. }
  678.  
  679. /*
  680.  *  Convert a BSTR into a normal string.. copying the string into buf.
  681.  *  I use normal strings for internal storage, and convert back and forth
  682.  *  when required.
  683.  */
  684.  
  685. void btos(LONG bstr, char *buf)
  686. {
  687.     unsigned char *str = BTOC(bstr);
  688.     bmov((char *) str+1, buf, *str);
  689.     buf[*str] = 0;
  690. }
  691.  
  692. /*
  693.  *  Some EXEC list handling routines not found in the EXEC library.
  694.  */
  695.  
  696. void *NextNode (NODE *node)
  697. {
  698.     node = node->mln_Succ;
  699.     if (node->mln_Succ == NULL)
  700.     return(NULL);
  701.     return(node);
  702. }
  703.  
  704. void *GetHead (LIST *list)
  705. {
  706.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  707.     return(list->mlh_Head);
  708.     return(NULL);
  709. }
  710.  
  711. /*
  712.  *  The lock function.    The file has already been checked to see if it
  713.  *  is lockable given the mode.
  714.  */
  715.  
  716. LOCK *cdlock(CDROM_OBJ *cdfile, int mode)
  717. {
  718.   LOCK *lock = dosalloc (sizeof(LOCK));
  719.  
  720.   cdfile->volume->locks++;
  721.   lock->fl_Key = (long) cdfile;
  722.   lock->fl_Access = ACCESS_READ;
  723.   lock->fl_Task = &DosProc->pr_MsgPort;
  724.   lock->fl_Volume = (BPTR) CTOB (DosNode);
  725.   return(lock);
  726. }
  727.  
  728. void cdunlock (LOCK *lock)
  729. {
  730.   CDROM_OBJ *obj = (CDROM_OBJ *) lock->fl_Key;
  731.  
  732.   if (--obj->volume->locks == 0 && !obj->volume->valid) {
  733.     Close_Volume (obj->volume);
  734.   }
  735.   Close_Object (obj);
  736.   dosfree ((ulong *) lock);                /* free lock        */
  737. }
  738.  
  739. /*
  740.  *  GETLOCKFILE(bptrlock)
  741.  *
  742.  *  Return the CDROM_OBJ (file or directory) associated with the
  743.  *  given lock, which is passed as a BPTR.
  744.  *
  745.  *  According to the DOS spec, the only way a NULL lock will ever be
  746.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  747.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  748.  *  the root directory of the CDROM.
  749.  */
  750.  
  751. CDROM_OBJ *getlockfile (LONG lock)
  752. {
  753.   LOCK *rl = BTOC (lock);
  754.  
  755.   if (rl)
  756.     return (CDROM_OBJ *) rl->fl_Key;
  757.   return g_top_level_obj;
  758. }
  759.  
  760. char *typetostr (int ty)
  761. {
  762.     switch(ty) {
  763.     case ACTION_DIE:        return("DIE");
  764.     case ACTION_FINDUPDATE:     return("OPEN-RW");
  765.     case ACTION_FINDINPUT:    return("OPEN-OLD");
  766.     case ACTION_FINDOUTPUT:    return("OPEN-NEW");
  767.     case ACTION_READ:        return("READ");
  768.     case ACTION_WRITE:        return("WRITE");
  769.     case ACTION_END:        return("CLOSE");
  770.     case ACTION_SEEK:        return("SEEK");
  771.     case ACTION_EXAMINE_NEXT:    return("EXAMINE NEXT");
  772.     case ACTION_EXAMINE_OBJECT: return("EXAMINE OBJ");
  773.     case ACTION_INFO:        return("INFO");
  774.     case ACTION_DISK_INFO:    return("DISK INFO");
  775.     case ACTION_PARENT:     return("PARENTDIR");
  776.     case ACTION_DELETE_OBJECT:    return("DELETE");
  777.     case ACTION_CREATE_DIR:    return("CREATEDIR");
  778.     case ACTION_LOCATE_OBJECT:    return("LOCK");
  779.     case ACTION_COPY_DIR:    return("DUPLOCK");
  780.     case ACTION_FREE_LOCK:    return("FREELOCK");
  781.     case ACTION_SET_PROTECT:    return("SETPROTECT");
  782.     case ACTION_SET_COMMENT:    return("SETCOMMENT");
  783.     case ACTION_RENAME_OBJECT:    return("RENAME");
  784.     case ACTION_INHIBIT:    return("INHIBIT");
  785.     case ACTION_RENAME_DISK:    return("RENAME DISK");
  786.     case ACTION_MORE_CACHE:    return("MORE CACHE");
  787.     case ACTION_WAIT_CHAR:    return("WAIT FOR CHAR");
  788.     case ACTION_FLUSH:        return("FLUSH");
  789.     case ACTION_SCREEN_MODE:    return("SCREENMODE");
  790.     case ACTION_IS_FILESYSTEM:    return("IS_FILESYSTEM");
  791.     case ACTION_SAME_LOCK:      return("SAME_LOCK");
  792.     case ACTION_COPY_DIR_FH:    return("COPY_DIR_FH");
  793.     case ACTION_PARENT_FH:      return("PARENT_FH");
  794.     case ACTION_EXAMINE_FH:     return("EXAMINE_FH");
  795.     case ACTION_FH_FROM_LOCK:   return("FH_FROM_LOCK");
  796.     case ACTION_CURRENT_VOLUME: return("CURRENT_VOLUME");
  797.     default:            return("---------UNKNOWN-------");
  798.     }
  799. }
  800.  
  801. static char *TheVersion = "$VER: CDROM-Handler " VERSION;
  802.  
  803. #ifndef NDEBUG
  804.  
  805. /*
  806.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  807.  *  devices from within a DOS device driver because they use the same
  808.  *  message port as the driver.  If you need to make such calls you must
  809.  *  create a port and construct the DOS messages yourself.  I do not
  810.  *  do this.  To get debugging info out another PROCESS is created to which
  811.  *  debugging messages can be sent.
  812.  *
  813.  *  You want the priority of the debug process to be larger than the
  814.  *  priority of your DOS handler.  This is so if your DOS handler crashes
  815.  *  you have a better idea of where it died from the debugging messages
  816.  *  (remember that the two processes are asyncronous from each other).
  817.  */
  818.  
  819. extern void debugproc();
  820.  
  821. void dbinit (void)
  822. {
  823.     TASK *task = FindTask(NULL);
  824.  
  825.     Dback = CreatePort(NULL, 0);
  826.     CreateProc((UBYTE *) "DEV_DB", task->tc_Node.ln_Pri+1, (BPTR) (CTOB(debugproc)),
  827.                4096);
  828.     WaitPort(Dback);                    /* handshake startup    */
  829.     GetMsg(Dback);                    /* remove dummy msg     */
  830.     dbprintf("Debugger running: %s, %s\n", TheVersion+6, __TIME__);
  831. }
  832.  
  833. void dbuninit (void)
  834. {
  835.     MSG killmsg;
  836.  
  837.     if (Dbport) {
  838.     killmsg.mn_Length = 0;        /*    0 means die        */
  839.     PutMsg(Dbport,&killmsg);
  840.     WaitPort(Dback);        /*    He's dead jim!      */
  841.     GetMsg(Dback);
  842.     DeletePort(Dback);
  843.  
  844.     /*
  845.      *  Since the debug process is running at a greater priority, I
  846.      *  am pretty sure that it is guarenteed to be completely removed
  847.      *  before this task gets control again.  Still, it doesn't hurt...
  848.      */
  849.  
  850.     Delay(50);            /*    ensure he's dead    */
  851.     }
  852. }
  853.  
  854. void dbprintf (char *format, ...)
  855. {
  856.     va_list arg;
  857.     char buf[256];
  858.     MSG *msg;
  859.  
  860.     va_start (arg, format);
  861.     if (Dbport && !DBDisable) {
  862.     vsprintf (buf, format, arg);
  863.     msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
  864.     msg->mn_Length = strlen(buf)+1;     /*    Length NEVER 0    */
  865.     strcpy((char *) (msg+1), buf);
  866.     PutMsg(Dbport,msg);
  867.     }
  868.     va_end (arg);
  869. }
  870.  
  871. /*
  872.  *  BTW, the DOS library used by debugmain() was actually openned by
  873.  *  the device driver.    Note: DummyMsg cannot be on debugmain()'s stack
  874.  *  since debugmain() goes away on the final handshake.
  875.  */
  876.  
  877. void debugmain (void)
  878. {
  879.     MSG *msg;
  880.     short len;
  881.     void *fh;
  882.  
  883.     Dbport = CreatePort(NULL, 0);
  884.     fh = (void *) Open ((UBYTE *) "con:0/0/640/100/debugwindow", 1006);
  885.     PutMsg(Dback, &DummyMsg);
  886.     for (;;) {
  887.     WaitPort(Dbport);
  888.     msg = GetMsg(Dbport);
  889.     len = msg->mn_Length;
  890.     if (len == 0)
  891.         break;
  892.     --len;                  /*  Fix length up   */
  893.     Write((BPTR) fh, msg+1, len);
  894.     FreeMem(msg,sizeof(MSG)+len+1);
  895.     }
  896.     Close ((BPTR) fh);
  897.     DeletePort(Dbport);
  898.     PutMsg(Dback,&DummyMsg);          /*  Kill handshake  */
  899. }
  900.  
  901. #endif /* !NDEBUG */
  902.  
  903. /*
  904.  * If p_pathname contains a ':' character, return the position of the first
  905.  * character after ':'
  906.  * Otherwise, return 0.
  907.  */
  908.  
  909. int Check_For_Volume_Name_Prefix (char *p_pathname)
  910. {
  911.   char *pos = strchr (p_pathname, ':');
  912.   
  913.   return pos ? (pos - p_pathname) + 1 : 0;
  914. }
  915.  
  916. /*
  917.  * Fills a FileInfoBlock with the information contained in the
  918.  * directory record of a CD-ROM directory or file.
  919.  */
  920.  
  921. void Fill_FileInfoBlock (FIB *p_fib, CDROM_INFO *p_info, VOLUME *p_volume)
  922. {
  923.   char *src = p_info->name;
  924.   char *dest = p_fib->fib_FileName+1;
  925.   int len = p_info->name_length;
  926.   struct DateTime dt;
  927.   char date[9], time[9];
  928.   directory_record *dir = &p_info->dir_record;
  929.   
  930.   p_fib->fib_DirEntryType = (dir->flags & 2)?2:-3;
  931.   
  932.   /* I don't know exactly why I have to set fib_EntryType, but other
  933.    * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
  934.    */
  935.    
  936.   p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  937.   
  938.   if (len == 1 && *src == ':') {
  939.     /* root of file system: */
  940.     p_fib->fib_DirEntryType = 2 /* was: 1 */;
  941.     /* file name == volume name: */
  942.     memcpy (p_fib->fib_FileName, g_vol_name, g_vol_name[0]+1);
  943.   } else {
  944.     /* copy file name (without version number): */
  945.     for (; len && *src != ';'; len--)
  946.       *dest++ = *src++;
  947.     p_fib->fib_FileName[0] = p_info->name_length-len;
  948.  
  949.     if (g_map_to_lowercase && !p_volume->use_rock_ridge) {
  950.       /* convert ISO filename to lowercase: */
  951.       int i, len = p_fib->fib_FileName[0];
  952.       char *cp = p_fib->fib_FileName + 1;
  953.     
  954.       for (i=0; i<len; i++, cp++)
  955.         *cp = tolower (*cp);
  956.     }
  957.   }
  958.   p_fib->fib_Protection = 0;
  959.   p_fib->fib_Size = dir->data_length_m;
  960.   p_fib->fib_NumBlocks = p_fib->fib_Size >> 11;
  961.   p_fib->fib_Comment[0] = 0;
  962.  
  963.   /* convert ISO date to Amiga date: */
  964.   dt.dat_Format = FORMAT_CDN;
  965.   dt.dat_Flags = 0;
  966.   sprintf (date, "%02d-%02d-%02d",
  967.          (int) dir->day, (int) dir->month, (int) dir->year);
  968.   dt.dat_StrDate = (UBYTE *) date;
  969.   sprintf (time, "%02d:%02d:%02d",
  970.          (int) dir->hour, (int) dir->minute, (int) dir->second);
  971.   dt.dat_StrTime = (UBYTE *) time;
  972.   if (StrToDate (&dt))
  973.     p_fib->fib_Date = dt.dat_Stamp;
  974.   else {
  975.     p_fib->fib_Date.ds_Days = 0;
  976.     p_fib->fib_Date.ds_Minute = 0;
  977.     p_fib->fib_Date.ds_Tick = 0;
  978.   }
  979. }
  980.  
  981. /*
  982.  *  Copy the ISO identifier p_ident with maximum length p_length
  983.  *  into the BCPL string buffer p_buf. Trailing blanks of p_ident
  984.  *  will be stripped.
  985.  */
  986.  
  987. void Copy_ISO_Identifier (char *p_buf, char *p_ident, int p_length)
  988. {
  989.   int len = p_length;
  990.   
  991.   while (len && p_ident[len-1] == ' ')
  992.     len--;
  993.   
  994.   if (len)
  995.     memcpy (p_buf+1, p_ident, len);
  996.   
  997.   p_buf[0] = len;
  998. }
  999.  
  1000. /*
  1001.  * Mount a volume.
  1002.  */
  1003.  
  1004. void Mount (void)
  1005. {
  1006.   DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1007.   DEVLIST *dl;
  1008.  
  1009.   g_volume = Open_Volume (g_cd, g_use_rock_ridge);
  1010.   if (!g_volume) {
  1011.     BUG(dbprintf ("!!! cannot open VOLUME !!!\n");)
  1012.     return;
  1013.   } else {
  1014.     g_top_level_obj = Open_Top_Level_Directory (g_volume);
  1015.     if (!g_top_level_obj) {
  1016.       BUG(dbprintf ("!!! cannot open top level directory !!!\n");)
  1017.       return;
  1018.     }
  1019.   }
  1020.   
  1021.   BUG(dbprintf ("***mounting*** ");)
  1022.   
  1023.   g_vol_name = dosalloc (128);
  1024.   Copy_ISO_Identifier (g_vol_name, g_volume->pvd.volume_id, 32);
  1025.  
  1026.   if (!(g_vol_name[0]))
  1027.     memcpy (g_vol_name, "\7Unnamed", 8);
  1028.  
  1029.   /*
  1030.    *    Create Volume node and add to the device list.    This will
  1031.    *    cause the WORKBENCH to recognize us as a disk.    If we don't
  1032.    *    create a Volume node, Wb will not recognize us.
  1033.    */
  1034.   
  1035.   Forbid ();
  1036.   DevList = dl = dosalloc(sizeof(DEVLIST));
  1037.   dl->dl_Type = DLT_VOLUME;
  1038.   dl->dl_Task = &DosProc->pr_MsgPort;
  1039.   dl->dl_DiskType = ID_DOS_DISK;
  1040.   /* dl->dl_Name = (int)DosNode->dn_Name; */
  1041.   dl->dl_Name = (BSTR) CTOB (g_vol_name);
  1042.   dl->dl_Next = di->di_DevInfo;
  1043.   di->di_DevInfo = (long)CTOB(dl);
  1044.   Permit ();
  1045.   
  1046.   Send_Event (TRUE);
  1047. }
  1048.  
  1049. /*
  1050.  *    Remove Volume entry.  Since DOS uses singly linked lists, we
  1051.  *    must (ugg) search it manually to find the link before our
  1052.  *    Volume entry.
  1053.  */
  1054.  
  1055. void Unmount (int p_remove_device)
  1056. {
  1057.   DOSINFO *di;
  1058.   DEVLIST *dl;
  1059.   DEVNODE *dn;
  1060.   void *dlp;
  1061.  
  1062.   Forbid ();
  1063.   di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1064.  
  1065.   if (DevList) {
  1066.     dlp = &di->di_DevInfo;
  1067.     for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
  1068.       dlp = &dl->dl_Next;
  1069.     if (dl == DevList) {
  1070.       *(BPTR *)dlp = dl->dl_Next;
  1071.       dosfree((ulong *) dl);
  1072.     } else {
  1073.       BUG(dbprintf("****PANIC: Unable to find volume node\n");)
  1074.     }
  1075.     DevList = NULL;
  1076.  
  1077.     Close_Object (g_top_level_obj);
  1078.     if (g_volume->locks == 0)
  1079.       Close_Volume (g_volume);
  1080.     else {
  1081.       g_volume->valid = 0;
  1082.     }
  1083.     dosfree ((ulong *) g_vol_name);
  1084.   }
  1085.  
  1086.   Send_Event (FALSE);
  1087.  
  1088.   g_volume = 0;
  1089.  
  1090.   /* when the handler code exits the corresponding device
  1091.    * node (e.g. "CD0") will be modified. The handler code
  1092.    * will be unloaded and the task entry will be set to
  1093.    * zero, so the next device access will reload and
  1094.    * restart the handler code.
  1095.    */
  1096.  
  1097.   if (p_remove_device) {
  1098.     di = BTOC (((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  1099.     dlp = &di->di_DevInfo;
  1100.     dn = BTOC (di->di_DevInfo);
  1101.  
  1102.     while (dn) {
  1103.       if (dn->dn_Task == DosTask) {
  1104.         BUG(dbprintf("got it! %b\n",dn->dn_Name);)
  1105.     if (TypeOfMem (BADDR (dn->dn_SegList))) {
  1106.       UnLoadSeg (dn->dn_SegList);
  1107.       dn->dn_SegList = 0;
  1108.     } else
  1109.       BUG(dbprintf("not a valid seglist\n");)
  1110.  
  1111.     dn->dn_Task = NULL;
  1112.  
  1113.         *(BPTR *) dlp = dn->dn_Next;
  1114.         dosfree ((ulong *) dn);
  1115.  
  1116.     break;
  1117.       }    else {
  1118.         dlp = &dn->dn_Next;
  1119.     dn = BTOC (dn->dn_Next);
  1120.       }
  1121.     }
  1122.   } else
  1123.     Permit ();
  1124. }
  1125.  
  1126. /*
  1127.  * Mount_Check returns 1 if a disk is inserted in the drive. A check is
  1128.  * only performed if previously the drive was empty.
  1129.  */
  1130.  
  1131. int Mount_Check (void)
  1132. {
  1133.   if (DevList == NULL) {
  1134.    /*
  1135.     * No disk was inserted up to now: we will check whether
  1136.     * a disk has been inserted by sending the test unit ready
  1137.     * command. We have to send the command twice because
  1138.     * the first SCSI command after inserting a new disk is
  1139.     * always rejected.
  1140.     */
  1141.     if (Test_Unit_Ready (g_cd) ||
  1142.         Test_Unit_Ready (g_cd)) {
  1143.       Mount ();
  1144.     } else {
  1145.       return 0;
  1146.     }
  1147.     if (DevList)
  1148.       return 1;
  1149.     else {
  1150.       /* Mount() did not succeed: */
  1151.       return 0;
  1152.     }
  1153.   }
  1154.   return 1;
  1155. }
  1156.  
  1157. /*
  1158.  *  Open timer device structures:
  1159.  */
  1160.  
  1161. int Open_Timer_Device (void)
  1162. {
  1163.   if (!(g_timer_mp = CreatePort (NULL, 0))) {
  1164.     BUG(dbprintf ("cannot create timer message port!\n");)
  1165.     return 0;
  1166.   }
  1167.   if (!(g_timer_io = (struct timerequest *)
  1168.        CreateExtIO (g_timer_mp, sizeof (struct timerequest)))) {
  1169.     BUG(dbprintf ("cannot create timer i/o structure!\n");)
  1170.     DeletePort (g_timer_mp);
  1171.     return 0;
  1172.   }
  1173.   if (OpenDevice ((UBYTE *) TIMERNAME, UNIT_VBLANK,
  1174.             (struct IORequest *) g_timer_io, 0)) {
  1175.     BUG(dbprintf ("cannot open timer device!\n");)
  1176.     DeleteExtIO ((struct IORequest *) g_timer_io);
  1177.     DeletePort (g_timer_mp);
  1178.     return 0;
  1179.   }
  1180.   g_timer_sigbit = 1L << g_timer_mp->mp_SigBit;
  1181.   return 1;
  1182. }
  1183.  
  1184. /*
  1185.  *  Remove timer device structures:
  1186.  */
  1187.  
  1188. void Cleanup_Timer_Device (void)
  1189. {
  1190.   /* remove any pending requests: */
  1191.   if (!CheckIO ((struct IORequest *) g_timer_io))
  1192.     AbortIO ((struct IORequest *) g_timer_io);
  1193.   WaitIO ((struct IORequest *) g_timer_io);
  1194.   
  1195.   CloseDevice ((struct IORequest *) g_timer_io);
  1196.   DeleteExtIO ((struct IORequest *) g_timer_io);
  1197.   DeletePort (g_timer_mp);
  1198. }
  1199.  
  1200. /*
  1201.  *  Send timer request
  1202.  */
  1203.  
  1204. void Send_Timer_Request (void)
  1205. {
  1206.   g_timer_io->tr_node.io_Command = TR_ADDREQUEST;
  1207.   g_timer_io->tr_time.tv_secs = CHECK_INTERVAL;
  1208.   g_timer_io->tr_time.tv_micro = 0;
  1209.   SendIO ((struct IORequest *) g_timer_io);
  1210. }
  1211.  
  1212. /*
  1213.  *  Check whether the disk has been removed or inserted.
  1214.  */
  1215.  
  1216. void Check_Disk (void)
  1217. {
  1218.   BUG(dbprintf ("Checking Disk... ");)
  1219.   if (DevList) {
  1220.     if (Test_Unit_Ready (g_cd)) {
  1221.       BUG(dbprintf ("no disk change  "));
  1222.     } else {
  1223.       BUG(dbprintf ("disk has been removed  ");)
  1224.       if (DevList)
  1225.         Unmount (FALSE);
  1226.     }
  1227.   }
  1228.   if (DevList == NULL) {
  1229.     if (Test_Unit_Ready (g_cd) ||
  1230.         Test_Unit_Ready (g_cd)) {
  1231.       BUG(dbprintf ("disk has been inserted");)
  1232.       Mount ();
  1233.     }
  1234.   }
  1235.   BUG(dbprintf ("\n");)
  1236. }
  1237.  
  1238. /*
  1239.  * Extract information from Mountlist "Startup" field.
  1240.  */
  1241.  
  1242. int Get_Startup (LONG p_startup)
  1243. {
  1244.   char buf[100];
  1245.   char *cp;
  1246.   int i;
  1247.  
  1248.   btos (p_startup, buf);
  1249.   
  1250.   cp = buf;
  1251.   if (*cp == '"')  /* skip quote */
  1252.     cp++;
  1253.  
  1254.   for (i=0; *cp && *cp != ':'; ) {    /* get SCSI device name */
  1255.     g_device[i++] = *cp++;
  1256.     if (i == sizeof (g_device)) {
  1257.       Display_Error ("Mountlist field 'Startup':\n"
  1258.                    "SCSI device name too long");
  1259.       return 0;
  1260.     }
  1261.   }
  1262.   g_device[i] = 0;
  1263.   if (*cp != ':' || !isdigit (cp[1])) {
  1264.     Display_Error ("Mountlist field 'Startup':\n"
  1265.                "SCSI unit number is missing");
  1266.     return 0;
  1267.   }
  1268.   for (cp++, i=0; *cp && isdigit (*cp); cp++)    /* get SCSI unit number */
  1269.     i = 10 * i + *cp - '0';
  1270.   g_unit = i;
  1271.  
  1272.   /* Initialize CDROM: */
  1273.   g_cd = Open_CDROM (g_device, g_unit, g_trackdisk, g_fastmem);
  1274.   if (!g_cd) {
  1275.     Display_Error ("Cannot open %s unit %d", g_device, g_unit);
  1276.     return 0;
  1277.   }
  1278.  
  1279.   g_use_rock_ridge = 0;
  1280.   g_map_to_lowercase = 0;
  1281.   g_trackdisk = 0;
  1282.   g_fastmem = 0;
  1283.  
  1284.   if (*cp == ':') {
  1285.     /* parse options: */
  1286.     for (cp++; isalpha (*cp); cp++) {
  1287.       switch (*cp) {
  1288.         case 'r':
  1289.         case 'R':
  1290.       g_use_rock_ridge = 1;
  1291.       break;
  1292.         case 'l':
  1293.         case 'L':
  1294.       g_map_to_lowercase = 1;
  1295.       break;
  1296.     case 't':
  1297.     case 'T':
  1298.       g_trackdisk = 1;
  1299.       break;
  1300.     case 'f':
  1301.     case 'F':
  1302.       g_fastmem = 1;
  1303.       break;
  1304.     default:
  1305.       Display_Error ("Mountlist field 'Startup':\n"
  1306.                "Illegal option character '%c'", *cp);
  1307.       return 0;
  1308.       }
  1309.     }
  1310.   }
  1311.  
  1312.   return 1;
  1313. }
  1314.  
  1315. /* The following lines will generate a `disk inserted/removed' event, in order
  1316.  * to get Workbench to rescan the DosList and update the list of
  1317.  * volume icons.
  1318.  */
  1319.  
  1320. void Send_Event (int p_inserted)
  1321. {
  1322.   struct IOStdReq *InputRequest;/* OLSEN */
  1323.   struct MsgPort *InputPort;    /* OLSEN */
  1324.  
  1325.   if (InputPort = (struct MsgPort *) CreateMsgPort ()) {
  1326.     if (InputRequest = (struct IOStdReq *)
  1327.         CreateIORequest (InputPort, sizeof (struct IOStdReq))) {
  1328.       if (!OpenDevice ((UBYTE *) "input.device", 0,
  1329.                      (struct IORequest *) InputRequest, 0)) {
  1330.     static struct InputEvent InputEvent;
  1331.  
  1332.     memset (&InputEvent, 0, sizeof (struct InputEvent));
  1333.  
  1334.     InputEvent.ie_Class = p_inserted ? IECLASS_DISKINSERTED :
  1335.                        IECLASS_DISKREMOVED;
  1336.  
  1337.     InputRequest->io_Command = IND_WRITEEVENT;
  1338.     InputRequest->io_Data = &InputEvent;
  1339.     InputRequest->io_Length = sizeof (struct InputEvent);
  1340.  
  1341.     DoIO ((struct IORequest *) InputRequest);
  1342.  
  1343.     CloseDevice ((struct IORequest *) InputRequest);
  1344.       }
  1345.       DeleteIORequest (InputRequest);
  1346.     }
  1347.     DeleteMsgPort (InputPort);
  1348.   }
  1349. }
  1350.  
  1351.  
  1352. #ifndef NDEBUG
  1353.  
  1354. /*
  1355.  *  The assembly tag for the DOS process:  CNOP causes alignment problems
  1356.  *  with the Aztec assembler for some reason.  I assume then, that the
  1357.  *  alignment is unknown.  Since the BCPL conversion basically zero's the
  1358.  *  lower two bits of the address the actual code may start anywhere around
  1359.  *  the label....  Sigh....  (see CreatProc() above).
  1360.  */
  1361.  
  1362. #asm
  1363.     public    _debugproc
  1364.     public    _debugmain
  1365.  
  1366.     cseg
  1367.     nop
  1368.     nop
  1369.     nop
  1370. _debugproc:
  1371.     nop
  1372.     nop
  1373.     movem.l D2-D7/A2-A6,-(sp)
  1374.     jsr    _debugmain
  1375.     movem.l (sp)+,D2-D7/A2-A6
  1376.     rts
  1377. #endasm
  1378.  
  1379.  
  1380. #endif /* !NDEBUG */
  1381.