[comp.sys.mac.programmer] How do I install a driver with an INIT?

stoms@castor.ncgia.ucsb.edu (David Stoms) (05/31/90)

A while back I remember a lengthly discussion of the installation of
drivers during start up. I need to install a driver, like ATM, with
an INIT. Could someone mail or post a summery or opinion of how this
should be done? Specifically, what is the algorithm to determine in
which slot to install the driver into the Unit Table and once the
slot is found, how to install it.

Thanks, Josh.

jholt@adobe.COM (Joe Holt) (06/01/90)

Newsgroups: comp.sys.mac.programmer
Subject: Re: How do I install a driver with an INIT?
References: <5560@hub.ucsb.edu>
Reply-To: jholt@adobe.com (Joe Holt)
Organization: Adobe Systems Incorporated, Mountain View
Keywords: INITs driver

Here's a small code resource INIT I use to open a driver at startup time.
I write the guts of my "INIT" as a driver, then paste this resource into
it, and I'm off.  With Think C, it even handles multi-segmented drivers.
If you have any questions, just ask.

-------- CUT HERE --------

/**

  OPEN DRIVER INIT

  Think C 4.0

  This bit of code should be compiled as a Code Resource, Type INIT, ID 0 (or
  whatever you like).  Change the name DRIVER_NAME to the name of the driver
  you want opened at start up.  Place this compiled INIT resource in the
  driver and change the driver's file type to INIT.

  When this starts up, it finds an empty slot in the driver unit table and
  sticks your driver there.  It then opens your driver.  You should write the
  driver to handle whatever ref num it's assigned.

 **/


/**--------------------------------------------------------------------------
 **
 **    Compilation Flags
 **
 **/

/**

  MULTI_SEGMENT generates code which is needed to init a multi-segmented
  driver.  Single-segment drivers can be inited also, so there is no logical
  requirement to ever turn this off, except where code size is a concern.

 **/

#define MULTI_SEGMENT    1


/**--------------------------------------------------------------------------
 **
 **    Include Files
 **
 **/

    /* none */


/**--------------------------------------------------------------------------
 **
 **    Private Macros
 **
 **/

/**

  UNIT_ENTRIES_NEEDED and FIRST_POSSIBLE_UNIT are used when determining the
  driver reference number for your driver.  This assigns the driver reference
  number dynamically, looking at FIRST_POSSIBLE_UNIT and on up for an unused
  number.  It increases the unit table size to UNIT_ENTRIES_NEEDED if
  there aren't that many unit numbers.  This occurs on Mac Pluses and Mac SEs
  with pre-System 6.0, where the unit table defaults to forty-eight entries,
  which doesn't leave any room for custom drivers like ours.

**/

#define UNIT_ENTRIES_NEEDED     (64)
#define FIRST_POSSIBLE_UNIT     (48)

#define DRIVER_NAME             "\p.your name here"


/**--------------------------------------------------------------------------
 **
 **    Private Functions
 **
 **/

int main(void);

main()
{
    static char     driverName[] = DRIVER_NAME;
    int             theID;
    IOParam         ioPB;

    asm {
            movem.l D3-D4/A2-A4, -(A7)
            movea.l A0, A4


/**

  Change the resource attributes of our DRVR so that it will be loaded into
  the System Heap and locked.

 **/

            clr.b   -(A7)
            _SetResLoad

            clr.l   -(A7)
            move.l  #'DRVR', -(A7)
            pea     driverName
            _GetNamedResource
            move.l  (A7)+, D3
            beq     @abort

            move.l  D3, -(A7)
            move.w  #resSysHeap + resLocked, -(A7)
            _SetResAttrs
            move.l  D3, -(A7)     ; so that the res handle will be in SysHeap!
            _ReleaseResource

            move.b  #1, -(A7)
            _SetResLoad


/**

  Pick an unused driver reference num for our DRVR and renumber the resource
  to use this new reference number.  We first increase the number of entries
  in the unit table if less than UNIT_ENTRIES_NEEDED, then begin looking at
  FIRST_POSSIBLE_UNIT.

 **/

            clr.l   -(A7)
            move.l  #'DRVR', -(A7)
            pea     driverName
            _GetNamedResource
            move.l  (A7)+, D3
            beq     @abort

            move.l  D3, A3
            move.l  A3, -(A7)
            _DetachResource
            move.w  #UNIT_ENTRIES_NEEDED, D1
            sub.w   UnitNtryCnt, D1
            ble.s   @1

            bsr     @updrivers
            bne     @abort

@1:         movea.l UTableBase, A1
            move.w  #FIRST_POSSIBLE_UNIT * 4, D4
            move.w  #FIRST_POSSIBLE_UNIT, D3
@2:         cmp.w   UnitNtryCnt, D3
            bgt     @abort

            tst.l   0(A1, D4.w)
            beq.s   @3

            addq.w  #4, D4
            addq.w  #1, D3
            bra.s   @2

@3:         move.w  D3, D0
            not.w   D0
            movea.l (A3), A0
            dc.w    0xA43D              ; _DrvrInstall 4
            bne     @abort

            movea.l UTableBase, A1
            movea.l 0(A1, D4.w), A0
            _HLock
            movea.l (A0), A2
            move.l  A3, (A2)
            movea.l (A3), A3
            move.w  (A3), 4(A2)
            bset    #6, 5(A2)


/**

  Now set the resources which THINK C uses for drivers to load into the System
  Heap as locked, also.  We especially want to lock down any DCOD resources
  because the THINK C segment loader does a MoveHHi() on em when first loaded,
  which is not a good idea in the System Heap at INIT time.

 **/

            clr.b   -(A7)
            _SetResLoad

            clr.l   -(A7)
            move.l  #'DATA', -(A7)
            move.w  #1, -(A7)
            _Get1IndResource
            move.l  (A7)+, D3
            beq     @abort

            move.l  D3, -(A7)
            move.w  0x18(A2), D0
            not.w   D0
            lsl.w   #5, D0
            or.w    #0xC000, D0             ; DATA resource is always ID 0
            move.w  D0, -(A7)
            clr.l   -(A7)
            _SetResInfo
            move.l  D3, -(A7)
            move.w  #resSysHeap + resLocked, -(A7)
            _SetResAttrs
            move.l  D3, -(A7)
            _ReleaseResource


#if MULTI_SEGMENT

            subq.w  #2, A7
            move.l  #'DCOD', -(A7)
            _Count1Resources
            move.w  (A7)+, D4
            beq.s   @DCODout

DCODtop:    clr.l   -(A7)
            move.l  #'DCOD', -(A7)
            move.w  D4, -(A7)
            _Get1IndResource
            move.l  (A7)+, D3
            beq     @abort

            move.l  D3, -(A7)
            pea     theID
            clr.l   -(A7)
            clr.l   -(A7)
            _GetResInfo

            move.l  D3, -(A7)
            move.w  0x18(A2), D0
            not.w   D0
            lsl.w   #5, D0
            move.w  theID, D1
            and.w   #0xF01F, D1
            add.w   D1, D0
            move.w  D0, -(A7)
            clr.l   -(A7)
            _SetResInfo
            move.l  D3, -(A7)
            move.w  #resSysHeap + resLocked, -(A7)
            _SetResAttrs
            move.l  D3, -(A7)
            _ReleaseResource
            subq.w  #1, D4
            bne.s   @DCODtop

#endif    /* if MULTI_SEGMENT */

DCODout:    move.b  #1, -(A7)
            _SetResLoad

            bra.s   @open


;**
;
;    Increase the number of available entries in the unit table.
;
;**

@updrivers: move.w  UnitNtryCnt, D0
            add.w   D1, D0
            mulu    #4, D0
            _NewPtr SYS+CLEAR
            bne.s   @9

            move    SR, -(A7)
            move    #0x2600, SR
            movea.l A0, A1
            movea.l UTableBase, A0
            move.w  UnitNtryCnt, D0
            mulu    #4, D0
            _BlockMove
            _DisposPtr
            move.l  A1, UTableBase
            add.w   D1, UnitNtryCnt
            move    (A7)+, SR
            moveq   #0, D0
@9:         rts
    }
open:
    ioPB.ioNamePtr = (StringPtr)driverName;
    ioPB.ioPermssn = 0;
    PBOpen(&ioPB, FALSE);
abort:
    asm {
            movem.l (A7)+, D3-D4/A2-A4
    }
}