home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / drvrnstl.sit / driver.c next >
Text File  |  1991-01-28  |  15KB  |  506 lines

  1. /* driver.c */
  2.  
  3. /*
  4.  *    The following code is to install and remove RAM drivers in the system
  5.  *    heap. Written by Pete Resnick with the help of Joe Holt, Phil Shapiro,
  6.  *    Tom Johnson, Michael A. Libes, Matthias Urlichs, John Norstad, and
  7.  *    Charles Martin.
  8.  *
  9.  *    Change Log
  10.  *    ----------
  11.  *    Date:        Change:                                        Who:
  12.  *    -----        -------                                        ----
  13.  *    22 Jan 91    Changed "if (UTableSize < UnitNtryCnt) {"    pr
  14.  *                to "if (UTableSize > UnitNtryCnt) {" in
  15.  *                DriverAvail.
  16.  *
  17.  *    28 Jan 91    Make sure resource map is updated to        pr
  18.  *                change back the resource ID's in
  19.  *                InstallRAMDriver by adding code to
  20.  *                SetResFileAttrs and UpdateResFile.
  21.  */
  22.  
  23. #include <MacTypes.h>
  24. #include <DeviceMgr.h>
  25. #include <FileMgr.h>
  26. #include <MemoryMgr.h>
  27. #include <ResourceMgr.h>
  28. #include "driver.h"
  29.  
  30. #define LOW_UNIT        48        /* First Unit Table Entry to use    */
  31. #define NEW_UNIT        64        /* Size of a "normal" Unit Table    */
  32. #define MAX_UNIT        128        /* Maximum size of a Unit Table        */
  33. #define UP_UNIT            4        /* Size to bounce up Unit Table        */
  34. #define nil                0L        /* Just nil                            */
  35. #define SCCLockOut        0x2600    /* Disable interrupts flag            */
  36.  
  37. pascal OSErr DrvrInstall(Handle drvrHandle, short refNum)
  38. {
  39.     asm {
  40.         MOVE.W    refNum, D0        ; driver reference number
  41.         MOVEA.L    drvrHandle, A0    ; handle to driver 
  42.         MOVEA.L    (A0), A0        ; pointer to driver
  43.         DC.W    0xA03D            ; _DrvrInstall
  44.         ; error is in DO (and is pushed on stack)
  45.     }
  46. }
  47.  
  48. pascal OSErr DrvrRemove(short refNum)
  49. {
  50.     asm {
  51.         MOVE.W    refNum, D0    ; driver reference number
  52.         DC.W    0xA03E        ; _DrvrRemove
  53.         ; error is in DO (and is pushed on stack)
  54.     }
  55. }
  56.  
  57. /*
  58.  *    InstallRAMDriver will install the named driver into the system heap
  59.  *    locked and return the driver reference number in refNum. Make sure
  60.  *    that the DRVR resources are numbered between 0 and 47 and that the
  61.  *    resources owned by the driver are also numbered appropriately. Using
  62.  *    resource ID's of 48 and higher may cause conflicts if you are using
  63.  *    the THINK C global data DATA resource or the THINK C multi-segment
  64.  *    DCOD resource, which get temporarily renumbered by this routine.
  65.  *    One major kludge: the ioMisc field of the ioParam block is not used
  66.  *    for non-file operations, so it is used to store a pointer to a block
  67.  *    containing the addresses of the DCOD resources (if they are being
  68.  *    used) so that they can be removed by RemoveRAMDriver. If Apple ever
  69.  *    uses that field, that mechanism will be gone. See driver.h for the
  70.  *    drvrInstFlags.
  71.  */
  72.  
  73. OSErr InstallRAMDriver(Str255 drvrName, short *refNum, Byte drvrInstFlags)
  74. {
  75.     OSErr errCode;
  76.     short index, rsrcID, dcodRsrcID, unitNum, dcodSegments, dcodIndex;
  77.     ResType rsrcType;
  78.     Str255 rsrcName;
  79.     Handle dataHandle, drvrHandle, *dcodHList = nil, tempHandle;
  80.     ioParam openBlock;
  81.     register DriverPtr drvrPtr;
  82.     register DCtlPtr ctlEntryPtr;
  83.     
  84.     /* Get the unit number for the driver */
  85.     errCode = DriverAvail(&unitNum);
  86.     if(errCode != noErr)
  87.         return(errCode);
  88.  
  89.     /* The driver must load into the system heap locked. */
  90.     SetResLoad(false);
  91.     drvrHandle = Get1NamedResource('DRVR', drvrName);
  92.     SetResLoad(true);
  93.     if(drvrHandle == nil)
  94.         return(dInstErr);
  95.     SetResAttrs(drvrHandle, resSysHeap + resLocked);
  96.     if(ResErr != noErr) {
  97.         errCode = ResErr;
  98.         ReleaseResource(drvrHandle);
  99.         return(errCode);
  100.     }
  101.     
  102.     /* Save the resource info for later use */
  103.     GetResInfo(drvrHandle, &rsrcID, &rsrcType, &rsrcName);
  104.     if(ResErr != noErr) {
  105.         errCode = ResErr;
  106.         ReleaseResource(drvrHandle);
  107.         return(errCode);
  108.     }
  109.     
  110.     /* Now load it and detach it */
  111.     LoadResource(drvrHandle);
  112.     if(ResErr != noErr) {
  113.         errCode = ResErr;
  114.         ReleaseResource(drvrHandle);
  115.         return(errCode);
  116.     }
  117.     DetachResource(drvrHandle);
  118.  
  119.     if(drvrInstFlags & thinkDATA) {
  120.         /*
  121.          *    Make sure the DATA resource will load into the system heap,
  122.          *    locked, and is owned by our driver, where the ID is the
  123.          *    unitNum in bits 5 through 10 (or 11 if needed), zeros in
  124.          *    bits 11 (if there is room) 12 and 13 (which means DRVR), zeros
  125.          *    in bits 0 through 4 (since there is only 1 DATA resource), and
  126.          *    ones in bits 14 and 15. If any errors occur after the resource
  127.          *    ID is changed, it must be changed back!
  128.          */
  129.         SetResLoad(false);
  130.         dataHandle = Get1Resource('DATA', (rsrcID << 5) | 0xC000);
  131.         SetResLoad(true);
  132.         if(dataHandle == nil) {
  133.             errCode = ResErr;
  134.             DisposHandle(drvrHandle);
  135.             return(errCode != noErr ? errCode : resNotFound);
  136.         }
  137.         SetResAttrs(dataHandle, resSysHeap + resLocked);
  138.         if(ResErr != noErr) {
  139.             errCode = ResErr;
  140.             DisposHandle(drvrHandle);
  141.             return(errCode);
  142.         }
  143.         SetResInfo(dataHandle, (unitNum << 5) | 0xC000, 0);
  144.         if(ResErr != noErr) {
  145.             errCode = ResErr;
  146.             DisposHandle(drvrHandle);
  147.             return(errCode);
  148.         }
  149.     }
  150.  
  151.     if(drvrInstFlags & thinkMultSeg) {
  152.         /*
  153.          *    Make sure the DCOD resources will load into the system heap,
  154.          *    locked, and are owned by our driver, where the ID is the
  155.          *    unitNum in bits 5 through 10 (or 11 if needed), zeros in
  156.          *    bits 11 (if there is room) 12 and 13 (which means DRVR),
  157.          *    the same ID in bits 0 through 4, and ones in bits 14 and 15.
  158.          *    Keep a block containing the handles to those segments so that
  159.          *    they can be thrown away later if needed. If any errors
  160.          *    occur after the resource ID's are changed, they are changed
  161.          *    back in ReleaseDrvrSegments. 
  162.          */
  163.         dcodSegments = 0;
  164.         errCode = noErr;
  165.         SetResLoad(false);
  166.         
  167.         /* Count how many segments there are */
  168.         for(index = 1;
  169.             (index <= Count1Resources('DCOD')) && (errCode == noErr);
  170.             ++index) {
  171.             tempHandle = Get1IndResource('DCOD', index);
  172.             if(tempHandle == nil)
  173.                 errCode = (ResErr != noErr ? ResErr : resNotFound);
  174.             GetResInfo(tempHandle, &dcodRsrcID, &rsrcType, &rsrcName);
  175.             ReleaseResource(tempHandle);
  176.             if((dcodRsrcID & ~0xF01F) >> 5 == rsrcID)
  177.                 ++dcodSegments;
  178.         }
  179.         SetResLoad(true);
  180.  
  181.         if(errCode != noErr) {
  182.             if(drvrInstFlags & thinkDATA) {
  183.                 SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
  184.                 SetResFileAttrs(CurResFile(),
  185.                                 GetResFileAttrs(index) | mapChanged);
  186.                 UpdateResFile(CurResFile());
  187.                 ReleaseResource(dataHandle);
  188.             }
  189.             DisposHandle(drvrHandle);
  190.             return(errCode);
  191.         }
  192.  
  193.         /* Get a block of memory to hold the handles */
  194.         dcodHList = (Handle *)NewPtrSysClear(sizeof(Handle) * dcodSegments);
  195.         if(dcodHList == nil) {
  196.             if(drvrInstFlags & thinkDATA) {
  197.                 SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
  198.                 SetResFileAttrs(CurResFile(),
  199.                                 GetResFileAttrs(index) | mapChanged);
  200.                 UpdateResFile(CurResFile());
  201.                 ReleaseResource(dataHandle);
  202.             }
  203.             DisposHandle(drvrHandle);
  204.             return(memFullErr);
  205.         }
  206.  
  207.         /* Get the resources and change the attributes and ID's */
  208.         dcodIndex = 0;
  209.         SetResLoad(false);
  210.         for(index = 1;
  211.             (index <= Count1Resources('DCOD')) && (errCode == noErr);
  212.             ++index) {
  213.             tempHandle = Get1IndResource('DCOD', index);
  214.             if(tempHandle == nil) {
  215.                 errCode = (ResErr != noErr ? ResErr : resNotFound);
  216.             } else {
  217.                 GetResInfo(tempHandle, &dcodRsrcID, &rsrcType, &rsrcName);
  218.                 if((dcodRsrcID & ~0xF01F) >> 5 == rsrcID) {
  219.                     dcodHList[dcodIndex] = tempHandle;
  220.                     SetResAttrs(dcodHList[dcodIndex],
  221.                                 resSysHeap + resLocked);
  222.                     if(ResErr != noErr) {
  223.                         errCode = ResErr;
  224.                     } else {
  225.                         SetResInfo(dcodHList[dcodIndex],
  226.                                     (dcodRsrcID & 0xF01F) + (unitNum << 5),
  227.                                     0);
  228.                         errCode = ResErr;
  229.                     }
  230.                     ++dcodIndex;
  231.                 }
  232.             }
  233.         }
  234.         SetResLoad(true);
  235.         
  236.         if(errCode != noErr) {
  237.             if(drvrInstFlags & thinkDATA) {
  238.                 SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
  239.                 ReleaseResource(dataHandle);
  240.             }
  241.             ReleaseDrvrSegments(dcodHList, rsrcID, false);
  242.             DisposHandle(drvrHandle);
  243.             return(dInstErr);
  244.         }
  245.     }
  246.  
  247.     /* Install with the refNum. The refNum is the -(unitNum + 1) */
  248.     errCode = DrvrInstall(drvrHandle, ~unitNum);
  249.     if(errCode != noErr) {
  250.         if(drvrInstFlags & thinkDATA) {
  251.             SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
  252.             SetResFileAttrs(CurResFile(),
  253.                             GetResFileAttrs(index) | mapChanged);
  254.             UpdateResFile(CurResFile());
  255.             ReleaseResource(dataHandle);
  256.         }
  257.         if(drvrInstFlags & thinkMultSeg)
  258.             ReleaseDrvrSegments(dcodHList, rsrcID, false);
  259.         DisposHandle(drvrHandle);
  260.         return(dInstErr);
  261.     }
  262.     
  263.     /* Move the important information to the driver entry */
  264.     ctlEntryPtr = *UTableBase[unitNum];
  265.     drvrPtr = *(DriverHandle)drvrHandle;
  266.     ctlEntryPtr->dCtlDriver = (Ptr)drvrHandle;
  267.     ctlEntryPtr->dCtlFlags = drvrPtr->drvrFlags;
  268.     ctlEntryPtr->dCtlDelay = drvrPtr->drvrDelay;
  269.     ctlEntryPtr->dCtlEMask = drvrPtr->drvrEMask;
  270.     ctlEntryPtr->dCtlMenu = drvrPtr->drvrMenu;
  271.     ctlEntryPtr->dCtlFlags |= dRAMBased;
  272.     
  273.     /* Hang onto the refNum just in case open changes it. */
  274.     index = CurResFile();
  275.     
  276.     /*
  277.      *    The open routine better load all the DATA and DCOD resources. If
  278.      *    the driver is going to want to be closed, it should store what
  279.      *    is passed to it in ioMisc and pass it back when close is called.
  280.      */
  281.     if(drvrInstFlags & open) {
  282.         openBlock.ioCompletion = nil;
  283.         openBlock.ioNamePtr = drvrName;
  284.         openBlock.ioPermssn = fsCurPerm;
  285.         openBlock.ioMisc = (Ptr)dcodHList;
  286.         errCode = PBOpen(&openBlock, false);
  287.     }
  288.     
  289.     /* Change CurResFile back to our original one. */
  290.     UseResFile(index);
  291.     
  292.     if(drvrInstFlags & thinkDATA) {
  293.         /*
  294.          *    If the open was successful, the dataHandle will be detached.
  295.          *    If the open failed, dataHandle may or may not be an attached
  296.          *    resource, but probably isn't attached. Therefore, the resource
  297.          *    must be retrieved to change the resource ID back, just in case
  298.          *    the open routine changed the file's resource map. After that,
  299.          *    release it. Errors here will be horrific because the file will
  300.          *    basically be corrupted if the ID can't be changed back, so
  301.          *    don't bother checking. At this point in the game, errors
  302.          *    shouldn't occur anyway.
  303.          */
  304.         SetResLoad(false);
  305.         dataHandle = Get1Resource('DATA', (unitNum << 5) | 0xC000);
  306.         SetResLoad(true);
  307.         if(dataHandle != nil) {
  308.             SetResInfo(dataHandle, (rsrcID << 5) | 0xC000, 0);
  309.             SetResFileAttrs(CurResFile(),
  310.                             GetResFileAttrs(index) | mapChanged);
  311.             UpdateResFile(CurResFile());
  312.             ReleaseResource(dataHandle);
  313.         }
  314.     }
  315.     
  316.     /* If an error occurred during the open */
  317.     if(errCode != noErr) {
  318.         RemoveRAMDriver(~unitNum, false);
  319.         if(drvrInstFlags & thinkMultSeg)
  320.             ReleaseDrvrSegments(dcodHList, rsrcID, false);
  321.     } else {
  322.         ReleaseDrvrSegments(dcodHList, rsrcID, true);
  323.         *refNum = ~unitNum;
  324.     }
  325.     return(errCode);
  326. }
  327.  
  328. /*
  329.  *    Removes the driver installed in the system heap by InstallRAMDriver.
  330.  *    See the warning on InstallRAMDriver about the ioMisc field.
  331.  */
  332.  
  333. OSErr RemoveRAMDriver(short refNum, Boolean dcodRemove)
  334. {
  335.     OSErr errCode = noErr, dcodHandles, index;
  336.     Handle dataHandle = nil, *dcodHList = nil, drvrHandle;
  337.     ioParam closeBlock;
  338.     
  339.     /* If the driver is open, close it */
  340.     if((**UTableBase[~refNum]).dCtlFlags & dOpened) {
  341.         closeBlock.ioCompletion = nil;
  342.         closeBlock.ioRefNum = refNum;
  343.         errCode = PBClose(&closeBlock, false);
  344.         if(errCode != noErr)
  345.             return(errCode);
  346.         dcodHList = (Handle *)closeBlock.ioMisc;
  347.         dataHandle = (Handle)(**UTableBase[~refNum]).dCtlStorage;
  348.     }
  349.     
  350.     /*
  351.      *    Since the driver has been detached, it will have to be disposed of
  352.      *    later since DrvrRemove just does a ReleaseResource on the handle.
  353.      */
  354.     drvrHandle = (Handle)(**UTableBase[~refNum]).dCtlDriver;
  355.     errCode = DrvrRemove(refNum);
  356.     if(errCode != noErr)
  357.         return(errCode);
  358.     if(drvrHandle != nil) {
  359.         DisposHandle(drvrHandle);
  360.         if(dcodRemove && (dcodHList != nil)) {
  361.  
  362.             /*    The driver has passed back the handles to its segments so
  363.              *    they can be disposed of.
  364.              */
  365.             dcodHandles = GetPtrSize(&dcodHList) / sizeof(Handle);
  366.             for(index = 0; index < dcodHandles; ++index)
  367.                 DisposHandle(dcodHList[index]);
  368.             DisposPtr(dcodHList);
  369.         }
  370.     }
  371.     return(noErr);
  372. }
  373.  
  374. short GetDrvrRefNum(Str255 drvrName)
  375. {
  376.     short unitNum;
  377.     DCtlHandle curDCtlEntry;
  378.     DriverPtr curDrvrPtr;
  379.     
  380.     /* Walk through the Unit Table */
  381.     for(unitNum = 0; unitNum < UnitNtryCnt; ++unitNum) {
  382.         curDCtlEntry = GetDCtlEntry(~unitNum);
  383.         if(curDCtlEntry != nil) {
  384.         
  385.             /* If this is a RAM driver, it's a handle. ROM is a pointer */
  386.             if((**curDCtlEntry).dCtlFlags & dRAMBased)
  387.                 curDrvrPtr = *(DriverHandle)(**curDCtlEntry).dCtlDriver;
  388.             else
  389.                 curDrvrPtr = (DriverPtr)(**curDCtlEntry).dCtlDriver;
  390.             
  391.             /* Does the driver name match? */
  392.             if(curDrvrPtr != nil)
  393.                 if(EqualString(drvrName, curDrvrPtr->drvrName,
  394.                                false, false))
  395.                     return(~unitNum);
  396.         }
  397.     }
  398.     return(0);
  399. }
  400.  
  401. OSErr GrowUTable(short newEntries)
  402. {
  403.     DCtlHandle *newUTableBase;
  404.     
  405.     /* Make room for the new Unit Table */
  406.     newUTableBase = (DCtlHandle *)NewPtrSysClear((UnitNtryCnt + newEntries)
  407.                                                     * sizeof(DCtlHandle));
  408.     if(MemError() != noErr)
  409.         return(MemError());
  410.     asm {
  411.         MOVE    SR,-(SP)        ; Save status register
  412.         MOVE    #SCCLockOut,SR    ; Disable interrupts
  413.     }
  414.     
  415.     /* Move the old Unit Table to the new Unit Table */
  416.     BlockMove(UTableBase, newUTableBase, UnitNtryCnt * sizeof(DCtlHandle));
  417.     DisposPtr(UTableBase);
  418.     UTableBase = newUTableBase;
  419.     UnitNtryCnt += newEntries;
  420.     asm {
  421.         MOVE    (SP)+,SR        ; Restore status register
  422.     }
  423.     return(noErr);
  424. }
  425.  
  426. OSErr DriverAvail(short *unitNum)
  427. {
  428.     short unitIndex;
  429.     Size UTableSize;
  430.     OSErr errCode = noErr;
  431.     
  432.     *unitNum = 0;
  433.     
  434.     /* Increase Unit Table size for Mac Plus */
  435.     if(UnitNtryCnt <= LOW_UNIT)
  436.         errCode = GrowUTable(NEW_UNIT - UnitNtryCnt);
  437.     if(errCode != noErr)
  438.         return(errCode);
  439.     
  440.     /* Look for an empty slot in what's already there */
  441.     for(unitIndex = LOW_UNIT;
  442.             (unitIndex < UnitNtryCnt) && (*unitNum == 0);
  443.             ++unitIndex)
  444.         if(UTableBase[unitIndex] == nil)
  445.             *unitNum = unitIndex;
  446.     
  447.     /* Unit Table full up to UnitNtryCnt, so increase it */
  448.     if(*unitNum == 0) {
  449.         UTableSize = GetPtrSize(UTableBase) / sizeof(DCtlHandle);
  450.         
  451.         /* If there is space in the Unit Table, just up the count */
  452.         if(UTableSize > UnitNtryCnt) {
  453.             *unitNum = UnitNtryCnt;
  454.             UnitNtryCnt += (UTableSize - UnitNtryCnt < UP_UNIT
  455.                                 ? UTableSize - UnitNtryCnt
  456.                                 : UP_UNIT);
  457.         
  458.         /* If there isn't enough space, try to increase it */
  459.         } else {
  460.             if(MAX_UNIT - UnitNtryCnt != 0) {
  461.                 unitIndex = UnitNtryCnt;
  462.                 errCode = GrowUTable(MAX_UNIT - UnitNtryCnt < UP_UNIT
  463.                                         ? MAX_UNIT - UnitNtryCnt
  464.                                         : UP_UNIT);
  465.                 if(errCode != noErr)
  466.                     return(errCode);
  467.                 *unitNum = unitIndex;
  468.             }
  469.         }
  470.     }
  471.     if(*unitNum == 0)
  472.         return(unitTblFullErr);
  473.     else
  474.         return(noErr);
  475. }
  476.  
  477. void ReleaseDrvrSegments(Handle *dcodHList, short rsrcID, Boolean detach)
  478. {
  479.     short index, dcodHandles, dcodRsrcID;
  480.     long rsrcType;
  481.     Str255 rsrcName;
  482.     
  483.     dcodHandles = GetPtrSize(&dcodHList) / sizeof(Handle);
  484.     if(rsrcID != 0) {
  485.         for(index = 0; index < dcodHandles; ++index)
  486.             if(dcodHList[index]) {
  487.                 GetResInfo(dcodHList[index], &dcodRsrcID,
  488.                            &rsrcType, &rsrcName);
  489.                 SetResInfo(dcodHList[index],
  490.                             (dcodRsrcID & 0xF01F) + (rsrcID << 5),
  491.                             0);
  492.             }
  493.         SetResFileAttrs(CurResFile(), GetResFileAttrs(index) | mapChanged);
  494.         UpdateResFile(CurResFile());
  495.     }
  496.     for(index = 0; index < dcodHandles; ++index)
  497.         if(dcodHList[index]) {
  498.             if(detach)
  499.                 DetachResource(dcodHList[index]);
  500.             else
  501.                 ReleaseResource(dcodHList[index]);
  502.         }
  503.     if(!detach)
  504.         DisposPtr(dcodHList);
  505. }
  506.