;       SCCSID = @(#)smrdelcb.asm	6.5 92/01/27
PAGE 60,132                             ;
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;**************************************************************************
;
; Source File Name:     SMRDELCB.ASM
;
; Subroutine Name:      DOSSMDELSGCB
;
; Descriptive Name:     Delete screen group queue element from the
;                       active screen group queue
;
; Function:     Relinks the active screen group queue to eliminate
;               the specified screen group from the queue.
;
; Notes:
;      Dependencies:    The active screen group queue should never
;                       be empty.
;
;                       The queue must be protected by a RAM
;                       semaphore from the calling subroutine.
;
;                       Parent screen groups must be marked non-
;                       parent prior to calling this procedure.
;
;       Restrictions:   None
;
; Change History:
;   @@A2  02/15/89  PTR B788085 Give foreground priority to VDM
;                               made windowed from fullscreen.
;   @CJ2  02/26/90  PTM B711664 Reset BackRelative when child process dies
;   @TL7  04/05/90  PTR B712376 Enable for MMIO
;   @MHW  09/13/90  PTR B715818 In-line performance (MMIO) hooks
;   CJ26  05/12/91  PTR B722846 Free memory allocated for Cwait thread stack.
;   CJ33  06/10/91  PTR B723808 Deallocate memory allcoated in subsystems.
;   @GDW  08/26/91  PTR B725436 Fix to allow semaphore loop on INTERUPT
;   CJ52  01/27/92  PTR B731604 Don't reuse last SG# freed for next SG#.
;
; Entry Point:
;       Linkage:  EXTRN DOSSMDELSGCB : NEAR
;                       CALL  DOSSMDELSGCB
;
; Inputs:
;       DX      SGID        Screen group ID to be deleted
;       ES:DI   DelSGCB     Address of element to delete from queue
;       DS      RDATA       Queue header information
;
; Exit Normal:
;       AX      ReturnCode Value = 0, Screen group deleted from queue
;
; Exit Errors:
;       AX      ReturnCode error_smg_invalid_session_id
;
; Effects:      All other registers preserved.
;
; Internal References:
;          Routines:
;                       DOSSMFREESGID
;
; External References:
;          Routines:
;
;**************************************************************************
ifdef I1
;
;
;   If passed in ID = ID in SGCB
;     DOSFSRAMSEMREQUEST (SGCB_QueueRamSem)
;
;     Previous_SGCB.Next <-- Deleted_SGCB.Next
;     Next_SGCB.Previous <-- Deleted_SGCB.Previous
;
;     If Deleted SGCB = bottomost
;       Bottommost = Previous SGCB
;     EndIf
;
;     If Deleted SGCB = topmost
;       Topmost = Deletet SGCB.Next
;       Indicate Topmost by deletion, must switch
;     EndIf
;
;     If DelQueue = Lastelement
;       LastElement = PrevQueue
;     EndIf
;
;     DOSFSRAMSEMCLEAR (SGCB_QueueRamSem)
;     If Child screen group
;       Find parent and fix up their SGCB
;       DOSSMGETSGCB (Parent's SGID)
;
;       If Deleting Parent's FirstChild
;          Parent.1st_Child = Deleted_SGCB.Relative
;         If More children?
;           SGCB_FirstChild = 0
;           No more children, not a parent!
;         EndIf
;
;       ElseIf SGCB_BackRelative <> 0
;         DOSSMGETSGCB (BackRelative)
;         Some_SGCB.Relative <-- Delted_SGCB.Relative
;       EndIf
;     EndIf
;
;     DOSFSRAMSEMREQUEST (SGCB_QueueRamSem)
;     DOSSMFREESGID                     ; Make screen group ID available
;     DOSSMFREEMEM                      ; Free the SGCBs memory
;
;     Clear out the SGCB Address Array
;     Clear out the SGCB PID Array
;
;     CALL DOSFSRAMSEMCLEAR (SGCB_QueueRamSem)
;
;   Else
;     RC = Error_SMG_Invalid_Session_ID
;   EndIf
;**************************************************************************
else

.386C
    EXTRN BottomMost         : DWORD
    EXTRN LastElement        : DWORD
    EXTRN TopMost            : DWORD
    EXTRN SGCB_Array         : DWORD
    EXTRN SGCB_PIDArray      : DWORD
    EXTRN SGCB_QueueRamSem   : DWORD    ; Address of the semaphore
    EXTRN LastSGFreed        : WORD     ; Last SG # freed               ;CJ52

    EXTRN DOSSMFREESGID      : NEAR     ; Free screen group number
    EXTRN DOSSMFREEMEM       : FAR
    EXTRN DOSSMGETSGCB       : FAR
    EXTRN DOSFSRAMSEMREQUEST : FAR
    EXTRN DOSFSRAMSEMCLEAR   : FAR
.xlist
    INCLUDE SMRSGCB.INC
    INCLUDE SMRRDATA.INC
    INCLUDE INFOSEG.INC                 ; needed by smmmpha.inc         ;MHW
    INCLUDE SMMMPHA.INC                 ; Performance hook macros       ;MHW
.xcref
    INCLUDE STRUC.INC
    INCLUDE ERROR2.INC
.cref
.list

CODE SEGMENT WORD PUBLIC 'CODE' USE16
    ASSUME CS:CODE,DS:RDATA,SS:NOTHING,ES:NOTHING


    PUBLIC DOSSMDELSGCB
DOSSMDELSGCB PROC NEAR

    Local_Bytes  EQU 4
    Local_Var1   EQU SS:[BP][-2]        ; Local variable on stack
    Local_Var2   EQU SS:[BP][-4]        ; Local variable on stack

    ENTER Local_Bytes,0

    PUSH SI                             ; Save registers
    PUSH DI
    PUSH BX
    PUSH GS

    MMPHPreDOSSMDelSGQueue              ; Performance Hook (8107h)      ;MHW

;   ********************************************************************
;   *  Verify requested queue element has correct screen group ID and  *
;   *  modify links to remove the queue element from the active queue. *
;   ********************************************************************
    .IF  < ES:[DI].SGCB_ID e DX > NEAR  ; Verify correct queue specified

;     ************************************
;     *  Grab the SGCB Queue semaphore.  *
;     ************************************
      .repeat                                                           ;@GDW
;CJ10   LGS  BX, SGCB_QueueRamSem
        PUSH SGCB_QueueRamSem                                           ;CJ10
;CJ10   PUSH BX
        PUSH DWORD PTR -1                                               ;CJ10
;CJ10   PUSH -1
        CALL DOSFSRAMSEMREQUEST
      .until  <ax ne ERROR_INTERRUPT>                                   ;@GDW

      LFS  SI, ES:[DI].SGCB_Next
      LGS  BX, ES:[DI].SGCB_Previous
;     ****************************************
;     *  ES:[DI] --> SGCB to be deleted      *
;     *  FS:[SI] --> SGCB Next in queue      *
;     *  GS:[BX] --> SGCB Previous in queue  *
;     ****************************************

;     **********************************************
;     *  Previous_SGCB.Next <-- Deleted_SGCB.Next  *
;     **********************************************
      MOV  WORD PTR GS:[BX].SGCB_Next[2], FS
      MOV  WORD PTR GS:[BX].SGCB_Next, SI

;     **************************************************
;     *  Next_SGCB.Previous <-- Deleted_SGCB.Previous  *
;     **************************************************
      MOV  WORD PTR FS:[SI].SGCB_Previous[2], GS
      MOV  WORD PTR FS:[SI].SGCB_Previous, BX

;     ***********************************************
;     *  Adjust top most and bottom most pointers.  *
;     ***********************************************
;     *******************************
;     *  EAX <-- @ of Deleted SGCB  *
;     *******************************
      MOV  AX, ES                       ; Offset
      SHL  EAX, 16                      ; Move to high word of EAX
      MOV  AX, DI                       ; Selector

      .IF  < BottomMost eq EAX >        ; Deleted SGCB = bottomost?
        MOV  WORD PTR BottomMost[2], GS ; Bottommost = Previous SGCB
        MOV  WORD PTR BottomMost, BX
      .ENDIF

      .IF  < TopMost eq EAX >           ; Deleted SGCB = topmost
        MOV  WORD PTR TopMost[2], FS    ; Topmost = Deletet SGCB.Next
        MOV  WORD PTR TopMost, SI
        OR   FS:[SI].SGCB_Flags, 4      ; Topmost by deletion, must switch
      .ENDIF

      .IF  < LastElement eq EAX >        ; DelQueue = Lastelement
        MOV  WORD PTR LastElement[2], GS ; LastElem.=PrevQueue
        MOV  WORD PTR LastElement, BX    ; LastElem.=PrevQueue
      .ENDIF

;     ************************************
;     *  Free the SGCB Queue semaphore.  *
;     ************************************
;CJ10 LGS  BX, SGCB_QueueRamSem
;CJ10 PUSH GS
;CJ10 PUSH BX
;CJ10 CALL DOSFSRAMSEMCLEAR

      TEST ES:[DI].SGCB_FamilyType, Child ; Child screen group?
      .IF  <nz>                         ; Yes
;       ***************************************
;       *  Find parent and fix up their SGCB  *
;       ***************************************
        MOV  BX, ES:[DI].SGCB_Relative  ; Save Deleted_SGCB.Relative

        LEA  SI, Local_Var2             ; @ return @ of SGCB
        PUSH SS
        PUSH SI
        PUSH ES:[DI].SGCB_ParentSID     ; Parent's SGID
        PUSH SGID_Lookup + 8000H        ; Look up SGID not PID and      ;CJ10
        CALL DOSSMGETSGCB               ;   don't serialize QueueRamSem

        LFS  SI, Local_Var2             ; FS:[SI] --> Parent's SGCB
;       *****************************************************
;       *  If 1st and only child, make parent a non parent  *
;       *  Deleted_SGCB.Relative = Deleted_SGCB.Parent if   *
;       *  it is the one and only child                     *
;       *  BX = Deleted_SGCB.Relative                       *
;       *****************************************************
        .IF  < <BYTE PTR FS:[SI].SGCB_FirstChild> eq DL >  ; First child?  @@A2
          MOV  FS:[SI].SGCB_FirstChild, BX      ; Parent.1st_Child = Deleted_SGCB.Relative
          .IF  < ES:[DI].SGCB_ParentSID eq BX > ; More children?
            MOV  FS:[SI].SGCB_FirstChild, 0     ; No.
            AND  FS:[SI].SGCB_FamilyType, NOT parent ; No more children, not a parent!
          .ENDIF

        .ELSEIF < ES:[DI].SGCB_BackRelative ne 0 > ; If BackRelative exists
          LEA  SI, Local_Var2            ; @ return @ of SGCB
          PUSH SS
          PUSH SI
          PUSH ES:[DI].SGCB_BackRelative ; Get the next SGCB in family
          PUSH SGID_Lookup + 8000H       ; Look up SGID not PID and     ;CJ10
          CALL DOSSMGETSGCB              ;   don't serialize QueueRamSem

          LFS  SI, Local_Var2            ; FS:[SI] --> BackRelative's SGCB
          MOV  FS:[SI].SGCB_Relative, BX ; Some_SGCB.Relative <-- Delted_SGCB.Relative

;         *****************************************************
;         *  If parent ne relative (not last in chain), make  *
;         *  [Deleted_SGCB.Relative].BackRelative =           *
;         *  Deleted_SGCB.BackRelative                    @CJ2*
;         *****************************************************
          .IF  < ES:[DI].SGCB_ParentSID ne BX >                            ;@CJ2
            LEA  SI, Local_Var2            ; @ return @ of SGCB            ;@CJ2
            PUSH SS                                                        ;@CJ2
            PUSH SI                                                        ;@CJ2
            PUSH ES:[DI].SGCB_Relative     ; Get the next SGCB in family   ;@CJ2
            PUSH SGID_Lookup + 8000H       ; Look up SGID not PID and      ;@CJ2
            CALL DOSSMGETSGCB              ;   don't serialize QueueRamSem ;@CJ2

            LFS  SI, Local_Var2                 ; FS:[SI] --> Relative SGCB @CJ2
            MOV  BX, ES:[DI].SGCB_BackRelative  ; Save Deleted_SGCB.BackRel @CJ2
            MOV  FS:[SI].SGCB_BackRelative, BX  ; Rel_SGCB.BackRel <-- Delted_SGCB.BackRel @CJ2
          .ENDIF                                                           ;@CJ2

        .ENDIF
      .ENDIF

;     ************************************
;     *  Grab the SGCB Queue semaphore.  *
;     ************************************
;CJ10 LGS  BX, SGCB_QueueRamSem
;CJ10 PUSH GS
;CJ10 PUSH BX
;CJ10 PUSH -1
;CJ10 PUSH -1
;CJ10 CALL DOSFSRAMSEMREQUEST

;     ***************************************************************
;     *  Clean up SGCB Control Information                          *
;     *                                                             *
;     *  Don't free up SG# now - free it up when the next session   *     ;CJ52
;     *  goes away.  This way we won't reuse the same SG# right     *     ;CJ52
;     *  away.  This caused problems when we would reuse a SG#      *     ;CJ52
;     *  that just died because the Shell had not been notified it  *     ;CJ52
;     *  was gone yet and thought the new SG was still the old one. *     ;CJ52
;     ***************************************************************     ;CJ52
      .IF <LastSGFreed ne 0>            ; If SG died previously then      ;CJ52
        CALL  DOSSMFREESGID             ; free up it's SG# now            ;CJ52
      .ENDIF                                                              ;CJ52
      MOV  LastSGFreed, DX              ; Store this SG# to be freed later;CJ52
      XOR  EAX, EAX                     ; Successful return code

;     ****************************
;     *  Free The SGCB's Memory  *
;     ****************************
      MOV  BX, DX                       ; Use BX as an index
      XOR  BH, BH                       ; Clear Session Type Byte
      SHL  BX, 3                        ; x 8 for 2 addresses (4 words) ;CJ26
      LFS  SI, SGCB_Array               ; FS:[SI] --> @ of SGCB Array
      LFS  SI, FS:[SI]                  ; FS:[SI] --> SGCB Array
      ADD  SI, 2                        ; Point past reserved word (seg. size)
      ADD  SI, BX                       ; Add in offset to correct DWORD

;     ********************************************                      ;CJ33
;     *  Free memory allocated by the subsystems *                      ;CJ33
;     *  VIOcalls, KBDcalls, MOUcalls, BMScalls  *                      ;CJ33
;     ********************************************                      ;CJ33
      LGS  DI, DWORD PTR FS:[SI]                ; Get SGCB address      ;CJ33
      .IF  < GS:[DI].VIO_Avscbptr ne 0 >        ; If ptr nonzero        ;CJ33
        PUSH  GS:[DI].VIO_Avscbptr                                      ;CJ33
        CALL DOSSMFREEMEM                       ; Free the memory!      ;CJ33
      .ENDIF                                                            ;CJ33

      .IF  < GS:[DI].KBD_AKSCB ne 0 >           ; If ptr nonzero        ;CJ33
        PUSH  GS:[DI].KBD_AKSCB                                         ;CJ33
        CALL DOSSMFREEMEM                       ; Free the memory!      ;CJ33
      .ENDIF                                                            ;CJ33

      .IF  < GS:[DI].MOU_AMSCB ne 0 >           ; If ptr nonzero        ;CJ33
        PUSH  GS:[DI].MOU_AMSCB                                         ;CJ33
        CALL DOSSMFREEMEM                       ; Free the memory!      ;CJ33
      .ENDIF                                                            ;CJ33

      .IF  < GS:[DI].BMS_TEXTCB ne 0 >          ; If ptr nonzero        ;CJ33
        PUSH  GS:[DI].BMS_TEXTCB                                        ;CJ33
        CALL DOSSMFREEMEM                       ; Free the memory!      ;CJ33
      .ENDIF                                                            ;CJ33

      PUSH DWORD PTR FS:[SI]            ; Offset of SGCB Address        ;CJ10
      CALL DOSSMFREEMEM                 ; Free the memory!

;     **************************************
;     *  Clear out the SGCB Address Array  *
;     **************************************
      MOV  FS:[SI], EAX                 ; Zero out Array Address

;     **********************************
;     *  Clear out the SGCB PID Array  *
;     **********************************
      SHR  BX, 2                        ; ID x 2 for WORD offsets       ;CJ26
      LFS  SI, SGCB_PIDArray            ; FS:[SI] --> @ of PID Array
      LFS  SI, FS:[SI]                  ; FS:[SI] --> PID Array
      ADD  SI, 2                        ; Point past reserved word (seg. size)
      ADD  SI, BX                       ; Add in offset to correct WORD
      MOV  FS:[SI], AX                  ; Zero out PID

;     ************************************
;     *  Free the SGCB Queue semaphore.  *
;     ************************************
      PUSH AX                           ; Save RC
;CJ10 LGS  BX, SGCB_QueueRamSem
      PUSH SGCB_QueueRamSem                                             ;CJ10
;CJ10 PUSH BX
      CALL DOSFSRAMSEMCLEAR

      POP  AX                           ; Restore RC
    .ELSE
      MOV  AX, Error_SMG_Invalid_Session_ID ; Invalid SG
    .ENDIF

    POP  GS
    POP  BX                             ; Restore Registers
    POP  DI
    POP  SI

    MMPHPostDOSSMDelSGQueue             ; Performance Hook (8187h)      ;MHW

    LEAVE
    RET                                 ; Return to caller

DOSSMDELSGCB ENDP

CODE ENDS
endif
    END
