INITInstall.a

;------------------------------------------------------------------------------
;
;   Apple Macintosh Developer Technical Support
;
;   Sample Control Panel Device and INIT Combination
;
;   Program:    INIT - CDEV
;   File:       INITInstall - Asm source
;
;   Copyright © 1990 Apple Computer, Inc.
;   All rights reserved.
;
;------------------------------------------------------------------------------
 
                include 'ToolEqu.a'
                include 'SysEqu.a'
                include 'QuickEqu.a'
                include 'Traps.a'
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;   These are the IDs for the icons used by ShowINIT. ShowINIT is a really
;   cool hack by Paul Mercer that displays those icons across the bottom of
;   your screen when you boot up. You can choose what icon to show up, based
;   on how the installation went. If the installation went OK, we show the
;   INIT's icon. Because this is also a CDEV, the Icon resource ID is -4064
;   (per Inside Mac on Control Panels). If the installation didn't work, we
;   show a version of the icon with an X through it. The ID for this icon
;   doesn't have any restrictions on it, so we just use the ID of 128 that
;   ResEdit gave us.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
IconID          EQU     -4064
BadIconID       EQU     128
 
SystemTaskTrap  EQU     $A9B4                   ; trap number of routine to patch
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;   MACRO
;       ChangeTrap  &trap, &type, &newAddress, &oldAddressStore
;
;       Macro used to change the trap address and optionally save the old
;       routine's address. You pass in the trap number of the trap you want
;       to patch, the type of the trap (newTool or newOS), the address of the
;       routine to store in the trap table, and a pointer to a memory location
;       that will hold the old address. If &oldAddressStore is some value other
;       than NIL, this macro will get the old trap's address and save it there.
;
;       NOTE:   This macro translates &newAddress and &oldAddressStore into
;               their new locations. To do this, it relies on A1 pointing to
;               the block in the system heap that holds the patch, and for
;               FirstResByte to be defined.
;
;   Input:
;       A1: address of patch code in system heap
;
;   Output:
;       oldAddressStore: address of old trap routine
;       D0, A0 are destroyed.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
            MACRO
            ChangeTrap  &trap,&type,&newAddress,&oldAddressStore
 
            IF (&oldAddressStore ­ 'NIL') THEN
 
                move.w  #&trap,D0
                _GetTrapAddress ,&type
                move.l  A0,&oldAddressStore-FirstResByte(A1)
 
            ENDIF
 
                move.w  #&trap,D0
                lea     &newAddress-FirstResByte(A1),A0
                _SetTrapAddress ,&type
 
            ENDM
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;   Generic install routine. This is the code that gets executed when INIT 31
;   calls our INIT. The first thing we do is check to see if any of the scare
;   buttons are being pressed. If the user is holding down the shift key or
;   mouse button, then don't install, and show the unhappy icon. If not, then
;   find out how large our resident code will be, and get a non-relocatable
;   block of memory in the heap that size by calling _NewPtr. We determine the
;   size of our resident code by getting the size of our INIT, and subtracting
;   everything that comes before "FirstResByte".
;
;   If we can't get a block of memory that size, we blow out with an unhappy
;   icon. Otherwise, we call BlockMove to move our resident code into the
;   System heap. Then we call a C routine that does some more installation
;   stuff. In our case, we want to make sure that we can make PPCToolbox
;   calls. If there are any errors, we de-allocate our memory and exit with
;   an unhappy icon. If everything went OK in the C world, we patch in our
;   trap routine, and display a happy icon.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
INITInstall     PROC    EXPORT
                IMPORT  SHOWINIT
                IMPORT  a_SystemTask:CODE
                IMPORT  c_Install:CODE
                IMPORT  oldSystemTask:DATA
 
FirstResByte    EQU     a_SystemTask            ; first resident byte
ShiftKey        EQU     56                      ; key code for Shift key
 
                tst.b   MBState                 ; don't install if mouse button is down
                bpl.s   NoInstall               ;
 
                btst    #(ShiftKey//8),KeyMap+(ShiftKey/8)  ; or if shift key is down
                bne.s   NoInstall               ;
 
                lea     INITInstall,A0          ; get location of the INIT
                _RecoverHandle                  ; get our handle
                _GetHandleSize                  ; find out how large we are in D0
                lea     FirstResByte,A0         ; first byte of resident code
                lea     INITInstall,A1          ; first byte of header
                sub.l   A1,A0                   ; size of header to be discarded
                sub.l   A0,D0                   ; remove header from INIT to get resident size
                move.l  D0,D1                   ; save size later for BlockMove
 
                _NewPtr ,sys                    ; make the resident block in System heap
                tst.w   d0                      ; check for getting an error
                bne.s   NoInstall               ; got one, blow out
                move.l  A0,A1                   ; save new location for _BlockMove
 
                lea     FirstResByte,A0         ; set A0 to source
                move.l  D1,D0                   ; set D0 to size
                _BlockMove
 
                move.l  A1,-(sp)                ; save A1 for ChangeTrap call
                lea     c_Install-FirstResByte(A1),A0   ; set to call C installation code in its new location
                jsr     (A0)                    ; call it
                move.l  (sp)+,A1                ; restore A1 for ChangeTrap call
                tst.w   D0                      ; any errors?
                bne.s   RemoveNoInstall         ; yes, so de-allocate our memory
 
                ;
                ; note: this macro destroys D0, A0
                ;       and relies on A1 being set.
                ;
 
                ChangeTrap  SystemTaskTrap, newTool, a_SystemTask, oldSystemTask
 
ExitInit
                move.w  #IconID,-(sp)           ; ICN# ID of happy icon
                bra.s   ShowTheIcon             ;
 
RemoveNoInstall
                move.l  A1,A0                   ; dispose of our memory in case of error
                _DisposPtr
NoInstall
                move.w  #BadIconID,-(sp)        ; ICN# ID of unhappy icon
ShowTheIcon
                move.w  #-1,-(sp)               ; use default moveX
                bsr     SHOWINIT                ; draw the icon
                rts                             ; return to INIT 31
 
                ENDP
                END